1139825Simp/*-
2103619Sgrehan * Copyright 2002 by Peter Grehan. All rights reserved.
3103619Sgrehan *
4103619Sgrehan * Redistribution and use in source and binary forms, with or without
5103619Sgrehan * modification, are permitted provided that the following conditions
6103619Sgrehan * are met:
7103619Sgrehan * 1. Redistributions of source code must retain the above copyright
8103619Sgrehan *    notice, this list of conditions and the following disclaimer.
9103619Sgrehan * 2. Redistributions in binary form must reproduce the above copyright
10103619Sgrehan *    notice, this list of conditions and the following disclaimer in the
11103619Sgrehan *    documentation and/or other materials provided with the distribution.
12103619Sgrehan * 3. The name of the author may not be used to endorse or promote products
13103619Sgrehan *    derived from this software without specific prior written permission.
14103619Sgrehan *
15103619Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16103619Sgrehan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17103619Sgrehan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18103619Sgrehan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19103619Sgrehan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20103619Sgrehan * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21103619Sgrehan * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22103619Sgrehan * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23103619Sgrehan * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24103619Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25103619Sgrehan * SUCH DAMAGE.
26103619Sgrehan *
27103619Sgrehan * $FreeBSD$
28103619Sgrehan */
29103619Sgrehan
30103619Sgrehan/*
31103619Sgrehan * Driver for KeyLargo/Pangea, the MacPPC south bridge ASIC.
32103619Sgrehan */
33103619Sgrehan
34103619Sgrehan#include <sys/param.h>
35103619Sgrehan#include <sys/systm.h>
36103619Sgrehan#include <sys/kernel.h>
37103619Sgrehan#include <sys/malloc.h>
38131102Sgrehan#include <sys/module.h>
39103619Sgrehan#include <sys/bus.h>
40103619Sgrehan#include <sys/rman.h>
41103619Sgrehan
42103619Sgrehan#include <vm/vm.h>
43103619Sgrehan#include <vm/pmap.h>
44209298Snwhitehorn
45209298Snwhitehorn#include <machine/bus.h>
46209298Snwhitehorn#include <machine/intr_machdep.h>
47103619Sgrehan#include <machine/resource.h>
48209298Snwhitehorn#include <machine/vmparam.h>
49103619Sgrehan
50133589Smarius#include <dev/ofw/ofw_bus.h>
51153050Smarius#include <dev/ofw/ofw_bus_subr.h>
52103619Sgrehan#include <dev/ofw/openfirm.h>
53103619Sgrehan
54103619Sgrehan#include <powerpc/powermac/maciovar.h>
55103619Sgrehan
56103619Sgrehan#include <dev/pci/pcivar.h>
57103619Sgrehan#include <dev/pci/pcireg.h>
58103619Sgrehan
59131400Sgrehan/*
60131400Sgrehan * Macio softc
61131400Sgrehan */
62131400Sgrehanstruct macio_softc {
63131400Sgrehan	phandle_t    sc_node;
64131400Sgrehan	vm_offset_t  sc_base;
65131400Sgrehan	vm_offset_t  sc_size;
66131400Sgrehan	struct rman  sc_mem_rman;
67221519Snwhitehorn
68221519Snwhitehorn	/* FCR registers */
69221519Snwhitehorn	int          sc_memrid;
70221519Snwhitehorn	struct resource	*sc_memr;
71131400Sgrehan};
72131400Sgrehan
73103619Sgrehanstatic MALLOC_DEFINE(M_MACIO, "macio", "macio device information");
74103619Sgrehan
75103619Sgrehanstatic int  macio_probe(device_t);
76103619Sgrehanstatic int  macio_attach(device_t);
77103619Sgrehanstatic int  macio_print_child(device_t dev, device_t child);
78103619Sgrehanstatic void macio_probe_nomatch(device_t, device_t);
79103619Sgrehanstatic struct   resource *macio_alloc_resource(device_t, device_t, int, int *,
80294883Sjhibbits					       rman_res_t, rman_res_t, rman_res_t,
81294883Sjhibbits					       u_int);
82103619Sgrehanstatic int  macio_activate_resource(device_t, device_t, int, int,
83103619Sgrehan				    struct resource *);
84103619Sgrehanstatic int  macio_deactivate_resource(device_t, device_t, int, int,
85103619Sgrehan				      struct resource *);
86103619Sgrehanstatic int  macio_release_resource(device_t, device_t, int, int,
87103619Sgrehan				   struct resource *);
88103619Sgrehanstatic struct resource_list *macio_get_resource_list (device_t, device_t);
89153050Smariusstatic ofw_bus_get_devinfo_t macio_get_devinfo;
90103619Sgrehan
91103619Sgrehan/*
92103619Sgrehan * Bus interface definition
93103619Sgrehan */
94103619Sgrehanstatic device_method_t macio_methods[] = {
95103619Sgrehan	/* Device interface */
96103619Sgrehan	DEVMETHOD(device_probe,         macio_probe),
97103619Sgrehan	DEVMETHOD(device_attach,        macio_attach),
98103619Sgrehan	DEVMETHOD(device_detach,        bus_generic_detach),
99103619Sgrehan	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
100103619Sgrehan	DEVMETHOD(device_suspend,       bus_generic_suspend),
101103619Sgrehan	DEVMETHOD(device_resume,        bus_generic_resume),
102103619Sgrehan
103103619Sgrehan	/* Bus interface */
104103619Sgrehan	DEVMETHOD(bus_print_child,      macio_print_child),
105103619Sgrehan	DEVMETHOD(bus_probe_nomatch,    macio_probe_nomatch),
106103619Sgrehan	DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
107103619Sgrehan	DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
108103619Sgrehan
109103619Sgrehan        DEVMETHOD(bus_alloc_resource,   macio_alloc_resource),
110103619Sgrehan        DEVMETHOD(bus_release_resource, macio_release_resource),
111103619Sgrehan        DEVMETHOD(bus_activate_resource, macio_activate_resource),
112103619Sgrehan        DEVMETHOD(bus_deactivate_resource, macio_deactivate_resource),
113103619Sgrehan        DEVMETHOD(bus_get_resource_list, macio_get_resource_list),
114103619Sgrehan
115186128Snwhitehorn	DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
116186128Snwhitehorn
117133589Smarius	/* ofw_bus interface */
118153050Smarius	DEVMETHOD(ofw_bus_get_devinfo,	macio_get_devinfo),
119153050Smarius	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
120153050Smarius	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
121153050Smarius	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
122153050Smarius	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
123153050Smarius	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
124133589Smarius
125103619Sgrehan	{ 0, 0 }
126103619Sgrehan};
127103619Sgrehan
128103619Sgrehanstatic driver_t macio_pci_driver = {
129103619Sgrehan        "macio",
130103619Sgrehan        macio_methods,
131103619Sgrehan	sizeof(struct macio_softc)
132103619Sgrehan};
133103619Sgrehan
134103619Sgrehandevclass_t macio_devclass;
135103619Sgrehan
136103619SgrehanDRIVER_MODULE(macio, pci, macio_pci_driver, macio_devclass, 0, 0);
137103619Sgrehan
138103619Sgrehan/*
139103619Sgrehan * PCI ID search table
140103619Sgrehan */
141103619Sgrehanstatic struct macio_pci_dev {
142103619Sgrehan        u_int32_t  mpd_devid;
143103619Sgrehan	char    *mpd_desc;
144103619Sgrehan} macio_pci_devlist[] = {
145112428Sgrehan	{ 0x0017106b, "Paddington I/O Controller" },
146112428Sgrehan	{ 0x0022106b, "KeyLargo I/O Controller" },
147103619Sgrehan	{ 0x0025106b, "Pangea I/O Controller" },
148112428Sgrehan	{ 0x003e106b, "Intrepid I/O Controller" },
149183882Snwhitehorn	{ 0x0041106b, "K2 KeyLargo I/O Controller" },
150183882Snwhitehorn	{ 0x004f106b, "Shasta I/O Controller" },
151112428Sgrehan	{ 0, NULL }
152103619Sgrehan};
153103619Sgrehan
154103619Sgrehan/*
155103619Sgrehan * Devices to exclude from the probe
156103619Sgrehan * XXX some of these may be required in the future...
157103619Sgrehan */
158108991Sbenno#define	MACIO_QUIRK_IGNORE		0x00000001
159108991Sbenno#define	MACIO_QUIRK_CHILD_HAS_INTR	0x00000002
160186805Snwhitehorn#define	MACIO_QUIRK_USE_CHILD_REG	0x00000004
161108991Sbenno
162108991Sbennostruct macio_quirk_entry {
163108991Sbenno	const char	*mq_name;
164108991Sbenno	int		mq_quirks;
165103619Sgrehan};
166103619Sgrehan
167108991Sbennostatic struct macio_quirk_entry macio_quirks[] = {
168108991Sbenno	{ "escc-legacy",		MACIO_QUIRK_IGNORE },
169108991Sbenno	{ "timer",			MACIO_QUIRK_IGNORE },
170108991Sbenno	{ "escc",			MACIO_QUIRK_CHILD_HAS_INTR },
171186805Snwhitehorn        { "i2s", 			MACIO_QUIRK_CHILD_HAS_INTR |
172186805Snwhitehorn					MACIO_QUIRK_USE_CHILD_REG },
173186805Snwhitehorn	{ NULL,				0 }
174108991Sbenno};
175108991Sbenno
176103619Sgrehanstatic int
177108991Sbennomacio_get_quirks(const char *name)
178103619Sgrehan{
179108991Sbenno        struct	macio_quirk_entry *mqe;
180103619Sgrehan
181108991Sbenno        for (mqe = macio_quirks; mqe->mq_name != NULL; mqe++)
182108991Sbenno                if (strcmp(name, mqe->mq_name) == 0)
183108991Sbenno                        return (mqe->mq_quirks);
184103619Sgrehan        return (0);
185103619Sgrehan}
186103619Sgrehan
187103619Sgrehan
188103619Sgrehan/*
189103619Sgrehan * Add an interrupt to the dev's resource list if present
190103619Sgrehan */
191103619Sgrehanstatic void
192103619Sgrehanmacio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo)
193103619Sgrehan{
194209298Snwhitehorn	phandle_t iparent;
195178599Smarcel	int	*intr;
196178599Smarcel	int	i, nintr;
197178599Smarcel	int 	icells;
198108991Sbenno
199178599Smarcel	if (dinfo->mdi_ninterrupts >= 6) {
200178599Smarcel		printf("macio: device has more than 6 interrupts\n");
201108991Sbenno		return;
202108991Sbenno	}
203108991Sbenno
204178599Smarcel	nintr = OF_getprop_alloc(devnode, "interrupts", sizeof(*intr),
205178599Smarcel		(void **)&intr);
206178599Smarcel	if (nintr == -1) {
207178599Smarcel		nintr = OF_getprop_alloc(devnode, "AAPL,interrupts",
208178599Smarcel			sizeof(*intr), (void **)&intr);
209178599Smarcel		if (nintr == -1)
210108991Sbenno			return;
211108991Sbenno	}
212108991Sbenno
213178599Smarcel	if (intr[0] == -1)
214108991Sbenno		return;
215108991Sbenno
216209298Snwhitehorn	if (OF_getprop(devnode, "interrupt-parent", &iparent, sizeof(iparent))
217209298Snwhitehorn	    <= 0)
218209298Snwhitehorn		panic("Interrupt but no interrupt parent!\n");
219209298Snwhitehorn
220270945Sian	if (OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells,
221258274Snwhitehorn	    sizeof(icells)) <= 0)
222258274Snwhitehorn		icells = 1;
223258274Snwhitehorn
224178599Smarcel	for (i = 0; i < nintr; i+=icells) {
225218184Smarcel		u_int irq = MAP_IRQ(iparent, intr[i]);
226218184Smarcel
227178599Smarcel		resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ,
228218184Smarcel		    dinfo->mdi_ninterrupts, irq, irq, 1);
229108991Sbenno
230218184Smarcel		dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = irq;
231178599Smarcel		dinfo->mdi_ninterrupts++;
232178599Smarcel	}
233103619Sgrehan}
234103619Sgrehan
235103619Sgrehan
236103619Sgrehanstatic void
237103619Sgrehanmacio_add_reg(phandle_t devnode, struct macio_devinfo *dinfo)
238103619Sgrehan{
239260934Sandreast	struct		macio_reg *reg, *regp;
240260934Sandreast	phandle_t 	child;
241260934Sandreast	char		buf[8];
242260934Sandreast	int		i, layout_id = 0, nreg, res;
243110080Sbenno
244110080Sbenno	nreg = OF_getprop_alloc(devnode, "reg", sizeof(*reg), (void **)&reg);
245110080Sbenno	if (nreg == -1)
246110080Sbenno		return;
247110080Sbenno
248260934Sandreast        /*
249260934Sandreast         *  Some G5's have broken properties in the i2s-a area. If so we try
250260934Sandreast         *  to fix it. Right now we know of two different cases, one for
251260934Sandreast         *  sound layout-id 36 and the other one for sound layout-id 76.
252260934Sandreast         *  What is missing is the base address for the memory addresses.
253260934Sandreast         *  We take them from the parent node (i2s) and use the size
254260934Sandreast         *  information from the child.
255260934Sandreast         */
256260934Sandreast
257260934Sandreast        if (reg[0].mr_base == 0) {
258260934Sandreast		child = OF_child(devnode);
259260934Sandreast		while (child != 0) {
260260934Sandreast			res = OF_getprop(child, "name", buf, sizeof(buf));
261260934Sandreast			if (res > 0 && strcmp(buf, "sound") == 0)
262260934Sandreast				break;
263260934Sandreast			child = OF_peer(child);
264260934Sandreast		}
265260934Sandreast
266260934Sandreast                res = OF_getprop(child, "layout-id", &layout_id,
267260934Sandreast				sizeof(layout_id));
268260934Sandreast
269260934Sandreast                if (res > 0 && (layout_id == 36 || layout_id == 76)) {
270260934Sandreast                        res = OF_getprop_alloc(OF_parent(devnode), "reg",
271260934Sandreast						sizeof(*regp), (void **)&regp);
272260934Sandreast                        reg[0] = regp[0];
273260934Sandreast                        reg[1].mr_base = regp[1].mr_base;
274260934Sandreast                        reg[2].mr_base = regp[1].mr_base + reg[1].mr_size;
275260934Sandreast                }
276260934Sandreast        }
277260934Sandreast
278110080Sbenno	for (i = 0; i < nreg; i++) {
279110080Sbenno		resource_list_add(&dinfo->mdi_resources, SYS_RES_MEMORY, i,
280110080Sbenno		    reg[i].mr_base, reg[i].mr_base + reg[i].mr_size,
281110080Sbenno		    reg[i].mr_size);
282103619Sgrehan	}
283103619Sgrehan}
284103619Sgrehan
285103619Sgrehan/*
286103619Sgrehan * PCI probe
287103619Sgrehan */
288103619Sgrehanstatic int
289103619Sgrehanmacio_probe(device_t dev)
290103619Sgrehan{
291103619Sgrehan        int i;
292103619Sgrehan        u_int32_t devid;
293103619Sgrehan
294103619Sgrehan        devid = pci_get_devid(dev);
295103619Sgrehan        for (i = 0; macio_pci_devlist[i].mpd_desc != NULL; i++) {
296103619Sgrehan                if (devid == macio_pci_devlist[i].mpd_devid) {
297103619Sgrehan                        device_set_desc(dev, macio_pci_devlist[i].mpd_desc);
298103619Sgrehan                        return (0);
299103619Sgrehan                }
300103619Sgrehan        }
301103619Sgrehan
302103619Sgrehan        return (ENXIO);
303103619Sgrehan}
304103619Sgrehan
305103619Sgrehan/*
306133862Smarius * PCI attach: scan Open Firmware child nodes, and attach these as children
307103619Sgrehan * of the macio bus
308103619Sgrehan */
309103619Sgrehanstatic int
310103619Sgrehanmacio_attach(device_t dev)
311103619Sgrehan{
312103619Sgrehan	struct macio_softc *sc;
313103619Sgrehan        struct macio_devinfo *dinfo;
314103619Sgrehan        phandle_t  root;
315103619Sgrehan	phandle_t  child;
316108991Sbenno	phandle_t  subchild;
317103619Sgrehan        device_t cdev;
318103619Sgrehan        u_int reg[3];
319260934Sandreast	char compat[32];
320179746Skevlo	int error, quirks;
321103619Sgrehan
322103619Sgrehan	sc = device_get_softc(dev);
323183882Snwhitehorn	root = sc->sc_node = ofw_bus_get_node(dev);
324103619Sgrehan
325103619Sgrehan	/*
326103619Sgrehan	 * Locate the device node and it's base address
327103619Sgrehan	 */
328103619Sgrehan	if (OF_getprop(root, "assigned-addresses",
329230398Snwhitehorn		       reg, sizeof(reg)) < (ssize_t)sizeof(reg)) {
330103619Sgrehan		return (ENXIO);
331103619Sgrehan	}
332103619Sgrehan
333260934Sandreast	/* Used later to see if we have to enable the I2S part. */
334260934Sandreast	OF_getprop(root, "compatible", compat, sizeof(compat));
335260934Sandreast
336103619Sgrehan	sc->sc_base = reg[2];
337103619Sgrehan	sc->sc_size = MACIO_REG_SIZE;
338103619Sgrehan
339221519Snwhitehorn	sc->sc_memrid = PCIR_BAR(0);
340221519Snwhitehorn	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
341221519Snwhitehorn	    &sc->sc_memrid, RF_ACTIVE);
342221519Snwhitehorn
343103619Sgrehan	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
344110080Sbenno	sc->sc_mem_rman.rm_descr = "MacIO Device Memory";
345179746Skevlo	error = rman_init(&sc->sc_mem_rman);
346179746Skevlo	if (error) {
347179746Skevlo		device_printf(dev, "rman_init() failed. error = %d\n", error);
348179746Skevlo		return (error);
349179746Skevlo	}
350179746Skevlo	error = rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size);
351179746Skevlo	if (error) {
352103619Sgrehan		device_printf(dev,
353179746Skevlo		    "rman_manage_region() failed. error = %d\n", error);
354179746Skevlo		return (error);
355103619Sgrehan	}
356103619Sgrehan
357103619Sgrehan	/*
358103619Sgrehan	 * Iterate through the sub-devices
359103619Sgrehan	 */
360103619Sgrehan	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
361153050Smarius		dinfo = malloc(sizeof(*dinfo), M_MACIO, M_WAITOK | M_ZERO);
362153050Smarius		if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) !=
363153050Smarius		    0) {
364153050Smarius			free(dinfo, M_MACIO);
365153050Smarius			continue;
366153050Smarius		}
367153050Smarius		quirks = macio_get_quirks(dinfo->mdi_obdinfo.obd_name);
368108991Sbenno		if ((quirks & MACIO_QUIRK_IGNORE) != 0) {
369153050Smarius			ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo);
370153050Smarius			free(dinfo, M_MACIO);
371103619Sgrehan			continue;
372103619Sgrehan		}
373153050Smarius		resource_list_init(&dinfo->mdi_resources);
374153050Smarius		dinfo->mdi_ninterrupts = 0;
375153050Smarius		macio_add_intr(child, dinfo);
376186805Snwhitehorn		if ((quirks & MACIO_QUIRK_USE_CHILD_REG) != 0)
377186805Snwhitehorn			macio_add_reg(OF_child(child), dinfo);
378186805Snwhitehorn		else
379186805Snwhitehorn			macio_add_reg(child, dinfo);
380153050Smarius		if ((quirks & MACIO_QUIRK_CHILD_HAS_INTR) != 0)
381153050Smarius			for (subchild = OF_child(child); subchild != 0;
382153050Smarius			    subchild = OF_peer(subchild))
383153050Smarius				macio_add_intr(subchild, dinfo);
384103619Sgrehan		cdev = device_add_child(dev, NULL, -1);
385153050Smarius		if (cdev == NULL) {
386153050Smarius			device_printf(dev, "<%s>: device_add_child failed\n",
387153050Smarius			    dinfo->mdi_obdinfo.obd_name);
388153050Smarius			resource_list_free(&dinfo->mdi_resources);
389153050Smarius			ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo);
390153050Smarius			free(dinfo, M_MACIO);
391153050Smarius			continue;
392103619Sgrehan		}
393153050Smarius		device_set_ivars(cdev, dinfo);
394221519Snwhitehorn
395221519Snwhitehorn		/* Set FCRs to enable some devices */
396221519Snwhitehorn		if (sc->sc_memr == NULL)
397221519Snwhitehorn			continue;
398221519Snwhitehorn
399221519Snwhitehorn		if (strcmp(ofw_bus_get_name(cdev), "bmac") == 0 ||
400221519Snwhitehorn		    strcmp(ofw_bus_get_compat(cdev), "bmac+") == 0) {
401221519Snwhitehorn			uint32_t fcr;
402221519Snwhitehorn
403221519Snwhitehorn			fcr = bus_read_4(sc->sc_memr, HEATHROW_FCR);
404221519Snwhitehorn
405221519Snwhitehorn			fcr |= FCR_ENET_ENABLE & ~FCR_ENET_RESET;
406221519Snwhitehorn			bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr);
407221519Snwhitehorn			DELAY(50000);
408221519Snwhitehorn			fcr |= FCR_ENET_RESET;
409221519Snwhitehorn			bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr);
410221519Snwhitehorn			DELAY(50000);
411221519Snwhitehorn			fcr &= ~FCR_ENET_RESET;
412221519Snwhitehorn			bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr);
413221519Snwhitehorn			DELAY(50000);
414221519Snwhitehorn
415221519Snwhitehorn			bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr);
416221519Snwhitehorn		}
417260934Sandreast
418260934Sandreast		/*
419260934Sandreast		 * Make sure the I2S0 and the I2S0_CLK are enabled.
420260934Sandreast		 * On certain G5's they are not.
421260934Sandreast		 */
422260934Sandreast		if ((strcmp(ofw_bus_get_name(cdev), "i2s") == 0) &&
423260934Sandreast		    (strcmp(compat, "K2-Keylargo") == 0)) {
424260934Sandreast
425260934Sandreast			uint32_t fcr1;
426260934Sandreast
427260934Sandreast			fcr1 = bus_read_4(sc->sc_memr, KEYLARGO_FCR1);
428260934Sandreast			fcr1 |= FCR1_I2S0_CLK_ENABLE | FCR1_I2S0_ENABLE;
429260934Sandreast			bus_write_4(sc->sc_memr, KEYLARGO_FCR1, fcr1);
430260934Sandreast		}
431260934Sandreast
432103619Sgrehan	}
433103619Sgrehan
434103619Sgrehan	return (bus_generic_attach(dev));
435103619Sgrehan}
436103619Sgrehan
437103619Sgrehan
438103619Sgrehanstatic int
439103619Sgrehanmacio_print_child(device_t dev, device_t child)
440103619Sgrehan{
441103619Sgrehan        struct macio_devinfo *dinfo;
442103619Sgrehan        struct resource_list *rl;
443103619Sgrehan        int retval = 0;
444103619Sgrehan
445103619Sgrehan        dinfo = device_get_ivars(child);
446103619Sgrehan        rl = &dinfo->mdi_resources;
447103619Sgrehan
448103619Sgrehan        retval += bus_print_child_header(dev, child);
449103619Sgrehan
450297199Sjhibbits        retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
451297199Sjhibbits        retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
452103619Sgrehan
453103619Sgrehan        retval += bus_print_child_footer(dev, child);
454103619Sgrehan
455103619Sgrehan        return (retval);
456103619Sgrehan}
457103619Sgrehan
458103619Sgrehan
459103619Sgrehanstatic void
460103619Sgrehanmacio_probe_nomatch(device_t dev, device_t child)
461103619Sgrehan{
462110080Sbenno        struct macio_devinfo *dinfo;
463110080Sbenno        struct resource_list *rl;
464133589Smarius	const char *type;
465103619Sgrehan
466103619Sgrehan	if (bootverbose) {
467110080Sbenno		dinfo = device_get_ivars(child);
468110080Sbenno		rl = &dinfo->mdi_resources;
469103619Sgrehan
470133589Smarius		if ((type = ofw_bus_get_type(child)) == NULL)
471133589Smarius			type = "(unknown)";
472133589Smarius		device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child));
473297199Sjhibbits		resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
474297199Sjhibbits		resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
475110080Sbenno		printf(" (no driver attached)\n");
476103619Sgrehan	}
477103619Sgrehan}
478103619Sgrehan
479103619Sgrehan
480103619Sgrehanstatic struct resource *
481103619Sgrehanmacio_alloc_resource(device_t bus, device_t child, int type, int *rid,
482294883Sjhibbits		     rman_res_t start, rman_res_t end, rman_res_t count,
483294883Sjhibbits		     u_int flags)
484103619Sgrehan{
485110080Sbenno	struct		macio_softc *sc;
486110080Sbenno	int		needactivate;
487110080Sbenno	struct		resource *rv;
488110080Sbenno	struct		rman *rm;
489110080Sbenno	u_long		adjstart, adjend, adjcount;
490110080Sbenno	struct		macio_devinfo *dinfo;
491110080Sbenno	struct		resource_list_entry *rle;
492103619Sgrehan
493103619Sgrehan	sc = device_get_softc(bus);
494108994Sbenno	dinfo = device_get_ivars(child);
495103619Sgrehan
496103619Sgrehan	needactivate = flags & RF_ACTIVE;
497103619Sgrehan	flags &= ~RF_ACTIVE;
498103619Sgrehan
499103619Sgrehan	switch (type) {
500103619Sgrehan	case SYS_RES_MEMORY:
501103619Sgrehan	case SYS_RES_IOPORT:
502110080Sbenno		rle = resource_list_find(&dinfo->mdi_resources, SYS_RES_MEMORY,
503110080Sbenno		    *rid);
504110080Sbenno		if (rle == NULL) {
505110080Sbenno			device_printf(bus, "no rle for %s memory %d\n",
506110080Sbenno			    device_get_nameunit(child), *rid);
507110080Sbenno			return (NULL);
508110080Sbenno		}
509110080Sbenno
510110080Sbenno		if (start < rle->start)
511110080Sbenno			adjstart = rle->start;
512110080Sbenno		else if (start > rle->end)
513110080Sbenno			adjstart = rle->end;
514110080Sbenno		else
515110080Sbenno			adjstart = start;
516110080Sbenno
517110080Sbenno		if (end < rle->start)
518110080Sbenno			adjend = rle->start;
519110080Sbenno		else if (end > rle->end)
520110080Sbenno			adjend = rle->end;
521110080Sbenno		else
522110080Sbenno			adjend = end;
523110080Sbenno
524110080Sbenno		adjcount = adjend - adjstart;
525110080Sbenno
526103619Sgrehan		rm = &sc->sc_mem_rman;
527103619Sgrehan		break;
528110080Sbenno
529103619Sgrehan	case SYS_RES_IRQ:
530184299Snwhitehorn		/* Check for passthrough from subattachments like macgpio */
531184299Snwhitehorn		if (device_get_parent(child) != bus)
532184299Snwhitehorn			return BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
533184299Snwhitehorn			    type, rid, start, end, count, flags);
534184299Snwhitehorn
535110436Sbenno		rle = resource_list_find(&dinfo->mdi_resources, SYS_RES_IRQ,
536110436Sbenno		    *rid);
537110436Sbenno		if (rle == NULL) {
538178599Smarcel			if (dinfo->mdi_ninterrupts >= 6) {
539110436Sbenno				device_printf(bus,
540178599Smarcel				    "%s has more than 6 interrupts\n",
541110436Sbenno				    device_get_nameunit(child));
542110436Sbenno				return (NULL);
543110436Sbenno			}
544110436Sbenno			resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ,
545110436Sbenno			    dinfo->mdi_ninterrupts, start, start, 1);
546110436Sbenno
547110436Sbenno			dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = start;
548110436Sbenno			dinfo->mdi_ninterrupts++;
549110436Sbenno		}
550110436Sbenno
551108994Sbenno		return (resource_list_alloc(&dinfo->mdi_resources, bus, child,
552108994Sbenno		    type, rid, start, end, count, flags));
553110080Sbenno
554103619Sgrehan	default:
555103619Sgrehan		device_printf(bus, "unknown resource request from %s\n",
556103619Sgrehan			      device_get_nameunit(child));
557103619Sgrehan		return (NULL);
558103619Sgrehan	}
559103619Sgrehan
560110080Sbenno	rv = rman_reserve_resource(rm, adjstart, adjend, adjcount, flags,
561110080Sbenno	    child);
562103619Sgrehan	if (rv == NULL) {
563110080Sbenno		device_printf(bus,
564110080Sbenno		    "failed to reserve resource %#lx - %#lx (%#lx) for %s\n",
565110080Sbenno		    adjstart, adjend, adjcount, device_get_nameunit(child));
566103619Sgrehan		return (NULL);
567103619Sgrehan	}
568103619Sgrehan
569157895Simp	rman_set_rid(rv, *rid);
570103619Sgrehan
571103619Sgrehan	if (needactivate) {
572103619Sgrehan		if (bus_activate_resource(child, type, *rid, rv) != 0) {
573103619Sgrehan                        device_printf(bus,
574103619Sgrehan				      "failed to activate resource for %s\n",
575103619Sgrehan				      device_get_nameunit(child));
576103619Sgrehan			rman_release_resource(rv);
577103619Sgrehan			return (NULL);
578103619Sgrehan                }
579103619Sgrehan        }
580103619Sgrehan
581110080Sbenno	return (rv);
582103619Sgrehan}
583103619Sgrehan
584103619Sgrehan
585103619Sgrehanstatic int
586103619Sgrehanmacio_release_resource(device_t bus, device_t child, int type, int rid,
587103619Sgrehan		       struct resource *res)
588103619Sgrehan{
589103619Sgrehan	if (rman_get_flags(res) & RF_ACTIVE) {
590103619Sgrehan		int error = bus_deactivate_resource(child, type, rid, res);
591103619Sgrehan		if (error)
592103619Sgrehan			return error;
593103619Sgrehan	}
594103619Sgrehan
595103619Sgrehan	return (rman_release_resource(res));
596103619Sgrehan}
597103619Sgrehan
598103619Sgrehan
599103619Sgrehanstatic int
600103619Sgrehanmacio_activate_resource(device_t bus, device_t child, int type, int rid,
601103619Sgrehan			   struct resource *res)
602103619Sgrehan{
603103619Sgrehan	struct macio_softc *sc;
604103619Sgrehan	void    *p;
605103619Sgrehan
606103619Sgrehan	sc = device_get_softc(bus);
607103619Sgrehan
608103619Sgrehan	if (type == SYS_RES_IRQ)
609103619Sgrehan                return (bus_activate_resource(bus, type, rid, res));
610103619Sgrehan
611103619Sgrehan	if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
612103619Sgrehan		p = pmap_mapdev((vm_offset_t)rman_get_start(res) + sc->sc_base,
613103619Sgrehan				(vm_size_t)rman_get_size(res));
614103619Sgrehan		if (p == NULL)
615103619Sgrehan			return (ENOMEM);
616103619Sgrehan		rman_set_virtual(res, p);
617174822Smarcel		rman_set_bustag(res, &bs_le_tag);
618103619Sgrehan		rman_set_bushandle(res, (u_long)p);
619103619Sgrehan	}
620103619Sgrehan
621103619Sgrehan	return (rman_activate_resource(res));
622103619Sgrehan}
623103619Sgrehan
624103619Sgrehan
625103619Sgrehanstatic int
626103619Sgrehanmacio_deactivate_resource(device_t bus, device_t child, int type, int rid,
627103619Sgrehan			  struct resource *res)
628103619Sgrehan{
629103619Sgrehan        /*
630103619Sgrehan         * If this is a memory resource, unmap it.
631103619Sgrehan         */
632103619Sgrehan        if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
633103619Sgrehan		u_int32_t psize;
634103619Sgrehan
635103619Sgrehan		psize = rman_get_size(res);
636103619Sgrehan		pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
637103619Sgrehan	}
638103619Sgrehan
639103619Sgrehan	return (rman_deactivate_resource(res));
640103619Sgrehan}
641103619Sgrehan
642103619Sgrehan
643103619Sgrehanstatic struct resource_list *
644103619Sgrehanmacio_get_resource_list (device_t dev, device_t child)
645103619Sgrehan{
646133589Smarius	struct macio_devinfo *dinfo;
647133589Smarius
648153050Smarius	dinfo = device_get_ivars(child);
649153050Smarius	return (&dinfo->mdi_resources);
650133589Smarius}
651133589Smarius
652153050Smariusstatic const struct ofw_bus_devinfo *
653153050Smariusmacio_get_devinfo(device_t dev, device_t child)
654133589Smarius{
655133589Smarius	struct macio_devinfo *dinfo;
656133589Smarius
657153050Smarius	dinfo = device_get_ivars(child);
658153050Smarius	return (&dinfo->mdi_obdinfo);
659133589Smarius}
660253825Sjhibbits
661253825Sjhibbitsint
662253825Sjhibbitsmacio_enable_wireless(device_t dev, bool enable)
663253825Sjhibbits{
664253825Sjhibbits	struct macio_softc *sc = device_get_softc(dev);
665253825Sjhibbits	uint32_t x;
666253825Sjhibbits
667253825Sjhibbits	if (enable) {
668253825Sjhibbits		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
669253825Sjhibbits		x |= 0x4;
670253825Sjhibbits		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
671253825Sjhibbits
672253825Sjhibbits		/* Enable card slot. */
673253825Sjhibbits		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0f, 5);
674253825Sjhibbits		DELAY(1000);
675253825Sjhibbits		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0f, 4);
676253825Sjhibbits		DELAY(1000);
677253825Sjhibbits		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
678253825Sjhibbits		x &= ~0x80000000;
679253825Sjhibbits
680253825Sjhibbits		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
681253825Sjhibbits		/* out8(gpio + 0x10, 4); */
682253825Sjhibbits
683253825Sjhibbits		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0b, 0);
684253825Sjhibbits		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0a, 0x28);
685253825Sjhibbits		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0d, 0x28);
686253825Sjhibbits		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0d, 0x28);
687253825Sjhibbits		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0e, 0x28);
688253825Sjhibbits		bus_write_4(sc->sc_memr, 0x1c000, 0);
689253825Sjhibbits
690253825Sjhibbits		/* Initialize the card. */
691253825Sjhibbits		bus_write_4(sc->sc_memr, 0x1a3e0, 0x41);
692253825Sjhibbits		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
693253825Sjhibbits		x |= 0x80000000;
694253825Sjhibbits		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
695253825Sjhibbits	} else {
696253825Sjhibbits		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
697253825Sjhibbits		x &= ~0x4;
698253825Sjhibbits		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
699253825Sjhibbits		/* out8(gpio + 0x10, 0); */
700253825Sjhibbits	}
701253825Sjhibbits
702253825Sjhibbits	return (0);
703253825Sjhibbits}
704