xref: /netbsd-src/sys/arch/arm/altera/cycv_clkmgr.c (revision cef8759bd76c1b621f8eab8faa6f208faabc2e15)
1 /* $NetBSD: cycv_clkmgr.c,v 1.4 2019/10/18 06:50:08 skrll Exp $ */
2 
3 /* This file is in the public domain. */
4 
5 #include <sys/cdefs.h>
6 __KERNEL_RCSID(0, "$NetBSD: cycv_clkmgr.c,v 1.4 2019/10/18 06:50:08 skrll Exp $");
7 
8 #include <sys/param.h>
9 #include <sys/bus.h>
10 #include <sys/device.h>
11 #include <sys/intr.h>
12 #include <sys/systm.h>
13 #include <sys/kernel.h>
14 #include <sys/atomic.h>
15 #include <sys/kmem.h>
16 
17 #include <dev/clk/clk_backend.h>
18 
19 #include <arm/altera/cycv_reg.h>
20 #include <arm/altera/cycv_var.h>
21 
22 #include <dev/fdt/fdtvar.h>
23 
24 #define CYCV_CLOCK_OSC1		25000000
25 
26 static int cycv_clkmgr_match(device_t, cfdata_t, void *);
27 static void cycv_clkmgr_attach(device_t, device_t, void *);
28 
29 static struct clk *cycv_clkmgr_clock_decode(device_t, int, const void *,
30 					    size_t);
31 
32 static const struct fdtbus_clock_controller_func cycv_clkmgr_fdtclock_funcs = {
33 	.decode = cycv_clkmgr_clock_decode
34 };
35 
36 static struct clk *cycv_clkmgr_clock_get(void *, const char *);
37 static void cycv_clkmgr_clock_put(void *, struct clk *);
38 static u_int cycv_clkmgr_clock_get_rate(void *, struct clk *);
39 static int cycv_clkmgr_clock_set_rate(void *, struct clk *, u_int);
40 static int cycv_clkmgr_clock_enable(void *, struct clk *);
41 static int cycv_clkmgr_clock_disable(void *, struct clk *);
42 static int cycv_clkmgr_clock_set_parent(void *, struct clk *, struct clk *);
43 static struct clk *cycv_clkmgr_clock_get_parent(void *, struct clk *);
44 
45 static const struct clk_funcs cycv_clkmgr_clock_funcs = {
46 	.get = cycv_clkmgr_clock_get,
47 	.put = cycv_clkmgr_clock_put,
48 	.get_rate = cycv_clkmgr_clock_get_rate,
49 	.set_rate = cycv_clkmgr_clock_set_rate,
50 	.enable = cycv_clkmgr_clock_enable,
51 	.disable = cycv_clkmgr_clock_disable,
52 	.get_parent = cycv_clkmgr_clock_get_parent,
53 	.set_parent = cycv_clkmgr_clock_set_parent,
54 };
55 
56 struct cycv_clk {
57 	struct clk base;
58 
59 	int id;
60 	u_int refcnt;
61 
62 	struct cycv_clk *parent;	/* cached and valid if not NULL */
63 	/* parent_id is not zero and filled with dtb if only one parent clock */
64 	int parent_id;
65 
66 	int type;
67 #define CYCV_CLK_TYPE_PLL	0x0001
68 #define CYCV_CLK_TYPE_FIXED	0x0002
69 #define CYCV_CLK_TYPE_FIXED_DIV	0x0003
70 #define CYCV_CLK_TYPE_DIV	0x0004
71 
72 	int flags;
73 #define CYCV_CLK_FLAG_HAVE_GATE	0x0001
74 #define CYCV_CLK_FLAG_IS_AVAIL	0x0002
75 
76 	union {
77 		bus_addr_t pll_addr;
78 		uint32_t fixed_freq;
79 		uint32_t fixed_div;
80 		struct {
81 			bus_addr_t addr;
82 			uint32_t mask;
83 			int shift;
84 		} div;
85 	} u;
86 
87 	bus_addr_t gate_addr;
88 	int gate_shift;
89 };
90 
91 struct cycv_clkmgr_softc {
92 	device_t sc_dev;
93 	struct clk_domain sc_clkdom;
94 
95 	bus_space_tag_t sc_bst;
96 	bus_space_handle_t sc_bsh;
97 
98 	struct cycv_clk *sc_clocks;
99 	u_int sc_nclocks;
100 };
101 
102 static void cycv_clkmgr_init(struct cycv_clkmgr_softc *, int);
103 static void cycv_clkmgr_clock_parse(struct cycv_clkmgr_softc *, int, u_int);
104 static u_int cycv_clkmgr_clocks_traverse(struct cycv_clkmgr_softc *, int,
105 	void (*)(struct cycv_clkmgr_softc *, int, u_int), u_int);
106 static struct cycv_clk_mux_info *cycv_clkmgr_get_mux_info(const char *);
107 static void cycv_clkmgr_clock_print(struct cycv_clkmgr_softc *,
108 	struct cycv_clk *);
109 
110 CFATTACH_DECL_NEW(cycvclkmgr, sizeof (struct cycv_clkmgr_softc),
111 	cycv_clkmgr_match, cycv_clkmgr_attach, NULL, NULL);
112 
113 static int
114 cycv_clkmgr_match(device_t parent, cfdata_t cf, void *aux)
115 {
116 	const char *compatible[] = { "altr,clk-mgr", NULL };
117 	struct fdt_attach_args *faa = aux;
118 
119 	return of_match_compatible(faa->faa_phandle, compatible);
120 }
121 
122 static void
123 cycv_clkmgr_attach(device_t parent, device_t self, void *aux)
124 {
125 	struct cycv_clkmgr_softc *sc = device_private(self);
126 	struct fdt_attach_args *faa = aux;
127 	int phandle = faa->faa_phandle;
128 	bus_addr_t addr;
129 	bus_size_t size;
130 	int error;
131 
132 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
133 		aprint_error(": couldn't get registers\n");
134 		return;
135 	}
136 
137 	sc->sc_dev = self;
138 	sc->sc_bst = faa->faa_bst;
139 	error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
140 	if (error) {
141 		aprint_error(": couldn't map %#" PRIxBUSADDR ": %d",
142 			     addr, error);
143 		return;
144 	}
145 
146 	aprint_normal(": clock manager\n");
147 
148 	sc->sc_clkdom.funcs = &cycv_clkmgr_clock_funcs;
149 	sc->sc_clkdom.priv = sc;
150 
151 	cycv_clkmgr_init(sc, phandle);
152 }
153 
154 static void
155 cycv_clkmgr_init(struct cycv_clkmgr_softc *sc, int clkmgr_handle)
156 {
157 	int clocks_handle;
158 
159 	clocks_handle = of_find_firstchild_byname(clkmgr_handle, "clocks");
160 	if (clocks_handle == -1) {
161 		aprint_error_dev(sc->sc_dev, "no clocks property\n");
162 		return;
163 	}
164 
165 	sc->sc_nclocks = cycv_clkmgr_clocks_traverse(sc, clocks_handle, NULL,
166 						     0);
167 
168 	sc->sc_clocks = kmem_zalloc(sc->sc_nclocks * sizeof *sc->sc_clocks,
169 				    KM_SLEEP);
170 	cycv_clkmgr_clocks_traverse(sc, clocks_handle, cycv_clkmgr_clock_parse,
171 				    0);
172 
173 #if 1
174 	for (int i = 0; i < sc->sc_nclocks; i++)
175 		cycv_clkmgr_clock_print(sc, &sc->sc_clocks[i]);
176 #else
177 	(void) cycv_clkmgr_clock_print;
178 #endif
179 }
180 
181 #define CYCV_CLK_MAX_PARENTS 3
182 
183 static struct cycv_clk_mux_info {
184 	const char *name;
185 	const char *parents[CYCV_CLK_MAX_PARENTS];
186 	int nparents;
187 	bus_addr_t addr;
188 	uint32_t mask;
189 } cycv_clk_mux_tree[] = {
190 	{ "periph_pll", { "osc1", "osc2", "f2s_periph_ref_clk" }, 3,
191 		0x80, 0x00c00000 },
192 	{ "sdram_pll", { "osc1", "osc2", "f2s_sdram_ref_clk" }, 3,
193 		0xc0, 0x00c00000 },
194 	{ "l4_mp_clk", { "mainclk", "per_base_clk" }, 2, 0x70, 0x00000001 },
195 	{ "l4_sp_clk", { "mainclk", "per_base_clk" }, 2, 0x70, 0x00000002 },
196 	{ "sdmmc_clk",
197 	    { "f2s_periph_ref_clk", "main_nand_sdmmc_clk", "per_nand_mmc_clk" },
198 	    3, 0xac, 0x00000003 },
199 	{ "nand_x_clk",
200 	    { "f2s_periph_ref_clk", "main_nand_sdmmc_clk", "per_nand_mmc_clk" },
201 	    3, 0xac, 0x0000000c },
202 	{ "qspi_clk", { "f2s_periph_ref_clk", "main_qspi_clk", "per_qsi_clk" },
203 	    3, 0xac, 0x00000030 },
204 
205 	/* Don't special case bypass */
206 	{ "dbg_base_clk", { "main_pll" }, 1, 0, 0 },
207 	/* Bug in dtb */
208 	{ "nand_clk", { "nand_x_clk" }, 1, 0, 0 },
209 };
210 
211 static const char * const cycv_clkmgr_compat_fixed[] = { "fixed-clock", NULL };
212 static const char * const cycv_clkmgr_compat_pll[] = { "altr,socfpga-pll-clock",
213 	NULL };
214 static const char * const cycv_clkmgr_compat_perip[] = {
215 	"altr,socfpga-perip-clk",
216 	"altr,socfpga-gate-clk",
217 	NULL
218 };
219 
220 static void
221 cycv_clkmgr_clock_parse(struct cycv_clkmgr_softc *sc, int handle, u_int clkno)
222 {
223 	struct cycv_clk *clk = &sc->sc_clocks[clkno];
224 	int flags = 0;
225 	const uint8_t *buf;
226 	int len;
227 
228 	clk->base.domain = &sc->sc_clkdom;
229 	clk->base.name = fdtbus_get_string(handle, "name");
230 	clk->base.flags = 0;
231 
232 	clk->id = handle;
233 	clk->parent = NULL;
234 	clk->parent_id = 0;
235 	clk->refcnt = 0;
236 
237 	if (of_compatible(handle, cycv_clkmgr_compat_fixed) != -1) {
238 		clk->type = CYCV_CLK_TYPE_FIXED;
239 		if (of_getprop_uint32(handle, "clock-frequency",
240 				      &clk->u.fixed_freq) == 0) {
241 			flags |= CYCV_CLK_FLAG_IS_AVAIL;
242 		}
243 	} else if (of_compatible(handle, cycv_clkmgr_compat_pll) != -1) {
244 		if (fdtbus_get_reg(handle, 0, &clk->u.pll_addr, NULL) != 0)
245 			goto err;
246 		clk->type = CYCV_CLK_TYPE_PLL;
247 		flags |= CYCV_CLK_FLAG_IS_AVAIL;
248 	} else if (of_compatible(handle, cycv_clkmgr_compat_perip) != -1) {
249 		if (of_getprop_uint32(handle, "fixed-divider",
250 				      &clk->u.fixed_div) == 0) {
251 			clk->type = CYCV_CLK_TYPE_FIXED_DIV;
252 		} else if (fdtbus_get_reg(handle, 0, &clk->u.div.addr, NULL) ==
253 				0) {
254 			clk->type = CYCV_CLK_TYPE_DIV;
255 			clk->u.div.shift = 0;
256 			clk->u.div.mask = 0xff;
257 		} else if ((buf = fdtbus_get_prop(handle, "div-reg", &len)) !=
258 				NULL) {
259 			if (len != 3 * 4)
260 				goto err;
261 
262 			clk->type = CYCV_CLK_TYPE_DIV;
263 			clk->u.div.addr = of_decode_int(buf);
264 			clk->u.div.shift = of_decode_int(buf + 4);
265 			clk->u.div.mask = ((1 << of_decode_int(buf + 8)) - 1) <<
266 				clk->u.div.shift;
267 		} else {
268 			/* Simply a gate and/or a mux */
269 			clk->type = CYCV_CLK_TYPE_FIXED_DIV;
270 			clk->u.fixed_div = 1;
271 		}
272 		flags |= CYCV_CLK_FLAG_IS_AVAIL;
273 	} else
274 		goto err;
275 
276 	if ((buf = fdtbus_get_prop(handle, "clk-gate", &len)) != NULL) {
277 		clk->gate_addr = of_decode_int(buf);
278 		clk->gate_shift = of_decode_int(buf + 4);
279 		flags |= CYCV_CLK_FLAG_HAVE_GATE;
280 	}
281 
282 	buf = fdtbus_get_prop(handle, "clocks", &len);
283 	if (buf != NULL && len == sizeof (uint32_t)) {
284 		clk->parent_id =
285 			fdtbus_get_phandle_from_native(of_decode_int(buf));
286 	}
287 
288 	clk->flags = flags;
289 
290 	fdtbus_register_clock_controller(sc->sc_dev, handle,
291 		&cycv_clkmgr_fdtclock_funcs);
292 
293 	return;
294 err:
295 	aprint_debug_dev(sc->sc_dev, "(%s) error parsing phandle %d\n",
296 		clk->base.name, handle);
297 }
298 
299 static u_int
300 cycv_clkmgr_clocks_traverse(struct cycv_clkmgr_softc *sc, int clocks_handle,
301 			    void func(struct cycv_clkmgr_softc *, int, u_int),
302 			    u_int nclocks)
303 {
304 	int clk_handle;
305 
306 	for (clk_handle = OF_child(clocks_handle); clk_handle != 0;
307 					clk_handle = OF_peer(clk_handle)) {
308 		if (func != NULL)
309 			func(sc, clk_handle, nclocks);
310 		nclocks++;
311 
312 		nclocks = cycv_clkmgr_clocks_traverse(sc, clk_handle, func,
313 						      nclocks);
314 	}
315 
316 	return nclocks;
317 }
318 
319 static struct cycv_clk_mux_info *
320 cycv_clkmgr_get_mux_info(const char *name)
321 {
322 	size_t i;
323 
324 	for (i = 0; i < __arraycount(cycv_clk_mux_tree); i++) {
325 		struct cycv_clk_mux_info *cand = &cycv_clk_mux_tree[i];
326 		if (strncmp(name, cand->name, strlen(cand->name)) == 0)
327 			return cand;
328 	}
329 
330 	return NULL;
331 }
332 
333 static struct cycv_clk *
334 cycv_clkmgr_clock_lookup_by_id(struct cycv_clkmgr_softc *sc, int id)
335 {
336 	size_t i;
337 
338 	for (i = 0; i < sc->sc_nclocks; i++) {
339 		if (sc->sc_clocks[i].id == id)
340 			return &sc->sc_clocks[i];
341 	}
342 
343 	return NULL;
344 }
345 
346 static struct cycv_clk *
347 cycv_clkmgr_clock_lookup_by_name(struct cycv_clkmgr_softc *sc, const char *name)
348 {
349 	size_t i;
350 
351 	for (i = 0; i < sc->sc_nclocks; i++) {
352 		struct cycv_clk *cand = &sc->sc_clocks[i];
353 		if (strncmp(cand->base.name, name, strlen(name)) == 0)
354 			return cand;
355 	}
356 
357 	return NULL;
358 }
359 
360 static void
361 cycv_clkmgr_clock_print(struct cycv_clkmgr_softc *sc, struct cycv_clk *clk)
362 {
363 	uint32_t numer;
364 	uint32_t denom;
365 	uint32_t tmp;
366 
367 	aprint_debug("clock %s, id %d, frequency %uHz:\n", clk->base.name,
368 		     clk->id, cycv_clkmgr_clock_get_rate(sc, &clk->base));
369 	if (clk->parent != NULL)
370 		aprint_debug("parent: %s", clk->parent->base.name);
371 	else
372 		aprint_debug("parent_id: %d", clk->parent_id);
373 	aprint_debug(", flags: %d\n", clk->flags);
374 	switch (clk->type) {
375 	case CYCV_CLK_TYPE_PLL:
376 		tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, clk->u.pll_addr);
377 		numer = __SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1;
378 		denom = __SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1;
379 		aprint_debug(" PLL num = %u, den = %u\n", numer, denom);
380 		break;
381 	case CYCV_CLK_TYPE_FIXED:
382 		aprint_debug(" Fixed frequency = %u\n", clk->u.fixed_freq);
383 		break;
384 	case CYCV_CLK_TYPE_FIXED_DIV:
385 		aprint_debug(" Fixed divisor = %u\n", clk->u.fixed_div);
386 		break;
387 	case CYCV_CLK_TYPE_DIV:
388 		tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, clk->u.div.addr);
389 		tmp = (tmp & clk->u.div.mask) >> clk->u.div.shift;
390 		if (__SHIFTOUT_MASK(clk->u.div.mask) > 0xf)
391 			tmp += 1;
392 		else
393 			tmp = (1 << tmp);
394 		aprint_debug(" Divisor = %u\n", tmp);
395 		break;
396 	default:
397 		aprint_debug(" Unknown!!!\n");
398 		break;
399 	}
400 
401 	if (clk->flags & CYCV_CLK_FLAG_HAVE_GATE) {
402 		tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, clk->gate_addr);
403 		tmp &= (1 << clk->gate_shift);
404 		aprint_debug(" Gate %s\n", tmp? "on" : "off");
405 	}
406 
407 
408 }
409 
410 static struct clk *
411 cycv_clkmgr_clock_decode(device_t dev, int cc_phandle, const void *data,
412 			 size_t len)
413 {
414 	struct cycv_clkmgr_softc *sc = device_private(dev);
415 	struct cycv_clk *clk;
416 
417 	if (data != NULL || len != 0) {
418 		aprint_debug_dev(dev, "can't decode clock entry\n");
419 		return NULL;
420 	}
421 
422 	clk = cycv_clkmgr_clock_lookup_by_id(sc, cc_phandle);
423 
424 	return clk == NULL? NULL : &clk->base;
425 }
426 
427 static struct clk *
428 cycv_clkmgr_clock_get(void *priv, const char *name)
429 {
430 	aprint_debug("%s: called and not implemented\n", __func__);
431 	(void) cycv_clkmgr_get_mux_info;
432 	(void) cycv_clkmgr_clock_lookup_by_name;
433 
434 	return NULL;
435 }
436 
437 static void
438 cycv_clkmgr_clock_put(void *priv, struct clk *clk)
439 {
440 	aprint_debug("%s: called and not implemented\n", __func__);
441 }
442 
443 static u_int
444 cycv_clkmgr_clock_get_rate(void *priv, struct clk *base_clk)
445 {
446 	struct cycv_clkmgr_softc *sc = priv;
447 	struct cycv_clk *clk = (struct cycv_clk *) base_clk;
448 	struct cycv_clk *parent;
449 	uint32_t parent_rate = 0;
450 	uint32_t divisor = 0;
451 	uint32_t numer;
452 	uint32_t tmp;
453 
454 	if (clk->type == CYCV_CLK_TYPE_FIXED)
455 		return clk->u.fixed_freq;
456 
457 	parent = (struct cycv_clk *)
458 		cycv_clkmgr_clock_get_parent(priv, base_clk);
459 	if (parent == NULL) {
460 		aprint_debug_dev(sc->sc_dev, "can't get parent of clock %s\n",
461 				 clk->base.name);
462 		return 0;
463 	}
464 	parent_rate = cycv_clkmgr_clock_get_rate(priv, &parent->base);
465 
466 	if (strncmp(clk->base.name, "mpuclk@", strlen("mpuclk@")) == 0)
467 		parent_rate /= 2;
468 	else if (strncmp(clk->base.name, "mainclk@", strlen("mainclk@")) == 0)
469 		parent_rate /= 4;
470 	else if (strncmp(clk->base.name, "dbgatclk@", strlen("dbgatclk@")) == 0)
471 		parent_rate /= 4;
472 
473 	switch (clk->type) {
474 	case CYCV_CLK_TYPE_FIXED_DIV:
475 		return parent_rate / clk->u.fixed_div;
476 
477 	case CYCV_CLK_TYPE_DIV:
478 		divisor = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
479 					   clk->u.div.addr);
480 		divisor = (divisor & clk->u.div.mask) >> clk->u.div.shift;
481 		if (__SHIFTOUT_MASK(clk->u.div.mask) > 0xf)
482 			divisor += 1;
483 		else
484 			divisor = (1 << divisor);
485 
486 		return parent_rate / divisor;
487 
488 	case CYCV_CLK_TYPE_PLL:
489 		tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, clk->u.pll_addr);
490 		numer = __SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1;
491 		divisor = __SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1;
492 
493 		return (uint64_t) parent_rate * numer / divisor;
494 	}
495 
496 	aprint_debug_dev(sc->sc_dev, "unknown clock type %d\n", clk->type);
497 
498 	return 0;
499 }
500 
501 static int
502 cycv_clkmgr_clock_set_rate(void *priv, struct clk *clk, u_int rate)
503 {
504 	aprint_debug("%s: called and not implemented\n", __func__);
505 	return EINVAL;
506 }
507 
508 static int
509 cycv_clkmgr_clock_set(void *priv, struct clk *base_clk, int val)
510 {
511 	struct cycv_clkmgr_softc *sc = priv;
512 	struct cycv_clk *clk = (struct cycv_clk *) base_clk;
513 
514 	if (clk->flags & CYCV_CLK_FLAG_HAVE_GATE) {
515 		uint32_t tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
516 			clk->gate_addr);
517 		tmp &= ~(1 << clk->gate_shift);
518 		tmp |= val << clk->gate_shift;
519 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, clk->gate_addr, tmp);
520 	} else
521 		/* XXX should iterate to the root of the clock domain */
522 		return 0;
523 
524 	return 0;
525 }
526 
527 static int
528 cycv_clkmgr_clock_enable(void *priv, struct clk *clk)
529 {
530 	return cycv_clkmgr_clock_set(priv, clk, 1);
531 }
532 
533 static int
534 cycv_clkmgr_clock_disable(void *priv, struct clk *clk)
535 {
536 	return cycv_clkmgr_clock_set(priv, clk, 0);
537 }
538 
539 static int
540 cycv_clkmgr_clock_set_parent(void *priv, struct clk *clk,
541     struct clk *clk_parent)
542 {
543 	/* lookup clk in muxinfo table */
544 	/* if not found, parent is not settable */
545 	/* check if clk_parent can be a parent (by name) */
546 	/* beware of special case where there is only one parent in mux */
547 	/* enact reparenting h/w wise, update clk->parent */
548 	aprint_debug("%s: called and not implemented\n", __func__);
549 	return EINVAL;
550 }
551 
552 static struct clk *
553 cycv_clkmgr_clock_get_parent(void *priv, struct clk *base_clk)
554 {
555 	struct cycv_clkmgr_softc *sc = priv;
556 	struct cycv_clk *clk = (struct cycv_clk *) base_clk;
557 	struct cycv_clk_mux_info *mux;
558 	struct cycv_clk *parent = clk->parent;
559 	int parent_index;
560 	uint32_t tmp;
561 
562 	if (parent != NULL)
563 		goto update;
564 
565 	if (clk->parent_id != 0) {
566 		parent = cycv_clkmgr_clock_lookup_by_id(sc, clk->parent_id);
567 		goto update;
568 	}
569 
570 	mux = cycv_clkmgr_get_mux_info(clk->base.name);
571 
572 	if (mux == NULL)
573 		goto update;
574 
575 	if (mux->nparents == 1)
576 		parent_index = 0;
577 	else {
578 		tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, mux->addr);
579 		parent_index = __SHIFTOUT(tmp, mux->mask);
580 	}
581 
582 	if (parent_index >= mux->nparents) {
583 		aprint_error_dev(sc->sc_dev,
584 				 "clock %s parent has non existent index %d\n",
585 				 clk->base.name, parent_index);
586 		goto update;
587 	}
588 
589 	parent = cycv_clkmgr_clock_lookup_by_name(sc,
590 						  mux->parents[parent_index]);
591 
592 update:
593 	clk->parent = parent;
594 	return &parent->base;
595 }
596 
597 /*
598  * Functions called during early startup, possibly before autoconfiguration.
599  */
600 
601 uint32_t
602 cycv_clkmgr_early_get_mpu_clk(void)
603 {
604 	bus_space_tag_t bst = &armv7_generic_bs_tag;
605 	bus_space_handle_t bsh;
606 	uint32_t tmp;
607 	uint64_t vco;
608 
609 	bus_space_map(bst, CYCV_CLKMGR_BASE, CYCV_CLKMGR_SIZE, 0, &bsh);
610 
611 	tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_VCO);
612 	vco = (uint64_t) CYCV_CLOCK_OSC1 *
613 		(__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1) /
614 		(__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1);
615 	tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_MPUCLK);
616 
617 	return vco / 2 / (__SHIFTOUT(tmp, CYCV_CLKMGR_MAIN_PLL_MPUCLK_CNT) + 1);
618 }
619 
620 uint32_t
621 cycv_clkmgr_early_get_l4_sp_clk(void)
622 {
623 	bus_space_tag_t bst = &armv7_generic_bs_tag;
624 	bus_space_handle_t bsh;
625 	uint32_t tmp;
626 	uint32_t res;
627 	uint64_t vco;
628 
629 	bus_space_map(bst, CYCV_CLKMGR_BASE, CYCV_CLKMGR_SIZE, 0, &bsh);
630 
631 	tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_L4SRC);
632 	if (__SHIFTOUT(tmp, CYCV_CLKMGR_MAIN_PLL_L4SRC_L4SP) == 0) {
633 		/* L4 SP clock driven by main clock */
634 		vco = (uint64_t) CYCV_CLOCK_OSC1 *
635 			(__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1) /
636 			(__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1);
637 		tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_MAINCLK);
638 		tmp = __SHIFTOUT(tmp, CYCV_CLKMGR_MAIN_PLL_MAINCLK_CNT);
639 
640 		res = vco / 4 / (tmp + 1);
641 	} else {
642 		/* L4 SP clock driven by periph clock */
643 		vco = (uint64_t) CYCV_CLOCK_OSC1 *
644 			(__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1) /
645 			(__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1);
646 		tmp = bus_space_read_4(bst, bsh,
647 			CYCV_CLKMGR_PERI_PLL_PERBASECLK);
648 		tmp = __SHIFTOUT(tmp, CYCV_CLKMGR_PERI_PLL_PERBASECLK_CNT);
649 
650 		res = vco / (tmp + 1);
651 	}
652 
653 	tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_MAINDIV);
654 	tmp = __SHIFTOUT(tmp, CYCV_CLKMGR_MAIN_PLL_MAINDIV_L4SP);
655 
656 	printf("%s: returning %u\n", __func__, (uint32_t)
657 		(res / (1 << tmp)));
658 	return res / (1 << tmp);
659 }
660