1 /* $NetBSD: imc.c,v 1.22 2004/09/05 13:32:10 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.22 2004/09/05 13:32:10 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(parent, match, aux) 87 struct device *parent; 88 struct cfdata *match; 89 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(parent, self, aux) 100 struct device *parent; 101 struct device *self; 102 void *aux; 103 { 104 u_int32_t reg; 105 struct imc_attach_args iaa; 106 struct mainbus_attach_args *ma = aux; 107 u_int32_t sysid; 108 109 isc.iot = SGIMIPS_BUS_SPACE_HPC; 110 if (bus_space_map(isc.iot, ma->ma_addr, 0, 111 BUS_SPACE_MAP_LINEAR, &isc.ioh)) 112 panic("imc_attach: could not allocate memory\n"); 113 114 platform.bus_reset = imc_bus_reset; 115 platform.watchdog_reset = imc_watchdog_reset; 116 platform.watchdog_disable = imc_watchdog_disable; 117 platform.watchdog_enable = imc_watchdog_enable; 118 119 sysid = bus_space_read_4(isc.iot, isc.ioh, IMC_SYSID); 120 121 /* We can't trust the "EISA present" bit on Indys */ 122 if (mach_subtype == MACH_SGI_IP22_GUINESS) 123 isc.eisa_present = 0; 124 else 125 isc.eisa_present = (sysid & IMC_SYSID_HAVEISA); 126 127 printf(": revision %d", (sysid & IMC_SYSID_REVMASK)); 128 129 if (isc.eisa_present) 130 printf(", EISA bus present"); 131 132 printf("\n"); 133 134 /* Clear CPU/GIO error status registers to clear any leftover bits. */ 135 imc_bus_reset(); 136 137 /* Hook the bus error handler into the ISR */ 138 platform.intr4 = imc_bus_error; 139 140 /* 141 * Enable parity reporting on GIO/main memory transactions. 142 * Disable parity checking on CPU bus transactions (as turning 143 * it on seems to cause spurious bus errors), but enable parity 144 * checking on CPU reads from main memory (note that this bit 145 * has the opposite sense... Turning it on turns the checks off!). 146 * Finally, turn on interrupt writes to the CPU from the MC. 147 */ 148 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 149 reg &= ~IMC_CPUCTRL0_NCHKMEMPAR; 150 reg |= (IMC_CPUCTRL0_GPR | IMC_CPUCTRL0_MPR | IMC_CPUCTRL0_INTENA); 151 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 152 153 /* Setup the MC write buffer depth */ 154 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL1); 155 reg = (reg & ~IMC_CPUCTRL1_MCHWMSK) | 13; 156 157 /* 158 * Force endianness on the onboard HPC and both slots. 159 * This should be safe for Fullhouse, but leave it conditional 160 * for now. 161 */ 162 if (mach_type == MACH_SGI_IP20 || (mach_type == MACH_SGI_IP22 && 163 mach_subtype == MACH_SGI_IP22_GUINESS)) { 164 reg |= IMC_CPUCTRL1_HPCFX; 165 reg |= IMC_CPUCTRL1_EXP0FX; 166 reg |= IMC_CPUCTRL1_EXP1FX; 167 reg &= ~IMC_CPUCTRL1_HPCLITTLE; 168 reg &= ~IMC_CPUCTRL1_EXP0LITTLE; 169 reg &= ~IMC_CPUCTRL1_EXP1LITTLE; 170 } 171 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL1, reg); 172 173 174 /* 175 * Set GIO64 arbitrator configuration register: 176 * 177 * Preserve PROM-set graphics-related bits, as they seem to depend 178 * on the graphics variant present and I'm not sure how to figure 179 * that out or 100% sure what the correct settings are for each. 180 */ 181 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_GIO64ARB); 182 reg &= (IMC_GIO64ARB_GRX64 | IMC_GIO64ARB_GRXRT | IMC_GIO64ARB_GRXMST); 183 184 /* Rest of settings are machine/board dependant */ 185 if (mach_type == MACH_SGI_IP20) 186 { 187 reg |= IMC_GIO64ARB_ONEGIO; 188 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT); 189 reg |= (IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST); 190 reg &= ~(IMC_GIO64ARB_HPC64 | 191 IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EISA64 | 192 IMC_GIO64ARB_EXP064 | IMC_GIO64ARB_EXP164 | 193 IMC_GIO64ARB_EXP0PIPE | IMC_GIO64ARB_EXP1PIPE); 194 } 195 else 196 { 197 /* 198 * GIO64 invariant for all IP22 platforms: one GIO bus, 199 * HPC1 @ 64 200 */ 201 reg |= IMC_GIO64ARB_ONEGIO | IMC_GIO64ARB_HPC64; 202 203 switch (mach_subtype) { 204 case MACH_SGI_IP22_GUINESS: 205 /* XXX is MST mutually exclusive? */ 206 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1RT); 207 reg |= (IMC_GIO64ARB_EXP0MST | IMC_GIO64ARB_EXP1MST); 208 209 /* EISA can bus-master, is 64-bit */ 210 reg |= (IMC_GIO64ARB_EISAMST | IMC_GIO64ARB_EISA64); 211 break; 212 213 case MACH_SGI_IP22_FULLHOUSE: 214 /* 215 * All Fullhouse boards have a 64-bit HPC2 and pipelined 216 * EXP0 slot. 217 */ 218 reg |= (IMC_GIO64ARB_HPCEXP64 | IMC_GIO64ARB_EXP0PIPE); 219 220 if (mach_boardrev < 2) { 221 /* EXP0 realtime, EXP1 can master */ 222 reg |= (IMC_GIO64ARB_EXP0RT | IMC_GIO64ARB_EXP1MST); 223 } else { 224 /* EXP1 pipelined as well, EISA masters */ 225 reg |= (IMC_GIO64ARB_EXP1PIPE | IMC_GIO64ARB_EISAMST); 226 } 227 break; 228 } 229 } 230 231 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO64ARB, reg); 232 233 if (isc.eisa_present) { 234 #if notyet 235 memset(&iaa, 0, sizeof(iaa)); 236 237 iaa.iaa_name = "eisa"; 238 config_found_ia(self, "eisabus", (void*)&iaa, imc_print); 239 #endif 240 } 241 242 memset(&iaa, 0, sizeof(iaa)); 243 244 iaa.iaa_name = "gio"; 245 config_found_ia(self, "giobus", (void*)&iaa, imc_print); 246 247 imc_watchdog_enable(); 248 } 249 250 251 static int 252 imc_print(aux, name) 253 void *aux; 254 const char *name; 255 { 256 struct imc_attach_args* iaa = aux; 257 258 if (name) 259 aprint_normal("%s at %s", iaa->iaa_name, name); 260 261 return UNCONF; 262 } 263 264 static void 265 imc_bus_reset(void) 266 { 267 bus_space_write_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT, 0); 268 bus_space_write_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT, 0); 269 } 270 271 static void 272 imc_bus_error(u_int32_t status, u_int32_t cause, u_int32_t pc, u_int32_t ipending) 273 { 274 printf("bus error: cpu_stat %08x addr %08x, gio_stat %08x addr %08x\n", 275 bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRSTAT), 276 bus_space_read_4(isc.iot, isc.ioh, IMC_CPU_ERRADDR), 277 bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRSTAT), 278 bus_space_read_4(isc.iot, isc.ioh, IMC_GIO_ERRADDR) ); 279 imc_bus_reset(); 280 } 281 282 static void 283 imc_watchdog_reset(void) 284 { 285 bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0); 286 } 287 288 static void 289 imc_watchdog_disable(void) 290 { 291 u_int32_t reg; 292 293 bus_space_write_4(isc.iot, isc.ioh, IMC_WDOG, 0); 294 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 295 reg &= ~(IMC_CPUCTRL0_WDOG); 296 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 297 } 298 299 static void 300 imc_watchdog_enable(void) 301 { 302 u_int32_t reg; 303 304 /* enable watchdog and clear it */ 305 reg = bus_space_read_4(isc.iot, isc.ioh, IMC_CPUCTRL0); 306 reg |= IMC_CPUCTRL0_WDOG; 307 bus_space_write_4(isc.iot, isc.ioh, IMC_CPUCTRL0, reg); 308 imc_watchdog_reset(); 309 } 310