Home | History | Annotate | Line # | Download | only in altera
      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
    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
    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
    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
    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
    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 *
    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 *
    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 *
    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
    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 *
    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 *
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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