xref: /freebsd/sys/dev/clk/spacemit/k1_clk.c (revision dcb10e3add17259715352885dfc55ca92061d2ed)
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