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 **)®);
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 **)®p);
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