1 /*
2 * Copyright (c) 2026 Bojan Novković <bnovkov@FreeBSD.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 /*
8 * Generic clock routines for the SpacemiT K1 SoC.
9 *
10 * Written using SpacemiT's K1 Chip Product Documentation,
11 * Section 9., "Top System (1/2)", available at
12 * https://www.spacemit.com/community/document/
13 */
14
15 #include <sys/cdefs.h>
16
17 #include <sys/param.h>
18 #include <sys/systm.h>
19 #include <sys/bus.h>
20 #include <sys/kernel.h>
21 #include <sys/module.h>
22 #include <sys/mutex.h>
23
24 #include <machine/bus.h>
25 #include <sys/rman.h>
26 #include <machine/resource.h>
27
28 #include <dev/fdt/simplebus.h>
29
30 #include <dev/ofw/ofw_bus.h>
31 #include <dev/ofw/ofw_bus_subr.h>
32
33 #include <dev/clk/clk.h>
34
35 #include <dev/hwreset/hwreset.h>
36
37 #include "k1_clk.h"
38 #include "clkdev_if.h"
39 #include "hwreset_if.h"
40
41 #define K1_CLK_FCREQ_NRETRIES 5
42
43 #define DEVICE_LOCK(_clk) \
44 CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
45 #define DEVICE_UNLOCK(_clk) \
46 CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
47
48 #define READ4(sc, reg) bus_read_4((sc)->res, (reg))
49 #define WRITE4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
50
51 static int
k1_clk_register(struct clkdom * clkdom,const struct k1_clk_def * clkdef,clknode_class_t class)52 k1_clk_register(struct clkdom *clkdom,
53 const struct k1_clk_def *clkdef, clknode_class_t class)
54 {
55 struct k1_clk_def *sc;
56 struct clknode *clk;
57
58 clk = clknode_create(clkdom, class,
59 &clkdef->clkdef);
60 if (clk == NULL)
61 return (1);
62
63 sc = clknode_get_softc(clk);
64 *sc = *clkdef;
65 clknode_register(clkdom, clk);
66
67 return (0);
68 }
69
70 static void
k1_clkdev_lock(device_t dev)71 k1_clkdev_lock(device_t dev)
72 {
73 struct k1_clkdev_softc *sc;
74
75 sc = device_get_softc(dev);
76 mtx_lock(&sc->mtx);
77 }
78
79 static void
k1_clkdev_unlock(device_t dev)80 k1_clkdev_unlock(device_t dev)
81 {
82 struct k1_clkdev_softc *sc;
83
84 sc = device_get_softc(dev);
85 mtx_unlock(&sc->mtx);
86 }
87
88 int
k1_clk_attach(device_t dev)89 k1_clk_attach(device_t dev)
90 {
91 struct k1_clkdev_softc *sc;
92 clknode_class_t class;
93 int error, rid, i;
94
95 sc = device_get_softc(dev);
96 mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
97
98 if (sc->resets != NULL)
99 hwreset_register_ofw_provider(dev);
100
101 sc->clkdom = clkdom_create(dev);
102 if (sc->clkdom == NULL) {
103 device_printf(dev, "Couldn't create clkdom\n");
104 return (ENXIO);
105 }
106
107 rid = 0;
108 sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
109 &rid, RF_ACTIVE);
110 if (sc->res == NULL) {
111 device_printf(dev, "Can't allocate memory\n");
112 return (ENXIO);
113 }
114
115 class = sc->clknode_class != NULL ?
116 sc->clknode_class : &k1_clknode_class;
117 for (i = 0; i < sc->nclks; i++) {
118 error = k1_clk_register(sc->clkdom, &sc->clks[i], class);
119 if (error != 0) {
120 device_printf(dev, "Failed to register clock '%s'\n",
121 sc->clks[i].clkdef.name);
122 bus_free_resource(dev, SYS_RES_MEMORY, sc->res);
123 return (error);
124 }
125 }
126
127 error = clkdom_finit(sc->clkdom);
128 if (error != 0) {
129 device_printf(dev, "clkdom_finit() returned %d\n", error);
130 bus_free_resource(dev, SYS_RES_MEMORY, sc->res);
131 return (error);
132 }
133
134 if (bootverbose)
135 clkdom_dump(sc->clkdom);
136
137 return (0);
138 }
139
140 static int
k1_clkdev_reset_assert(device_t dev,intptr_t id,bool assert)141 k1_clkdev_reset_assert(device_t dev, intptr_t id, bool assert)
142 {
143 struct k1_clkdev_softc *sc;
144 const struct k1_reset_def *rdef;
145 uint32_t val;
146
147 sc = device_get_softc(dev);
148
149 if (id >= sc->nresets)
150 return (0);
151 rdef = &sc->resets[id];
152 if (rdef->reg == 0)
153 return (0);
154
155 mtx_lock(&sc->mtx);
156 val = READ4(sc, rdef->reg);
157 if (assert)
158 val |= rdef->assert_mask;
159 else
160 val &= ~rdef->deassert_mask;
161 WRITE4(sc, rdef->reg, val);
162 mtx_unlock(&sc->mtx);
163
164 return (0);
165 }
166
167 static device_method_t k1_clkdev_methods[] = {
168 /* clkdev interface */
169 DEVMETHOD(clkdev_device_lock, k1_clkdev_lock),
170 DEVMETHOD(clkdev_device_unlock, k1_clkdev_unlock),
171
172 /* Reset interface */
173 DEVMETHOD(hwreset_assert, k1_clkdev_reset_assert),
174
175 DEVMETHOD_END
176 };
177 DEFINE_CLASS_0(k1_clkdev, k1_clkdev_driver, k1_clkdev_methods,
178 sizeof(struct k1_clkdev_softc));
179
180 static int
k1_clk_set_gate(struct clknode * clk,bool enable)181 k1_clk_set_gate(struct clknode *clk, bool enable)
182 {
183 struct k1_clkdev_softc *sc;
184 struct k1_clk_def *clk_sc;
185 uint32_t reg;
186
187 sc = device_get_softc(clknode_get_device(clk));
188 clk_sc = clknode_get_softc(clk);
189 if (clk_sc->gate_mask == 0 || clk_sc->reg == 0)
190 return (0);
191
192 DEVICE_LOCK(clk);
193 reg = READ4(sc, clk_sc->reg);
194 if (enable)
195 reg |= clk_sc->gate_mask;
196 else
197 reg &= ~clk_sc->gate_mask;
198 WRITE4(sc, clk_sc->reg, reg);
199 DEVICE_UNLOCK(clk);
200
201 return (0);
202 }
203
204 static bool
k1_clk_rounding_check(uint64_t curfreq,uint64_t req,int flags)205 k1_clk_rounding_check(uint64_t curfreq, uint64_t req, int flags)
206 {
207 switch (CLK_SET_ROUND(flags)) {
208 case CLK_SET_ROUND_DOWN:
209 return curfreq <= req;
210 case CLK_SET_ROUND_UP:
211 return curfreq >= req;
212 case CLK_SET_ROUND_EXACT:
213 /* CLK_SET_ROUND_EXACT is enforced in 'k1_clk_set_freq'. */
214 case CLK_SET_ROUND_ANY:
215 default:
216 return true;
217 }
218 }
219
220 /*
221 * Find the closest matching rate given the requested frequency 'req' and
222 * rounding mode in 'flags' by going through all possible combinations of
223 * frequency divisor values and parent clock rates.
224 */
225 static uint64_t
k1_clk_find_best_rate(struct clknode * clk,struct k1_clk_def * sc,uint64_t req,int flags,int * parentp,uint32_t * divp)226 k1_clk_find_best_rate(struct clknode *clk, struct k1_clk_def *sc, uint64_t req,
227 int flags, int *parentp, uint32_t *divp)
228 {
229 uint64_t best_match, best_delta, p_freq, candidate_freq;
230 uint32_t i, divmax, best_div;
231 struct clknode *p_clk;
232 const char **p_names;
233 int best_parent;
234 int p_idx;
235
236 best_div = 1;
237 best_match = 0;
238 best_parent = 0;
239 best_delta = UINT64_MAX;
240 p_names = clknode_get_parent_names(clk);
241 for (p_idx = 0; p_idx != clknode_get_parents_num(clk); p_idx++) {
242 p_clk = clknode_find_by_name(p_names[p_idx]);
243 clknode_get_freq(p_clk, &p_freq);
244
245 divmax = 1 << sc->div_nbits;
246 for (i = 1; i <= divmax; i++) {
247 candidate_freq = p_freq / i;
248 if (clk_freq_diff(req, candidate_freq) < best_delta &&
249 k1_clk_rounding_check(candidate_freq, req, flags)) {
250 best_match = candidate_freq;
251 best_parent = p_idx;
252 best_delta = clk_freq_diff(req, candidate_freq);
253 best_div = i;
254 }
255 }
256 }
257
258 *parentp = best_parent;
259 *divp = best_div;
260
261 return (best_match);
262 }
263
264 /*
265 * Certain clocks must perform a "frequency change request" after
266 * reparenting or changing the clock's frequency divisor. This is done
267 * by setting the appropriate FC bit in the clock's configuration
268 * register and waiting until the hardware clears it, indicating
269 * that the clock's divisor or parent index was successfully updated.
270 */
271 static int
k1_clk_send_fc_req(struct clknode * clk)272 k1_clk_send_fc_req(struct clknode *clk)
273 {
274 struct k1_clkdev_softc *sc;
275 struct k1_clk_def *clk_sc;
276 uint32_t val;
277 int retries;
278
279 sc = device_get_softc(clknode_get_device(clk));
280 clk_sc = clknode_get_softc(clk);
281
282 if (clk_sc->fc_mask == 0)
283 return (0);
284
285 retries = K1_CLK_FCREQ_NRETRIES;
286 val = READ4(sc, clk_sc->reg);
287 val |= clk_sc->fc_mask;
288 WRITE4(sc, clk_sc->reg, val);
289 while (retries-- > 0) {
290 DELAY(1000);
291 val = READ4(sc, clk_sc->reg);
292 if ((val & clk_sc->fc_mask) == 0)
293 break;
294 }
295 if ((val & clk_sc->fc_mask) != 0) {
296 /* The FC bit is still set, something went wrong. */
297 return (ENXIO);
298 }
299
300 return (0);
301 }
302
303 static int
k1_clk_set_freq(struct clknode * clk,uint64_t fparent,uint64_t * fout,int flags,int * stop)304 k1_clk_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout,
305 int flags, int *stop)
306 {
307 uint32_t div_mask, mux_mask;
308 int best_div, best_parent;
309 struct k1_clkdev_softc *sc;
310 struct k1_clk_def *clk_sc;
311 uint64_t best_match;
312 uint32_t val;
313 device_t dev;
314 int p_idx;
315
316 dev = clknode_get_device(clk);
317 sc = device_get_softc(clknode_get_device(clk));
318 clk_sc = clknode_get_softc(clk);
319 p_idx = clknode_get_parent_idx(clk);
320
321 best_match = k1_clk_find_best_rate(clk, clk_sc, *fout, flags,
322 &best_parent, &best_div);
323 *stop = 1;
324 if (best_match == 0 ||
325 (best_match != *fout &&
326 CLK_SET_ROUND(flags) == CLK_SET_ROUND_EXACT))
327 return (ERANGE);
328
329 *fout = best_match;
330 if ((flags & CLK_SET_DRYRUN) != 0)
331 return (0);
332
333 DEVICE_LOCK(clk);
334 if (clk_sc->mux_nbits != 0 && p_idx != best_parent) {
335
336 clknode_set_parent_by_idx(clk, best_parent);
337 mux_mask = (1 << clk_sc->mux_nbits) - 1;
338 mux_mask <<= clk_sc->mux_shift;
339 val = READ4(sc, clk_sc->reg);
340 val &= ~mux_mask;
341 val |= (p_idx << clk_sc->mux_shift);
342 WRITE4(sc, clk_sc->reg, val);
343
344 if (k1_clk_send_fc_req(clk) != 0) {
345 device_printf(dev,
346 "%s: failed mux frequency change request for '%s'\n",
347 __func__, clk_sc->clkdef.name);
348 DEVICE_UNLOCK(clk);
349 return (ENXIO);
350 }
351 }
352
353 if (clk_sc->div_nbits != 0) {
354 div_mask = (1 << clk_sc->div_nbits) - 1;
355 val = READ4(sc, clk_sc->reg);
356 val &= ~(div_mask << clk_sc->div_shift);
357
358 /* The final divisor value is calculated as 'div_value' + 1. */
359 val |= (best_div - 1) << clk_sc->div_shift;
360 WRITE4(sc, clk_sc->reg, val);
361
362 if (k1_clk_send_fc_req(clk) != 0) {
363 device_printf(dev,
364 "%s: failed div frequency change request for '%s'\n",
365 __func__, clk_sc->clkdef.name);
366 DEVICE_UNLOCK(clk);
367 return (ENXIO);
368 }
369 }
370 DEVICE_UNLOCK(clk);
371
372 return (0);
373 }
374
375 static int
k1_clk_init(struct clknode * clk,device_t dev)376 k1_clk_init(struct clknode *clk, device_t dev)
377 {
378 struct k1_clkdev_softc *sc;
379 struct k1_clk_def *clk_sc;
380 uint32_t val, mux_mask;
381 int pidx;
382
383 sc = device_get_softc(clknode_get_device(clk));
384 clk_sc = clknode_get_softc(clk);
385
386 if (clk_sc->mux_shift == 0) {
387 clknode_init_parent_idx(clk, 0);
388 return (0);
389 }
390 DEVICE_LOCK(clk);
391 val = READ4(sc, clk_sc->reg);
392 DEVICE_UNLOCK(clk);
393 mux_mask = (1 << clk_sc->mux_nbits) - 1;
394 pidx = (val >> clk_sc->mux_shift) & mux_mask;
395
396 clknode_init_parent_idx(clk, pidx);
397
398 return (0);
399 }
400
401 static clknode_method_t k1_clknode_methods[] = {
402 CLKNODEMETHOD(clknode_init, k1_clk_init),
403 CLKNODEMETHOD(clknode_set_gate, k1_clk_set_gate),
404 CLKNODEMETHOD(clknode_set_freq, k1_clk_set_freq),
405 CLKNODEMETHOD_END
406 };
407
408 DEFINE_CLASS_1(k1_clknode, k1_clknode_class,
409 k1_clknode_methods, sizeof(struct k1_clk_def), clknode_class);
410