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