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