xref: /freebsd/sys/powerpc/powermac/macio.c (revision 1323ec571215a77ddd21294f0871979d5ad6b992)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright 2002 by Peter Grehan. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 /*
33  * Driver for KeyLargo/Pangea, the MacPPC south bridge ASIC.
34  */
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/bus.h>
42 #include <sys/rman.h>
43 
44 #include <vm/vm.h>
45 #include <vm/pmap.h>
46 
47 #include <machine/bus.h>
48 #include <machine/intr_machdep.h>
49 #include <machine/resource.h>
50 #include <machine/vmparam.h>
51 
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
54 #include <dev/ofw/openfirm.h>
55 
56 #include <powerpc/powermac/maciovar.h>
57 #include <powerpc/powermac/platform_powermac.h>
58 
59 #include <dev/pci/pcivar.h>
60 #include <dev/pci/pcireg.h>
61 
62 /*
63  * Macio softc
64  */
65 struct macio_softc {
66 	phandle_t    sc_node;
67 	vm_offset_t  sc_base;
68 	vm_offset_t  sc_size;
69 	struct rman  sc_mem_rman;
70 
71 	/* FCR registers */
72 	int          sc_memrid;
73 	struct resource	*sc_memr;
74 
75 	/* GPIO offsets */
76 	int          sc_timebase;
77 };
78 
79 static MALLOC_DEFINE(M_MACIO, "macio", "macio device information");
80 
81 static int  macio_probe(device_t);
82 static int  macio_attach(device_t);
83 static int  macio_print_child(device_t dev, device_t child);
84 static void macio_probe_nomatch(device_t, device_t);
85 static struct   resource *macio_alloc_resource(device_t, device_t, int, int *,
86 					       rman_res_t, rman_res_t, rman_res_t,
87 					       u_int);
88 static int  macio_activate_resource(device_t, device_t, int, int,
89 				    struct resource *);
90 static int  macio_deactivate_resource(device_t, device_t, int, int,
91 				      struct resource *);
92 static int  macio_release_resource(device_t, device_t, int, int,
93 				   struct resource *);
94 static struct resource_list *macio_get_resource_list (device_t, device_t);
95 static ofw_bus_get_devinfo_t macio_get_devinfo;
96 #if !defined(__powerpc64__) && defined(SMP)
97 static void macio_freeze_timebase(device_t, bool);
98 #endif
99 
100 /*
101  * Bus interface definition
102  */
103 static device_method_t macio_methods[] = {
104 	/* Device interface */
105 	DEVMETHOD(device_probe,         macio_probe),
106 	DEVMETHOD(device_attach,        macio_attach),
107 	DEVMETHOD(device_detach,        bus_generic_detach),
108 	DEVMETHOD(device_shutdown,      bus_generic_shutdown),
109 	DEVMETHOD(device_suspend,       bus_generic_suspend),
110 	DEVMETHOD(device_resume,        bus_generic_resume),
111 
112 	/* Bus interface */
113 	DEVMETHOD(bus_print_child,      macio_print_child),
114 	DEVMETHOD(bus_probe_nomatch,    macio_probe_nomatch),
115 	DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
116 	DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
117 
118         DEVMETHOD(bus_alloc_resource,   macio_alloc_resource),
119         DEVMETHOD(bus_release_resource, macio_release_resource),
120         DEVMETHOD(bus_activate_resource, macio_activate_resource),
121         DEVMETHOD(bus_deactivate_resource, macio_deactivate_resource),
122         DEVMETHOD(bus_get_resource_list, macio_get_resource_list),
123 
124 	DEVMETHOD(bus_child_pnpinfo,	ofw_bus_gen_child_pnpinfo),
125 
126 	/* ofw_bus interface */
127 	DEVMETHOD(ofw_bus_get_devinfo,	macio_get_devinfo),
128 	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
129 	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
130 	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
131 	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
132 	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
133 	{ 0, 0 }
134 };
135 
136 static driver_t macio_pci_driver = {
137         "macio",
138         macio_methods,
139 	sizeof(struct macio_softc)
140 };
141 
142 devclass_t macio_devclass;
143 
144 EARLY_DRIVER_MODULE(macio, pci, macio_pci_driver, macio_devclass, 0, 0,
145     BUS_PASS_BUS);
146 
147 /*
148  * PCI ID search table
149  */
150 static struct macio_pci_dev {
151         u_int32_t  mpd_devid;
152 	char    *mpd_desc;
153 } macio_pci_devlist[] = {
154 	{ 0x0017106b, "Paddington I/O Controller" },
155 	{ 0x0022106b, "KeyLargo I/O Controller" },
156 	{ 0x0025106b, "Pangea I/O Controller" },
157 	{ 0x003e106b, "Intrepid I/O Controller" },
158 	{ 0x0041106b, "K2 KeyLargo I/O Controller" },
159 	{ 0x004f106b, "Shasta I/O Controller" },
160 	{ 0, NULL }
161 };
162 
163 /*
164  * Devices to exclude from the probe
165  * XXX some of these may be required in the future...
166  */
167 #define	MACIO_QUIRK_IGNORE		0x00000001
168 #define	MACIO_QUIRK_CHILD_HAS_INTR	0x00000002
169 #define	MACIO_QUIRK_USE_CHILD_REG	0x00000004
170 
171 struct macio_quirk_entry {
172 	const char	*mq_name;
173 	int		mq_quirks;
174 };
175 
176 static struct macio_quirk_entry macio_quirks[] = {
177 	{ "escc-legacy",		MACIO_QUIRK_IGNORE },
178 	{ "timer",			MACIO_QUIRK_IGNORE },
179 	{ "escc",			MACIO_QUIRK_CHILD_HAS_INTR },
180         { "i2s", 			MACIO_QUIRK_CHILD_HAS_INTR |
181 					MACIO_QUIRK_USE_CHILD_REG },
182 	{ NULL,				0 }
183 };
184 
185 static int
186 macio_get_quirks(const char *name)
187 {
188         struct	macio_quirk_entry *mqe;
189 
190         for (mqe = macio_quirks; mqe->mq_name != NULL; mqe++)
191                 if (strcmp(name, mqe->mq_name) == 0)
192                         return (mqe->mq_quirks);
193         return (0);
194 }
195 
196 /*
197  * Add an interrupt to the dev's resource list if present
198  */
199 static void
200 macio_add_intr(phandle_t devnode, struct macio_devinfo *dinfo)
201 {
202 	phandle_t iparent;
203 	int	*intr;
204 	int	i, nintr;
205 	int 	icells;
206 
207 	if (dinfo->mdi_ninterrupts >= 6) {
208 		printf("macio: device has more than 6 interrupts\n");
209 		return;
210 	}
211 
212 	nintr = OF_getprop_alloc_multi(devnode, "interrupts", sizeof(*intr),
213 		(void **)&intr);
214 	if (nintr == -1) {
215 		nintr = OF_getprop_alloc_multi(devnode, "AAPL,interrupts",
216 			sizeof(*intr), (void **)&intr);
217 		if (nintr == -1)
218 			return;
219 	}
220 
221 	if (intr[0] == -1)
222 		return;
223 
224 	if (OF_getprop(devnode, "interrupt-parent", &iparent, sizeof(iparent))
225 	    <= 0)
226 		panic("Interrupt but no interrupt parent!\n");
227 
228 	if (OF_getprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells,
229 	    sizeof(icells)) <= 0)
230 		icells = 1;
231 
232 	for (i = 0; i < nintr; i+=icells) {
233 		u_int irq = MAP_IRQ(iparent, intr[i]);
234 
235 		resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ,
236 		    dinfo->mdi_ninterrupts, irq, irq, 1);
237 
238 		dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = irq;
239 		dinfo->mdi_ninterrupts++;
240 	}
241 }
242 
243 static void
244 macio_add_reg(phandle_t devnode, struct macio_devinfo *dinfo)
245 {
246 	struct		macio_reg *reg, *regp;
247 	phandle_t 	child;
248 	char		buf[8];
249 	int		i, layout_id = 0, nreg, res;
250 
251 	nreg = OF_getprop_alloc_multi(devnode, "reg", sizeof(*reg), (void **)&reg);
252 	if (nreg == -1)
253 		return;
254 
255         /*
256          *  Some G5's have broken properties in the i2s-a area. If so we try
257          *  to fix it. Right now we know of two different cases, one for
258          *  sound layout-id 36 and the other one for sound layout-id 76.
259          *  What is missing is the base address for the memory addresses.
260          *  We take them from the parent node (i2s) and use the size
261          *  information from the child.
262          */
263 
264         if (reg[0].mr_base == 0) {
265 		child = OF_child(devnode);
266 		while (child != 0) {
267 			res = OF_getprop(child, "name", buf, sizeof(buf));
268 			if (res > 0 && strcmp(buf, "sound") == 0)
269 				break;
270 			child = OF_peer(child);
271 		}
272 
273                 res = OF_getprop(child, "layout-id", &layout_id,
274 				sizeof(layout_id));
275 
276                 if (res > 0 && (layout_id == 36 || layout_id == 76)) {
277                         res = OF_getprop_alloc_multi(OF_parent(devnode), "reg",
278 						sizeof(*regp), (void **)&regp);
279                         reg[0] = regp[0];
280                         reg[1].mr_base = regp[1].mr_base;
281                         reg[2].mr_base = regp[1].mr_base + reg[1].mr_size;
282                 }
283         }
284 
285 	for (i = 0; i < nreg; i++) {
286 		resource_list_add(&dinfo->mdi_resources, SYS_RES_MEMORY, i,
287 		    reg[i].mr_base, reg[i].mr_base + reg[i].mr_size,
288 		    reg[i].mr_size);
289 	}
290 }
291 
292 /*
293  * PCI probe
294  */
295 static int
296 macio_probe(device_t dev)
297 {
298         int i;
299         u_int32_t devid;
300 
301         devid = pci_get_devid(dev);
302         for (i = 0; macio_pci_devlist[i].mpd_desc != NULL; i++) {
303                 if (devid == macio_pci_devlist[i].mpd_devid) {
304                         device_set_desc(dev, macio_pci_devlist[i].mpd_desc);
305                         return (0);
306                 }
307         }
308 
309         return (ENXIO);
310 }
311 
312 /*
313  * PCI attach: scan Open Firmware child nodes, and attach these as children
314  * of the macio bus
315  */
316 static int
317 macio_attach(device_t dev)
318 {
319 	struct macio_softc *sc;
320         struct macio_devinfo *dinfo;
321         phandle_t  root;
322 	phandle_t  child;
323 	phandle_t  subchild;
324         device_t cdev;
325         u_int reg[3];
326 	char compat[32];
327 	int error, quirks;
328 
329 	sc = device_get_softc(dev);
330 	root = sc->sc_node = ofw_bus_get_node(dev);
331 
332 	/*
333 	 * Locate the device node and it's base address
334 	 */
335 	if (OF_getprop(root, "assigned-addresses",
336 		       reg, sizeof(reg)) < (ssize_t)sizeof(reg)) {
337 		return (ENXIO);
338 	}
339 
340 	/* Used later to see if we have to enable the I2S part. */
341 	OF_getprop(root, "compatible", compat, sizeof(compat));
342 
343 	sc->sc_base = reg[2];
344 	sc->sc_size = MACIO_REG_SIZE;
345 
346 	sc->sc_memrid = PCIR_BAR(0);
347 	sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
348 	    &sc->sc_memrid, RF_ACTIVE);
349 
350 	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
351 	sc->sc_mem_rman.rm_descr = "MacIO Device Memory";
352 	error = rman_init(&sc->sc_mem_rman);
353 	if (error) {
354 		device_printf(dev, "rman_init() failed. error = %d\n", error);
355 		return (error);
356 	}
357 	error = rman_manage_region(&sc->sc_mem_rman, 0, sc->sc_size);
358 	if (error) {
359 		device_printf(dev,
360 		    "rman_manage_region() failed. error = %d\n", error);
361 		return (error);
362 	}
363 
364 	/*
365 	 * Iterate through the sub-devices
366 	 */
367 	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
368 		dinfo = malloc(sizeof(*dinfo), M_MACIO, M_WAITOK | M_ZERO);
369 		if (ofw_bus_gen_setup_devinfo(&dinfo->mdi_obdinfo, child) !=
370 		    0) {
371 			free(dinfo, M_MACIO);
372 			continue;
373 		}
374 		quirks = macio_get_quirks(dinfo->mdi_obdinfo.obd_name);
375 		if ((quirks & MACIO_QUIRK_IGNORE) != 0) {
376 			ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo);
377 			free(dinfo, M_MACIO);
378 			continue;
379 		}
380 		resource_list_init(&dinfo->mdi_resources);
381 		dinfo->mdi_ninterrupts = 0;
382 		macio_add_intr(child, dinfo);
383 		if ((quirks & MACIO_QUIRK_USE_CHILD_REG) != 0)
384 			macio_add_reg(OF_child(child), dinfo);
385 		else
386 			macio_add_reg(child, dinfo);
387 		if ((quirks & MACIO_QUIRK_CHILD_HAS_INTR) != 0)
388 			for (subchild = OF_child(child); subchild != 0;
389 			    subchild = OF_peer(subchild))
390 				macio_add_intr(subchild, dinfo);
391 		cdev = device_add_child(dev, NULL, -1);
392 		if (cdev == NULL) {
393 			device_printf(dev, "<%s>: device_add_child failed\n",
394 			    dinfo->mdi_obdinfo.obd_name);
395 			resource_list_free(&dinfo->mdi_resources);
396 			ofw_bus_gen_destroy_devinfo(&dinfo->mdi_obdinfo);
397 			free(dinfo, M_MACIO);
398 			continue;
399 		}
400 		device_set_ivars(cdev, dinfo);
401 
402 		/* Set FCRs to enable some devices */
403 		if (sc->sc_memr == NULL)
404 			continue;
405 
406 		if (strcmp(ofw_bus_get_name(cdev), "bmac") == 0 ||
407 		    (ofw_bus_get_compat(cdev) != NULL &&
408 		    strcmp(ofw_bus_get_compat(cdev), "bmac+") == 0)) {
409 			uint32_t fcr;
410 
411 			fcr = bus_read_4(sc->sc_memr, HEATHROW_FCR);
412 
413 			fcr |= FCR_ENET_ENABLE & ~FCR_ENET_RESET;
414 			bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr);
415 			DELAY(50000);
416 			fcr |= FCR_ENET_RESET;
417 			bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr);
418 			DELAY(50000);
419 			fcr &= ~FCR_ENET_RESET;
420 			bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr);
421 			DELAY(50000);
422 
423 			bus_write_4(sc->sc_memr, HEATHROW_FCR, fcr);
424 		}
425 
426 		/*
427 		 * Make sure the I2S0 and the I2S0_CLK are enabled.
428 		 * On certain G5's they are not.
429 		 */
430 		if ((strcmp(ofw_bus_get_name(cdev), "i2s") == 0) &&
431 		    (strcmp(compat, "K2-Keylargo") == 0)) {
432 			uint32_t fcr1;
433 
434 			fcr1 = bus_read_4(sc->sc_memr, KEYLARGO_FCR1);
435 			fcr1 |= FCR1_I2S0_CLK_ENABLE | FCR1_I2S0_ENABLE;
436 			bus_write_4(sc->sc_memr, KEYLARGO_FCR1, fcr1);
437 		}
438 	}
439 
440 #if !defined(__powerpc64__) && defined(SMP)
441 	/*
442 	 * Detect an SMP G4 machine.
443 	 *
444 	 * On SMP G4, timebase freeze is via a GPIO on macio.
445 	 *
446 	 * When we are on an SMP G4, we need to install a handler to
447 	 * perform timebase freeze/unfreeze on behalf of the platform.
448 	 */
449 	if ((child = OF_finddevice("/cpus/PowerPC,G4@0")) != -1 &&
450 	    OF_peer(child) != -1) {
451 		if (OF_getprop(child, "timebase-enable", &sc->sc_timebase,
452 		    sizeof(sc->sc_timebase)) <= 0)
453 			sc->sc_timebase = KEYLARGO_GPIO_BASE + 0x09;
454 		powermac_register_timebase(dev, macio_freeze_timebase);
455                 device_printf(dev, "GPIO timebase control at 0x%x\n",
456 		    sc->sc_timebase);
457 	}
458 #endif
459 
460 	return (bus_generic_attach(dev));
461 }
462 
463 static int
464 macio_print_child(device_t dev, device_t child)
465 {
466         struct macio_devinfo *dinfo;
467         struct resource_list *rl;
468         int retval = 0;
469 
470         dinfo = device_get_ivars(child);
471         rl = &dinfo->mdi_resources;
472 
473         retval += bus_print_child_header(dev, child);
474 
475         retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
476         retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
477 
478         retval += bus_print_child_footer(dev, child);
479 
480         return (retval);
481 }
482 
483 static void
484 macio_probe_nomatch(device_t dev, device_t child)
485 {
486         struct macio_devinfo *dinfo;
487         struct resource_list *rl;
488 	const char *type;
489 
490 	if (bootverbose) {
491 		dinfo = device_get_ivars(child);
492 		rl = &dinfo->mdi_resources;
493 
494 		if ((type = ofw_bus_get_type(child)) == NULL)
495 			type = "(unknown)";
496 		device_printf(dev, "<%s, %s>", type, ofw_bus_get_name(child));
497 		resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
498 		resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
499 		printf(" (no driver attached)\n");
500 	}
501 }
502 
503 static struct resource *
504 macio_alloc_resource(device_t bus, device_t child, int type, int *rid,
505 		     rman_res_t start, rman_res_t end, rman_res_t count,
506 		     u_int flags)
507 {
508 	struct		macio_softc *sc;
509 	int		needactivate;
510 	struct		resource *rv;
511 	struct		rman *rm;
512 	u_long		adjstart, adjend, adjcount;
513 	struct		macio_devinfo *dinfo;
514 	struct		resource_list_entry *rle;
515 
516 	sc = device_get_softc(bus);
517 	dinfo = device_get_ivars(child);
518 
519 	needactivate = flags & RF_ACTIVE;
520 	flags &= ~RF_ACTIVE;
521 
522 	switch (type) {
523 	case SYS_RES_MEMORY:
524 	case SYS_RES_IOPORT:
525 		rle = resource_list_find(&dinfo->mdi_resources, SYS_RES_MEMORY,
526 		    *rid);
527 		if (rle == NULL) {
528 			device_printf(bus, "no rle for %s memory %d\n",
529 			    device_get_nameunit(child), *rid);
530 			return (NULL);
531 		}
532 
533 		if (start < rle->start)
534 			adjstart = rle->start;
535 		else if (start > rle->end)
536 			adjstart = rle->end;
537 		else
538 			adjstart = start;
539 
540 		if (end < rle->start)
541 			adjend = rle->start;
542 		else if (end > rle->end)
543 			adjend = rle->end;
544 		else
545 			adjend = end;
546 
547 		adjcount = adjend - adjstart;
548 
549 		rm = &sc->sc_mem_rman;
550 		break;
551 
552 	case SYS_RES_IRQ:
553 		/* Check for passthrough from subattachments like macgpio */
554 		if (device_get_parent(child) != bus)
555 			return BUS_ALLOC_RESOURCE(device_get_parent(bus), child,
556 			    type, rid, start, end, count, flags);
557 
558 		rle = resource_list_find(&dinfo->mdi_resources, SYS_RES_IRQ,
559 		    *rid);
560 		if (rle == NULL) {
561 			if (dinfo->mdi_ninterrupts >= 6) {
562 				device_printf(bus,
563 				    "%s has more than 6 interrupts\n",
564 				    device_get_nameunit(child));
565 				return (NULL);
566 			}
567 			resource_list_add(&dinfo->mdi_resources, SYS_RES_IRQ,
568 			    dinfo->mdi_ninterrupts, start, start, 1);
569 
570 			dinfo->mdi_interrupts[dinfo->mdi_ninterrupts] = start;
571 			dinfo->mdi_ninterrupts++;
572 		}
573 
574 		return (resource_list_alloc(&dinfo->mdi_resources, bus, child,
575 		    type, rid, start, end, count, flags));
576 
577 	default:
578 		device_printf(bus, "unknown resource request from %s\n",
579 			      device_get_nameunit(child));
580 		return (NULL);
581 	}
582 
583 	rv = rman_reserve_resource(rm, adjstart, adjend, adjcount, flags,
584 	    child);
585 	if (rv == NULL) {
586 		device_printf(bus,
587 		    "failed to reserve resource %#lx - %#lx (%#lx) for %s\n",
588 		    adjstart, adjend, adjcount, device_get_nameunit(child));
589 		return (NULL);
590 	}
591 
592 	rman_set_rid(rv, *rid);
593 
594 	if (needactivate) {
595 		if (bus_activate_resource(child, type, *rid, rv) != 0) {
596                         device_printf(bus,
597 				      "failed to activate resource for %s\n",
598 				      device_get_nameunit(child));
599 			rman_release_resource(rv);
600 			return (NULL);
601                 }
602         }
603 
604 	return (rv);
605 }
606 
607 static int
608 macio_release_resource(device_t bus, device_t child, int type, int rid,
609 		       struct resource *res)
610 {
611 	if (rman_get_flags(res) & RF_ACTIVE) {
612 		int error = bus_deactivate_resource(child, type, rid, res);
613 		if (error)
614 			return error;
615 	}
616 
617 	return (rman_release_resource(res));
618 }
619 
620 static int
621 macio_activate_resource(device_t bus, device_t child, int type, int rid,
622 			   struct resource *res)
623 {
624 	struct macio_softc *sc;
625 	void    *p;
626 
627 	sc = device_get_softc(bus);
628 
629 	if (type == SYS_RES_IRQ)
630                 return (bus_activate_resource(bus, type, rid, res));
631 
632 	if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
633 		p = pmap_mapdev((vm_offset_t)rman_get_start(res) + sc->sc_base,
634 				(vm_size_t)rman_get_size(res));
635 		if (p == NULL)
636 			return (ENOMEM);
637 		rman_set_virtual(res, p);
638 		rman_set_bustag(res, &bs_le_tag);
639 		rman_set_bushandle(res, (u_long)p);
640 	}
641 
642 	return (rman_activate_resource(res));
643 }
644 
645 static int
646 macio_deactivate_resource(device_t bus, device_t child, int type, int rid,
647 			  struct resource *res)
648 {
649         /*
650          * If this is a memory resource, unmap it.
651          */
652         if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) {
653 		u_int32_t psize;
654 
655 		psize = rman_get_size(res);
656 		pmap_unmapdev((vm_offset_t)rman_get_virtual(res), psize);
657 	}
658 
659 	return (rman_deactivate_resource(res));
660 }
661 
662 static struct resource_list *
663 macio_get_resource_list (device_t dev, device_t child)
664 {
665 	struct macio_devinfo *dinfo;
666 
667 	dinfo = device_get_ivars(child);
668 	return (&dinfo->mdi_resources);
669 }
670 
671 static const struct ofw_bus_devinfo *
672 macio_get_devinfo(device_t dev, device_t child)
673 {
674 	struct macio_devinfo *dinfo;
675 
676 	dinfo = device_get_ivars(child);
677 	return (&dinfo->mdi_obdinfo);
678 }
679 
680 int
681 macio_enable_wireless(device_t dev, bool enable)
682 {
683 	struct macio_softc *sc = device_get_softc(dev);
684 	uint32_t x;
685 
686 	if (enable) {
687 		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
688 		x |= 0x4;
689 		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
690 
691 		/* Enable card slot. */
692 		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0f, 5);
693 		DELAY(1000);
694 		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0f, 4);
695 		DELAY(1000);
696 		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
697 		x &= ~0x80000000;
698 
699 		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
700 		/* out8(gpio + 0x10, 4); */
701 
702 		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0b, 0);
703 		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0a, 0x28);
704 		bus_write_1(sc->sc_memr, KEYLARGO_EXTINT_GPIO_REG_BASE + 0x0d, 0x28);
705 		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0d, 0x28);
706 		bus_write_1(sc->sc_memr, KEYLARGO_GPIO_BASE + 0x0e, 0x28);
707 		bus_write_4(sc->sc_memr, 0x1c000, 0);
708 
709 		/* Initialize the card. */
710 		bus_write_4(sc->sc_memr, 0x1a3e0, 0x41);
711 		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
712 		x |= 0x80000000;
713 		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
714 	} else {
715 		x = bus_read_4(sc->sc_memr, KEYLARGO_FCR2);
716 		x &= ~0x4;
717 		bus_write_4(sc->sc_memr, KEYLARGO_FCR2, x);
718 		/* out8(gpio + 0x10, 0); */
719 	}
720 
721 	return (0);
722 }
723 
724 #if !defined(__powerpc64__) && defined(SMP)
725 static void
726 macio_freeze_timebase(device_t dev, bool freeze)
727 {
728 	struct macio_softc *sc = device_get_softc(dev);
729 
730 	if (freeze) {
731 		bus_write_1(sc->sc_memr, sc->sc_timebase, 4);
732 	} else {
733 		bus_write_1(sc->sc_memr, sc->sc_timebase, 0);
734 	}
735 	bus_read_1(sc->sc_memr, sc->sc_timebase);
736 }
737 #endif
738