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