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