1/* $NetBSD: imc.c,v 1.31 2011/06/30 20:09:35 wiz 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.31 2011/06/30 20:09:35 wiz 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 51struct 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 60static int imc_match(struct device *, struct cfdata *, void *); 61static void imc_attach(struct device *, struct device *, void *); 62static int imc_print(void *, const char *); 63static void imc_bus_reset(void); 64static void imc_bus_error(vaddr_t, uint32_t, uint32_t); 65static void imc_watchdog_reset(void); 66static void imc_watchdog_disable(void); 67static void imc_watchdog_enable(void); 68 69CFATTACH_DECL(imc, sizeof(struct imc_softc), 70 imc_match, imc_attach, NULL, NULL); 71 72struct 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 86int imc_gio64_arb_config(int, uint32_t); 87 88struct imc_softc isc; 89 90static int 91imc_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 100static void 101imc_attach(struct device *parent, struct device *self, void *aux) 102{ 103 uint32_t reg; 104 struct imc_attach_args iaa; 105 struct mainbus_attach_args *ma = aux; 106 uint32_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 dependent */ 184 if (mach_type == MACH_SGI_IP20) { 185 reg |= IMC_GIO64ARB_ONEGIO; 186 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT); 187 reg |= (IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST); 188 reg &= ~(IMC_GIO64ARB_HPC64 | 189 IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 | 190 IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 | 191 IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE); 192 } else { 193 /* 194 * GIO64 invariant for all IP22 platforms: one GIO bus, 195 * HPC1 @ 64 196 */ 197 reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64; 198 199 switch (mach_subtype) { 200 case MACH_SGI_IP22_GUINNESS: 201 /* XXX is MST mutually exclusive? */ 202 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT); 203 reg |= (IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST); 204 205 /* EISA can bus-master, is 64-bit */ 206 reg |= (IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64); 207 break; 208 209 case MACH_SGI_IP22_FULLHOUSE: 210 /* 211 * All Fullhouse boards have a 64-bit HPC2 and pipelined 212 * EXP0 slot. 213 */ 214 reg |= (IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE); 215 216 if (mach_boardrev < 2) { 217 /* EXP0 realtime, EXP1 can master */ 218 reg |= (IMC_GIO64ARB_EXP0RT | 219 IMC_GIO64ARB_EXP1MST); 220 } else { 221 /* EXP1 pipelined as well, EISA masters */ 222 reg |= (IMC_GIO64ARB_EXP1PIPE | 223 IMC_GIO64ARB_EISAMST); 224 } 225 break; 226 } 227 } 228 229 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO64ARB, reg); 230 231 if (isc.eisa_present) { 232#if notyet 233 memset(&iaa, 0, sizeof(iaa)); 234 235 config_found_ia(self, "eisabus", (void*)&iaa, eisabusprint); 236#endif 237 } 238 239 memset(&iaa, 0, sizeof(iaa)); 240 241 config_found_ia(self, "giobus", (void*)&iaa, imc_print); 242 243 imc_watchdog_enable(); 244} 245 246 247static int 248imc_print(void *aux, const char *name) 249{ 250 251 if (name) 252 aprint_normal("gio at %s", name); 253 254 return UNCONF; 255} 256 257static void 258imc_bus_reset(void) 259{ 260 261 bus_space_write_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT, 0); 262 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT, 0); 263} 264 265static void 266imc_bus_error(vaddr_t pc, uint32_t status, uint32_t ipending) 267{ 268 269 printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n", 270 bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT), 271 bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRADDR), 272 bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT), 273 bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRADDR) ); 274 imc_bus_reset(); 275} 276 277static void 278imc_watchdog_reset(void) 279{ 280 281 bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0); 282} 283 284static void 285imc_watchdog_disable(void) 286{ 287 uint32_t reg; 288 289 bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0); 290 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 291 reg &= ~(IMC_CPUCTRL0_WDOG); 292 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 293} 294 295static void 296imc_watchdog_enable(void) 297{ 298 uint32_t reg; 299 300 /* enable watchdog and clear it */ 301 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 302 reg |= IMC_CPUCTRL0_WDOG; 303 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 304 imc_watchdog_reset(); 305} 306 307/* intended to be called from gio/gio.c only */ 308int 309imc_gio64_arb_config(int slot, uint32_t flags) 310{ 311 uint32_t reg; 312 313 /* GIO_SLOT_EXP1 is unusable on Fullhouse */ 314 if (slot == GIO_SLOT_EXP1 && mach_subtype == MACH_SGI_IP22_FULLHOUSE) 315 return EINVAL; 316 317 /* GIO_SLOT_GFX is only usable on Fullhouse */ 318 if (slot == GIO_SLOT_GFX && mach_subtype != MACH_SGI_IP22_FULLHOUSE) 319 return EINVAL; 320 321 /* GIO_SLOT_GFX is always pipelined */ 322 if (slot == GIO_SLOT_GFX && (flags & GIO_ARB_NOPIPE)) 323 return EINVAL; 324 325 /* IP20 does not support pipelining (XXX what about Indy?) */ 326 if (((flags & GIO_ARB_PIPE) || (flags & GIO_ARB_NOPIPE)) && 327 mach_type == MACH_SGI_IP20) 328 return EINVAL; 329 330 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_GIO64ARB); 331 332 if (flags & GIO_ARB_RT) { 333 if (slot == GIO_SLOT_EXP0) 334 reg |= IMC_GIO64ARB_EXP0RT; 335 else if (slot == GIO_SLOT_EXP1) 336 reg |= IMC_GIO64ARB_EXP1RT; 337 else if (slot == GIO_SLOT_GFX) 338 reg |= IMC_GIO64ARB_GRXRT; 339 } 340 341 if (flags & GIO_ARB_MST) { 342 if (slot == GIO_SLOT_EXP0) 343 reg |= IMC_GIO64ARB_EXP0MST; 344 else if (slot == GIO_SLOT_EXP1) 345 reg |= IMC_GIO64ARB_EXP1MST; 346 else if (slot == GIO_SLOT_GFX) 347 reg |= IMC_GIO64ARB_GRXMST; 348 } 349 350 if (flags & GIO_ARB_PIPE) { 351 if (slot == GIO_SLOT_EXP0) 352 reg |= IMC_GIO64ARB_EXP0PIPE; 353 else if (slot == GIO_SLOT_EXP1) 354 reg |= IMC_GIO64ARB_EXP1PIPE; 355 } 356 357 if (flags & GIO_ARB_LB) { 358 if (slot == GIO_SLOT_EXP0) 359 reg &= ~IMC_GIO64ARB_EXP0RT; 360 else if (slot == GIO_SLOT_EXP1) 361 reg &= ~IMC_GIO64ARB_EXP1RT; 362 else if (slot == GIO_SLOT_GFX) 363 reg &= ~IMC_GIO64ARB_GRXRT; 364 } 365 366 if (flags & GIO_ARB_SLV) { 367 if (slot == GIO_SLOT_EXP0) 368 reg &= ~IMC_GIO64ARB_EXP0MST; 369 else if (slot == GIO_SLOT_EXP1) 370 reg &= ~IMC_GIO64ARB_EXP1MST; 371 else if (slot == GIO_SLOT_GFX) 372 reg &= ~IMC_GIO64ARB_GRXMST; 373 } 374 375 if (flags & GIO_ARB_NOPIPE) { 376 if (slot == GIO_SLOT_EXP0) 377 reg &= ~IMC_GIO64ARB_EXP0PIPE; 378 else if (slot == GIO_SLOT_EXP1) 379 reg &= ~IMC_GIO64ARB_EXP1PIPE; 380 } 381 382 if (flags & GIO_ARB_32BIT) { 383 if (slot == GIO_SLOT_EXP0) 384 reg &= ~IMC_GIO64ARB_EXP064; 385 else if (slot == GIO_SLOT_EXP1) 386 reg &= ~IMC_GIO64ARB_EXP164; 387 } 388 389 if (flags & GIO_ARB_64BIT) { 390 if (slot == GIO_SLOT_EXP0) 391 reg |= IMC_GIO64ARB_EXP064; 392 else if (slot == GIO_SLOT_EXP1) 393 reg |= IMC_GIO64ARB_EXP164; 394 } 395 396 if (flags & GIO_ARB_HPC2_32BIT) 397 reg &= ~IMC_GIO64ARB_HPCEXP64; 398 399 if (flags & GIO_ARB_HPC2_64BIT) 400 reg |= IMC_GIO64ARB_HPCEXP64; 401 402 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO64ARB, reg); 403 404 return 0; 405} 406 407/* 408 * According to chapter 19 of the "IRIX Device Driver Programmer's Guide", 409 * some GIO devices, which do not drive all data lines, may cause false 410 * memory read parity errors on the SysAD bus. The workaround is to disable 411 * parity checking. 412 */ 413void 414imc_disable_sysad_parity(void) 415{ 416 uint32_t reg; 417 418 if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22) 419 return; 420 421 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 422 reg |= IMC_CPUCTRL0_NCHKMEMPAR; 423 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 424} 425 426void 427imc_enable_sysad_parity(void) 428{ 429 uint32_t reg; 430 431 if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22) 432 return; 433 434 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 435 reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; 436 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 437} 438 439int 440imc_is_sysad_parity_enabled(void) 441{ 442 uint32_t reg; 443 444 if (mach_type != MACH_SGI_IP20 && mach_type != MACH_SGI_IP22) 445 return 0; 446 447 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 448 449 return reg & IMC_CPUCTRL0_NCHKMEMPAR; 450} 451