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