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