160727d8bSWarner Losh /*- 271e3c308SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 371e3c308SPedro F. Giffuni * 411b370b1SPeter Grehan * Copyright 2002 by Peter Grehan. All rights reserved. 511b370b1SPeter Grehan * 611b370b1SPeter Grehan * Redistribution and use in source and binary forms, with or without 711b370b1SPeter Grehan * modification, are permitted provided that the following conditions 811b370b1SPeter Grehan * are met: 911b370b1SPeter Grehan * 1. Redistributions of source code must retain the above copyright 1011b370b1SPeter Grehan * notice, this list of conditions and the following disclaimer. 1111b370b1SPeter Grehan * 2. Redistributions in binary form must reproduce the above copyright 1211b370b1SPeter Grehan * notice, this list of conditions and the following disclaimer in the 1311b370b1SPeter Grehan * documentation and/or other materials provided with the distribution. 1411b370b1SPeter Grehan * 3. The name of the author may not be used to endorse or promote products 1511b370b1SPeter Grehan * derived from this software without specific prior written permission. 1611b370b1SPeter Grehan * 1711b370b1SPeter Grehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1811b370b1SPeter Grehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1911b370b1SPeter Grehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2011b370b1SPeter Grehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2111b370b1SPeter Grehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2211b370b1SPeter Grehan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2311b370b1SPeter Grehan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2411b370b1SPeter Grehan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2511b370b1SPeter Grehan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2611b370b1SPeter Grehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2711b370b1SPeter Grehan * SUCH DAMAGE. 2811b370b1SPeter Grehan */ 2911b370b1SPeter Grehan 3011b370b1SPeter Grehan /* 3111b370b1SPeter Grehan * Driver for KeyLargo/Pangea, the MacPPC south bridge ASIC. 3211b370b1SPeter Grehan */ 3311b370b1SPeter Grehan 3411b370b1SPeter Grehan #include <sys/param.h> 3511b370b1SPeter Grehan #include <sys/systm.h> 3611b370b1SPeter Grehan #include <sys/kernel.h> 3711b370b1SPeter Grehan #include <sys/malloc.h> 3840cdee9dSPeter Grehan #include <sys/module.h> 3911b370b1SPeter Grehan #include <sys/bus.h> 4011b370b1SPeter Grehan #include <sys/rman.h> 4111b370b1SPeter Grehan 4211b370b1SPeter Grehan #include <vm/vm.h> 4311b370b1SPeter Grehan #include <vm/pmap.h> 4411b370b1SPeter Grehan 45eaef5f0aSNathan Whitehorn #include <machine/bus.h> 46eaef5f0aSNathan Whitehorn #include <machine/intr_machdep.h> 4711b370b1SPeter Grehan #include <machine/resource.h> 48eaef5f0aSNathan Whitehorn #include <machine/vmparam.h> 4911b370b1SPeter Grehan 5026280d88SMarius Strobl #include <dev/ofw/ofw_bus.h> 51d8154a2aSMarius Strobl #include <dev/ofw/ofw_bus_subr.h> 5211b370b1SPeter Grehan #include <dev/ofw/openfirm.h> 5311b370b1SPeter Grehan 5411b370b1SPeter Grehan #include <powerpc/powermac/maciovar.h> 55c583b025SBrandon Bergren #include <powerpc/powermac/platform_powermac.h> 5611b370b1SPeter Grehan 5711b370b1SPeter Grehan #include <dev/pci/pcivar.h> 5811b370b1SPeter Grehan #include <dev/pci/pcireg.h> 5911b370b1SPeter Grehan 6057dc54dbSPeter Grehan /* 6157dc54dbSPeter Grehan * Macio softc 6257dc54dbSPeter Grehan */ 6357dc54dbSPeter Grehan struct macio_softc { 6457dc54dbSPeter Grehan phandle_t sc_node; 6557dc54dbSPeter Grehan vm_offset_t sc_base; 6657dc54dbSPeter Grehan vm_offset_t sc_size; 6757dc54dbSPeter Grehan struct rman sc_mem_rman; 68cc734417SNathan Whitehorn 69cc734417SNathan Whitehorn /* FCR registers */ 70cc734417SNathan Whitehorn int sc_memrid; 71cc734417SNathan Whitehorn struct resource *sc_memr; 72c583b025SBrandon Bergren 73c583b025SBrandon Bergren /* GPIO offsets */ 74c583b025SBrandon Bergren int sc_timebase; 7557dc54dbSPeter Grehan }; 7657dc54dbSPeter Grehan 7711b370b1SPeter Grehan static MALLOC_DEFINE(M_MACIO, "macio", "macio device information"); 7811b370b1SPeter Grehan 7911b370b1SPeter Grehan static int macio_probe(device_t); 8011b370b1SPeter Grehan static int macio_attach(device_t); 8111b370b1SPeter Grehan static int macio_print_child(device_t dev, device_t child); 8211b370b1SPeter Grehan static void macio_probe_nomatch(device_t, device_t); 83af081ec6SJohn Baldwin static struct rman *macio_get_rman(device_t, int, u_int); 8411b370b1SPeter Grehan static struct resource *macio_alloc_resource(device_t, device_t, int, int *, 852dd1bdf1SJustin Hibbits rman_res_t, rman_res_t, rman_res_t, 862dd1bdf1SJustin Hibbits u_int); 87fef01f04SJohn Baldwin static int macio_adjust_resource(device_t, device_t, struct resource *, 88af081ec6SJohn Baldwin rman_res_t, rman_res_t); 892baed46eSJohn Baldwin static int macio_activate_resource(device_t, device_t, struct resource *); 902baed46eSJohn Baldwin static int macio_deactivate_resource(device_t, device_t, struct resource *); 919dbf5b0eSJohn Baldwin static int macio_release_resource(device_t, device_t, struct resource *); 92d77f2092SJohn Baldwin static int macio_map_resource(device_t, device_t, struct resource *, 93af081ec6SJohn Baldwin struct resource_map_request *, 94af081ec6SJohn Baldwin struct resource_map *); 95d77f2092SJohn Baldwin static int macio_unmap_resource(device_t, device_t, struct resource *, 96af081ec6SJohn Baldwin struct resource_map *); 9711b370b1SPeter Grehan static struct resource_list *macio_get_resource_list (device_t, device_t); 98d8154a2aSMarius Strobl static ofw_bus_get_devinfo_t macio_get_devinfo; 99c583b025SBrandon Bergren #if !defined(__powerpc64__) && defined(SMP) 100c583b025SBrandon Bergren static void macio_freeze_timebase(device_t, bool); 101c583b025SBrandon Bergren #endif 10211b370b1SPeter Grehan 10311b370b1SPeter Grehan /* 10411b370b1SPeter Grehan * Bus interface definition 10511b370b1SPeter Grehan */ 10611b370b1SPeter Grehan static device_method_t macio_methods[] = { 10711b370b1SPeter Grehan /* Device interface */ 10811b370b1SPeter Grehan DEVMETHOD(device_probe, macio_probe), 10911b370b1SPeter Grehan DEVMETHOD(device_attach, macio_attach), 11011b370b1SPeter Grehan DEVMETHOD(device_detach, bus_generic_detach), 11111b370b1SPeter Grehan DEVMETHOD(device_shutdown, bus_generic_shutdown), 11211b370b1SPeter Grehan DEVMETHOD(device_suspend, bus_generic_suspend), 11311b370b1SPeter Grehan DEVMETHOD(device_resume, bus_generic_resume), 11411b370b1SPeter Grehan 11511b370b1SPeter Grehan /* Bus interface */ 11611b370b1SPeter Grehan DEVMETHOD(bus_print_child, macio_print_child), 11711b370b1SPeter Grehan DEVMETHOD(bus_probe_nomatch, macio_probe_nomatch), 11811b370b1SPeter Grehan DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 11911b370b1SPeter Grehan DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 12011b370b1SPeter Grehan 121af081ec6SJohn Baldwin DEVMETHOD(bus_get_rman, macio_get_rman), 12211b370b1SPeter Grehan DEVMETHOD(bus_alloc_resource, macio_alloc_resource), 123af081ec6SJohn Baldwin DEVMETHOD(bus_adjust_resource, macio_adjust_resource), 12411b370b1SPeter Grehan DEVMETHOD(bus_release_resource, macio_release_resource), 12511b370b1SPeter Grehan DEVMETHOD(bus_activate_resource, macio_activate_resource), 12611b370b1SPeter Grehan DEVMETHOD(bus_deactivate_resource, macio_deactivate_resource), 127af081ec6SJohn Baldwin DEVMETHOD(bus_map_resource, macio_map_resource), 128af081ec6SJohn Baldwin DEVMETHOD(bus_unmap_resource, macio_unmap_resource), 12911b370b1SPeter Grehan DEVMETHOD(bus_get_resource_list, macio_get_resource_list), 13011b370b1SPeter Grehan 131ddfc9c4cSWarner Losh DEVMETHOD(bus_child_pnpinfo, ofw_bus_gen_child_pnpinfo), 13294b4a038SNathan Whitehorn 13326280d88SMarius Strobl /* ofw_bus interface */ 134d8154a2aSMarius Strobl DEVMETHOD(ofw_bus_get_devinfo, macio_get_devinfo), 135d8154a2aSMarius Strobl DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 136d8154a2aSMarius Strobl DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 137d8154a2aSMarius Strobl DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 138d8154a2aSMarius Strobl DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 139d8154a2aSMarius Strobl DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 14011b370b1SPeter Grehan { 0, 0 } 14111b370b1SPeter Grehan }; 14211b370b1SPeter Grehan 14311b370b1SPeter Grehan static driver_t macio_pci_driver = { 14411b370b1SPeter Grehan "macio", 14511b370b1SPeter Grehan macio_methods, 14611b370b1SPeter Grehan sizeof(struct macio_softc) 14711b370b1SPeter Grehan }; 14811b370b1SPeter Grehan 149992ae60bSJohn Baldwin EARLY_DRIVER_MODULE(macio, pci, macio_pci_driver, 0, 0, BUS_PASS_BUS); 15011b370b1SPeter Grehan 15111b370b1SPeter Grehan /* 15211b370b1SPeter Grehan * PCI ID search table 15311b370b1SPeter Grehan */ 15411b370b1SPeter Grehan static struct macio_pci_dev { 15511b370b1SPeter Grehan u_int32_t mpd_devid; 15611b370b1SPeter Grehan char *mpd_desc; 15711b370b1SPeter Grehan } macio_pci_devlist[] = { 1580b86d93fSPeter Grehan { 0x0017106b, "Paddington I/O Controller" }, 15911b370b1SPeter Grehan { 0x0022106b, "KeyLargo I/O Controller" }, 1600b86d93fSPeter Grehan { 0x0025106b, "Pangea I/O Controller" }, 1610b86d93fSPeter Grehan { 0x003e106b, "Intrepid I/O Controller" }, 16251d163d3SNathan Whitehorn { 0x0041106b, "K2 KeyLargo I/O Controller" }, 16351d163d3SNathan Whitehorn { 0x004f106b, "Shasta I/O Controller" }, 16411b370b1SPeter Grehan { 0, NULL } 16511b370b1SPeter Grehan }; 16611b370b1SPeter Grehan 16711b370b1SPeter Grehan /* 16811b370b1SPeter Grehan * Devices to exclude from the probe 16911b370b1SPeter Grehan * XXX some of these may be required in the future... 17011b370b1SPeter Grehan */ 17130081705SBenno Rice #define MACIO_QUIRK_IGNORE 0x00000001 17230081705SBenno Rice #define MACIO_QUIRK_CHILD_HAS_INTR 0x00000002 173f3b0e834SNathan Whitehorn #define MACIO_QUIRK_USE_CHILD_REG 0x00000004 17430081705SBenno Rice 17530081705SBenno Rice struct macio_quirk_entry { 17630081705SBenno Rice const char *mq_name; 17730081705SBenno Rice int mq_quirks; 17830081705SBenno Rice }; 17930081705SBenno Rice 18030081705SBenno Rice static struct macio_quirk_entry macio_quirks[] = { 18130081705SBenno Rice { "escc-legacy", MACIO_QUIRK_IGNORE }, 18230081705SBenno Rice { "timer", MACIO_QUIRK_IGNORE }, 18330081705SBenno Rice { "escc", MACIO_QUIRK_CHILD_HAS_INTR }, 184f3b0e834SNathan Whitehorn { "i2s", MACIO_QUIRK_CHILD_HAS_INTR | 185f3b0e834SNathan Whitehorn MACIO_QUIRK_USE_CHILD_REG }, 18630081705SBenno Rice { NULL, 0 } 18711b370b1SPeter Grehan }; 18811b370b1SPeter Grehan 18911b370b1SPeter Grehan static int 19030081705SBenno Rice macio_get_quirks(const char *name) 19111b370b1SPeter Grehan { 19230081705SBenno Rice struct macio_quirk_entry *mqe; 19311b370b1SPeter Grehan 19430081705SBenno Rice for (mqe = macio_quirks; mqe->mq_name != NULL; mqe++) 19530081705SBenno Rice if (strcmp(name, mqe->mq_name) == 0) 19630081705SBenno Rice return (mqe->mq_quirks); 19711b370b1SPeter Grehan return (0); 19811b370b1SPeter Grehan } 19911b370b1SPeter Grehan 20011b370b1SPeter Grehan /* 20111b370b1SPeter Grehan * Add an interrupt to the dev's resource list if present 20211b370b1SPeter Grehan */ 20311b370b1SPeter Grehan static void 20411b370b1SPeter Grehan macio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo) 20511b370b1SPeter Grehan { 206eaef5f0aSNathan Whitehorn phandle_t iparent; 2074924db93SMarcel Moolenaar int *intr; 2084924db93SMarcel Moolenaar int i, nintr; 2094924db93SMarcel Moolenaar int icells; 21011b370b1SPeter Grehan 2114924db93SMarcel Moolenaar if (dinfo->mdi_ninterrupts >= 6) { 2124924db93SMarcel Moolenaar printf("macio: device has more than 6 interrupts\n"); 21330081705SBenno Rice return; 21411b370b1SPeter Grehan } 21530081705SBenno Rice 216217d17bcSOleksandr Tymoshenko nintr = OF_getprop_alloc_multi(devnode, "interrupts", sizeof(*intr), 2174924db93SMarcel Moolenaar (void **)&intr); 2184924db93SMarcel Moolenaar if (nintr == -1) { 219217d17bcSOleksandr Tymoshenko nintr = OF_getprop_alloc_multi(devnode, "AAPL,interrupts", 2204924db93SMarcel Moolenaar sizeof(*intr), (void **)&intr); 2214924db93SMarcel Moolenaar if (nintr == -1) 22230081705SBenno Rice return; 22330081705SBenno Rice } 22430081705SBenno Rice 2254924db93SMarcel Moolenaar if (intr[0] == -1) 22630081705SBenno Rice return; 22730081705SBenno Rice 228eaef5f0aSNathan Whitehorn if (OF_getprop(devnode, "interrupt-parent", &iparent, sizeof(iparent)) 229eaef5f0aSNathan Whitehorn <= 0) 230eaef5f0aSNathan Whitehorn panic("Interrupt but no interrupt parent!\n"); 231eaef5f0aSNathan Whitehorn 232752ba930SIan Lepore if (OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, 2338ec08b0aSNathan Whitehorn sizeof(icells)) <= 0) 2348ec08b0aSNathan Whitehorn icells = 1; 2358ec08b0aSNathan Whitehorn 2364924db93SMarcel Moolenaar for (i = 0; i < nintr; i+=icells) { 237607ebaafSMarcel Moolenaar u_int irq = MAP_IRQ(iparent, intr[i]); 23830081705SBenno Rice 239607ebaafSMarcel Moolenaar resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ, 240607ebaafSMarcel Moolenaar dinfo->mdi_ninterrupts, irq, irq, 1); 241607ebaafSMarcel Moolenaar 242607ebaafSMarcel Moolenaar dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = irq; 24330081705SBenno Rice dinfo->mdi_ninterrupts++; 24411b370b1SPeter Grehan } 2454924db93SMarcel Moolenaar } 24611b370b1SPeter Grehan 24711b370b1SPeter Grehan static void 24811b370b1SPeter Grehan macio_add_reg(phandle_t devnode, struct macio_devinfo *dinfo) 24911b370b1SPeter Grehan { 250d25b22e1SAndreas Tobler struct macio_reg *reg, *regp; 251d25b22e1SAndreas Tobler phandle_t child; 252d25b22e1SAndreas Tobler char buf[8]; 253d25b22e1SAndreas Tobler int i, layout_id = 0, nreg, res; 25411b370b1SPeter Grehan 255217d17bcSOleksandr Tymoshenko nreg = OF_getprop_alloc_multi(devnode, "reg", sizeof(*reg), (void **)®); 256fe5e7c6bSBenno Rice if (nreg == -1) 257fe5e7c6bSBenno Rice return; 25811b370b1SPeter Grehan 259d25b22e1SAndreas Tobler /* 260d25b22e1SAndreas Tobler * Some G5's have broken properties in the i2s-a area. If so we try 261d25b22e1SAndreas Tobler * to fix it. Right now we know of two different cases, one for 262d25b22e1SAndreas Tobler * sound layout-id 36 and the other one for sound layout-id 76. 263d25b22e1SAndreas Tobler * What is missing is the base address for the memory addresses. 264d25b22e1SAndreas Tobler * We take them from the parent node (i2s) and use the size 265d25b22e1SAndreas Tobler * information from the child. 266d25b22e1SAndreas Tobler */ 267d25b22e1SAndreas Tobler 268d25b22e1SAndreas Tobler if (reg[0].mr_base == 0) { 269d25b22e1SAndreas Tobler child = OF_child(devnode); 270d25b22e1SAndreas Tobler while (child != 0) { 271d25b22e1SAndreas Tobler res = OF_getprop(child, "name", buf, sizeof(buf)); 272d25b22e1SAndreas Tobler if (res > 0 && strcmp(buf, "sound") == 0) 273d25b22e1SAndreas Tobler break; 274d25b22e1SAndreas Tobler child = OF_peer(child); 275d25b22e1SAndreas Tobler } 276d25b22e1SAndreas Tobler 277d25b22e1SAndreas Tobler res = OF_getprop(child, "layout-id", &layout_id, 278d25b22e1SAndreas Tobler sizeof(layout_id)); 279d25b22e1SAndreas Tobler 280d25b22e1SAndreas Tobler if (res > 0 && (layout_id == 36 || layout_id == 76)) { 281217d17bcSOleksandr Tymoshenko res = OF_getprop_alloc_multi(OF_parent(devnode), "reg", 282d25b22e1SAndreas Tobler sizeof(*regp), (void **)®p); 283d25b22e1SAndreas Tobler reg[0] = regp[0]; 284d25b22e1SAndreas Tobler reg[1].mr_base = regp[1].mr_base; 285d25b22e1SAndreas Tobler reg[2].mr_base = regp[1].mr_base + reg[1].mr_size; 286d25b22e1SAndreas Tobler } 287d25b22e1SAndreas Tobler } 288d25b22e1SAndreas Tobler 289fe5e7c6bSBenno Rice for (i = 0; i < nreg; i++) { 290fe5e7c6bSBenno Rice resource_list_add(&dinfo->mdi_resources, SYS_RES_MEMORY, i, 291fe5e7c6bSBenno Rice reg[i].mr_base, reg[i].mr_base + reg[i].mr_size, 292fe5e7c6bSBenno Rice reg[i].mr_size); 29311b370b1SPeter Grehan } 29411b370b1SPeter Grehan } 29511b370b1SPeter Grehan 29611b370b1SPeter Grehan /* 29711b370b1SPeter Grehan * PCI probe 29811b370b1SPeter Grehan */ 29911b370b1SPeter Grehan static int 30011b370b1SPeter Grehan macio_probe(device_t dev) 30111b370b1SPeter Grehan { 30211b370b1SPeter Grehan int i; 30311b370b1SPeter Grehan u_int32_t devid; 30411b370b1SPeter Grehan 30511b370b1SPeter Grehan devid = pci_get_devid(dev); 30611b370b1SPeter Grehan for (i = 0; macio_pci_devlist[i].mpd_desc != NULL; i++) { 30711b370b1SPeter Grehan if (devid == macio_pci_devlist[i].mpd_devid) { 30811b370b1SPeter Grehan device_set_desc(dev, macio_pci_devlist[i].mpd_desc); 30911b370b1SPeter Grehan return (0); 31011b370b1SPeter Grehan } 31111b370b1SPeter Grehan } 31211b370b1SPeter Grehan 31311b370b1SPeter Grehan return (ENXIO); 31411b370b1SPeter Grehan } 31511b370b1SPeter Grehan 31611b370b1SPeter Grehan /* 31711b370b1SPeter Grehan * PCI attach: scan Open Firmware child nodes, and attach these as children 31811b370b1SPeter Grehan * of the macio bus 31911b370b1SPeter Grehan */ 32011b370b1SPeter Grehan static int 32111b370b1SPeter Grehan macio_attach(device_t dev) 32211b370b1SPeter Grehan { 32311b370b1SPeter Grehan struct macio_softc *sc; 32411b370b1SPeter Grehan struct macio_devinfo *dinfo; 32511b370b1SPeter Grehan phandle_t root; 32611b370b1SPeter Grehan phandle_t child; 32730081705SBenno Rice phandle_t subchild; 32811b370b1SPeter Grehan device_t cdev; 32911b370b1SPeter Grehan u_int reg[3]; 330d25b22e1SAndreas Tobler char compat[32]; 331bda386dbSKevin Lo int error, quirks; 33211b370b1SPeter Grehan 33311b370b1SPeter Grehan sc = device_get_softc(dev); 33451d163d3SNathan Whitehorn root = sc->sc_node = ofw_bus_get_node(dev); 33511b370b1SPeter Grehan 33611b370b1SPeter Grehan /* 33711b370b1SPeter Grehan * Locate the device node and it's base address 33811b370b1SPeter Grehan */ 33911b370b1SPeter Grehan if (OF_getprop(root, "assigned-addresses", 3408bab0d80SNathan Whitehorn reg, sizeof(reg)) < (ssize_t)sizeof(reg)) { 34111b370b1SPeter Grehan return (ENXIO); 34211b370b1SPeter Grehan } 34311b370b1SPeter Grehan 344d25b22e1SAndreas Tobler /* Used later to see if we have to enable the I2S part. */ 345d25b22e1SAndreas Tobler OF_getprop(root, "compatible", compat, sizeof(compat)); 346d25b22e1SAndreas Tobler 34711b370b1SPeter Grehan sc->sc_base = reg[2]; 34811b370b1SPeter Grehan sc->sc_size = MACIO_REG_SIZE; 34911b370b1SPeter Grehan 350cc734417SNathan Whitehorn sc->sc_memrid = PCIR_BAR(0); 351cc734417SNathan Whitehorn sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 352cc734417SNathan Whitehorn &sc->sc_memrid, RF_ACTIVE); 353cc734417SNathan Whitehorn 35411b370b1SPeter Grehan sc->sc_mem_rman.rm_type = RMAN_ARRAY; 355fe5e7c6bSBenno Rice sc->sc_mem_rman.rm_descr = "MacIO Device Memory"; 356bda386dbSKevin Lo error = rman_init(&sc->sc_mem_rman); 357bda386dbSKevin Lo if (error) { 358bda386dbSKevin Lo device_printf(dev, "rman_init() failed. error = %d\n", error); 359bda386dbSKevin Lo return (error); 36011b370b1SPeter Grehan } 361bda386dbSKevin Lo error = rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size); 362bda386dbSKevin Lo if (error) { 363bda386dbSKevin Lo device_printf(dev, 364bda386dbSKevin Lo "rman_manage_region() failed. error = %d\n", error); 365bda386dbSKevin Lo return (error); 366bda386dbSKevin Lo } 36711b370b1SPeter Grehan 36811b370b1SPeter Grehan /* 36911b370b1SPeter Grehan * Iterate through the sub-devices 37011b370b1SPeter Grehan */ 37111b370b1SPeter Grehan for (child = OF_child(root); child != 0; child = OF_peer(child)) { 372d8154a2aSMarius Strobl dinfo = malloc(sizeof(*dinfo), M_MACIO, M_WAITOK | M_ZERO); 373d8154a2aSMarius Strobl if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) != 374d8154a2aSMarius Strobl 0) { 375d8154a2aSMarius Strobl free(dinfo, M_MACIO); 37611b370b1SPeter Grehan continue; 37711b370b1SPeter Grehan } 378d8154a2aSMarius Strobl quirks = macio_get_quirks(dinfo->mdi_obdinfo.obd_name); 379d8154a2aSMarius Strobl if ((quirks & MACIO_QUIRK_IGNORE) != 0) { 380d8154a2aSMarius Strobl ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); 381d8154a2aSMarius Strobl free(dinfo, M_MACIO); 382d8154a2aSMarius Strobl continue; 383d8154a2aSMarius Strobl } 38411b370b1SPeter Grehan resource_list_init(&dinfo->mdi_resources); 38530081705SBenno Rice dinfo->mdi_ninterrupts = 0; 38611b370b1SPeter Grehan macio_add_intr(child, dinfo); 387f3b0e834SNathan Whitehorn if ((quirks & MACIO_QUIRK_USE_CHILD_REG) != 0) 388f3b0e834SNathan Whitehorn macio_add_reg(OF_child(child), dinfo); 389f3b0e834SNathan Whitehorn else 39011b370b1SPeter Grehan macio_add_reg(child, dinfo); 391d8154a2aSMarius Strobl if ((quirks & MACIO_QUIRK_CHILD_HAS_INTR) != 0) 39230081705SBenno Rice for (subchild = OF_child(child); subchild != 0; 393d8154a2aSMarius Strobl subchild = OF_peer(subchild)) 39430081705SBenno Rice macio_add_intr(subchild, dinfo); 3955b56413dSWarner Losh cdev = device_add_child(dev, NULL, DEVICE_UNIT_ANY); 396d8154a2aSMarius Strobl if (cdev == NULL) { 397d8154a2aSMarius Strobl device_printf(dev, "<%s>: device_add_child failed\n", 398d8154a2aSMarius Strobl dinfo->mdi_obdinfo.obd_name); 399d8154a2aSMarius Strobl resource_list_free(&dinfo->mdi_resources); 400d8154a2aSMarius Strobl ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo); 401d8154a2aSMarius Strobl free(dinfo, M_MACIO); 402d8154a2aSMarius Strobl continue; 40330081705SBenno Rice } 40411b370b1SPeter Grehan device_set_ivars(cdev, dinfo); 405cc734417SNathan Whitehorn 406cc734417SNathan Whitehorn /* Set FCRs to enable some devices */ 407cc734417SNathan Whitehorn if (sc->sc_memr == NULL) 408cc734417SNathan Whitehorn continue; 409cc734417SNathan Whitehorn 410cc734417SNathan Whitehorn if (strcmp(ofw_bus_get_name(cdev), "bmac") == 0 || 41147280ef1SNathan Whitehorn (ofw_bus_get_compat(cdev) != NULL && 41247280ef1SNathan Whitehorn strcmp(ofw_bus_get_compat(cdev), "bmac+") == 0)) { 413cc734417SNathan Whitehorn uint32_t fcr; 414cc734417SNathan Whitehorn 415cc734417SNathan Whitehorn fcr = bus_read_4(sc->sc_memr, HEATHROW_FCR); 416cc734417SNathan Whitehorn 417cc734417SNathan Whitehorn fcr |= FCR_ENET_ENABLE & ~FCR_ENET_RESET; 418cc734417SNathan Whitehorn bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr); 419cc734417SNathan Whitehorn DELAY(50000); 420cc734417SNathan Whitehorn fcr |= FCR_ENET_RESET; 421cc734417SNathan Whitehorn bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr); 422cc734417SNathan Whitehorn DELAY(50000); 423cc734417SNathan Whitehorn fcr &= ~FCR_ENET_RESET; 424cc734417SNathan Whitehorn bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr); 425cc734417SNathan Whitehorn DELAY(50000); 426cc734417SNathan Whitehorn 427cc734417SNathan Whitehorn bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr); 428cc734417SNathan Whitehorn } 429d25b22e1SAndreas Tobler 430d25b22e1SAndreas Tobler /* 431d25b22e1SAndreas Tobler * Make sure the I2S0 and the I2S0_CLK are enabled. 432d25b22e1SAndreas Tobler * On certain G5's they are not. 433d25b22e1SAndreas Tobler */ 434d25b22e1SAndreas Tobler if ((strcmp(ofw_bus_get_name(cdev), "i2s") == 0) && 435d25b22e1SAndreas Tobler (strcmp(compat, "K2-Keylargo") == 0)) { 436d25b22e1SAndreas Tobler uint32_t fcr1; 437d25b22e1SAndreas Tobler 438d25b22e1SAndreas Tobler fcr1 = bus_read_4(sc->sc_memr, KEYLARGO_FCR1); 439d25b22e1SAndreas Tobler fcr1 |= FCR1_I2S0_CLK_ENABLE | FCR1_I2S0_ENABLE; 440d25b22e1SAndreas Tobler bus_write_4(sc->sc_memr, KEYLARGO_FCR1, fcr1); 441d25b22e1SAndreas Tobler } 44211b370b1SPeter Grehan } 44311b370b1SPeter Grehan 444c583b025SBrandon Bergren #if !defined(__powerpc64__) && defined(SMP) 445c583b025SBrandon Bergren /* 446c583b025SBrandon Bergren * Detect an SMP G4 machine. 447c583b025SBrandon Bergren * 448c583b025SBrandon Bergren * On SMP G4, timebase freeze is via a GPIO on macio. 449c583b025SBrandon Bergren * 450c583b025SBrandon Bergren * When we are on an SMP G4, we need to install a handler to 451c583b025SBrandon Bergren * perform timebase freeze/unfreeze on behalf of the platform. 452c583b025SBrandon Bergren */ 453c583b025SBrandon Bergren if ((child = OF_finddevice("/cpus/PowerPC,G4@0")) != -1 && 454c583b025SBrandon Bergren OF_peer(child) != -1) { 455c583b025SBrandon Bergren if (OF_getprop(child, "timebase-enable", &sc->sc_timebase, 456c583b025SBrandon Bergren sizeof(sc->sc_timebase)) <= 0) 457c583b025SBrandon Bergren sc->sc_timebase = KEYLARGO_GPIO_BASE + 0x09; 458c583b025SBrandon Bergren powermac_register_timebase(dev, macio_freeze_timebase); 459c583b025SBrandon Bergren device_printf(dev, "GPIO timebase control at 0x%x\n", 460c583b025SBrandon Bergren sc->sc_timebase); 461c583b025SBrandon Bergren } 462c583b025SBrandon Bergren #endif 463c583b025SBrandon Bergren 464*18250ec6SJohn Baldwin bus_attach_children(dev); 465*18250ec6SJohn Baldwin return (0); 46611b370b1SPeter Grehan } 46711b370b1SPeter Grehan 46811b370b1SPeter Grehan static int 46911b370b1SPeter Grehan macio_print_child(device_t dev, device_t child) 47011b370b1SPeter Grehan { 47111b370b1SPeter Grehan struct macio_devinfo *dinfo; 47211b370b1SPeter Grehan struct resource_list *rl; 47311b370b1SPeter Grehan int retval = 0; 47411b370b1SPeter Grehan 47511b370b1SPeter Grehan dinfo = device_get_ivars(child); 47611b370b1SPeter Grehan rl = &dinfo->mdi_resources; 47711b370b1SPeter Grehan 47811b370b1SPeter Grehan retval += bus_print_child_header(dev, child); 47911b370b1SPeter Grehan 480f8fd3fb5SJustin Hibbits retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 481f8fd3fb5SJustin Hibbits retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 48211b370b1SPeter Grehan 48311b370b1SPeter Grehan retval += bus_print_child_footer(dev, child); 48411b370b1SPeter Grehan 48511b370b1SPeter Grehan return (retval); 48611b370b1SPeter Grehan } 48711b370b1SPeter Grehan 48811b370b1SPeter Grehan static void 48911b370b1SPeter Grehan macio_probe_nomatch(device_t dev, device_t child) 49011b370b1SPeter Grehan { 491fe5e7c6bSBenno Rice struct macio_devinfo *dinfo; 492fe5e7c6bSBenno Rice struct resource_list *rl; 49326280d88SMarius Strobl const char *type; 49411b370b1SPeter Grehan 49511b370b1SPeter Grehan if (bootverbose) { 496fe5e7c6bSBenno Rice dinfo = device_get_ivars(child); 497fe5e7c6bSBenno Rice rl = &dinfo->mdi_resources; 49811b370b1SPeter Grehan 49926280d88SMarius Strobl if ((type = ofw_bus_get_type(child)) == NULL) 50026280d88SMarius Strobl type = "(unknown)"; 50126280d88SMarius Strobl device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child)); 502f8fd3fb5SJustin Hibbits resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 503f8fd3fb5SJustin Hibbits resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 504fe5e7c6bSBenno Rice printf(" (no driver attached)\n"); 50511b370b1SPeter Grehan } 50611b370b1SPeter Grehan } 50711b370b1SPeter Grehan 508af081ec6SJohn Baldwin static struct rman * 509af081ec6SJohn Baldwin macio_get_rman(device_t bus, int type, u_int flags) 510af081ec6SJohn Baldwin { 511af081ec6SJohn Baldwin struct macio_softc *sc; 512af081ec6SJohn Baldwin 513af081ec6SJohn Baldwin sc = device_get_softc(bus); 514af081ec6SJohn Baldwin switch (type) { 515af081ec6SJohn Baldwin case SYS_RES_MEMORY: 516af081ec6SJohn Baldwin case SYS_RES_IOPORT: 517af081ec6SJohn Baldwin return (&sc->sc_mem_rman); 518af081ec6SJohn Baldwin default: 519af081ec6SJohn Baldwin return (NULL); 520af081ec6SJohn Baldwin } 521af081ec6SJohn Baldwin } 522af081ec6SJohn Baldwin 52311b370b1SPeter Grehan static struct resource * 52411b370b1SPeter Grehan macio_alloc_resource(device_t bus, device_t child, int type, int *rid, 5252dd1bdf1SJustin Hibbits rman_res_t start, rman_res_t end, rman_res_t count, 5262dd1bdf1SJustin Hibbits u_int flags) 52711b370b1SPeter Grehan { 528af081ec6SJohn Baldwin rman_res_t adjstart, adjend, adjcount; 5293599b2baSBenno Rice struct macio_devinfo *dinfo; 530fe5e7c6bSBenno Rice struct resource_list_entry *rle; 53111b370b1SPeter Grehan 5323599b2baSBenno Rice dinfo = device_get_ivars(child); 53311b370b1SPeter Grehan 53411b370b1SPeter Grehan switch (type) { 53511b370b1SPeter Grehan case SYS_RES_MEMORY: 53611b370b1SPeter Grehan case SYS_RES_IOPORT: 537fe5e7c6bSBenno Rice rle = resource_list_find(&dinfo->mdi_resources, SYS_RES_MEMORY, 538fe5e7c6bSBenno Rice *rid); 539fe5e7c6bSBenno Rice if (rle == NULL) { 540fe5e7c6bSBenno Rice device_printf(bus, "no rle for %s memory %d\n", 541fe5e7c6bSBenno Rice device_get_nameunit(child), *rid); 542fe5e7c6bSBenno Rice return (NULL); 543fe5e7c6bSBenno Rice } 544fe5e7c6bSBenno Rice 545fe5e7c6bSBenno Rice if (start < rle->start) 546fe5e7c6bSBenno Rice adjstart = rle->start; 547fe5e7c6bSBenno Rice else if (start > rle->end) 548fe5e7c6bSBenno Rice adjstart = rle->end; 549fe5e7c6bSBenno Rice else 550fe5e7c6bSBenno Rice adjstart = start; 551fe5e7c6bSBenno Rice 552fe5e7c6bSBenno Rice if (end < rle->start) 553fe5e7c6bSBenno Rice adjend = rle->start; 554fe5e7c6bSBenno Rice else if (end > rle->end) 555fe5e7c6bSBenno Rice adjend = rle->end; 556fe5e7c6bSBenno Rice else 557fe5e7c6bSBenno Rice adjend = end; 558fe5e7c6bSBenno Rice 559fe5e7c6bSBenno Rice adjcount = adjend - adjstart; 560fe5e7c6bSBenno Rice 561af081ec6SJohn Baldwin return (bus_generic_rman_alloc_resource(bus, child, type, rid, 562af081ec6SJohn Baldwin adjstart, adjend, adjcount, flags)); 563fe5e7c6bSBenno Rice 56411b370b1SPeter Grehan case SYS_RES_IRQ: 565b4dbc599SNathan Whitehorn /* Check for passthrough from subattachments like macgpio */ 566b4dbc599SNathan Whitehorn if (device_get_parent(child) != bus) 567b4dbc599SNathan Whitehorn return BUS_ALLOC_RESOURCE(device_get_parent(bus), child, 568b4dbc599SNathan Whitehorn type, rid, start, end, count, flags); 569b4dbc599SNathan Whitehorn 57024b51ed0SBenno Rice rle = resource_list_find(&dinfo->mdi_resources, SYS_RES_IRQ, 57124b51ed0SBenno Rice *rid); 57224b51ed0SBenno Rice if (rle == NULL) { 5734924db93SMarcel Moolenaar if (dinfo->mdi_ninterrupts >= 6) { 57424b51ed0SBenno Rice device_printf(bus, 5754924db93SMarcel Moolenaar "%s has more than 6 interrupts\n", 57624b51ed0SBenno Rice device_get_nameunit(child)); 57724b51ed0SBenno Rice return (NULL); 57824b51ed0SBenno Rice } 57924b51ed0SBenno Rice resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ, 58024b51ed0SBenno Rice dinfo->mdi_ninterrupts, start, start, 1); 58124b51ed0SBenno Rice 58224b51ed0SBenno Rice dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = start; 58324b51ed0SBenno Rice dinfo->mdi_ninterrupts++; 58424b51ed0SBenno Rice } 58524b51ed0SBenno Rice 5863599b2baSBenno Rice return (resource_list_alloc(&dinfo->mdi_resources, bus, child, 5873599b2baSBenno Rice type, rid, start, end, count, flags)); 588fe5e7c6bSBenno Rice 58911b370b1SPeter Grehan default: 59011b370b1SPeter Grehan device_printf(bus, "unknown resource request from %s\n", 59111b370b1SPeter Grehan device_get_nameunit(child)); 59211b370b1SPeter Grehan return (NULL); 59311b370b1SPeter Grehan } 59411b370b1SPeter Grehan } 59511b370b1SPeter Grehan 596af081ec6SJohn Baldwin static int 597fef01f04SJohn Baldwin macio_adjust_resource(device_t bus, device_t child, struct resource *r, 598fef01f04SJohn Baldwin rman_res_t start, rman_res_t end) 599af081ec6SJohn Baldwin { 600fef01f04SJohn Baldwin switch (rman_get_type(r)) { 601af081ec6SJohn Baldwin case SYS_RES_IOPORT: 602af081ec6SJohn Baldwin case SYS_RES_MEMORY: 603fef01f04SJohn Baldwin return (bus_generic_rman_adjust_resource(bus, child, r, start, 604af081ec6SJohn Baldwin end)); 605fef01f04SJohn Baldwin case SYS_RES_IRQ: 606fef01f04SJohn Baldwin return (bus_generic_adjust_resource(bus, child, r, start, end)); 607af081ec6SJohn Baldwin default: 608af081ec6SJohn Baldwin return (EINVAL); 60911b370b1SPeter Grehan } 61011b370b1SPeter Grehan } 61111b370b1SPeter Grehan 61211b370b1SPeter Grehan static int 6139dbf5b0eSJohn Baldwin macio_release_resource(device_t bus, device_t child, struct resource *res) 61411b370b1SPeter Grehan { 6159dbf5b0eSJohn Baldwin switch (rman_get_type(res)) { 616af081ec6SJohn Baldwin case SYS_RES_IOPORT: 617af081ec6SJohn Baldwin case SYS_RES_MEMORY: 6189dbf5b0eSJohn Baldwin return (bus_generic_rman_release_resource(bus, child, res)); 619af081ec6SJohn Baldwin case SYS_RES_IRQ: 6209dbf5b0eSJohn Baldwin return (bus_generic_rl_release_resource(bus, child, res)); 621af081ec6SJohn Baldwin default: 622af081ec6SJohn Baldwin return (EINVAL); 62311b370b1SPeter Grehan } 62411b370b1SPeter Grehan } 62511b370b1SPeter Grehan 62611b370b1SPeter Grehan static int 6272baed46eSJohn Baldwin macio_activate_resource(device_t bus, device_t child, struct resource *res) 62811b370b1SPeter Grehan { 6292baed46eSJohn Baldwin switch (rman_get_type(res)) { 630af081ec6SJohn Baldwin case SYS_RES_IOPORT: 631af081ec6SJohn Baldwin case SYS_RES_MEMORY: 6322baed46eSJohn Baldwin return (bus_generic_rman_activate_resource(bus, child, res)); 633af081ec6SJohn Baldwin case SYS_RES_IRQ: 6342baed46eSJohn Baldwin return (bus_generic_activate_resource(bus, child, res)); 635af081ec6SJohn Baldwin default: 636af081ec6SJohn Baldwin return (EINVAL); 63711b370b1SPeter Grehan } 63811b370b1SPeter Grehan } 63911b370b1SPeter Grehan 64011b370b1SPeter Grehan static int 6412baed46eSJohn Baldwin macio_deactivate_resource(device_t bus, device_t child, struct resource *res) 64211b370b1SPeter Grehan { 6432baed46eSJohn Baldwin switch (rman_get_type(res)) { 644af081ec6SJohn Baldwin case SYS_RES_IOPORT: 645af081ec6SJohn Baldwin case SYS_RES_MEMORY: 6462baed46eSJohn Baldwin return (bus_generic_rman_deactivate_resource(bus, child, res)); 647af081ec6SJohn Baldwin case SYS_RES_IRQ: 6482baed46eSJohn Baldwin return (bus_generic_deactivate_resource(bus, child, res)); 649af081ec6SJohn Baldwin default: 650af081ec6SJohn Baldwin return (EINVAL); 651af081ec6SJohn Baldwin } 652af081ec6SJohn Baldwin } 653af081ec6SJohn Baldwin 654af081ec6SJohn Baldwin static int 655d77f2092SJohn Baldwin macio_map_resource(device_t bus, device_t child, struct resource *r, 656d77f2092SJohn Baldwin struct resource_map_request *argsp, struct resource_map *map) 657af081ec6SJohn Baldwin { 658af081ec6SJohn Baldwin struct resource_map_request args; 659af081ec6SJohn Baldwin struct macio_softc *sc; 660af081ec6SJohn Baldwin rman_res_t length, start; 661af081ec6SJohn Baldwin int error; 662af081ec6SJohn Baldwin 663af081ec6SJohn Baldwin /* Resources must be active to be mapped. */ 664af081ec6SJohn Baldwin if (!(rman_get_flags(r) & RF_ACTIVE)) 665af081ec6SJohn Baldwin return (ENXIO); 666af081ec6SJohn Baldwin 667af081ec6SJohn Baldwin /* Mappings are only supported on I/O and memory resources. */ 668d77f2092SJohn Baldwin switch (rman_get_type(r)) { 669af081ec6SJohn Baldwin case SYS_RES_IOPORT: 670af081ec6SJohn Baldwin case SYS_RES_MEMORY: 671af081ec6SJohn Baldwin break; 672af081ec6SJohn Baldwin default: 673af081ec6SJohn Baldwin return (EINVAL); 674af081ec6SJohn Baldwin } 675af081ec6SJohn Baldwin 676af081ec6SJohn Baldwin resource_init_map_request(&args); 677af081ec6SJohn Baldwin error = resource_validate_map_request(r, argsp, &args, &start, &length); 678af081ec6SJohn Baldwin if (error) 679af081ec6SJohn Baldwin return (error); 680af081ec6SJohn Baldwin 681af081ec6SJohn Baldwin if (bootverbose) 682af081ec6SJohn Baldwin printf("nexus mapdev: start %jx, len %jd\n", 683af081ec6SJohn Baldwin (uintmax_t)start, (uintmax_t)length); 684af081ec6SJohn Baldwin 685af081ec6SJohn Baldwin sc = device_get_softc(bus); 686af081ec6SJohn Baldwin map->r_vaddr = pmap_mapdev_attr((vm_paddr_t)start + sc->sc_base, 687af081ec6SJohn Baldwin length, args.memattr); 688af081ec6SJohn Baldwin if (map->r_vaddr == NULL) 689af081ec6SJohn Baldwin return (ENOMEM); 690f03a2e7bSJustin Hibbits map->r_size = length; 691af081ec6SJohn Baldwin map->r_bustag = &bs_le_tag; 692af081ec6SJohn Baldwin map->r_bushandle = (bus_space_handle_t)map->r_vaddr; 693af081ec6SJohn Baldwin return (0); 694af081ec6SJohn Baldwin } 695af081ec6SJohn Baldwin 696af081ec6SJohn Baldwin static int 697d77f2092SJohn Baldwin macio_unmap_resource(device_t bus, device_t child, struct resource *r, 698d77f2092SJohn Baldwin struct resource_map *map) 699af081ec6SJohn Baldwin { 70011b370b1SPeter Grehan /* 70111b370b1SPeter Grehan * If this is a memory resource, unmap it. 70211b370b1SPeter Grehan */ 703d77f2092SJohn Baldwin switch (rman_get_type(r)) { 704af081ec6SJohn Baldwin case SYS_RES_IOPORT: 705af081ec6SJohn Baldwin case SYS_RES_MEMORY: 706af081ec6SJohn Baldwin pmap_unmapdev(map->r_vaddr, map->r_size); 707af081ec6SJohn Baldwin break; 708af081ec6SJohn Baldwin default: 709af081ec6SJohn Baldwin return (EINVAL); 71011b370b1SPeter Grehan } 711af081ec6SJohn Baldwin return (0); 71211b370b1SPeter Grehan } 71311b370b1SPeter Grehan 71411b370b1SPeter Grehan static struct resource_list * 71511b370b1SPeter Grehan macio_get_resource_list (device_t dev, device_t child) 71611b370b1SPeter Grehan { 717d8154a2aSMarius Strobl struct macio_devinfo *dinfo; 71811b370b1SPeter Grehan 719d8154a2aSMarius Strobl dinfo = device_get_ivars(child); 720d8154a2aSMarius Strobl return (&dinfo->mdi_resources); 72111b370b1SPeter Grehan } 72226280d88SMarius Strobl 723d8154a2aSMarius Strobl static const struct ofw_bus_devinfo * 724d8154a2aSMarius Strobl macio_get_devinfo(device_t dev, device_t child) 72526280d88SMarius Strobl { 72626280d88SMarius Strobl struct macio_devinfo *dinfo; 72726280d88SMarius Strobl 728d8154a2aSMarius Strobl dinfo = device_get_ivars(child); 729d8154a2aSMarius Strobl return (&dinfo->mdi_obdinfo); 73026280d88SMarius Strobl } 73184cd55bbSJustin Hibbits 73284cd55bbSJustin Hibbits int 73384cd55bbSJustin Hibbits macio_enable_wireless(device_t dev, bool enable) 73484cd55bbSJustin Hibbits { 73584cd55bbSJustin Hibbits struct macio_softc *sc = device_get_softc(dev); 73684cd55bbSJustin Hibbits uint32_t x; 73784cd55bbSJustin Hibbits 73884cd55bbSJustin Hibbits if (enable) { 73984cd55bbSJustin Hibbits x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2); 74084cd55bbSJustin Hibbits x |= 0x4; 74184cd55bbSJustin Hibbits bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x); 74284cd55bbSJustin Hibbits 74384cd55bbSJustin Hibbits /* Enable card slot. */ 74484cd55bbSJustin Hibbits bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0f, 5); 74584cd55bbSJustin Hibbits DELAY(1000); 74684cd55bbSJustin Hibbits bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0f, 4); 74784cd55bbSJustin Hibbits DELAY(1000); 74884cd55bbSJustin Hibbits x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2); 74984cd55bbSJustin Hibbits x &= ~0x80000000; 75084cd55bbSJustin Hibbits 75184cd55bbSJustin Hibbits bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x); 75284cd55bbSJustin Hibbits /* out8(gpio + 0x10, 4); */ 75384cd55bbSJustin Hibbits 75484cd55bbSJustin Hibbits bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0b, 0); 75584cd55bbSJustin Hibbits bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0a, 0x28); 75684cd55bbSJustin Hibbits bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0d, 0x28); 75784cd55bbSJustin Hibbits bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0d, 0x28); 75884cd55bbSJustin Hibbits bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0e, 0x28); 75984cd55bbSJustin Hibbits bus_write_4(sc->sc_memr, 0x1c000, 0); 76084cd55bbSJustin Hibbits 76184cd55bbSJustin Hibbits /* Initialize the card. */ 76284cd55bbSJustin Hibbits bus_write_4(sc->sc_memr, 0x1a3e0, 0x41); 76384cd55bbSJustin Hibbits x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2); 76484cd55bbSJustin Hibbits x |= 0x80000000; 76584cd55bbSJustin Hibbits bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x); 76684cd55bbSJustin Hibbits } else { 76784cd55bbSJustin Hibbits x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2); 76884cd55bbSJustin Hibbits x &= ~0x4; 76984cd55bbSJustin Hibbits bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x); 77084cd55bbSJustin Hibbits /* out8(gpio + 0x10, 0); */ 77184cd55bbSJustin Hibbits } 77284cd55bbSJustin Hibbits 77384cd55bbSJustin Hibbits return (0); 77484cd55bbSJustin Hibbits } 775c583b025SBrandon Bergren 776c583b025SBrandon Bergren #if !defined(__powerpc64__) && defined(SMP) 777c583b025SBrandon Bergren static void 778c583b025SBrandon Bergren macio_freeze_timebase(device_t dev, bool freeze) 779c583b025SBrandon Bergren { 780c583b025SBrandon Bergren struct macio_softc *sc = device_get_softc(dev); 781c583b025SBrandon Bergren 782c583b025SBrandon Bergren if (freeze) { 783c583b025SBrandon Bergren bus_write_1(sc->sc_memr, sc->sc_timebase, 4); 784c583b025SBrandon Bergren } else { 785c583b025SBrandon Bergren bus_write_1(sc->sc_memr, sc->sc_timebase, 0); 786c583b025SBrandon Bergren } 787c583b025SBrandon Bergren bus_read_1(sc->sc_memr, sc->sc_timebase); 788c583b025SBrandon Bergren } 789c583b025SBrandon Bergren #endif 790