1 /* $NetBSD: imc.c,v 1.23 2004/09/29 03:11:28 sekiya Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Rafal K. Boni 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __KERNEL_RCSID(0, "$NetBSD: imc.c,v 1.23 2004/09/29 03:11:28 sekiya Exp $"); 32 33 #include <sys/param.h> 34 #include <sys/device.h> 35 #include <sys/systm.h> 36 37 #include <machine/cpu.h> 38 #include <machine/locore.h> 39 #include <machine/autoconf.h> 40 #include <machine/bus.h> 41 #include <machine/machtype.h> 42 #include <machine/sysconf.h> 43 44 #include <sgimips/dev/imcreg.h> 45 46 #include "locators.h" 47 48 struct imc_softc { 49 struct device sc_dev; 50 51 bus_space_tag_t iot; 52 bus_space_handle_t ioh; 53 54 int eisa_present; 55 }; 56 57 static int imc_match(struct device *, struct cfdata *, void *); 58 static void imc_attach(struct device *, struct device *, void *); 59 static int imc_print(void *, const char *); 60 static void imc_bus_reset(void); 61 static void imc_bus_error(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 62 static void imc_watchdog_reset(void); 63 static void imc_watchdog_disable(void); 64 static void imc_watchdog_enable(void); 65 66 CFATTACH_DECL(imc, sizeof(struct imc_softc), 67 imc_match, imc_attach, NULL, NULL); 68 69 struct imc_attach_args { 70 const char* iaa_name; 71 72 bus_space_tag_t iaa_st; 73 bus_space_handle_t iaa_sh; 74 75 /* ? */ 76 long iaa_offset; 77 int iaa_intr; 78 #if 0 79 int iaa_stride; 80 #endif 81 }; 82 83 struct imc_softc isc; 84 85 static int 86 imc_match(struct device *parent, struct cfdata *match, void *aux) 87 { 88 89 if ( (mach_type == MACH_SGI_IP22) || (mach_type == MACH_SGI_IP20) ) 90 return (1); 91 92 return (0); 93 } 94 95 static void 96 imc_attach(struct device *parent, struct device *self, void *aux) 97 { 98 u_int32_t reg; 99 struct imc_attach_args iaa; 100 struct mainbus_attach_args *ma = aux; 101 u_int32_t sysid; 102 103 isc.iot = SGIMIPS_BUS_SPACE_HPC; 104 if (bus_space_map(isc.iot, ma->ma_addr, 0, 105 BUS_SPACE_MAP_LINEAR, &isc.ioh)) 106 panic("imc_attach: could not allocate memory\n"); 107 108 platform.bus_reset = imc_bus_reset; 109 platform.watchdog_reset = imc_watchdog_reset; 110 platform.watchdog_disable = imc_watchdog_disable; 111 platform.watchdog_enable = imc_watchdog_enable; 112 113 sysid = bus_space_read_4(isc.iot, isc.ioh, IMC_SYSID); 114 115 /* EISA exists on IP22 only */ 116 if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) 117 isc.eisa_present = (sysid & IMC_SYSID_HAVEISA); 118 else 119 isc.eisa_present = 0; 120 121 printf(": revision %d", (sysid & IMC_SYSID_REVMASK)); 122 123 if (isc.eisa_present) 124 printf(", EISA bus present"); 125 126 printf("\n"); 127 128 /* Clear CPU/GIO error status registers to clear any leftover bits. */ 129 imc_bus_reset(); 130 131 /* Hook the bus error handler into the ISR */ 132 platform.intr4 = imc_bus_error; 133 134 /* 135 * Enable parity reporting on GIO/main memory transactions. 136 * Disable parity checking on CPU bus transactions (as turning 137 * it on seems to cause spurious bus errors), but enable parity 138 * checking on CPU reads from main memory (note that this bit 139 * has the opposite sense... Turning it on turns the checks off!). 140 * Finally, turn on interrupt writes to the CPU from the MC. 141 */ 142 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 143 reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; 144 reg |= (IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR | IMC_CPUCTRL0_INTENA); 145 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 146 147 /* Setup the MC write buffer depth */ 148 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL1); 149 reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13; 150 151 /* 152 * Force endianness on the onboard HPC and both slots. 153 * This should be safe for Fullhouse, but leave it conditional 154 * for now. 155 */ 156 if (mach_type == MACH_SGI_IP20 || (mach_type == MACH_SGI_IP22 && 157 mach_subtype == MACH_SGI_IP22_GUINESS)) { 158 reg |= IMC_CPUCTRL1_HPCFX; 159 reg |= IMC_CPUCTRL1_EXP0FX; 160 reg |= IMC_CPUCTRL1_EXP1FX; 161 reg &= ~IMC_CPUCTRL1_HPCLITTLE; 162 reg &= ~IMC_CPUCTRL1_EXP0LITTLE; 163 reg &= ~IMC_CPUCTRL1_EXP1LITTLE; 164 } 165 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL1, reg); 166 167 168 /* 169 * Set GIO64 arbitrator configuration register: 170 * 171 * Preserve PROM-set graphics-related bits, as they seem to depend 172 * on the graphics variant present and I'm not sure how to figure 173 * that out or 100% sure what the correct settings are for each. 174 */ 175 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_GIO64ARB); 176 reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST); 177 178 /* Rest of settings are machine/board dependant */ 179 if (mach_type == MACH_SGI_IP20) 180 { 181 reg |= IMC_GIO64ARB_ONEGIO; 182 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT); 183 reg |= (IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST); 184 reg &= ~(IMC_GIO64ARB_HPC64 | 185 IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 | 186 IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 | 187 IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE); 188 } 189 else 190 { 191 /* 192 * GIO64 invariant for all IP22 platforms: one GIO bus, 193 * HPC1 @ 64 194 */ 195 reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64; 196 197 switch (mach_subtype) { 198 case MACH_SGI_IP22_GUINESS: 199 /* XXX is MST mutually exclusive? */ 200 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT); 201 reg |= (IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST); 202 203 /* EISA can bus-master, is 64-bit */ 204 reg |= (IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64); 205 break; 206 207 case MACH_SGI_IP22_FULLHOUSE: 208 /* 209 * All Fullhouse boards have a 64-bit HPC2 and pipelined 210 * EXP0 slot. 211 */ 212 reg |= (IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE); 213 214 if (mach_boardrev < 2) { 215 /* EXP0 realtime, EXP1 can master */ 216 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1MST); 217 } else { 218 /* EXP1 pipelined as well, EISA masters */ 219 reg |= (IMC_GIO64ARB_EXP1PIPE | IMC_GIO64ARB_EISAMST); 220 } 221 break; 222 } 223 } 224 225 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO64ARB, reg); 226 227 if (isc.eisa_present) { 228 #if notyet 229 memset(&iaa, 0, sizeof(iaa)); 230 231 config_found_ia(self, "eisabus", (void*)&iaa, eisabusprint); 232 #endif 233 } 234 235 memset(&iaa, 0, sizeof(iaa)); 236 237 config_found_ia(self, "giobus", (void*)&iaa, imc_print); 238 239 imc_watchdog_enable(); 240 } 241 242 243 static int 244 imc_print(void *aux, const char *name) 245 { 246 if (name) 247 aprint_normal("gio at %s", name); 248 249 return UNCONF; 250 } 251 252 static void 253 imc_bus_reset(void) 254 { 255 bus_space_write_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT, 0); 256 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT, 0); 257 } 258 259 static void 260 imc_bus_error(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending) 261 { 262 printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n", 263 bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT), 264 bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRADDR), 265 bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT), 266 bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRADDR) ); 267 imc_bus_reset(); 268 } 269 270 static void 271 imc_watchdog_reset(void) 272 { 273 bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0); 274 } 275 276 static void 277 imc_watchdog_disable(void) 278 { 279 u_int32_t reg; 280 281 bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0); 282 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 283 reg &= ~(IMC_CPUCTRL0_WDOG); 284 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 285 } 286 287 static void 288 imc_watchdog_enable(void) 289 { 290 u_int32_t reg; 291 292 /* enable watchdog and clear it */ 293 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 294 reg |= IMC_CPUCTRL0_WDOG; 295 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 296 imc_watchdog_reset(); 297 } 298