Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/clk/starfive/jh7110_clk.c
39537 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2019 Emmanuel Vadot <[email protected]>
5
* Copyright (c) 2022 Mitchell Horne <[email protected]>
6
* Copyright (c) 2024 Jari Sihvola <[email protected]>
7
*/
8
9
#include <sys/param.h>
10
#include <sys/systm.h>
11
#include <sys/bus.h>
12
#include <sys/mutex.h>
13
#include <sys/rman.h>
14
15
#include <machine/bus.h>
16
#include <machine/intr.h>
17
#include <machine/resource.h>
18
19
#include <dev/clk/clk.h>
20
#include <dev/hwreset/hwreset.h>
21
22
#include <dt-bindings/clock/starfive,jh7110-crg.h>
23
24
#include <dev/clk/starfive/jh7110_clk.h>
25
26
#include "clkdev_if.h"
27
#include "hwreset_if.h"
28
29
#define JH7110_DIV_MASK 0xffffff
30
#define JH7110_MUX_SHIFT 24
31
#define JH7110_MUX_MASK 0x3f000000
32
#define JH7110_ENABLE_SHIFT 31
33
34
#define REG_SIZE 4
35
36
struct jh7110_clk_sc {
37
uint32_t offset;
38
uint32_t flags;
39
uint64_t d_max;
40
int id;
41
};
42
43
#define DIV_ROUND_CLOSEST(n, d) (((n) + (d) / 2) / (d))
44
45
#define READ4(_sc, _off) \
46
bus_read_4(_sc->mem_res, _off)
47
#define WRITE4(_sc, _off, _val) \
48
bus_write_4(_sc->mem_res, _off, _val)
49
50
#define DEVICE_LOCK(_clk) \
51
CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
52
#define DEVICE_UNLOCK(_clk) \
53
CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
54
55
/* Reset functions */
56
57
int
58
jh7110_reset_assert(device_t dev, intptr_t id, bool assert)
59
{
60
struct jh7110_clkgen_softc *sc;
61
uint32_t regvalue, offset, bitmask = 1UL << id % 32;
62
63
sc = device_get_softc(dev);
64
offset = sc->reset_selector_offset + id / 32 * 4;
65
66
mtx_lock(&sc->mtx);
67
68
regvalue = READ4(sc, offset);
69
70
if (assert)
71
regvalue |= bitmask;
72
else
73
regvalue &= ~bitmask;
74
WRITE4(sc, offset, regvalue);
75
76
mtx_unlock(&sc->mtx);
77
78
return (0);
79
}
80
81
int
82
jh7110_reset_is_asserted(device_t dev, intptr_t id, bool *reset)
83
{
84
struct jh7110_clkgen_softc *sc;
85
uint32_t regvalue, offset, bitmask;
86
87
sc = device_get_softc(dev);
88
offset = sc->reset_status_offset + id / 32 * 4;
89
90
mtx_lock(&sc->mtx);
91
92
regvalue = READ4(sc, offset);
93
bitmask = 1UL << id % 32;
94
95
mtx_unlock(&sc->mtx);
96
97
*reset = (regvalue & bitmask) == 0;
98
99
return (0);
100
}
101
102
/* Clock functions */
103
104
static int
105
jh7110_clk_init(struct clknode *clk, device_t dev)
106
{
107
struct jh7110_clkgen_softc *sc;
108
struct jh7110_clk_sc *sc_clk;
109
uint32_t reg;
110
int idx = 0;
111
112
sc = device_get_softc(clknode_get_device(clk));
113
sc_clk = clknode_get_softc(clk);
114
115
if (sc_clk->flags & JH7110_CLK_HAS_MUX) {
116
DEVICE_LOCK(clk);
117
reg = READ4(sc, sc_clk->offset);
118
DEVICE_UNLOCK(clk);
119
idx = (reg & JH7110_MUX_MASK) >> JH7110_MUX_SHIFT;
120
}
121
122
clknode_init_parent_idx(clk, idx);
123
124
return (0);
125
}
126
127
static int
128
jh7110_clk_set_gate(struct clknode *clk, bool enable)
129
{
130
struct jh7110_clkgen_softc *sc;
131
struct jh7110_clk_sc *sc_clk;
132
uint32_t reg;
133
134
sc = device_get_softc(clknode_get_device(clk));
135
sc_clk = clknode_get_softc(clk);
136
137
if ((sc_clk->flags & JH7110_CLK_HAS_GATE) == 0)
138
return (0);
139
140
DEVICE_LOCK(clk);
141
142
reg = READ4(sc, sc_clk->offset);
143
if (enable)
144
reg |= (1 << JH7110_ENABLE_SHIFT);
145
else
146
reg &= ~(1 << JH7110_ENABLE_SHIFT);
147
WRITE4(sc, sc_clk->offset, reg);
148
149
DEVICE_UNLOCK(clk);
150
151
return (0);
152
}
153
154
static int
155
jh7110_clk_set_mux(struct clknode *clk, int idx)
156
{
157
struct jh7110_clkgen_softc *sc;
158
struct jh7110_clk_sc *sc_clk;
159
uint32_t reg;
160
161
sc = device_get_softc(clknode_get_device(clk));
162
sc_clk = clknode_get_softc(clk);
163
164
if ((sc_clk->flags & JH7110_CLK_HAS_MUX) == 0)
165
return (ENXIO);
166
167
/* Checking index size */
168
if ((idx & (JH7110_MUX_MASK >> JH7110_MUX_SHIFT)) != idx)
169
return (EINVAL);
170
171
DEVICE_LOCK(clk);
172
173
reg = READ4(sc, sc_clk->offset) & ~JH7110_MUX_MASK;
174
reg |= idx << JH7110_MUX_SHIFT;
175
WRITE4(sc, sc_clk->offset, reg);
176
177
DEVICE_UNLOCK(clk);
178
179
return (0);
180
}
181
182
static int
183
jh7110_clk_recalc_freq(struct clknode *clk, uint64_t *freq)
184
{
185
struct jh7110_clkgen_softc *sc;
186
struct jh7110_clk_sc *sc_clk;
187
uint32_t divisor;
188
189
sc = device_get_softc(clknode_get_device(clk));
190
sc_clk = clknode_get_softc(clk);
191
192
/* Returning error here causes panic */
193
if ((sc_clk->flags & JH7110_CLK_HAS_DIV) == 0)
194
return (0);
195
196
DEVICE_LOCK(clk);
197
198
divisor = READ4(sc, sc_clk->offset) & JH7110_DIV_MASK;
199
200
DEVICE_UNLOCK(clk);
201
202
if (divisor)
203
*freq = *freq / divisor;
204
else
205
*freq = 0;
206
207
return (0);
208
}
209
210
static int
211
jh7110_clk_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout,
212
int flags, int *done)
213
{
214
struct jh7110_clkgen_softc *sc;
215
struct jh7110_clk_sc *sc_clk;
216
uint32_t divisor;
217
218
sc = device_get_softc(clknode_get_device(clk));
219
sc_clk = clknode_get_softc(clk);
220
221
if ((sc_clk->flags & JH7110_CLK_HAS_DIV) == 0)
222
return (0);
223
224
divisor = MIN(MAX(DIV_ROUND_CLOSEST(fin, *fout), 1UL), sc_clk->d_max);
225
226
if (flags & CLK_SET_DRYRUN)
227
goto done;
228
229
DEVICE_LOCK(clk);
230
231
divisor |= READ4(sc, sc_clk->offset) & ~JH7110_DIV_MASK;
232
WRITE4(sc, sc_clk->offset, divisor);
233
234
DEVICE_UNLOCK(clk);
235
236
done:
237
*fout = divisor;
238
*done = 1;
239
240
return (0);
241
}
242
243
static clknode_method_t jh7110_clknode_methods[] = {
244
/* Device interface */
245
CLKNODEMETHOD(clknode_init, jh7110_clk_init),
246
CLKNODEMETHOD(clknode_set_gate, jh7110_clk_set_gate),
247
CLKNODEMETHOD(clknode_set_mux, jh7110_clk_set_mux),
248
CLKNODEMETHOD(clknode_recalc_freq, jh7110_clk_recalc_freq),
249
CLKNODEMETHOD(clknode_set_freq, jh7110_clk_set_freq),
250
CLKNODEMETHOD_END
251
};
252
253
DEFINE_CLASS_1(jh7110_clknode, jh7110_clknode_class, jh7110_clknode_methods,
254
sizeof(struct jh7110_clk_sc), clknode_class);
255
256
int
257
jh7110_clk_register(struct clkdom *clkdom, const struct jh7110_clk_def *clkdef)
258
{
259
struct clknode *clk;
260
struct jh7110_clk_sc *sc;
261
262
clk = clknode_create(clkdom, &jh7110_clknode_class, &clkdef->clkdef);
263
if (clk == NULL)
264
return (-1);
265
266
sc = clknode_get_softc(clk);
267
268
sc->offset = clkdef->clkdef.id * REG_SIZE;
269
270
sc->flags = clkdef->flags;
271
sc->id = clkdef->clkdef.id;
272
sc->d_max = clkdef->d_max;
273
274
clknode_register(clkdom, clk);
275
276
return (0);
277
}
278
279