26 */ 27 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/module.h> 31#include <sys/bus.h> 32#include <sys/conf.h> 33#include <sys/kernel.h> 34 35#include <dev/ofw/openfirm.h> 36#include <dev/ofw/ofw_pci.h> 37#include <dev/ofw/ofw_bus.h> 38#include <dev/ofw/ofw_bus_subr.h> 39 40#include <dev/pci/pcivar.h> 41#include <dev/pci/pcireg.h> 42 43#include <machine/bus.h> 44#include <machine/intr_machdep.h> 45#include <machine/md_var.h> 46#include <machine/pio.h> 47#include <machine/resource.h> 48 49#include <sys/rman.h> 50 51#include <powerpc/powermac/uninorthvar.h> 52 53#include <vm/vm.h> 54#include <vm/pmap.h> 55 56/* 57 * Driver for the Uninorth chip itself. 58 */ 59 60static MALLOC_DEFINE(M_UNIN, "unin", "unin device information"); 61 62/* 63 * Device interface. 64 */ 65 66static int unin_chip_probe(device_t); 67static int unin_chip_attach(device_t); 68 69/* 70 * Bus interface. 71 */ 72static int unin_chip_print_child(device_t dev, device_t child); 73static void unin_chip_probe_nomatch(device_t, device_t); 74static struct resource *unin_chip_alloc_resource(device_t, device_t, int, int *, 75 u_long, u_long, u_long, u_int); 76static int unin_chip_activate_resource(device_t, device_t, int, int, 77 struct resource *); 78static int unin_chip_deactivate_resource(device_t, device_t, int, int, 79 struct resource *); 80static int unin_chip_release_resource(device_t, device_t, int, int, 81 struct resource *); 82static struct resource_list *unin_chip_get_resource_list (device_t, device_t); 83 84/* 85 * OFW Bus interface 86 */ 87 88static ofw_bus_get_devinfo_t unin_chip_get_devinfo; 89 90/* 91 * Local routines 92 */ 93 94static void unin_enable_gmac(device_t dev); 95static void unin_enable_mpic(device_t dev); 96 97/* 98 * Driver methods. 99 */ 100static device_method_t unin_chip_methods[] = { 101 102 /* Device interface */ 103 DEVMETHOD(device_probe, unin_chip_probe), 104 DEVMETHOD(device_attach, unin_chip_attach), 105 106 /* Bus interface */ 107 DEVMETHOD(bus_print_child, unin_chip_print_child), 108 DEVMETHOD(bus_probe_nomatch, unin_chip_probe_nomatch), 109 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 110 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 111 112 DEVMETHOD(bus_alloc_resource, unin_chip_alloc_resource), 113 DEVMETHOD(bus_release_resource, unin_chip_release_resource), 114 DEVMETHOD(bus_activate_resource, unin_chip_activate_resource), 115 DEVMETHOD(bus_deactivate_resource, unin_chip_deactivate_resource), 116 DEVMETHOD(bus_get_resource_list, unin_chip_get_resource_list), 117 118 DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 119 120 /* ofw_bus interface */ 121 DEVMETHOD(ofw_bus_get_devinfo, unin_chip_get_devinfo), 122 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 123 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 124 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 125 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 126 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 127 128 { 0, 0 } 129}; 130 131static driver_t unin_chip_driver = { 132 "unin", 133 unin_chip_methods, 134 sizeof(struct unin_chip_softc) 135}; 136 137static devclass_t unin_chip_devclass; 138 139/* 140 * Assume there is only one unin chip in a PowerMac, so that pmu.c functions can 141 * suspend the chip after the whole rest of the device tree is suspended, not 142 * earlier. 143 */ 144static device_t unin_chip; 145
|
147 148/* 149 * Add an interrupt to the dev's resource list if present 150 */ 151static void 152unin_chip_add_intr(phandle_t devnode, struct unin_chip_devinfo *dinfo) 153{ 154 phandle_t iparent; 155 int *intr; 156 int i, nintr; 157 int icells; 158 159 if (dinfo->udi_ninterrupts >= 6) { 160 printf("unin: device has more than 6 interrupts\n"); 161 return; 162 } 163 164 nintr = OF_getprop_alloc(devnode, "interrupts", sizeof(*intr), 165 (void **)&intr); 166 if (nintr == -1) { 167 nintr = OF_getprop_alloc(devnode, "AAPL,interrupts", 168 sizeof(*intr), (void **)&intr); 169 if (nintr == -1) 170 return; 171 } 172 173 if (intr[0] == -1) 174 return; 175 176 if (OF_getprop(devnode, "interrupt-parent", &iparent, sizeof(iparent)) 177 <= 0) 178 panic("Interrupt but no interrupt parent!\n"); 179 180 if (OF_searchprop(iparent, "#interrupt-cells", &icells, sizeof(icells)) 181 <= 0) 182 icells = 1; 183 184 for (i = 0; i < nintr; i+=icells) { 185 u_int irq = MAP_IRQ(iparent, intr[i]); 186 187 resource_list_add(&dinfo->udi_resources, SYS_RES_IRQ, 188 dinfo->udi_ninterrupts, irq, irq, 1); 189 190 if (icells > 1) { 191 powerpc_config_intr(irq, 192 (intr[i+1] & 1) ? INTR_TRIGGER_LEVEL : 193 INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); 194 } 195 196 dinfo->udi_interrupts[dinfo->udi_ninterrupts] = irq; 197 dinfo->udi_ninterrupts++; 198 } 199} 200 201static void 202unin_chip_add_reg(phandle_t devnode, struct unin_chip_devinfo *dinfo) 203{ 204 struct unin_chip_reg *reg; 205 int i, nreg; 206 207 nreg = OF_getprop_alloc(devnode, "reg", sizeof(*reg), (void **)®); 208 if (nreg == -1) 209 return; 210 211 for (i = 0; i < nreg; i++) { 212 resource_list_add(&dinfo->udi_resources, SYS_RES_MEMORY, i, 213 reg[i].mr_base, 214 reg[i].mr_base + reg[i].mr_size, 215 reg[i].mr_size); 216 } 217} 218 219static void 220unin_update_reg(device_t dev, uint32_t regoff, uint32_t set, uint32_t clr) 221{ 222 volatile u_int *reg; 223 struct unin_chip_softc *sc; 224 u_int32_t tmpl; 225 226 sc = device_get_softc(dev); 227 reg = (void *)(sc->sc_addr + regoff); 228 tmpl = inl(reg); 229 tmpl &= ~clr; 230 tmpl |= set; 231 outl(reg, tmpl); 232} 233 234static void 235unin_enable_gmac(device_t dev) 236{ 237 unin_update_reg(dev, UNIN_CLOCKCNTL, UNIN_CLOCKCNTL_GMAC, 0); 238} 239 240static void 241unin_enable_mpic(device_t dev) 242{ 243 unin_update_reg(dev, UNIN_TOGGLE_REG, UNIN_MPIC_RESET | UNIN_MPIC_OUTPUT_ENABLE, 0); 244} 245 246static int 247unin_chip_probe(device_t dev) 248{ 249 const char *name; 250 251 name = ofw_bus_get_name(dev); 252 253 if (name == NULL) 254 return (ENXIO); 255 256 if (strcmp(name, "uni-n") != 0 && strcmp(name, "u3") != 0 257 && strcmp(name, "u4") != 0) 258 return (ENXIO); 259 260 device_set_desc(dev, "Apple UniNorth System Controller"); 261 return (0); 262} 263 264static int 265unin_chip_attach(device_t dev) 266{ 267 struct unin_chip_softc *sc; 268 struct unin_chip_devinfo *dinfo; 269 phandle_t root; 270 phandle_t child; 271 phandle_t iparent; 272 device_t cdev; 273 cell_t acells, scells; 274 char compat[32]; 275 char name[32]; 276 u_int irq, reg[3]; 277 int error, i = 0; 278 279 sc = device_get_softc(dev); 280 root = ofw_bus_get_node(dev); 281 282 if (OF_getprop(root, "reg", reg, sizeof(reg)) < 8) 283 return (ENXIO); 284 285 acells = scells = 1; 286 OF_getprop(OF_parent(root), "#address-cells", &acells, sizeof(acells)); 287 OF_getprop(OF_parent(root), "#size-cells", &scells, sizeof(scells)); 288 289 i = 0; 290 sc->sc_physaddr = reg[i++]; 291 if (acells == 2) { 292 sc->sc_physaddr <<= 32; 293 sc->sc_physaddr |= reg[i++]; 294 } 295 sc->sc_size = reg[i++]; 296 if (scells == 2) { 297 sc->sc_size <<= 32; 298 sc->sc_size |= reg[i++]; 299 } 300 301 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 302 sc->sc_mem_rman.rm_descr = "UniNorth Device Memory"; 303 304 error = rman_init(&sc->sc_mem_rman); 305 306 if (error) { 307 device_printf(dev, "rman_init() failed. error = %d\n", error); 308 return (error); 309 } 310 311 error = rman_manage_region(&sc->sc_mem_rman, sc->sc_physaddr, 312 sc->sc_physaddr + sc->sc_size - 1); 313 if (error) { 314 device_printf(dev, 315 "rman_manage_region() failed. error = %d\n", 316 error); 317 return (error); 318 } 319 320 if (unin_chip == NULL) 321 unin_chip = dev; 322 323 /* 324 * Iterate through the sub-devices 325 */ 326 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 327 dinfo = malloc(sizeof(*dinfo), M_UNIN, M_WAITOK | M_ZERO); 328 if (ofw_bus_gen_setup_devinfo(&dinfo->udi_obdinfo, child) 329 != 0) 330 { 331 free(dinfo, M_UNIN); 332 continue; 333 } 334 335 resource_list_init(&dinfo->udi_resources); 336 dinfo->udi_ninterrupts = 0; 337 unin_chip_add_intr(child, dinfo); 338 339 /* 340 * Some Apple machines do have a bug in OF, they miss 341 * the interrupt entries on the U3 I2C node. That means they 342 * do not have an entry with number of interrupts nor the 343 * entry of the interrupt parent handle. 344 * We define an interrupt and hardwire it to the /u3/mpic 345 * handle. 346 */ 347 348 if (OF_getprop(child, "name", name, sizeof(name)) <= 0) 349 device_printf(dev, "device has no name!\n"); 350 if (dinfo->udi_ninterrupts == 0 && 351 (strcmp(name, "i2c-bus") == 0 || 352 strcmp(name, "i2c") == 0)) { 353 if (OF_getprop(child, "interrupt-parent", &iparent, 354 sizeof(iparent)) <= 0) { 355 iparent = OF_finddevice("/u3/mpic"); 356 device_printf(dev, "Set /u3/mpic as iparent!\n"); 357 } 358 /* Add an interrupt number 0 to the parent. */ 359 irq = MAP_IRQ(iparent, 0); 360 resource_list_add(&dinfo->udi_resources, SYS_RES_IRQ, 361 dinfo->udi_ninterrupts, irq, irq, 1); 362 dinfo->udi_interrupts[dinfo->udi_ninterrupts] = irq; 363 dinfo->udi_ninterrupts++; 364 } 365 366 unin_chip_add_reg(child, dinfo); 367 368 cdev = device_add_child(dev, NULL, -1); 369 if (cdev == NULL) { 370 device_printf(dev, "<%s>: device_add_child failed\n", 371 dinfo->udi_obdinfo.obd_name); 372 resource_list_free(&dinfo->udi_resources); 373 ofw_bus_gen_destroy_devinfo(&dinfo->udi_obdinfo); 374 free(dinfo, M_UNIN); 375 continue; 376 } 377 378 device_set_ivars(cdev, dinfo); 379 } 380 381 /* 382 * Only map the first page, since that is where the registers 383 * of interest lie. 384 */ 385 sc->sc_addr = (vm_offset_t)pmap_mapdev(sc->sc_physaddr, PAGE_SIZE); 386 387 sc->sc_version = *(u_int *)sc->sc_addr; 388 device_printf(dev, "Version %d\n", sc->sc_version); 389 390 /* 391 * Enable the GMAC Ethernet cell and the integrated OpenPIC 392 * if Open Firmware says they are used. 393 */ 394 for (child = OF_child(root); child; child = OF_peer(child)) { 395 memset(compat, 0, sizeof(compat)); 396 OF_getprop(child, "compatible", compat, sizeof(compat)); 397 if (strcmp(compat, "gmac") == 0) 398 unin_enable_gmac(dev); 399 if (strcmp(compat, "chrp,open-pic") == 0) 400 unin_enable_mpic(dev); 401 } 402 403 /* 404 * GMAC lives under the PCI bus, so just check if enet is gmac. 405 */ 406 child = OF_finddevice("enet"); 407 memset(compat, 0, sizeof(compat)); 408 OF_getprop(child, "compatible", compat, sizeof(compat)); 409 if (strcmp(compat, "gmac") == 0) 410 unin_enable_gmac(dev); 411 412 return (bus_generic_attach(dev)); 413} 414 415static int 416unin_chip_print_child(device_t dev, device_t child) 417{ 418 struct unin_chip_devinfo *dinfo; 419 struct resource_list *rl; 420 int retval = 0; 421 422 dinfo = device_get_ivars(child); 423 rl = &dinfo->udi_resources; 424 425 retval += bus_print_child_header(dev, child); 426 427 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 428 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 429 430 retval += bus_print_child_footer(dev, child); 431 432 return (retval); 433} 434 435static void 436unin_chip_probe_nomatch(device_t dev, device_t child) 437{ 438 struct unin_chip_devinfo *dinfo; 439 struct resource_list *rl; 440 const char *type; 441 442 if (bootverbose) { 443 dinfo = device_get_ivars(child); 444 rl = &dinfo->udi_resources; 445 446 if ((type = ofw_bus_get_type(child)) == NULL) 447 type = "(unknown)"; 448 device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child)); 449 resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 450 resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 451 printf(" (no driver attached)\n"); 452 } 453} 454 455 456static struct resource * 457unin_chip_alloc_resource(device_t bus, device_t child, int type, int *rid, 458 u_long start, u_long end, u_long count, u_int flags) 459{ 460 struct unin_chip_softc *sc; 461 int needactivate; 462 struct resource *rv; 463 struct rman *rm; 464 u_long adjstart, adjend, adjcount; 465 struct unin_chip_devinfo *dinfo; 466 struct resource_list_entry *rle; 467 468 sc = device_get_softc(bus); 469 dinfo = device_get_ivars(child); 470 471 needactivate = flags & RF_ACTIVE; 472 flags &= ~RF_ACTIVE; 473 474 switch (type) { 475 case SYS_RES_MEMORY: 476 case SYS_RES_IOPORT: 477 rle = resource_list_find(&dinfo->udi_resources, SYS_RES_MEMORY, 478 *rid); 479 if (rle == NULL) { 480 device_printf(bus, "no rle for %s memory %d\n", 481 device_get_nameunit(child), *rid); 482 return (NULL); 483 } 484 485 rle->end = rle->end - 1; /* Hack? */ 486 487 if (start < rle->start) 488 adjstart = rle->start; 489 else if (start > rle->end) 490 adjstart = rle->end; 491 else 492 adjstart = start; 493 494 if (end < rle->start) 495 adjend = rle->start; 496 else if (end > rle->end) 497 adjend = rle->end; 498 else 499 adjend = end; 500 501 adjcount = adjend - adjstart; 502 503 rm = &sc->sc_mem_rman; 504 break; 505 506 case SYS_RES_IRQ: 507 /* Check for passthrough from subattachments. */ 508 if (device_get_parent(child) != bus) 509 return BUS_ALLOC_RESOURCE(device_get_parent(bus), child, 510 type, rid, start, end, count, 511 flags); 512 513 rle = resource_list_find(&dinfo->udi_resources, SYS_RES_IRQ, 514 *rid); 515 if (rle == NULL) { 516 if (dinfo->udi_ninterrupts >= 6) { 517 device_printf(bus, 518 "%s has more than 6 interrupts\n", 519 device_get_nameunit(child)); 520 return (NULL); 521 } 522 resource_list_add(&dinfo->udi_resources, SYS_RES_IRQ, 523 dinfo->udi_ninterrupts, start, start, 524 1); 525 526 dinfo->udi_interrupts[dinfo->udi_ninterrupts] = start; 527 dinfo->udi_ninterrupts++; 528 } 529 530 return (resource_list_alloc(&dinfo->udi_resources, bus, child, 531 type, rid, start, end, count, 532 flags)); 533 default: 534 device_printf(bus, "unknown resource request from %s\n", 535 device_get_nameunit(child)); 536 return (NULL); 537 } 538 539 rv = rman_reserve_resource(rm, adjstart, adjend, adjcount, flags, 540 child); 541 if (rv == NULL) { 542 device_printf(bus, 543 "failed to reserve resource %#lx - %#lx (%#lx)" 544 " for %s\n", adjstart, adjend, adjcount, 545 device_get_nameunit(child)); 546 return (NULL); 547 } 548 549 rman_set_rid(rv, *rid); 550 551 if (needactivate) { 552 if (bus_activate_resource(child, type, *rid, rv) != 0) { 553 device_printf(bus, 554 "failed to activate resource for %s\n", 555 device_get_nameunit(child)); 556 rman_release_resource(rv); 557 return (NULL); 558 } 559 } 560 561 return (rv); 562} 563 564static int 565unin_chip_release_resource(device_t bus, device_t child, int type, int rid, 566 struct resource *res) 567{ 568 if (rman_get_flags(res) & RF_ACTIVE) { 569 int error = bus_deactivate_resource(child, type, rid, res); 570 if (error) 571 return error; 572 } 573 574 return (rman_release_resource(res)); 575} 576 577static int 578unin_chip_activate_resource(device_t bus, device_t child, int type, int rid, 579 struct resource *res) 580{ 581 void *p; 582 583 if (type == SYS_RES_IRQ) 584 return (bus_activate_resource(bus, type, rid, res)); 585 586 if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { 587 vm_offset_t start; 588 589 start = (vm_offset_t) rman_get_start(res); 590 591 if (bootverbose) 592 printf("unin mapdev: start %zx, len %ld\n", start, 593 rman_get_size(res)); 594 595 p = pmap_mapdev(start, (vm_size_t) rman_get_size(res)); 596 if (p == NULL) 597 return (ENOMEM); 598 rman_set_virtual(res, p); 599 rman_set_bustag(res, &bs_be_tag); 600 rman_set_bushandle(res, (u_long)p); 601 } 602 603 return (rman_activate_resource(res)); 604} 605 606 607static int 608unin_chip_deactivate_resource(device_t bus, device_t child, int type, int rid, 609 struct resource *res) 610{ 611 /* 612 * If this is a memory resource, unmap it. 613 */ 614 if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { 615 u_int32_t psize; 616 617 psize = rman_get_size(res); 618 pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize); 619 } 620 621 return (rman_deactivate_resource(res)); 622} 623 624 625static struct resource_list * 626unin_chip_get_resource_list (device_t dev, device_t child) 627{ 628 struct unin_chip_devinfo *dinfo; 629 630 dinfo = device_get_ivars(child); 631 return (&dinfo->udi_resources); 632} 633 634static const struct ofw_bus_devinfo * 635unin_chip_get_devinfo(device_t dev, device_t child) 636{ 637 struct unin_chip_devinfo *dinfo; 638 639 dinfo = device_get_ivars(child); 640 return (&dinfo->udi_obdinfo); 641} 642 643int 644unin_chip_wake(device_t dev) 645{ 646 647 if (dev == NULL) 648 dev = unin_chip; 649 unin_update_reg(dev, UNIN_PWR_MGMT, UNIN_PWR_NORMAL, UNIN_PWR_MASK); 650 DELAY(10); 651 unin_update_reg(dev, UNIN_HWINIT_STATE, UNIN_RUNNING, 0); 652 DELAY(100); 653 654 return (0); 655} 656 657int 658unin_chip_sleep(device_t dev, int idle) 659{ 660 if (dev == NULL) 661 dev = unin_chip; 662 663 unin_update_reg(dev, UNIN_HWINIT_STATE, UNIN_SLEEPING, 0); 664 DELAY(10); 665 if (idle) 666 unin_update_reg(dev, UNIN_PWR_MGMT, UNIN_PWR_IDLE2, UNIN_PWR_MASK); 667 else 668 unin_update_reg(dev, UNIN_PWR_MGMT, UNIN_PWR_SLEEP, UNIN_PWR_MASK); 669 DELAY(10); 670 671 return (0); 672}
|