xref: /freebsd-src/sys/powerpc/powermac/macio.c (revision 18250ec6c089c0c50cbd9fd87d78e03ff89916df)
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 **)&reg);
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 **)&regp);
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