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