1 /* $NetBSD: gio.c,v 1.34 2015/02/18 16:47:58 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 2000 Soren S. Jorvang 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the 18 * NetBSD Project. See http://www.NetBSD.org/ for 19 * information about NetBSD. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: gio.c,v 1.34 2015/02/18 16:47:58 macallan Exp $"); 37 38 #include "opt_ddb.h" 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/device.h> 43 44 #include <sys/bus.h> 45 #include <machine/machtype.h> 46 #include <machine/sysconf.h> 47 48 #include <sgimips/gio/gioreg.h> 49 #include <sgimips/gio/giovar.h> 50 #include <sgimips/gio/giodevs_data.h> 51 52 #include "locators.h" 53 #include "newport.h" 54 #include "grtwo.h" 55 #include "light.h" 56 #include "imc.h" 57 #include "pic.h" 58 59 #if (NNEWPORT > 0) 60 #include <sgimips/gio/newportvar.h> 61 #endif 62 63 #if (NGRTWO > 0) 64 #include <sgimips/gio/grtwovar.h> 65 #endif 66 67 #if (NLIGHT > 0) 68 #include <sgimips/gio/lightvar.h> 69 #endif 70 71 #if (NIMC > 0) 72 extern int imc_gio64_arb_config(int, uint32_t); 73 #endif 74 75 #if (NPIC > 0) 76 extern int pic_gio32_arb_config(int, uint32_t); 77 #endif 78 79 80 static int gio_match(device_t, cfdata_t, void *); 81 static void gio_attach(device_t, device_t, void *); 82 static int gio_print(void *, const char *); 83 static int gio_search(device_t, cfdata_t, const int *, void *); 84 static int gio_submatch(device_t, cfdata_t, const int *, void *); 85 86 CFATTACH_DECL_NEW(gio, 0, 87 gio_match, gio_attach, NULL, NULL); 88 89 struct gio_probe { 90 uint32_t slot; 91 uint32_t base; 92 uint32_t mach_type; 93 uint32_t mach_subtype; 94 }; 95 96 /* 97 * Expansion Slot Base Addresses 98 * 99 * IP12, IP20 and IP24 have two GIO connectors: GIO_SLOT_EXP0 and 100 * GIO_SLOT_EXP1. 101 * 102 * On IP24 these slots exist on the graphics board or the IOPLUS 103 * "mezzanine" on Indy and Challenge S, respectively. The IOPLUS or 104 * graphics board connects to the mainboard via a single GIO64 connector. 105 * 106 * IP22 has either three or four physical connectors, but only two 107 * electrically distinct slots: GIO_SLOT_GFX and GIO_SLOT_EXP0. 108 * 109 * It should also be noted that DMA is (mostly) not supported in Challenge 110 * S's GIO_SLOT_EXP1. See gio(4) for the story. 111 */ 112 static const struct gio_probe slot_bases[] = { 113 { GIO_SLOT_GFX, 0x1f000000, MACH_SGI_IP22, MACH_SGI_IP22_FULLHOUSE }, 114 115 { GIO_SLOT_EXP0, 0x1f400000, MACH_SGI_IP12, -1 }, 116 { GIO_SLOT_EXP0, 0x1f400000, MACH_SGI_IP20, -1 }, 117 { GIO_SLOT_EXP0, 0x1f400000, MACH_SGI_IP22, -1 }, 118 119 { GIO_SLOT_EXP1, 0x1f600000, MACH_SGI_IP12, -1 }, 120 { GIO_SLOT_EXP1, 0x1f600000, MACH_SGI_IP20, -1 }, 121 { GIO_SLOT_EXP1, 0x1f600000, MACH_SGI_IP22, MACH_SGI_IP22_GUINNESS }, 122 123 { 0, 0, 0, 0 } 124 }; 125 126 /* 127 * Graphic Board Base Addresses 128 * 129 * Graphics boards are not treated like expansion slot cards. Their base 130 * addresses do not necessarily correspond to GIO slot addresses and they 131 * do not contain product identification words. 132 */ 133 static const struct gio_probe gfx_bases[] = { 134 /* grtwo, and newport on IP22 */ 135 { -1, 0x1f000000, MACH_SGI_IP12, -1 }, 136 { -1, 0x1f000000, MACH_SGI_IP20, -1 }, 137 { -1, 0x1f000000, MACH_SGI_IP22, -1 }, 138 139 /* light */ 140 { -1, 0x1f3f0000, MACH_SGI_IP12, -1 }, 141 { -1, 0x1f3f0000, MACH_SGI_IP20, -1 }, 142 143 /* light (dual headed) */ 144 { -1, 0x1f3f8000, MACH_SGI_IP12, -1 }, 145 { -1, 0x1f3f8000, MACH_SGI_IP20, -1 }, 146 147 /* grtwo, and newport on IP22 */ 148 { -1, 0x1f400000, MACH_SGI_IP12, -1 }, 149 { -1, 0x1f400000, MACH_SGI_IP20, -1 }, 150 { -1, 0x1f400000, MACH_SGI_IP22, -1 }, 151 152 /* grtwo */ 153 { -1, 0x1f600000, MACH_SGI_IP12, -1 }, 154 { -1, 0x1f600000, MACH_SGI_IP20, -1 }, 155 { -1, 0x1f600000, MACH_SGI_IP22, -1 }, 156 157 /* newport */ 158 { -1, 0x1f800000, MACH_SGI_IP22, MACH_SGI_IP22_FULLHOUSE }, 159 160 /* newport */ 161 { -1, 0x1fc00000, MACH_SGI_IP22, MACH_SGI_IP22_FULLHOUSE }, 162 163 { 0, 0, 0, 0 } 164 }; 165 166 /* maximum number of graphics boards possible (arbitrarily large estimate) */ 167 #define MAXGFX 8 168 169 static int 170 gio_match(device_t parent, cfdata_t match, void *aux) 171 { 172 if (mach_type == MACH_SGI_IP12 || mach_type == MACH_SGI_IP20 || 173 mach_type == MACH_SGI_IP22) 174 return 1; 175 176 return 0; 177 } 178 179 static void 180 gio_attach(device_t parent, device_t self, void *aux) 181 { 182 struct gio_attach_args ga; 183 uint32_t gfx[MAXGFX]; 184 int i, j, ngfx; 185 186 printf("\n"); 187 188 ngfx = 0; 189 memset(gfx, 0, sizeof(gfx)); 190 191 /* 192 * Attach graphics devices first. They do not contain a Product 193 * Identification Word and have no slot number. 194 * 195 * Record addresses to which graphics devices attach so that 196 * we do not confuse them with expansion slots, should the 197 * addresses coincide. 198 */ 199 for (i = 0; gfx_bases[i].base != 0; i++) { 200 /* skip slots that don't apply to us */ 201 if (gfx_bases[i].mach_type != mach_type) 202 continue; 203 204 if (gfx_bases[i].mach_subtype != -1 && 205 gfx_bases[i].mach_subtype != mach_subtype) 206 continue; 207 208 ga.ga_slot = -1; 209 ga.ga_addr = gfx_bases[i].base; 210 ga.ga_iot = normal_memt; 211 /* XXX bus_space_map() */ 212 ga.ga_ioh = MIPS_PHYS_TO_KSEG1(ga.ga_addr); 213 ga.ga_dmat = &sgimips_default_bus_dma_tag; 214 ga.ga_product = -1; 215 216 if (platform.badaddr((void *)ga.ga_ioh, sizeof(uint32_t))) 217 continue; 218 219 if (config_found_sm_loc(self, "gio", NULL, &ga, gio_print, 220 gio_submatch)) { 221 if (ngfx == MAXGFX) 222 panic("gio_attach: MAXGFX"); 223 gfx[ngfx++] = gfx_bases[i].base; 224 } 225 } 226 227 /* 228 * Now attach any GIO expansion cards. 229 * 230 * Be sure to skip any addresses to which a graphics device has 231 * already been attached. 232 */ 233 for (i = 0; slot_bases[i].base != 0; i++) { 234 bool skip = false; 235 236 /* skip slots that don't apply to us */ 237 if (slot_bases[i].mach_type != mach_type) 238 continue; 239 240 if (slot_bases[i].mach_subtype != -1 && 241 slot_bases[i].mach_subtype != mach_subtype) 242 continue; 243 244 for (j = 0; j < ngfx; j++) { 245 if (slot_bases[i].base == gfx[j]) { 246 skip = true; 247 break; 248 } 249 } 250 if (skip) 251 continue; 252 253 ga.ga_slot = slot_bases[i].slot; 254 ga.ga_addr = slot_bases[i].base; 255 ga.ga_iot = normal_memt; 256 ga.ga_ioh = MIPS_PHYS_TO_KSEG1(ga.ga_addr); 257 ga.ga_dmat = &sgimips_default_bus_dma_tag; 258 259 if (platform.badaddr((void *)ga.ga_ioh, sizeof(uint32_t))) 260 continue; 261 262 ga.ga_product = bus_space_read_4(ga.ga_iot, ga.ga_ioh, 0); 263 264 config_found_sm_loc(self, "gio", NULL, &ga, gio_print, 265 gio_submatch); 266 } 267 268 config_search_ia(gio_search, self, "gio", &ga); 269 } 270 271 static int 272 gio_print(void *aux, const char *pnp) 273 { 274 struct gio_attach_args *ga = aux; 275 int i = 0; 276 277 /* gfx probe */ 278 if (ga->ga_product == -1) 279 return (QUIET); 280 281 if (pnp != NULL) { 282 int product, revision; 283 284 product = GIO_PRODUCT_PRODUCTID(ga->ga_product); 285 286 if (GIO_PRODUCT_32BIT_ID(ga->ga_product)) 287 revision = GIO_PRODUCT_REVISION(ga->ga_product); 288 else 289 revision = 0; 290 291 while (gio_knowndevs[i].productid != 0) { 292 if (gio_knowndevs[i].productid == product) { 293 aprint_normal("%s", gio_knowndevs[i].product); 294 break; 295 } 296 i++; 297 } 298 299 if (gio_knowndevs[i].productid == 0) 300 aprint_normal("unknown GIO card"); 301 302 aprint_normal(" (product 0x%02x revision 0x%02x) at %s", 303 product, revision, pnp); 304 } 305 306 if (ga->ga_slot != GIOCF_SLOT_DEFAULT) 307 aprint_normal(" slot %d", ga->ga_slot); 308 if (ga->ga_addr != (uint32_t) GIOCF_ADDR_DEFAULT) 309 aprint_normal(" addr 0x%x", ga->ga_addr); 310 311 return UNCONF; 312 } 313 314 static int 315 gio_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 316 { 317 struct gio_attach_args *ga = aux; 318 319 do { 320 /* Handled by direct configuration, so skip here */ 321 if (cf->cf_loc[GIOCF_ADDR] == GIOCF_ADDR_DEFAULT) 322 return 0; 323 324 ga->ga_slot = cf->cf_loc[GIOCF_SLOT]; 325 ga->ga_addr = cf->cf_loc[GIOCF_ADDR]; 326 ga->ga_iot = 0; 327 ga->ga_ioh = MIPS_PHYS_TO_KSEG1(ga->ga_addr); 328 329 if (config_match(parent, cf, ga) > 0) 330 config_attach(parent, cf, ga, gio_print); 331 } while (cf->cf_fstate == FSTATE_STAR); 332 333 return 0; 334 } 335 336 static int 337 gio_submatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 338 { 339 struct gio_attach_args *ga = aux; 340 341 if (cf->cf_loc[GIOCF_SLOT] != GIOCF_SLOT_DEFAULT && 342 cf->cf_loc[GIOCF_SLOT] != ga->ga_slot) 343 return 0; 344 345 if (cf->cf_loc[GIOCF_ADDR] != GIOCF_ADDR_DEFAULT && 346 cf->cf_loc[GIOCF_ADDR] != ga->ga_addr) 347 return 0; 348 349 return config_match(parent, cf, aux); 350 } 351 352 int 353 gio_cnattach(void) 354 { 355 struct gio_attach_args ga; 356 int i; 357 358 for (i = 0; gfx_bases[i].base != 0; i++) { 359 /* skip bases that don't apply to us */ 360 if (gfx_bases[i].mach_type != mach_type) 361 continue; 362 363 if (gfx_bases[i].mach_subtype != -1 && 364 gfx_bases[i].mach_subtype != mach_subtype) 365 continue; 366 367 ga.ga_slot = -1; 368 ga.ga_addr = gfx_bases[i].base; 369 ga.ga_iot = normal_memt; 370 ga.ga_ioh = MIPS_PHYS_TO_KSEG1(ga.ga_addr); 371 ga.ga_dmat = &sgimips_default_bus_dma_tag; 372 ga.ga_product = -1; 373 374 if (platform.badaddr((void *)ga.ga_ioh,sizeof(uint32_t))) 375 continue; 376 377 #if (NGRTWO > 0) 378 if (grtwo_cnattach(&ga) == 0) 379 return 0; 380 #endif 381 382 #if (NLIGHT > 0) 383 if (light_cnattach(&ga) == 0) 384 return 0; 385 #endif 386 387 #if (NNEWPORT > 0) 388 if (newport_cnattach(&ga) == 0) 389 return 0; 390 #endif 391 392 } 393 394 return ENXIO; 395 } 396 397 /* 398 * Devices living in the expansion slots must enable or disable some 399 * GIO arbiter settings. This is accomplished via imc(4) or pic(4) 400 * registers, depending on the machine in question. 401 */ 402 int 403 gio_arb_config(int slot, uint32_t flags) 404 { 405 406 if (flags == 0) 407 return (EINVAL); 408 409 if (flags & ~(GIO_ARB_RT | GIO_ARB_LB | GIO_ARB_MST | GIO_ARB_SLV | 410 GIO_ARB_PIPE | GIO_ARB_NOPIPE | GIO_ARB_32BIT | GIO_ARB_64BIT | 411 GIO_ARB_HPC2_32BIT | GIO_ARB_HPC2_64BIT)) 412 return (EINVAL); 413 414 if (((flags & GIO_ARB_RT) && (flags & GIO_ARB_LB)) || 415 ((flags & GIO_ARB_MST) && (flags & GIO_ARB_SLV)) || 416 ((flags & GIO_ARB_PIPE) && (flags & GIO_ARB_NOPIPE)) || 417 ((flags & GIO_ARB_32BIT) && (flags & GIO_ARB_64BIT)) || 418 ((flags & GIO_ARB_HPC2_32BIT) && (flags & GIO_ARB_HPC2_64BIT))) 419 return (EINVAL); 420 421 #if (NPIC > 0) 422 if (mach_type == MACH_SGI_IP12) 423 return (pic_gio32_arb_config(slot, flags)); 424 #endif 425 426 #if (NIMC > 0) 427 if (mach_type == MACH_SGI_IP20 || mach_type == MACH_SGI_IP22) 428 return (imc_gio64_arb_config(slot, flags)); 429 #endif 430 431 return (EINVAL); 432 } 433 434 /* 435 * Establish an interrupt handler for the specified slot. 436 * 437 * Indy and Challenge S have an interrupt per GIO slot. Indigo and Indigo2 438 * share a single interrupt, however. 439 */ 440 void * 441 gio_intr_establish(int slot, int level, int (*func)(void *), void *arg) 442 { 443 int intr; 444 445 switch (mach_type) { 446 case MACH_SGI_IP12: 447 case MACH_SGI_IP20: 448 if (slot == GIO_SLOT_GFX) 449 panic("gio_intr_establish: slot %d", slot); 450 intr = 6; 451 break; 452 453 case MACH_SGI_IP22: 454 if (mach_subtype == MACH_SGI_IP22_FULLHOUSE) { 455 if (slot == GIO_SLOT_EXP1) 456 panic("gio_intr_establish: slot %d", slot); 457 intr = 6; 458 } else { 459 if (slot == GIO_SLOT_GFX) 460 panic("gio_intr_establish: slot %d", slot); 461 intr = (slot == GIO_SLOT_EXP0) ? 22 : 23; 462 } 463 break; 464 465 default: 466 panic("gio_intr_establish: mach_type"); 467 } 468 469 return (cpu_intr_establish(intr, level, func, arg)); 470 } 471 472 const char * 473 gio_product_string(int prid) 474 { 475 int i; 476 477 for (i = 0; gio_knowndevs[i].product != NULL; i++) 478 if (gio_knowndevs[i].productid == prid) 479 return (gio_knowndevs[i].product); 480 481 return (NULL); 482 } 483