Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/riscv/sifive/sifive_prci.c
39478 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2019 Axiado Corporation
5
* All rights reserved.
6
* Copyright (c) 2021 Jessica Clarke <[email protected]>
7
*
8
* This software was developed in part by Kristof Provost under contract for
9
* Axiado Corporation.
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
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
* SUCH DAMAGE.
31
*/
32
33
#include <sys/param.h>
34
#include <sys/systm.h>
35
#include <sys/bus.h>
36
#include <sys/kernel.h>
37
#include <sys/lock.h>
38
#include <sys/module.h>
39
#include <sys/mutex.h>
40
#include <sys/rman.h>
41
42
#include <machine/bus.h>
43
#include <machine/cpu.h>
44
45
#include <dev/clk/clk.h>
46
#include <dev/clk/clk_fixed.h>
47
#include <dev/clk/clk_gate.h>
48
49
#include <dev/ofw/ofw_bus.h>
50
#include <dev/ofw/ofw_bus_subr.h>
51
#include <dev/ofw/openfirm.h>
52
53
#include "clkdev_if.h"
54
#include "hwreset_if.h"
55
56
static struct resource_spec prci_spec[] = {
57
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
58
RESOURCE_SPEC_END
59
};
60
61
struct prci_softc {
62
device_t dev;
63
64
struct mtx mtx;
65
66
struct clkdom *clkdom;
67
struct resource *res;
68
bus_space_tag_t bst;
69
bus_space_handle_t bsh;
70
71
int nresets;
72
};
73
74
struct prci_clk_pll_sc {
75
struct prci_softc *parent_sc;
76
uint32_t reg;
77
};
78
79
struct prci_clk_div_sc {
80
struct prci_softc *parent_sc;
81
uint32_t reg;
82
uint32_t bias;
83
};
84
85
#define PRCI_LOCK(sc) mtx_lock(&(sc)->mtx)
86
#define PRCI_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
87
#define PRCI_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED);
88
#define PRCI_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED);
89
90
#define PRCI_PLL_DIVR_MASK 0x3f
91
#define PRCI_PLL_DIVR_SHIFT 0
92
#define PRCI_PLL_DIVF_MASK 0x7fc0
93
#define PRCI_PLL_DIVF_SHIFT 6
94
#define PRCI_PLL_DIVQ_MASK 0x38000
95
#define PRCI_PLL_DIVQ_SHIFT 15
96
97
/* Called devicesresetreg on the FU540 */
98
#define PRCI_DEVICES_RESET_N 0x28
99
100
#define PRCI_READ(_sc, _reg) \
101
bus_space_read_4((_sc)->bst, (_sc)->bsh, (_reg))
102
#define PRCI_WRITE(_sc, _reg, _val) \
103
bus_space_write_4((_sc)->bst, (_sc)->bsh, (_reg), (_val))
104
105
struct prci_pll_def {
106
uint32_t id;
107
const char *name;
108
uint32_t reg;
109
};
110
111
#define PLL(_id, _name, _base) \
112
{ \
113
.id = (_id), \
114
.name = (_name), \
115
.reg = (_base), \
116
}
117
118
#define PLL_END PLL(0, NULL, 0)
119
120
struct prci_div_def {
121
uint32_t id;
122
const char *name;
123
const char *parent_name;
124
uint32_t reg;
125
uint32_t bias;
126
};
127
128
#define DIV(_id, _name, _parent_name, _base, _bias) \
129
{ \
130
.id = (_id), \
131
.name = (_name), \
132
.parent_name = (_parent_name), \
133
.reg = (_base), \
134
.bias = (_bias), \
135
}
136
137
#define DIV_END DIV(0, NULL, NULL, 0, 0)
138
139
struct prci_gate_def {
140
uint32_t id;
141
const char *name;
142
const char *parent_name;
143
uint32_t reg;
144
};
145
146
#define GATE(_id, _name, _parent_name, _base) \
147
{ \
148
.id = (_id), \
149
.name = (_name), \
150
.parent_name = (_parent_name), \
151
.reg = (_base), \
152
}
153
154
#define GATE_END GATE(0, NULL, NULL, 0)
155
156
struct prci_config {
157
struct prci_pll_def *pll_clks;
158
struct prci_div_def *div_clks;
159
struct prci_gate_def *gate_clks;
160
struct clk_fixed_def *tlclk_def;
161
int nresets;
162
};
163
164
/* FU540 clock numbers */
165
#define FU540_PRCI_CORECLK 0
166
#define FU540_PRCI_DDRCLK 1
167
#define FU540_PRCI_GEMGXLCLK 2
168
#define FU540_PRCI_TLCLK 3
169
170
/* FU540 registers */
171
#define FU540_PRCI_COREPLL_CFG0 0x4
172
#define FU540_PRCI_DDRPLL_CFG0 0xC
173
#define FU540_PRCI_GEMGXLPLL_CFG0 0x1C
174
175
/* FU540 PLL clocks */
176
static struct prci_pll_def fu540_pll_clks[] = {
177
PLL(FU540_PRCI_CORECLK, "coreclk", FU540_PRCI_COREPLL_CFG0),
178
PLL(FU540_PRCI_DDRCLK, "ddrclk", FU540_PRCI_DDRPLL_CFG0),
179
PLL(FU540_PRCI_GEMGXLCLK, "gemgxlclk", FU540_PRCI_GEMGXLPLL_CFG0),
180
PLL_END
181
};
182
183
/* FU540 fixed divisor clock TLCLK. */
184
static struct clk_fixed_def fu540_tlclk_def = {
185
.clkdef.id = FU540_PRCI_TLCLK,
186
.clkdef.name = "tlclk",
187
.clkdef.parent_names = (const char *[]){"coreclk"},
188
.clkdef.parent_cnt = 1,
189
.clkdef.flags = CLK_NODE_STATIC_STRINGS,
190
.mult = 1,
191
.div = 2,
192
};
193
194
/* FU540 config */
195
struct prci_config fu540_prci_config = {
196
.pll_clks = fu540_pll_clks,
197
.tlclk_def = &fu540_tlclk_def,
198
.nresets = 6,
199
};
200
201
/* FU740 clock numbers */
202
#define FU740_PRCI_CORECLK 0
203
#define FU740_PRCI_DDRCLK 1
204
#define FU740_PRCI_GEMGXLCLK 2
205
#define FU740_PRCI_DVFSCORECLK 3
206
#define FU740_PRCI_HFPCLK 4
207
#define FU740_PRCI_CLTXCLK 5
208
#define FU740_PRCI_TLCLK 6
209
#define FU740_PRCI_PCLK 7
210
#define FU740_PRCI_PCIEAUXCLK 8
211
212
/* FU740 registers */
213
#define FU740_PRCI_COREPLL_CFG0 0x4
214
#define FU740_PRCI_DDRPLL_CFG0 0xC
215
#define FU740_PRCI_PCIEAUX_GATE 0x14
216
#define FU740_PRCI_GEMGXLPLL_CFG0 0x1C
217
#define FU740_PRCI_DVFSCOREPLL_CFG0 0x38
218
#define FU740_PRCI_HFPCLKPLL_CFG0 0x50
219
#define FU740_PRCI_CLTXPLL_CFG0 0x30
220
#define FU740_PRCI_HFPCLK_DIV 0x5C
221
222
/* FU740 PLL clocks */
223
static struct prci_pll_def fu740_pll_clks[] = {
224
PLL(FU740_PRCI_CORECLK, "coreclk", FU740_PRCI_COREPLL_CFG0),
225
PLL(FU740_PRCI_DDRCLK, "ddrclk", FU740_PRCI_DDRPLL_CFG0),
226
PLL(FU740_PRCI_GEMGXLCLK, "gemgxlclk", FU740_PRCI_GEMGXLPLL_CFG0),
227
PLL(FU740_PRCI_DVFSCORECLK, "dvfscoreclk", FU740_PRCI_DVFSCOREPLL_CFG0),
228
PLL(FU740_PRCI_HFPCLK, "hfpclk", FU740_PRCI_HFPCLKPLL_CFG0),
229
PLL(FU740_PRCI_CLTXCLK, "cltxclk", FU740_PRCI_CLTXPLL_CFG0),
230
PLL_END
231
};
232
233
/* FU740 divisor clocks */
234
static struct prci_div_def fu740_div_clks[] = {
235
DIV(FU740_PRCI_PCLK, "pclk", "hfpclk", FU740_PRCI_HFPCLK_DIV, 2),
236
DIV_END
237
};
238
239
/* FU740 gated clocks */
240
static struct prci_gate_def fu740_gate_clks[] = {
241
GATE(FU740_PRCI_PCIEAUXCLK, "pcieauxclk", "hfclk", FU740_PRCI_PCIEAUX_GATE),
242
GATE_END
243
};
244
245
/* FU740 fixed divisor clock TLCLK. */
246
static struct clk_fixed_def fu740_tlclk_def = {
247
.clkdef.id = FU740_PRCI_TLCLK,
248
.clkdef.name = "tlclk",
249
.clkdef.parent_names = (const char *[]){"coreclk"},
250
.clkdef.parent_cnt = 1,
251
.clkdef.flags = CLK_NODE_STATIC_STRINGS,
252
.mult = 1,
253
.div = 2,
254
};
255
256
/* FU740 config */
257
struct prci_config fu740_prci_config = {
258
.pll_clks = fu740_pll_clks,
259
.div_clks = fu740_div_clks,
260
.gate_clks = fu740_gate_clks,
261
.tlclk_def = &fu740_tlclk_def,
262
.nresets = 7,
263
};
264
265
static struct ofw_compat_data compat_data[] = {
266
{ "sifive,aloeprci0", (uintptr_t)&fu540_prci_config },
267
{ "sifive,ux00prci0", (uintptr_t)&fu540_prci_config },
268
{ "sifive,fu540-c000-prci", (uintptr_t)&fu540_prci_config },
269
{ "sifive,fu740-c000-prci", (uintptr_t)&fu740_prci_config },
270
{ NULL, 0 },
271
};
272
273
static int
274
prci_clk_pll_init(struct clknode *clk, device_t dev)
275
{
276
277
clknode_init_parent_idx(clk, 0);
278
279
return (0);
280
}
281
282
static int
283
prci_clk_pll_recalc(struct clknode *clk, uint64_t *freq)
284
{
285
struct prci_clk_pll_sc *sc;
286
struct clknode *parent_clk;
287
uint32_t val;
288
uint64_t refclk, divf, divq, divr;
289
int err;
290
291
KASSERT(freq != NULL, ("freq cannot be NULL"));
292
293
sc = clknode_get_softc(clk);
294
295
PRCI_LOCK(sc->parent_sc);
296
297
/* Get refclock frequency. */
298
parent_clk = clknode_get_parent(clk);
299
err = clknode_get_freq(parent_clk, &refclk);
300
if (err) {
301
device_printf(sc->parent_sc->dev,
302
"Failed to get refclk frequency\n");
303
PRCI_UNLOCK(sc->parent_sc);
304
return (err);
305
}
306
307
/* Calculate the PLL output */
308
val = PRCI_READ(sc->parent_sc, sc->reg);
309
310
divf = (val & PRCI_PLL_DIVF_MASK) >> PRCI_PLL_DIVF_SHIFT;
311
divq = (val & PRCI_PLL_DIVQ_MASK) >> PRCI_PLL_DIVQ_SHIFT;
312
divr = (val & PRCI_PLL_DIVR_MASK) >> PRCI_PLL_DIVR_SHIFT;
313
314
*freq = refclk / (divr + 1) * (2 * (divf + 1)) / (1 << divq);
315
316
PRCI_UNLOCK(sc->parent_sc);
317
318
return (0);
319
}
320
321
static clknode_method_t prci_clk_pll_clknode_methods[] = {
322
CLKNODEMETHOD(clknode_init, prci_clk_pll_init),
323
CLKNODEMETHOD(clknode_recalc_freq, prci_clk_pll_recalc),
324
CLKNODEMETHOD_END
325
};
326
327
DEFINE_CLASS_1(prci_clk_pll_clknode, prci_clk_pll_clknode_class,
328
prci_clk_pll_clknode_methods, sizeof(struct prci_clk_pll_sc),
329
clknode_class);
330
331
static int
332
prci_clk_div_init(struct clknode *clk, device_t dev)
333
{
334
335
clknode_init_parent_idx(clk, 0);
336
337
return (0);
338
}
339
340
static int
341
prci_clk_div_recalc(struct clknode *clk, uint64_t *freq)
342
{
343
struct prci_clk_div_sc *sc;
344
struct clknode *parent_clk;
345
uint32_t div;
346
uint64_t refclk;
347
int err;
348
349
KASSERT(freq != NULL, ("freq cannot be NULL"));
350
351
sc = clknode_get_softc(clk);
352
353
PRCI_LOCK(sc->parent_sc);
354
355
/* Get refclock frequency. */
356
parent_clk = clknode_get_parent(clk);
357
err = clknode_get_freq(parent_clk, &refclk);
358
if (err) {
359
device_printf(sc->parent_sc->dev,
360
"Failed to get refclk frequency\n");
361
PRCI_UNLOCK(sc->parent_sc);
362
return (err);
363
}
364
365
/* Calculate the divisor output */
366
div = PRCI_READ(sc->parent_sc, sc->reg);
367
368
*freq = refclk / (div + sc->bias);
369
370
PRCI_UNLOCK(sc->parent_sc);
371
372
return (0);
373
}
374
375
static clknode_method_t prci_clk_div_clknode_methods[] = {
376
CLKNODEMETHOD(clknode_init, prci_clk_div_init),
377
CLKNODEMETHOD(clknode_recalc_freq, prci_clk_div_recalc),
378
CLKNODEMETHOD_END
379
};
380
381
DEFINE_CLASS_1(prci_clk_div_clknode, prci_clk_div_clknode_class,
382
prci_clk_div_clknode_methods, sizeof(struct prci_clk_div_sc),
383
clknode_class);
384
385
static int
386
prci_probe(device_t dev)
387
{
388
389
if (!ofw_bus_status_okay(dev))
390
return (ENXIO);
391
392
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
393
return (ENXIO);
394
395
device_set_desc(dev, "SiFive Power Reset Clocking Interrupt");
396
397
return (BUS_PROBE_DEFAULT);
398
}
399
400
static void
401
prci_pll_register(struct prci_softc *parent_sc, struct clknode_init_def *clkdef,
402
uint32_t reg)
403
{
404
struct clknode *clk;
405
struct prci_clk_pll_sc *sc;
406
407
clk = clknode_create(parent_sc->clkdom, &prci_clk_pll_clknode_class,
408
clkdef);
409
if (clk == NULL)
410
panic("Failed to create clknode");
411
412
sc = clknode_get_softc(clk);
413
sc->parent_sc = parent_sc;
414
sc->reg = reg;
415
416
clknode_register(parent_sc->clkdom, clk);
417
}
418
419
static void
420
prci_div_register(struct prci_softc *parent_sc, struct clknode_init_def *clkdef,
421
uint32_t reg, uint32_t bias)
422
{
423
struct clknode *clk;
424
struct prci_clk_div_sc *sc;
425
426
clk = clknode_create(parent_sc->clkdom, &prci_clk_div_clknode_class,
427
clkdef);
428
if (clk == NULL)
429
panic("Failed to create clknode");
430
431
sc = clknode_get_softc(clk);
432
sc->parent_sc = parent_sc;
433
sc->reg = reg;
434
sc->bias = bias;
435
436
clknode_register(parent_sc->clkdom, clk);
437
}
438
439
static int
440
prci_attach(device_t dev)
441
{
442
struct clknode_init_def clkdef, clkdef_div;
443
struct clk_gate_def clkdef_gate;
444
struct prci_softc *sc;
445
clk_t clk_parent;
446
phandle_t node;
447
int i, ncells, error;
448
struct prci_config *cfg;
449
struct prci_pll_def *pll_clk;
450
struct prci_div_def *div_clk;
451
struct prci_gate_def *gate_clk;
452
453
sc = device_get_softc(dev);
454
sc->dev = dev;
455
456
cfg = (struct prci_config *)ofw_bus_search_compatible(dev,
457
compat_data)->ocd_data;
458
459
mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF);
460
461
error = bus_alloc_resources(dev, prci_spec, &sc->res);
462
if (error) {
463
device_printf(dev, "Couldn't allocate resources\n");
464
goto fail;
465
}
466
sc->bst = rman_get_bustag(sc->res);
467
sc->bsh = rman_get_bushandle(sc->res);
468
469
node = ofw_bus_get_node(dev);
470
error = ofw_bus_parse_xref_list_get_length(node, "clocks",
471
"#clock-cells", &ncells);
472
if (error != 0 || ncells < 1) {
473
device_printf(dev, "couldn't find parent clock\n");
474
goto fail;
475
}
476
477
bzero(&clkdef, sizeof(clkdef));
478
clkdef.parent_names = mallocarray(ncells, sizeof(char *), M_OFWPROP,
479
M_WAITOK);
480
for (i = 0; i < ncells; i++) {
481
error = clk_get_by_ofw_index(dev, 0, i, &clk_parent);
482
if (error != 0) {
483
device_printf(dev, "cannot get clock %d\n", error);
484
goto fail1;
485
}
486
clkdef.parent_names[i] = clk_get_name(clk_parent);
487
if (bootverbose)
488
device_printf(dev, "clk parent: %s\n",
489
clkdef.parent_names[i]);
490
clk_release(clk_parent);
491
}
492
clkdef.parent_cnt = ncells;
493
494
sc->clkdom = clkdom_create(dev);
495
if (sc->clkdom == NULL) {
496
device_printf(dev, "Couldn't create clock domain\n");
497
goto fail;
498
}
499
500
/* We can't free a clkdom, so from now on we cannot fail. */
501
for (pll_clk = cfg->pll_clks; pll_clk->name; pll_clk++) {
502
clkdef.id = pll_clk->id;
503
clkdef.name = pll_clk->name;
504
prci_pll_register(sc, &clkdef, pll_clk->reg);
505
}
506
507
if (cfg->div_clks != NULL) {
508
bzero(&clkdef_div, sizeof(clkdef_div));
509
for (div_clk = cfg->div_clks; div_clk->name; div_clk++) {
510
clkdef_div.id = div_clk->id;
511
clkdef_div.name = div_clk->name;
512
clkdef_div.parent_names = &div_clk->parent_name;
513
clkdef_div.parent_cnt = 1;
514
prci_div_register(sc, &clkdef_div, div_clk->reg,
515
div_clk->bias);
516
}
517
}
518
519
if (cfg->gate_clks != NULL) {
520
bzero(&clkdef_gate, sizeof(clkdef_gate));
521
for (gate_clk = cfg->gate_clks; gate_clk->name; gate_clk++) {
522
clkdef_gate.clkdef.id = gate_clk->id;
523
clkdef_gate.clkdef.name = gate_clk->name;
524
clkdef_gate.clkdef.parent_names = &gate_clk->parent_name;
525
clkdef_gate.clkdef.parent_cnt = 1;
526
clkdef_gate.offset = gate_clk->reg;
527
clkdef_gate.shift = 0;
528
clkdef_gate.mask = 1;
529
clkdef_gate.on_value = 1;
530
clkdef_gate.off_value = 0;
531
error = clknode_gate_register(sc->clkdom,
532
&clkdef_gate);
533
if (error != 0) {
534
device_printf(dev,
535
"Couldn't create gated clock %s: %d\n",
536
gate_clk->name, error);
537
goto fail;
538
}
539
}
540
}
541
542
/*
543
* Register the fixed clock "tlclk".
544
*
545
* If an older device tree is being used, tlclk may appear as its own
546
* entity in the device tree, under soc/tlclk. If this is the case it
547
* will be registered automatically by the fixed_clk driver, and the
548
* version we register here will be an unreferenced duplicate.
549
*/
550
clknode_fixed_register(sc->clkdom, cfg->tlclk_def);
551
552
error = clkdom_finit(sc->clkdom);
553
if (error)
554
panic("Couldn't finalise clock domain");
555
556
sc->nresets = cfg->nresets;
557
558
return (0);
559
560
fail1:
561
free(clkdef.parent_names, M_OFWPROP);
562
563
fail:
564
bus_release_resources(dev, prci_spec, &sc->res);
565
mtx_destroy(&sc->mtx);
566
return (error);
567
}
568
569
static int
570
prci_write_4(device_t dev, bus_addr_t addr, uint32_t val)
571
{
572
struct prci_softc *sc;
573
574
sc = device_get_softc(dev);
575
576
PRCI_WRITE(sc, addr, val);
577
578
return (0);
579
}
580
581
static int
582
prci_read_4(device_t dev, bus_addr_t addr, uint32_t *val)
583
{
584
struct prci_softc *sc;
585
586
sc = device_get_softc(dev);
587
588
*val = PRCI_READ(sc, addr);
589
590
return (0);
591
}
592
593
static int
594
prci_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
595
{
596
struct prci_softc *sc;
597
uint32_t reg;
598
599
sc = device_get_softc(dev);
600
601
reg = PRCI_READ(sc, addr);
602
reg &= ~clr;
603
reg |= set;
604
PRCI_WRITE(sc, addr, reg);
605
606
return (0);
607
}
608
609
static void
610
prci_device_lock(device_t dev)
611
{
612
struct prci_softc *sc;
613
614
sc = device_get_softc(dev);
615
PRCI_LOCK(sc);
616
}
617
618
static void
619
prci_device_unlock(device_t dev)
620
{
621
struct prci_softc *sc;
622
623
sc = device_get_softc(dev);
624
PRCI_UNLOCK(sc);
625
}
626
627
static int
628
prci_reset_assert(device_t dev, intptr_t id, bool reset)
629
{
630
struct prci_softc *sc;
631
uint32_t reg;
632
633
sc = device_get_softc(dev);
634
635
if (id >= sc->nresets)
636
return (ENXIO);
637
638
PRCI_LOCK(sc);
639
reg = PRCI_READ(sc, PRCI_DEVICES_RESET_N);
640
if (reset)
641
reg &= ~(1u << id);
642
else
643
reg |= (1u << id);
644
PRCI_WRITE(sc, PRCI_DEVICES_RESET_N, reg);
645
PRCI_UNLOCK(sc);
646
647
return (0);
648
}
649
650
static int
651
prci_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
652
{
653
struct prci_softc *sc;
654
uint32_t reg;
655
656
sc = device_get_softc(dev);
657
658
if (id >= sc->nresets)
659
return (ENXIO);
660
661
PRCI_LOCK(sc);
662
reg = PRCI_READ(sc, PRCI_DEVICES_RESET_N);
663
*reset = (reg & (1u << id)) == 0;
664
PRCI_UNLOCK(sc);
665
666
return (0);
667
}
668
669
static device_method_t prci_methods[] = {
670
DEVMETHOD(device_probe, prci_probe),
671
DEVMETHOD(device_attach, prci_attach),
672
673
/* clkdev interface */
674
DEVMETHOD(clkdev_write_4, prci_write_4),
675
DEVMETHOD(clkdev_read_4, prci_read_4),
676
DEVMETHOD(clkdev_modify_4, prci_modify_4),
677
DEVMETHOD(clkdev_device_lock, prci_device_lock),
678
DEVMETHOD(clkdev_device_unlock, prci_device_unlock),
679
680
/* Reset interface */
681
DEVMETHOD(hwreset_assert, prci_reset_assert),
682
DEVMETHOD(hwreset_is_asserted, prci_reset_is_asserted),
683
684
DEVMETHOD_END
685
};
686
687
static driver_t prci_driver = {
688
"sifive_prci",
689
prci_methods,
690
sizeof(struct prci_softc)
691
};
692
693
/*
694
* hfclk and rtcclk appear later in the device tree than prci, so we must
695
* attach late.
696
*/
697
EARLY_DRIVER_MODULE(sifive_prci, simplebus, prci_driver, 0, 0,
698
BUS_PASS_BUS + BUS_PASS_ORDER_LATE);
699
700