1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2015-2016 Landon Fuller <[email protected]>
5 * Copyright (c) 2017 The FreeBSD Foundation
6 * All rights reserved.
7 *
8 * Portions of this software were developed by Landon Fuller
9 * under sponsorship from the FreeBSD Foundation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
19 * redistribution must be conditioned upon including a substantially
20 * similar Disclaimer requirement for further binary redistribution.
21 *
22 * NO WARRANTY
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
26 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
27 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
28 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
31 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 * THE POSSIBILITY OF SUCH DAMAGES.
34 */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 /*
40 * Broadcom Home Networking Division (HND) Bus Driver.
41 *
42 * The Broadcom HND family of devices consists of both SoCs and host-connected
43 * networking chipsets containing a common family of Broadcom IP cores,
44 * including an integrated MIPS and/or ARM cores.
45 *
46 * HND devices expose a nearly identical interface whether accessible over a
47 * native SoC interconnect, or when connected via a host interface such as
48 * PCIe. As a result, the majority of hardware support code should be re-usable
49 * across host drivers for HND networking chipsets, as well as FreeBSD support
50 * for Broadcom MIPS/ARM HND SoCs.
51 *
52 * Earlier HND models used the siba(4) on-chip interconnect, while later models
53 * use bcma(4); the programming model is almost entirely independent
54 * of the actual underlying interconect.
55 */
56
57 #include <sys/param.h>
58 #include <sys/kernel.h>
59 #include <sys/bus.h>
60 #include <sys/module.h>
61 #include <sys/systm.h>
62
63 #include <machine/bus.h>
64 #include <sys/rman.h>
65 #include <machine/resource.h>
66
67 #include <dev/bhnd/cores/pmu/bhnd_pmu.h>
68
69 #include "bhnd_chipc_if.h"
70 #include "bhnd_nvram_if.h"
71
72 #include "bhnd.h"
73 #include "bhndreg.h"
74 #include "bhndvar.h"
75
76 #include "bhnd_private.h"
77
78 MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures");
79
80 /**
81 * bhnd_generic_probe_nomatch() reporting configuration.
82 */
83 static const struct bhnd_nomatch {
84 uint16_t vendor; /**< core designer */
85 uint16_t device; /**< core id */
86 bool if_verbose; /**< print when bootverbose is set. */
87 } bhnd_nomatch_table[] = {
88 { BHND_MFGID_ARM, BHND_COREID_OOB_ROUTER, true },
89 { BHND_MFGID_ARM, BHND_COREID_EROM, true },
90 { BHND_MFGID_ARM, BHND_COREID_PL301, true },
91 { BHND_MFGID_ARM, BHND_COREID_APB_BRIDGE, true },
92 { BHND_MFGID_ARM, BHND_COREID_AXI_UNMAPPED, false },
93 { BHND_MFGID_INVALID, BHND_COREID_INVALID, false }
94 };
95
96 static int bhnd_delete_children(struct bhnd_softc *sc);
97
98 /**
99 * Default bhnd(4) bus driver implementation of DEVICE_ATTACH().
100 *
101 * This implementation calls device_probe_and_attach() for each of the device's
102 * children, in bhnd probe order.
103 */
104 int
bhnd_generic_attach(device_t dev)105 bhnd_generic_attach(device_t dev)
106 {
107 struct bhnd_softc *sc;
108 int error;
109
110 if (device_is_attached(dev))
111 return (EBUSY);
112
113 sc = device_get_softc(dev);
114 sc->dev = dev;
115
116 /* Probe and attach all children */
117 if ((error = bhnd_bus_probe_children(dev))) {
118 bhnd_delete_children(sc);
119 return (error);
120 }
121
122 return (0);
123 }
124
125 /**
126 * Detach and delete all children, in reverse of their attach order.
127 */
128 static int
bhnd_delete_children(struct bhnd_softc * sc)129 bhnd_delete_children(struct bhnd_softc *sc)
130 {
131 device_t *devs;
132 int ndevs;
133 int error;
134
135 /* Fetch children in detach order */
136 error = bhnd_bus_get_children(sc->dev, &devs, &ndevs,
137 BHND_DEVICE_ORDER_DETACH);
138 if (error)
139 return (error);
140
141 /* Perform detach */
142 for (int i = 0; i < ndevs; i++) {
143 device_t child = devs[i];
144
145 /* Terminate on first error */
146 if ((error = device_delete_child(sc->dev, child)))
147 goto cleanup;
148 }
149
150 cleanup:
151 bhnd_bus_free_children(devs);
152 return (error);
153 }
154
155 /**
156 * Default bhnd(4) bus driver implementation of DEVICE_DETACH().
157 *
158 * This implementation calls device_detach() for each of the device's
159 * children, in reverse bhnd probe order, terminating if any call to
160 * device_detach() fails.
161 */
162 int
bhnd_generic_detach(device_t dev)163 bhnd_generic_detach(device_t dev)
164 {
165 struct bhnd_softc *sc;
166 int error;
167
168 if (!device_is_attached(dev))
169 return (EBUSY);
170
171 sc = device_get_softc(dev);
172
173 if ((error = bhnd_delete_children(sc)))
174 return (error);
175
176 return (0);
177 }
178
179 /**
180 * Default bhnd(4) bus driver implementation of DEVICE_SHUTDOWN().
181 *
182 * This implementation calls device_shutdown() for each of the device's
183 * children, in reverse bhnd probe order, terminating if any call to
184 * device_shutdown() fails.
185 */
186 int
bhnd_generic_shutdown(device_t dev)187 bhnd_generic_shutdown(device_t dev)
188 {
189 device_t *devs;
190 int ndevs;
191 int error;
192
193 if (!device_is_attached(dev))
194 return (EBUSY);
195
196 /* Fetch children in detach order */
197 error = bhnd_bus_get_children(dev, &devs, &ndevs,
198 BHND_DEVICE_ORDER_DETACH);
199 if (error)
200 return (error);
201
202 /* Perform shutdown */
203 for (int i = 0; i < ndevs; i++) {
204 device_t child = devs[i];
205
206 /* Terminate on first error */
207 if ((error = device_shutdown(child)))
208 goto cleanup;
209 }
210
211 cleanup:
212 bhnd_bus_free_children(devs);
213 return (error);
214 }
215
216 /**
217 * Default bhnd(4) bus driver implementation of DEVICE_RESUME().
218 *
219 * This implementation calls BUS_RESUME_CHILD() for each of the device's
220 * children in bhnd probe order, terminating if any call to BUS_RESUME_CHILD()
221 * fails.
222 */
223 int
bhnd_generic_resume(device_t dev)224 bhnd_generic_resume(device_t dev)
225 {
226 device_t *devs;
227 int ndevs;
228 int error;
229
230 if (!device_is_attached(dev))
231 return (EBUSY);
232
233 /* Fetch children in attach order */
234 error = bhnd_bus_get_children(dev, &devs, &ndevs,
235 BHND_DEVICE_ORDER_ATTACH);
236 if (error)
237 return (error);
238
239 /* Perform resume */
240 for (int i = 0; i < ndevs; i++) {
241 device_t child = devs[i];
242
243 /* Terminate on first error */
244 if ((error = BUS_RESUME_CHILD(device_get_parent(child), child)))
245 goto cleanup;
246 }
247
248 cleanup:
249 bhnd_bus_free_children(devs);
250 return (error);
251 }
252
253 /**
254 * Default bhnd(4) bus driver implementation of DEVICE_SUSPEND().
255 *
256 * This implementation calls BUS_SUSPEND_CHILD() for each of the device's
257 * children in reverse bhnd probe order. If any call to BUS_SUSPEND_CHILD()
258 * fails, the suspend operation is terminated and any devices that were
259 * suspended are resumed immediately by calling their BUS_RESUME_CHILD()
260 * methods.
261 */
262 int
bhnd_generic_suspend(device_t dev)263 bhnd_generic_suspend(device_t dev)
264 {
265 device_t *devs;
266 int ndevs;
267 int error;
268
269 if (!device_is_attached(dev))
270 return (EBUSY);
271
272 /* Fetch children in detach order */
273 error = bhnd_bus_get_children(dev, &devs, &ndevs,
274 BHND_DEVICE_ORDER_DETACH);
275 if (error)
276 return (error);
277
278 /* Perform suspend */
279 for (int i = 0; i < ndevs; i++) {
280 device_t child = devs[i];
281 error = BUS_SUSPEND_CHILD(device_get_parent(child), child);
282
283 /* On error, resume suspended devices and then terminate */
284 if (error) {
285 for (int j = 0; j < i; j++) {
286 BUS_RESUME_CHILD(device_get_parent(devs[j]),
287 devs[j]);
288 }
289
290 goto cleanup;
291 }
292 }
293
294 cleanup:
295 bhnd_bus_free_children(devs);
296 return (error);
297 }
298
299 /**
300 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_PROBE_ORDER().
301 *
302 * This implementation determines probe ordering based on the device's class
303 * and other properties, including whether the device is serving as a host
304 * bridge.
305 */
306 int
bhnd_generic_get_probe_order(device_t dev,device_t child)307 bhnd_generic_get_probe_order(device_t dev, device_t child)
308 {
309 switch (bhnd_get_class(child)) {
310 case BHND_DEVCLASS_CC:
311 /* Must be early enough to provide NVRAM access to the
312 * host bridge */
313 return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_FIRST);
314
315 case BHND_DEVCLASS_CC_B:
316 /* fall through */
317 case BHND_DEVCLASS_PMU:
318 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY);
319
320 case BHND_DEVCLASS_SOC_ROUTER:
321 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE);
322
323 case BHND_DEVCLASS_SOC_BRIDGE:
324 return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST);
325
326 case BHND_DEVCLASS_CPU:
327 return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST);
328
329 case BHND_DEVCLASS_RAM:
330 /* fall through */
331 case BHND_DEVCLASS_MEMC:
332 return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY);
333
334 case BHND_DEVCLASS_NVRAM:
335 return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY);
336
337 case BHND_DEVCLASS_PCI:
338 case BHND_DEVCLASS_PCIE:
339 case BHND_DEVCLASS_PCCARD:
340 case BHND_DEVCLASS_ENET:
341 case BHND_DEVCLASS_ENET_MAC:
342 case BHND_DEVCLASS_ENET_PHY:
343 case BHND_DEVCLASS_WLAN:
344 case BHND_DEVCLASS_WLAN_MAC:
345 case BHND_DEVCLASS_WLAN_PHY:
346 case BHND_DEVCLASS_EROM:
347 case BHND_DEVCLASS_OTHER:
348 case BHND_DEVCLASS_INVALID:
349 if (bhnd_bus_find_hostb_device(dev) == child)
350 return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY);
351
352 return (BHND_PROBE_DEFAULT);
353 default:
354 return (BHND_PROBE_DEFAULT);
355 }
356 }
357
358 /**
359 * Default bhnd(4) bus driver implementation of BHND_BUS_ALLOC_PMU().
360 */
361 int
bhnd_generic_alloc_pmu(device_t dev,device_t child)362 bhnd_generic_alloc_pmu(device_t dev, device_t child)
363 {
364 struct bhnd_softc *sc;
365 struct bhnd_resource *r;
366 struct bhnd_core_clkctl *clkctl;
367 struct resource_list *rl;
368 struct resource_list_entry *rle;
369 device_t pmu_dev;
370 bhnd_addr_t r_addr;
371 bhnd_size_t r_size;
372 bus_size_t pmu_regs;
373 u_int max_latency;
374 int error;
375
376 GIANT_REQUIRED; /* for newbus */
377
378 if (device_get_parent(child) != dev)
379 return (EINVAL);
380
381 sc = device_get_softc(dev);
382 clkctl = bhnd_get_pmu_info(child);
383 pmu_regs = BHND_CLK_CTL_ST;
384
385 /* already allocated? */
386 if (clkctl != NULL) {
387 panic("duplicate PMU allocation for %s",
388 device_get_nameunit(child));
389 }
390
391 /* Determine address+size of the core's PMU register block */
392 error = bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &r_addr,
393 &r_size);
394 if (error) {
395 device_printf(sc->dev, "error fetching register block info for "
396 "%s: %d\n", device_get_nameunit(child), error);
397 return (error);
398 }
399
400 if (r_size < (pmu_regs + sizeof(uint32_t))) {
401 device_printf(sc->dev, "pmu offset %#jx would overrun %s "
402 "register block\n", (uintmax_t)pmu_regs,
403 device_get_nameunit(child));
404 return (ENODEV);
405 }
406
407 /* Locate actual resource containing the core's register block */
408 if ((rl = BUS_GET_RESOURCE_LIST(dev, child)) == NULL) {
409 device_printf(dev, "NULL resource list returned for %s\n",
410 device_get_nameunit(child));
411 return (ENXIO);
412 }
413
414 if ((rle = resource_list_find(rl, SYS_RES_MEMORY, 0)) == NULL) {
415 device_printf(dev, "cannot locate core register resource "
416 "for %s\n", device_get_nameunit(child));
417 return (ENXIO);
418 }
419
420 if (rle->res == NULL) {
421 device_printf(dev, "core register resource unallocated for "
422 "%s\n", device_get_nameunit(child));
423 return (ENXIO);
424 }
425
426 if (r_addr+pmu_regs < rman_get_start(rle->res) ||
427 r_addr+pmu_regs >= rman_get_end(rle->res))
428 {
429 device_printf(dev, "core register resource does not map PMU "
430 "registers at %#jx\n for %s\n", r_addr+pmu_regs,
431 device_get_nameunit(child));
432 return (ENXIO);
433 }
434
435 /* Adjust PMU register offset relative to the actual start address
436 * of the core's register block allocation.
437 *
438 * XXX: The saved offset will be invalid if bus_adjust_resource is
439 * used to modify the resource's start address.
440 */
441 if (rman_get_start(rle->res) > r_addr)
442 pmu_regs -= rman_get_start(rle->res) - r_addr;
443 else
444 pmu_regs -= r_addr - rman_get_start(rle->res);
445
446 /* Retain a PMU reference for the clkctl instance state */
447 pmu_dev = bhnd_retain_provider(child, BHND_SERVICE_PMU);
448 if (pmu_dev == NULL) {
449 device_printf(sc->dev, "PMU not found\n");
450 return (ENXIO);
451 }
452
453 /* Fetch the maximum transition latency from our PMU */
454 max_latency = bhnd_pmu_get_max_transition_latency(pmu_dev);
455
456 /* Allocate a new bhnd_resource wrapping the standard resource we
457 * fetched from the resource list; we'll free this in
458 * bhnd_generic_release_pmu() */
459 r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
460 if (r == NULL) {
461 bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
462 return (ENOMEM);
463 }
464
465 r->res = rle->res;
466 r->direct = ((rman_get_flags(rle->res) & RF_ACTIVE) != 0);
467
468 /* Allocate the clkctl instance */
469 clkctl = bhnd_alloc_core_clkctl(child, pmu_dev, r, pmu_regs,
470 max_latency);
471 if (clkctl == NULL) {
472 free(r, M_BHND);
473 bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
474 return (ENOMEM);
475 }
476
477 bhnd_set_pmu_info(child, clkctl);
478 return (0);
479 }
480
481 /**
482 * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_PMU().
483 */
484 int
bhnd_generic_release_pmu(device_t dev,device_t child)485 bhnd_generic_release_pmu(device_t dev, device_t child)
486 {
487 struct bhnd_softc *sc;
488 struct bhnd_core_clkctl *clkctl;
489 struct bhnd_resource *r;
490 device_t pmu_dev;
491
492 GIANT_REQUIRED; /* for newbus */
493
494 sc = device_get_softc(dev);
495
496 if (device_get_parent(child) != dev)
497 return (EINVAL);
498
499 clkctl = bhnd_get_pmu_info(child);
500 if (clkctl == NULL)
501 panic("pmu over-release for %s", device_get_nameunit(child));
502
503 /* Clear all FORCE, AREQ, and ERSRC flags, unless we're already in
504 * RESET. Suspending a core clears clkctl automatically (and attempting
505 * to access the PMU registers in a suspended core will trigger a
506 * system livelock). */
507 if (!bhnd_is_hw_suspended(clkctl->cc_dev)) {
508 BHND_CLKCTL_LOCK(clkctl);
509
510 /* Clear all FORCE, AREQ, and ERSRC flags */
511 BHND_CLKCTL_SET_4(clkctl, 0x0, BHND_CCS_FORCE_MASK |
512 BHND_CCS_AREQ_MASK | BHND_CCS_ERSRC_REQ_MASK);
513
514 BHND_CLKCTL_UNLOCK(clkctl);
515 }
516
517 /* Clear child's PMU info reference */
518 bhnd_set_pmu_info(child, NULL);
519
520 /* Before freeing the clkctl instance, save a pointer to resources we
521 * need to clean up manually */
522 r = clkctl->cc_res;
523 pmu_dev = clkctl->cc_pmu_dev;
524
525 /* Free the clkctl instance */
526 bhnd_free_core_clkctl(clkctl);
527
528 /* Free the child's bhnd resource wrapper */
529 free(r, M_BHND);
530
531 /* Release the child's PMU provider reference */
532 bhnd_release_provider(child, pmu_dev, BHND_SERVICE_PMU);
533
534 return (0);
535 }
536
537 /**
538 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_LATENCY().
539 */
540 int
bhnd_generic_get_clock_latency(device_t dev,device_t child,bhnd_clock clock,u_int * latency)541 bhnd_generic_get_clock_latency(device_t dev, device_t child, bhnd_clock clock,
542 u_int *latency)
543 {
544 struct bhnd_core_clkctl *clkctl;
545
546 if (device_get_parent(child) != dev)
547 return (EINVAL);
548
549 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
550 panic("no active PMU allocation");
551
552 return (bhnd_pmu_get_clock_latency(clkctl->cc_pmu_dev, clock, latency));
553 }
554
555 /**
556 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_CLOCK_FREQ().
557 */
558 int
bhnd_generic_get_clock_freq(device_t dev,device_t child,bhnd_clock clock,u_int * freq)559 bhnd_generic_get_clock_freq(device_t dev, device_t child, bhnd_clock clock,
560 u_int *freq)
561 {
562 struct bhnd_core_clkctl *clkctl;
563
564 if (device_get_parent(child) != dev)
565 return (EINVAL);
566
567 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
568 panic("no active PMU allocation");
569
570 return (bhnd_pmu_get_clock_freq(clkctl->cc_pmu_dev, clock, freq));
571 }
572
573 /**
574 * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_CLOCK().
575 */
576 int
bhnd_generic_request_clock(device_t dev,device_t child,bhnd_clock clock)577 bhnd_generic_request_clock(device_t dev, device_t child, bhnd_clock clock)
578 {
579 struct bhnd_softc *sc;
580 struct bhnd_core_clkctl *clkctl;
581 uint32_t avail;
582 uint32_t req;
583 int error;
584
585 sc = device_get_softc(dev);
586
587 if (device_get_parent(child) != dev)
588 return (EINVAL);
589
590 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
591 panic("no active PMU allocation");
592
593 BHND_ASSERT_CLKCTL_AVAIL(clkctl);
594
595 avail = 0x0;
596 req = 0x0;
597
598 switch (clock) {
599 case BHND_CLOCK_DYN:
600 break;
601 case BHND_CLOCK_ILP:
602 req |= BHND_CCS_FORCEILP;
603 break;
604 case BHND_CLOCK_ALP:
605 req |= BHND_CCS_FORCEALP;
606 avail |= BHND_CCS_ALPAVAIL;
607 break;
608 case BHND_CLOCK_HT:
609 req |= BHND_CCS_FORCEHT;
610 avail |= BHND_CCS_HTAVAIL;
611 break;
612 default:
613 device_printf(dev, "%s requested unknown clock: %#x\n",
614 device_get_nameunit(clkctl->cc_dev), clock);
615 return (ENODEV);
616 }
617
618 BHND_CLKCTL_LOCK(clkctl);
619
620 /* Issue request */
621 BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_FORCE_MASK);
622
623 /* Wait for clock availability */
624 error = bhnd_core_clkctl_wait(clkctl, avail, avail);
625
626 BHND_CLKCTL_UNLOCK(clkctl);
627
628 return (error);
629 }
630
631 /**
632 * Default bhnd(4) bus driver implementation of BHND_BUS_ENABLE_CLOCKS().
633 */
634 int
bhnd_generic_enable_clocks(device_t dev,device_t child,uint32_t clocks)635 bhnd_generic_enable_clocks(device_t dev, device_t child, uint32_t clocks)
636 {
637 struct bhnd_softc *sc;
638 struct bhnd_core_clkctl *clkctl;
639 uint32_t avail;
640 uint32_t req;
641 int error;
642
643 sc = device_get_softc(dev);
644
645 if (device_get_parent(child) != dev)
646 return (EINVAL);
647
648 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
649 panic("no active PMU allocation");
650
651 BHND_ASSERT_CLKCTL_AVAIL(clkctl);
652
653 sc = device_get_softc(dev);
654
655 avail = 0x0;
656 req = 0x0;
657
658 /* Build clock request flags */
659 if (clocks & BHND_CLOCK_DYN) /* nothing to enable */
660 clocks &= ~BHND_CLOCK_DYN;
661
662 if (clocks & BHND_CLOCK_ILP) /* nothing to enable */
663 clocks &= ~BHND_CLOCK_ILP;
664
665 if (clocks & BHND_CLOCK_ALP) {
666 req |= BHND_CCS_ALPAREQ;
667 avail |= BHND_CCS_ALPAVAIL;
668 clocks &= ~BHND_CLOCK_ALP;
669 }
670
671 if (clocks & BHND_CLOCK_HT) {
672 req |= BHND_CCS_HTAREQ;
673 avail |= BHND_CCS_HTAVAIL;
674 clocks &= ~BHND_CLOCK_HT;
675 }
676
677 /* Check for unknown clock values */
678 if (clocks != 0x0) {
679 device_printf(dev, "%s requested unknown clocks: %#x\n",
680 device_get_nameunit(clkctl->cc_dev), clocks);
681 return (ENODEV);
682 }
683
684 BHND_CLKCTL_LOCK(clkctl);
685
686 /* Issue request */
687 BHND_CLKCTL_SET_4(clkctl, req, BHND_CCS_AREQ_MASK);
688
689 /* Wait for clock availability */
690 error = bhnd_core_clkctl_wait(clkctl, avail, avail);
691
692 BHND_CLKCTL_UNLOCK(clkctl);
693
694 return (error);
695 }
696
697 /**
698 * Default bhnd(4) bus driver implementation of BHND_BUS_REQUEST_EXT_RSRC().
699 */
700 int
bhnd_generic_request_ext_rsrc(device_t dev,device_t child,u_int rsrc)701 bhnd_generic_request_ext_rsrc(device_t dev, device_t child, u_int rsrc)
702 {
703 struct bhnd_softc *sc;
704 struct bhnd_core_clkctl *clkctl;
705 uint32_t req;
706 uint32_t avail;
707 int error;
708
709 sc = device_get_softc(dev);
710
711 if (device_get_parent(child) != dev)
712 return (EINVAL);
713
714 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
715 panic("no active PMU allocation");
716
717 BHND_ASSERT_CLKCTL_AVAIL(clkctl);
718
719 sc = device_get_softc(dev);
720
721 if (rsrc > BHND_CCS_ERSRC_MAX)
722 return (EINVAL);
723
724 req = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
725 avail = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_STS);
726
727 BHND_CLKCTL_LOCK(clkctl);
728
729 /* Write request */
730 BHND_CLKCTL_SET_4(clkctl, req, req);
731
732 /* Wait for resource availability */
733 error = bhnd_core_clkctl_wait(clkctl, avail, avail);
734
735 BHND_CLKCTL_UNLOCK(clkctl);
736
737 return (error);
738 }
739
740 /**
741 * Default bhnd(4) bus driver implementation of BHND_BUS_RELEASE_EXT_RSRC().
742 */
743 int
bhnd_generic_release_ext_rsrc(device_t dev,device_t child,u_int rsrc)744 bhnd_generic_release_ext_rsrc(device_t dev, device_t child, u_int rsrc)
745 {
746 struct bhnd_softc *sc;
747 struct bhnd_core_clkctl *clkctl;
748 uint32_t mask;
749
750 sc = device_get_softc(dev);
751
752 if (device_get_parent(child) != dev)
753 return (EINVAL);
754
755 if ((clkctl = bhnd_get_pmu_info(child)) == NULL)
756 panic("no active PMU allocation");
757
758 BHND_ASSERT_CLKCTL_AVAIL(clkctl);
759
760 sc = device_get_softc(dev);
761
762 if (rsrc > BHND_CCS_ERSRC_MAX)
763 return (EINVAL);
764
765 mask = BHND_CCS_SET_BITS((1<<rsrc), BHND_CCS_ERSRC_REQ);
766
767 /* Clear request */
768 BHND_CLKCTL_LOCK(clkctl);
769 BHND_CLKCTL_SET_4(clkctl, 0x0, mask);
770 BHND_CLKCTL_UNLOCK(clkctl);
771
772 return (0);
773 }
774
775 /**
776 * Default bhnd(4) bus driver implementation of BHND_BUS_IS_REGION_VALID().
777 *
778 * This implementation assumes that port and region numbers are 0-indexed and
779 * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and
780 * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall
781 * within the defined range.
782 */
783 static bool
bhnd_generic_is_region_valid(device_t dev,device_t child,bhnd_port_type type,u_int port,u_int region)784 bhnd_generic_is_region_valid(device_t dev, device_t child,
785 bhnd_port_type type, u_int port, u_int region)
786 {
787 if (port >= bhnd_get_port_count(child, type))
788 return (false);
789
790 if (region >= bhnd_get_region_count(child, type, port))
791 return (false);
792
793 return (true);
794 }
795
796 /**
797 * Default bhnd(4) bus driver implementation of BHND_BUS_GET_NVRAM_VAR().
798 *
799 * This implementation searches @p dev for a registered NVRAM child device.
800 *
801 * If no NVRAM device is registered with @p dev, the request is delegated to
802 * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev.
803 */
804 int
bhnd_generic_get_nvram_var(device_t dev,device_t child,const char * name,void * buf,size_t * size,bhnd_nvram_type type)805 bhnd_generic_get_nvram_var(device_t dev, device_t child, const char *name,
806 void *buf, size_t *size, bhnd_nvram_type type)
807 {
808 struct bhnd_softc *sc;
809 device_t nvram, parent;
810 int error;
811
812 sc = device_get_softc(dev);
813
814 /* If a NVRAM device is available, consult it first */
815 nvram = bhnd_retain_provider(child, BHND_SERVICE_NVRAM);
816 if (nvram != NULL) {
817 error = BHND_NVRAM_GETVAR(nvram, name, buf, size, type);
818 bhnd_release_provider(child, nvram, BHND_SERVICE_NVRAM);
819 return (error);
820 }
821
822 /* Otherwise, try to delegate to parent */
823 if ((parent = device_get_parent(dev)) == NULL)
824 return (ENODEV);
825
826 return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child,
827 name, buf, size, type));
828 }
829
830 /**
831 * Default bhnd(4) bus driver implementation of BUS_PRINT_CHILD().
832 *
833 * This implementation requests the device's struct resource_list via
834 * BUS_GET_RESOURCE_LIST.
835 */
836 int
bhnd_generic_print_child(device_t dev,device_t child)837 bhnd_generic_print_child(device_t dev, device_t child)
838 {
839 struct resource_list *rl;
840 int retval = 0;
841
842 retval += bus_print_child_header(dev, child);
843
844 rl = BUS_GET_RESOURCE_LIST(dev, child);
845
846 if (rl != NULL) {
847 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
848 "%#jx");
849
850 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
851 "%#jd");
852 }
853
854 retval += printf(" at core %u", bhnd_get_core_index(child));
855
856 retval += bus_print_child_domain(dev, child);
857 retval += bus_print_child_footer(dev, child);
858
859 return (retval);
860 }
861
862 /**
863 * Default bhnd(4) bus driver implementation of BUS_PROBE_NOMATCH().
864 *
865 * This implementation requests the device's struct resource_list via
866 * BUS_GET_RESOURCE_LIST.
867 */
868 void
bhnd_generic_probe_nomatch(device_t dev,device_t child)869 bhnd_generic_probe_nomatch(device_t dev, device_t child)
870 {
871 struct resource_list *rl;
872 const struct bhnd_nomatch *nm;
873 bool report;
874
875 /* Fetch reporting configuration for this device */
876 report = true;
877 for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) {
878 if (nm->vendor != bhnd_get_vendor(child))
879 continue;
880
881 if (nm->device != bhnd_get_device(child))
882 continue;
883
884 report = false;
885 if (bootverbose && nm->if_verbose)
886 report = true;
887 break;
888 }
889
890 if (!report)
891 return;
892
893 /* Print the non-matched device info */
894 device_printf(dev, "<%s %s, rev %hhu>", bhnd_get_vendor_name(child),
895 bhnd_get_device_name(child), bhnd_get_hwrev(child));
896
897 rl = BUS_GET_RESOURCE_LIST(dev, child);
898 if (rl != NULL) {
899 resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
900 resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%#jd");
901 }
902
903 printf(" at core %u (no driver attached)\n",
904 bhnd_get_core_index(child));
905 }
906
907 /**
908 * Default implementation of BUS_CHILD_PNPINFO_STR().
909 */
910 static int
bhnd_child_pnpinfo_str(device_t dev,device_t child,char * buf,size_t buflen)911 bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf,
912 size_t buflen)
913 {
914 if (device_get_parent(child) != dev) {
915 return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child,
916 buf, buflen));
917 }
918
919 snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx",
920 bhnd_get_vendor(child), bhnd_get_device(child),
921 bhnd_get_hwrev(child));
922
923 return (0);
924 }
925
926 /**
927 * Default implementation of BUS_CHILD_LOCATION_STR().
928 */
929 static int
bhnd_child_location_str(device_t dev,device_t child,char * buf,size_t buflen)930 bhnd_child_location_str(device_t dev, device_t child, char *buf,
931 size_t buflen)
932 {
933 bhnd_addr_t addr;
934 bhnd_size_t size;
935
936 if (device_get_parent(child) != dev) {
937 return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child,
938 buf, buflen));
939 }
940
941 if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) {
942 /* No device default port/region */
943 if (buflen > 0)
944 *buf = '\0';
945 return (0);
946 }
947
948 snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr);
949 return (0);
950 }
951
952 /**
953 * Default bhnd(4) bus driver implementation of BUS_CHILD_DELETED().
954 *
955 * This implementation manages internal bhnd(4) state, and must be called
956 * by subclassing drivers.
957 */
958 void
bhnd_generic_child_deleted(device_t dev,device_t child)959 bhnd_generic_child_deleted(device_t dev, device_t child)
960 {
961 struct bhnd_softc *sc;
962
963 sc = device_get_softc(dev);
964
965 /* Free device info */
966 if (bhnd_get_pmu_info(child) != NULL) {
967 /* Releasing PMU requests automatically would be nice,
968 * but we can't reference per-core PMU register
969 * resource after driver detach */
970 panic("%s leaked device pmu state\n",
971 device_get_nameunit(child));
972 }
973 }
974
975 /**
976 * Helper function for implementing BUS_SUSPEND_CHILD().
977 *
978 * TODO: Power management
979 *
980 * If @p child is not a direct child of @p dev, suspension is delegated to
981 * the @p dev parent.
982 */
983 int
bhnd_generic_suspend_child(device_t dev,device_t child)984 bhnd_generic_suspend_child(device_t dev, device_t child)
985 {
986 if (device_get_parent(child) != dev)
987 BUS_SUSPEND_CHILD(device_get_parent(dev), child);
988
989 return bus_generic_suspend_child(dev, child);
990 }
991
992 /**
993 * Helper function for implementing BUS_RESUME_CHILD().
994 *
995 * TODO: Power management
996 *
997 * If @p child is not a direct child of @p dev, suspension is delegated to
998 * the @p dev parent.
999 */
1000 int
bhnd_generic_resume_child(device_t dev,device_t child)1001 bhnd_generic_resume_child(device_t dev, device_t child)
1002 {
1003 if (device_get_parent(child) != dev)
1004 BUS_RESUME_CHILD(device_get_parent(dev), child);
1005
1006 return bus_generic_resume_child(dev, child);
1007 }
1008
1009 /**
1010 * Default bhnd(4) bus driver implementation of BUS_SETUP_INTR().
1011 *
1012 * This implementation of BUS_SETUP_INTR() will delegate interrupt setup
1013 * to the parent of @p dev, if any.
1014 */
1015 int
bhnd_generic_setup_intr(device_t dev,device_t child,struct resource * irq,int flags,driver_filter_t * filter,driver_intr_t * intr,void * arg,void ** cookiep)1016 bhnd_generic_setup_intr(device_t dev, device_t child, struct resource *irq,
1017 int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg,
1018 void **cookiep)
1019 {
1020 return (bus_generic_setup_intr(dev, child, irq, flags, filter, intr,
1021 arg, cookiep));
1022 }
1023
1024 /*
1025 * Delegate all indirect I/O to the parent device. When inherited by
1026 * non-bridged bus implementations, resources will never be marked as
1027 * indirect, and these methods will never be called.
1028 */
1029 #define BHND_IO_READ(_type, _name, _method) \
1030 static _type \
1031 bhnd_read_ ## _name (device_t dev, device_t child, \
1032 struct bhnd_resource *r, bus_size_t offset) \
1033 { \
1034 return (BHND_BUS_READ_ ## _method( \
1035 device_get_parent(dev), child, r, offset)); \
1036 }
1037
1038 #define BHND_IO_WRITE(_type, _name, _method) \
1039 static void \
1040 bhnd_write_ ## _name (device_t dev, device_t child, \
1041 struct bhnd_resource *r, bus_size_t offset, _type value) \
1042 { \
1043 return (BHND_BUS_WRITE_ ## _method( \
1044 device_get_parent(dev), child, r, offset, \
1045 value)); \
1046 }
1047
1048 #define BHND_IO_MISC(_type, _op, _method) \
1049 static void \
1050 bhnd_ ## _op (device_t dev, device_t child, \
1051 struct bhnd_resource *r, bus_size_t offset, _type datap, \
1052 bus_size_t count) \
1053 { \
1054 BHND_BUS_ ## _method(device_get_parent(dev), child, r, \
1055 offset, datap, count); \
1056 }
1057
1058 #define BHND_IO_METHODS(_type, _size) \
1059 BHND_IO_READ(_type, _size, _size) \
1060 BHND_IO_WRITE(_type, _size, _size) \
1061 \
1062 BHND_IO_READ(_type, stream_ ## _size, STREAM_ ## _size) \
1063 BHND_IO_WRITE(_type, stream_ ## _size, STREAM_ ## _size) \
1064 \
1065 BHND_IO_MISC(_type*, read_multi_ ## _size, \
1066 READ_MULTI_ ## _size) \
1067 BHND_IO_MISC(_type*, write_multi_ ## _size, \
1068 WRITE_MULTI_ ## _size) \
1069 \
1070 BHND_IO_MISC(_type*, read_multi_stream_ ## _size, \
1071 READ_MULTI_STREAM_ ## _size) \
1072 BHND_IO_MISC(_type*, write_multi_stream_ ## _size, \
1073 WRITE_MULTI_STREAM_ ## _size) \
1074 \
1075 BHND_IO_MISC(_type, set_multi_ ## _size, SET_MULTI_ ## _size) \
1076 BHND_IO_MISC(_type, set_region_ ## _size, SET_REGION_ ## _size) \
1077 \
1078 BHND_IO_MISC(_type*, read_region_ ## _size, \
1079 READ_REGION_ ## _size) \
1080 BHND_IO_MISC(_type*, write_region_ ## _size, \
1081 WRITE_REGION_ ## _size) \
1082 \
1083 BHND_IO_MISC(_type*, read_region_stream_ ## _size, \
1084 READ_REGION_STREAM_ ## _size) \
1085 BHND_IO_MISC(_type*, write_region_stream_ ## _size, \
1086 WRITE_REGION_STREAM_ ## _size) \
1087
1088 BHND_IO_METHODS(uint8_t, 1);
1089 BHND_IO_METHODS(uint16_t, 2);
1090 BHND_IO_METHODS(uint32_t, 4);
1091
1092 static void
bhnd_barrier(device_t dev,device_t child,struct bhnd_resource * r,bus_size_t offset,bus_size_t length,int flags)1093 bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r,
1094 bus_size_t offset, bus_size_t length, int flags)
1095 {
1096 BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length,
1097 flags);
1098 }
1099
1100 static device_method_t bhnd_methods[] = {
1101 /* Device interface */ \
1102 DEVMETHOD(device_attach, bhnd_generic_attach),
1103 DEVMETHOD(device_detach, bhnd_generic_detach),
1104 DEVMETHOD(device_shutdown, bhnd_generic_shutdown),
1105 DEVMETHOD(device_suspend, bhnd_generic_suspend),
1106 DEVMETHOD(device_resume, bhnd_generic_resume),
1107
1108 /* Bus interface */
1109 DEVMETHOD(bus_child_deleted, bhnd_generic_child_deleted),
1110 DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch),
1111 DEVMETHOD(bus_print_child, bhnd_generic_print_child),
1112 DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str),
1113 DEVMETHOD(bus_child_location_str, bhnd_child_location_str),
1114
1115 DEVMETHOD(bus_suspend_child, bhnd_generic_suspend_child),
1116 DEVMETHOD(bus_resume_child, bhnd_generic_resume_child),
1117
1118 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
1119 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
1120 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
1121 DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
1122 DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
1123 DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
1124 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
1125 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
1126
1127 DEVMETHOD(bus_setup_intr, bhnd_generic_setup_intr),
1128 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
1129 DEVMETHOD(bus_config_intr, bus_generic_config_intr),
1130 DEVMETHOD(bus_bind_intr, bus_generic_bind_intr),
1131 DEVMETHOD(bus_describe_intr, bus_generic_describe_intr),
1132
1133 DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag),
1134
1135 /* BHND interface */
1136 DEVMETHOD(bhnd_bus_get_chipid, bhnd_bus_generic_get_chipid),
1137 DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled),
1138
1139 DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order),
1140
1141 DEVMETHOD(bhnd_bus_alloc_pmu, bhnd_generic_alloc_pmu),
1142 DEVMETHOD(bhnd_bus_release_pmu, bhnd_generic_release_pmu),
1143 DEVMETHOD(bhnd_bus_request_clock, bhnd_generic_request_clock),
1144 DEVMETHOD(bhnd_bus_enable_clocks, bhnd_generic_enable_clocks),
1145 DEVMETHOD(bhnd_bus_request_ext_rsrc, bhnd_generic_request_ext_rsrc),
1146 DEVMETHOD(bhnd_bus_release_ext_rsrc, bhnd_generic_release_ext_rsrc),
1147 DEVMETHOD(bhnd_bus_get_clock_latency, bhnd_generic_get_clock_latency),
1148 DEVMETHOD(bhnd_bus_get_clock_freq, bhnd_generic_get_clock_freq),
1149
1150 DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid),
1151 DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var),
1152
1153 /* BHND interface (bus I/O) */
1154 DEVMETHOD(bhnd_bus_read_1, bhnd_read_1),
1155 DEVMETHOD(bhnd_bus_read_2, bhnd_read_2),
1156 DEVMETHOD(bhnd_bus_read_4, bhnd_read_4),
1157 DEVMETHOD(bhnd_bus_write_1, bhnd_write_1),
1158 DEVMETHOD(bhnd_bus_write_2, bhnd_write_2),
1159 DEVMETHOD(bhnd_bus_write_4, bhnd_write_4),
1160
1161 DEVMETHOD(bhnd_bus_read_stream_1, bhnd_read_stream_1),
1162 DEVMETHOD(bhnd_bus_read_stream_2, bhnd_read_stream_2),
1163 DEVMETHOD(bhnd_bus_read_stream_4, bhnd_read_stream_4),
1164 DEVMETHOD(bhnd_bus_write_stream_1, bhnd_write_stream_1),
1165 DEVMETHOD(bhnd_bus_write_stream_2, bhnd_write_stream_2),
1166 DEVMETHOD(bhnd_bus_write_stream_4, bhnd_write_stream_4),
1167
1168 DEVMETHOD(bhnd_bus_read_multi_1, bhnd_read_multi_1),
1169 DEVMETHOD(bhnd_bus_read_multi_2, bhnd_read_multi_2),
1170 DEVMETHOD(bhnd_bus_read_multi_4, bhnd_read_multi_4),
1171 DEVMETHOD(bhnd_bus_write_multi_1, bhnd_write_multi_1),
1172 DEVMETHOD(bhnd_bus_write_multi_2, bhnd_write_multi_2),
1173 DEVMETHOD(bhnd_bus_write_multi_4, bhnd_write_multi_4),
1174
1175 DEVMETHOD(bhnd_bus_read_multi_stream_1, bhnd_read_multi_stream_1),
1176 DEVMETHOD(bhnd_bus_read_multi_stream_2, bhnd_read_multi_stream_2),
1177 DEVMETHOD(bhnd_bus_read_multi_stream_4, bhnd_read_multi_stream_4),
1178 DEVMETHOD(bhnd_bus_write_multi_stream_1,bhnd_write_multi_stream_1),
1179 DEVMETHOD(bhnd_bus_write_multi_stream_2,bhnd_write_multi_stream_2),
1180 DEVMETHOD(bhnd_bus_write_multi_stream_4,bhnd_write_multi_stream_4),
1181
1182 DEVMETHOD(bhnd_bus_set_multi_1, bhnd_set_multi_1),
1183 DEVMETHOD(bhnd_bus_set_multi_2, bhnd_set_multi_2),
1184 DEVMETHOD(bhnd_bus_set_multi_4, bhnd_set_multi_4),
1185
1186 DEVMETHOD(bhnd_bus_set_region_1, bhnd_set_region_1),
1187 DEVMETHOD(bhnd_bus_set_region_2, bhnd_set_region_2),
1188 DEVMETHOD(bhnd_bus_set_region_4, bhnd_set_region_4),
1189
1190 DEVMETHOD(bhnd_bus_read_region_1, bhnd_read_region_1),
1191 DEVMETHOD(bhnd_bus_read_region_2, bhnd_read_region_2),
1192 DEVMETHOD(bhnd_bus_read_region_4, bhnd_read_region_4),
1193 DEVMETHOD(bhnd_bus_write_region_1, bhnd_write_region_1),
1194 DEVMETHOD(bhnd_bus_write_region_2, bhnd_write_region_2),
1195 DEVMETHOD(bhnd_bus_write_region_4, bhnd_write_region_4),
1196
1197 DEVMETHOD(bhnd_bus_read_region_stream_1,bhnd_read_region_stream_1),
1198 DEVMETHOD(bhnd_bus_read_region_stream_2,bhnd_read_region_stream_2),
1199 DEVMETHOD(bhnd_bus_read_region_stream_4,bhnd_read_region_stream_4),
1200 DEVMETHOD(bhnd_bus_write_region_stream_1, bhnd_write_region_stream_1),
1201 DEVMETHOD(bhnd_bus_write_region_stream_2, bhnd_write_region_stream_2),
1202 DEVMETHOD(bhnd_bus_write_region_stream_4, bhnd_write_region_stream_4),
1203
1204 DEVMETHOD(bhnd_bus_barrier, bhnd_barrier),
1205
1206 DEVMETHOD_END
1207 };
1208
1209 devclass_t bhnd_devclass; /**< bhnd bus. */
1210 devclass_t bhnd_hostb_devclass; /**< bhnd bus host bridge. */
1211 devclass_t bhnd_nvram_devclass; /**< bhnd NVRAM device */
1212
1213 DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc));
1214 MODULE_VERSION(bhnd, 1);
1215