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