1 /* $NetBSD: imc.c,v 1.28 2007/02/19 20:14:30 rumble 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.28 2007/02/19 20:14:30 rumble 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 #include <sgimips/dev/imcvar.h> 46 47 #include <sgimips/gio/giovar.h> 48 49 #include "locators.h" 50 51 struct imc_softc { 52 struct device sc_dev; 53 54 bus_space_tag_t iot; 55 bus_space_handle_t ioh; 56 57 int eisa_present; 58 }; 59 60 static int imc_match(struct device *, struct cfdata *, void *); 61 static void imc_attach(struct device *, struct device *, void *); 62 static int imc_print(void *, const char *); 63 static void imc_bus_reset(void); 64 static void imc_bus_error(u_int32_t, u_int32_t, u_int32_t, u_int32_t); 65 static void imc_watchdog_reset(void); 66 static void imc_watchdog_disable(void); 67 static void imc_watchdog_enable(void); 68 69 CFATTACH_DECL(imc, sizeof(struct imc_softc), 70 imc_match, imc_attach, NULL, NULL); 71 72 struct imc_attach_args { 73 const char* iaa_name; 74 75 bus_space_tag_t iaa_st; 76 bus_space_handle_t iaa_sh; 77 78 /* ? */ 79 long iaa_offset; 80 int iaa_intr; 81 #if 0 82 int iaa_stride; 83 #endif 84 }; 85 86 int imc_gio64_arb_config(int, uint32_t); 87 88 struct imc_softc isc; 89 90 static int 91 imc_match(struct device *parent, struct cfdata *match, void *aux) 92 { 93 94 if ( (mach_type == MACH_SGI_IP22) || (mach_type == MACH_SGI_IP20) ) 95 return (1); 96 97 return (0); 98 } 99 100 static void 101 imc_attach(struct device *parent, struct device *self, void *aux) 102 { 103 u_int32_t reg; 104 struct imc_attach_args iaa; 105 struct mainbus_attach_args *ma = aux; 106 u_int32_t sysid; 107 108 isc.iot = SGIMIPS_BUS_SPACE_HPC; 109 if (bus_space_map(isc.iot, ma->ma_addr, 0, 110 BUS_SPACE_MAP_LINEAR, &isc.ioh)) 111 panic("imc_attach: could not allocate memory\n"); 112 113 platform.bus_reset = imc_bus_reset; 114 platform.watchdog_reset = imc_watchdog_reset; 115 platform.watchdog_disable = imc_watchdog_disable; 116 platform.watchdog_enable = imc_watchdog_enable; 117 118 sysid = bus_space_read_4(isc.iot, isc.ioh, IMC_SYSID); 119 120 /* EISA exists on IP22 only */ 121 if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) 122 isc.eisa_present = (sysid & IMC_SYSID_HAVEISA); 123 else 124 isc.eisa_present = 0; 125 126 printf(": revision %d", (sysid & IMC_SYSID_REVMASK)); 127 128 if (isc.eisa_present) 129 printf(", EISA bus present"); 130 131 printf("\n"); 132 133 /* Clear CPU/GIO error status registers to clear any leftover bits. */ 134 imc_bus_reset(); 135 136 /* Hook the bus error handler into the ISR */ 137 platform.intr4 = imc_bus_error; 138 139 /* 140 * Enable parity reporting on GIO/main memory transactions. 141 * Disable parity checking on CPU bus transactions (as turning 142 * it on seems to cause spurious bus errors), but enable parity 143 * checking on CPU reads from main memory (note that this bit 144 * has the opposite sense... Turning it on turns the checks off!). 145 * Finally, turn on interrupt writes to the CPU from the MC. 146 */ 147 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 148 reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; 149 reg |= (IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR | IMC_CPUCTRL0_INTENA); 150 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 151 152 /* Setup the MC write buffer depth */ 153 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL1); 154 reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13; 155 156 /* 157 * Force endianness on the onboard HPC and both slots. 158 * This should be safe for Fullhouse, but leave it conditional 159 * for now. 160 */ 161 if (mach_type == MACH_SGI_IP20 || (mach_type == MACH_SGI_IP22 && 162 mach_subtype == MACH_SGI_IP22_GUINNESS)) { 163 reg |= IMC_CPUCTRL1_HPCFX; 164 reg |= IMC_CPUCTRL1_EXP0FX; 165 reg |= IMC_CPUCTRL1_EXP1FX; 166 reg &= ~IMC_CPUCTRL1_HPCLITTLE; 167 reg &= ~IMC_CPUCTRL1_EXP0LITTLE; 168 reg &= ~IMC_CPUCTRL1_EXP1LITTLE; 169 } 170 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL1, reg); 171 172 173 /* 174 * Set GIO64 arbitrator configuration register: 175 * 176 * Preserve PROM-set graphics-related bits, as they seem to depend 177 * on the graphics variant present and I'm not sure how to figure 178 * that out or 100% sure what the correct settings are for each. 179 */ 180 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_GIO64ARB); 181 reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST); 182 183 /* Rest of settings are machine/board dependant */ 184 if (mach_type == MACH_SGI_IP20) 185 { 186 reg |= IMC_GIO64ARB_ONEGIO; 187 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT); 188 reg |= (IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST); 189 reg &= ~(IMC_GIO64ARB_HPC64 | 190 IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 | 191 IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 | 192 IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE); 193 } 194 else 195 { 196 /* 197 * GIO64 invariant for all IP22 platforms: one GIO bus, 198 * HPC1 @ 64 199 */ 200 reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64; 201 202 switch (mach_subtype) { 203 case MACH_SGI_IP22_GUINNESS: 204 /* XXX is MST mutually exclusive? */ 205 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT); 206 reg |= (IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST); 207 208 /* EISA can bus-master, is 64-bit */ 209 reg |= (IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64); 210 break; 211 212 case MACH_SGI_IP22_FULLHOUSE: 213 /* 214 * All Fullhouse boards have a 64-bit HPC2 and pipelined 215 * EXP0 slot. 216 */ 217 reg |= (IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE); 218 219 if (mach_boardrev < 2) { 220 /* EXP0 realtime, EXP1 can master */ 221 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1MST); 222 } else { 223 /* EXP1 pipelined as well, EISA masters */ 224 reg |= (IMC_GIO64ARB_EXP1PIPE | IMC_GIO64ARB_EISAMST); 225 } 226 break; 227 } 228 } 229 230 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO64ARB, reg); 231 232 if (isc.eisa_present) { 233 #if notyet 234 memset(&iaa, 0, sizeof(iaa)); 235 236 config_found_ia(self, "eisabus", (void*)&iaa, eisabusprint); 237 #endif 238 } 239 240 memset(&iaa, 0, sizeof(iaa)); 241 242 config_found_ia(self, "giobus", (void*)&iaa, imc_print); 243 244 imc_watchdog_enable(); 245 } 246 247 248 static int 249 imc_print(void *aux, const char *name) 250 { 251 if (name) 252 aprint_normal("gio at %s", name); 253 254 return UNCONF; 255 } 256 257 static void 258 imc_bus_reset(void) 259 { 260 bus_space_write_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT, 0); 261 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT, 0); 262 } 263 264 static void 265 imc_bus_error(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending) 266 { 267 printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n", 268 bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT), 269 bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRADDR), 270 bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT), 271 bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRADDR) ); 272 imc_bus_reset(); 273 } 274 275 static void 276 imc_watchdog_reset(void) 277 { 278 bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0); 279 } 280 281 static void 282 imc_watchdog_disable(void) 283 { 284 u_int32_t reg; 285 286 bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0); 287 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 288 reg &= ~(IMC_CPUCTRL0_WDOG); 289 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 290 } 291 292 static void 293 imc_watchdog_enable(void) 294 { 295 u_int32_t reg; 296 297 /* enable watchdog and clear it */ 298 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 299 reg |= IMC_CPUCTRL0_WDOG; 300 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 301 imc_watchdog_reset(); 302 } 303 304 /* intended to be called from gio/gio.c only */ 305 int 306 imc_gio64_arb_config(int slot, uint32_t flags) 307 { 308 uint32_t reg; 309 310 /* GIO_SLOT_EXP1 is unusable on Fullhouse */ 311 if (slot == GIO_SLOT_EXP1 && mach_subtype == MACH_SGI_IP22_FULLHOUSE) 312 return (EINVAL); 313 314 /* GIO_SLOT_GFX is only usable on Fullhouse */ 315 if (slot == GIO_SLOT_GFX && mach_subtype != MACH_SGI_IP22_FULLHOUSE) 316 return (EINVAL); 317 318 /* GIO_SLOT_GFX is always pipelined */ 319 if (slot == GIO_SLOT_GFX && (flags & GIO_ARB_NOPIPE)) 320 return (EINVAL); 321 322 /* IP20 does not support pipelining (XXX what about Indy?) */ 323 if (((flags & GIO_ARB_PIPE) || (flags & GIO_ARB_NOPIPE)) && 324 mach_type == MACH_SGI_IP20) 325 return (EINVAL); 326 327 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_GIO64ARB); 328 329 if (flags & GIO_ARB_RT) { 330 if (slot == GIO_SLOT_EXP0) 331 reg |= IMC_GIO64ARB_EXP0RT; 332 else if (slot == GIO_SLOT_EXP1) 333 reg |= IMC_GIO64ARB_EXP1RT; 334 else if (slot == GIO_SLOT_GFX) 335 reg |= IMC_GIO64ARB_GRXRT; 336 } 337 338 if (flags & GIO_ARB_MST) { 339 if (slot == GIO_SLOT_EXP0) 340 reg |= IMC_GIO64ARB_EXP0MST; 341 else if (slot == GIO_SLOT_EXP1) 342 reg |= IMC_GIO64ARB_EXP1MST; 343 else if (slot == GIO_SLOT_GFX) 344 reg |= IMC_GIO64ARB_GRXMST; 345 } 346 347 if (flags & GIO_ARB_PIPE) { 348 if (slot == GIO_SLOT_EXP0) 349 reg |= IMC_GIO64ARB_EXP0PIPE; 350 else if (slot == GIO_SLOT_EXP1) 351 reg |= IMC_GIO64ARB_EXP1PIPE; 352 } 353 354 if (flags & GIO_ARB_LB) { 355 if (slot == GIO_SLOT_EXP0) 356 reg &= ~IMC_GIO64ARB_EXP0RT; 357 else if (slot == GIO_SLOT_EXP1) 358 reg &= ~IMC_GIO64ARB_EXP1RT; 359 else if (slot == GIO_SLOT_GFX) 360 reg &= ~IMC_GIO64ARB_GRXRT; 361 } 362 363 if (flags & GIO_ARB_SLV) { 364 if (slot == GIO_SLOT_EXP0) 365 reg &= ~IMC_GIO64ARB_EXP0MST; 366 else if (slot == GIO_SLOT_EXP1) 367 reg &= ~IMC_GIO64ARB_EXP1MST; 368 else if (slot == GIO_SLOT_GFX) 369 reg &= ~IMC_GIO64ARB_GRXMST; 370 } 371 372 if (flags & GIO_ARB_NOPIPE) { 373 if (slot == GIO_SLOT_EXP0) 374 reg &= ~IMC_GIO64ARB_EXP0PIPE; 375 else if (slot == GIO_SLOT_EXP1) 376 reg &= ~IMC_GIO64ARB_EXP1PIPE; 377 } 378 379 if (flags & GIO_ARB_32BIT) { 380 if (slot == GIO_SLOT_EXP0) 381 reg &= ~IMC_GIO64ARB_EXP064; 382 else if (slot == GIO_SLOT_EXP1) 383 reg &= ~IMC_GIO64ARB_EXP164; 384 } 385 386 if (flags & GIO_ARB_64BIT) { 387 if (slot == GIO_SLOT_EXP0) 388 reg |= IMC_GIO64ARB_EXP064; 389 else if (slot == GIO_SLOT_EXP1) 390 reg |= IMC_GIO64ARB_EXP164; 391 } 392 393 if (flags & GIO_ARB_HPC2_32BIT) 394 reg &= ~IMC_GIO64ARB_HPCEXP64; 395 396 if (flags & GIO_ARB_HPC2_64BIT) 397 reg |= IMC_GIO64ARB_HPCEXP64; 398 399 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO64ARB, reg); 400 401 return (0); 402 } 403 404 /* 405 * According to chapter 19 of the "IRIX Device Driver Programmer's Guide", 406 * some GIO devices, which do not drive all data lines, may cause false 407 * memory read parity errors on the SysAD bus. The workaround is to disable 408 * parity checking. 409 */ 410 void 411 imc_disable_sysad_parity() 412 { 413 uint32_t reg; 414 415 if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22) 416 return; 417 418 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 419 reg |= IMC_CPUCTRL0_NCHKMEMPAR; 420 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 421 } 422 423 void 424 imc_enable_sysad_parity() 425 { 426 uint32_t reg; 427 428 if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22) 429 return; 430 431 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 432 reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; 433 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 434 } 435 436 int 437 imc_is_sysad_parity_enabled() 438 { 439 uint32_t reg; 440 441 if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22) 442 return (0); 443 444 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 445 446 return (reg & IMC_CPUCTRL0_NCHKMEMPAR); 447 } 448