cycv_clkmgr.c revision 1.2
1/* $NetBSD: cycv_clkmgr.c,v 1.2 2019/01/17 12:49:53 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.2 2019/01/17 12:49:53 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 26static int cycv_clkmgr_match(device_t, cfdata_t, void *); 27static void cycv_clkmgr_attach(device_t, device_t, void *); 28 29static struct clk *cycv_clkmgr_clock_decode(device_t, int, const void *, 30 size_t); 31 32static const struct fdtbus_clock_controller_func cycv_clkmgr_fdtclock_funcs = { 33 .decode = cycv_clkmgr_clock_decode 34}; 35 36static struct clk *cycv_clkmgr_clock_get(void *, const char *); 37static void cycv_clkmgr_clock_put(void *, struct clk *); 38static u_int cycv_clkmgr_clock_get_rate(void *, struct clk *); 39static int cycv_clkmgr_clock_set_rate(void *, struct clk *, u_int); 40static int cycv_clkmgr_clock_enable(void *, struct clk *); 41static int cycv_clkmgr_clock_disable(void *, struct clk *); 42static int cycv_clkmgr_clock_set_parent(void *, struct clk *, struct clk *); 43static struct clk *cycv_clkmgr_clock_get_parent(void *, struct clk *); 44 45static 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 56struct 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 91struct 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 102static void cycv_clkmgr_init(struct cycv_clkmgr_softc *, int); 103static void cycv_clkmgr_clock_parse(struct cycv_clkmgr_softc *, int, u_int); 104static u_int cycv_clkmgr_clocks_traverse(struct cycv_clkmgr_softc *, int, 105 void (*)(struct cycv_clkmgr_softc *, int, u_int), u_int); 106static struct cycv_clk_mux_info *cycv_clkmgr_get_mux_info(const char *); 107static void cycv_clkmgr_clock_print(struct cycv_clkmgr_softc *, 108 struct cycv_clk *); 109 110CFATTACH_DECL_NEW(cycvclkmgr, sizeof (struct cycv_clkmgr_softc), 111 cycv_clkmgr_match, cycv_clkmgr_attach, NULL, NULL); 112 113static int 114cycv_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 122static void 123cycv_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 154static void 155cycv_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 189static 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 217static const char * const cycv_clkmgr_compat_fixed[] = { "fixed-clock", NULL }; 218static const char * const cycv_clkmgr_compat_pll[] = { "altr,socfpga-pll-clock", 219 NULL }; 220static const char * const cycv_clkmgr_compat_perip[] = { 221 "altr,socfpga-perip-clk", 222 "altr,socfpga-gate-clk", 223 NULL 224}; 225 226static void 227cycv_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; 300err: 301 aprint_debug_dev(sc->sc_dev, "(%s) error parsing phandle %d\n", 302 clk->base.name, handle); 303} 304 305static u_int 306cycv_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 325static struct cycv_clk_mux_info * 326cycv_clkmgr_get_mux_info(const char *name) 327{ 328 size_t i; 329 330 for (i = 0; i < __arraycount(cycv_clk_mux_tree); i++) { 331 struct cycv_clk_mux_info *cand = &cycv_clk_mux_tree[i]; 332 if (strncmp(name, cand->name, strlen(cand->name)) == 0) 333 return cand; 334 } 335 336 return NULL; 337} 338 339static struct cycv_clk * 340cycv_clkmgr_clock_lookup_by_id(struct cycv_clkmgr_softc *sc, int id) 341{ 342 size_t i; 343 344 for (i = 0; i < sc->sc_nclocks; i++) { 345 if (sc->sc_clocks[i].id == id) 346 return &sc->sc_clocks[i]; 347 } 348 349 return NULL; 350} 351 352static struct cycv_clk * 353cycv_clkmgr_clock_lookup_by_name(struct cycv_clkmgr_softc *sc, const char *name) 354{ 355 size_t i; 356 357 for (i = 0; i < sc->sc_nclocks; i++) { 358 struct cycv_clk *cand = &sc->sc_clocks[i]; 359 if (strncmp(cand->base.name, name, strlen(name)) == 0) 360 return cand; 361 } 362 363 return NULL; 364} 365 366static void 367cycv_clkmgr_clock_print(struct cycv_clkmgr_softc *sc, struct cycv_clk *clk) 368{ 369 uint32_t numer; 370 uint32_t denom; 371 uint32_t tmp; 372 373 aprint_debug("clock %s, id %d, frequency %uHz:\n", clk->base.name, 374 clk->id, cycv_clkmgr_clock_get_rate(sc, &clk->base)); 375 if (clk->parent != NULL) 376 aprint_debug("parent: %s", clk->parent->base.name); 377 else 378 aprint_debug("parent_id: %d", clk->parent_id); 379 aprint_debug(", flags: %d\n", clk->flags); 380 switch (clk->type) { 381 case CYCV_CLK_TYPE_PLL: 382 tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, clk->u.pll_addr); 383 numer = __SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1; 384 denom = __SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1; 385 aprint_debug(" PLL num = %u, den = %u\n", numer, denom); 386 break; 387 case CYCV_CLK_TYPE_FIXED: 388 aprint_debug(" Fixed frequency = %u\n", clk->u.fixed_freq); 389 break; 390 case CYCV_CLK_TYPE_FIXED_DIV: 391 aprint_debug(" Fixed divisor = %u\n", clk->u.fixed_div); 392 break; 393 case CYCV_CLK_TYPE_DIV: 394 tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, clk->u.div.addr); 395 tmp = (tmp & clk->u.div.mask) >> clk->u.div.shift; 396 if (__SHIFTOUT_MASK(clk->u.div.mask) > 0xf) 397 tmp += 1; 398 else 399 tmp = (1 << tmp); 400 aprint_debug(" Divisor = %u\n", tmp); 401 break; 402 default: 403 aprint_debug(" Unknown!!!\n"); 404 break; 405 } 406 407 if (clk->flags & CYCV_CLK_FLAG_HAVE_GATE) { 408 tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, clk->gate_addr); 409 tmp &= (1 << clk->gate_shift); 410 aprint_debug(" Gate %s\n", tmp? "on" : "off"); 411 } 412 413 414} 415 416static struct clk * 417cycv_clkmgr_clock_decode(device_t dev, int cc_phandle, const void *data, 418 size_t len) 419{ 420 struct cycv_clkmgr_softc *sc = device_private(dev); 421 struct cycv_clk *clk; 422 423 if (data != NULL || len != 0) { 424 aprint_debug_dev(dev, "can't decode clock entry\n"); 425 return NULL; 426 } 427 428 clk = cycv_clkmgr_clock_lookup_by_id(sc, cc_phandle); 429 430 return clk == NULL? NULL : &clk->base; 431} 432 433static struct clk * 434cycv_clkmgr_clock_get(void *priv, const char *name) 435{ 436 aprint_debug("%s: called and not implemented\n", __func__); 437 (void) cycv_clkmgr_get_mux_info; 438 (void) cycv_clkmgr_clock_lookup_by_name; 439 440 return NULL; 441} 442 443static void 444cycv_clkmgr_clock_put(void *priv, struct clk *clk) 445{ 446 aprint_debug("%s: called and not implemented\n", __func__); 447} 448 449static u_int 450cycv_clkmgr_clock_get_rate(void *priv, struct clk *base_clk) 451{ 452 struct cycv_clkmgr_softc *sc = priv; 453 struct cycv_clk *clk = (struct cycv_clk *) base_clk; 454 struct cycv_clk *parent; 455 uint32_t parent_rate = 0; 456 uint32_t divisor = 0; 457 uint32_t numer; 458 uint32_t tmp; 459 460 if (clk->type == CYCV_CLK_TYPE_FIXED) 461 return clk->u.fixed_freq; 462 463 parent = (struct cycv_clk *) 464 cycv_clkmgr_clock_get_parent(priv, base_clk); 465 if (parent == NULL) { 466 aprint_debug_dev(sc->sc_dev, "can't get parent of clock %s\n", 467 clk->base.name); 468 return 0; 469 } 470 parent_rate = cycv_clkmgr_clock_get_rate(priv, &parent->base); 471 472 if (strncmp(clk->base.name, "mpuclk@", strlen("mpuclk@")) == 0) 473 parent_rate /= 2; 474 else if (strncmp(clk->base.name, "mainclk@", strlen("mainclk@")) == 0) 475 parent_rate /= 4; 476 else if (strncmp(clk->base.name, "dbgatclk@", strlen("dbgatclk@")) == 0) 477 parent_rate /= 4; 478 479 switch (clk->type) { 480 case CYCV_CLK_TYPE_FIXED_DIV: 481 return parent_rate / clk->u.fixed_div; 482 483 case CYCV_CLK_TYPE_DIV: 484 divisor = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 485 clk->u.div.addr); 486 divisor = (divisor & clk->u.div.mask) >> clk->u.div.shift; 487 if (__SHIFTOUT_MASK(clk->u.div.mask) > 0xf) 488 divisor += 1; 489 else 490 divisor = (1 << divisor); 491 492 return parent_rate / divisor; 493 494 case CYCV_CLK_TYPE_PLL: 495 tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, clk->u.pll_addr); 496 numer = __SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1; 497 divisor = __SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1; 498 499 return (uint64_t) parent_rate * numer / divisor; 500 } 501 502 aprint_debug_dev(sc->sc_dev, "unknown clock type %d\n", clk->type); 503 504 return 0; 505} 506 507static int 508cycv_clkmgr_clock_set_rate(void *priv, struct clk *clk, u_int rate) 509{ 510 aprint_debug("%s: called and not implemented\n", __func__); 511 return EINVAL; 512} 513 514static int 515cycv_clkmgr_clock_set(void *priv, struct clk *base_clk, int val) 516{ 517 struct cycv_clkmgr_softc *sc = priv; 518 struct cycv_clk *clk = (struct cycv_clk *) base_clk; 519 520 if (clk->flags & CYCV_CLK_FLAG_HAVE_GATE) { 521 uint32_t tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, 522 clk->gate_addr); 523 tmp &= ~(1 << clk->gate_shift); 524 tmp |= val << clk->gate_shift; 525 bus_space_write_4(sc->sc_bst, sc->sc_bsh, clk->gate_addr, tmp); 526 } else 527 /* XXX should iterate to the root of the clock domain */ 528 return 0; 529 530 return 0; 531} 532 533static int 534cycv_clkmgr_clock_enable(void *priv, struct clk *clk) 535{ 536 return cycv_clkmgr_clock_set(priv, clk, 1); 537} 538 539static int 540cycv_clkmgr_clock_disable(void *priv, struct clk *clk) 541{ 542 return cycv_clkmgr_clock_set(priv, clk, 0); 543} 544 545static int 546cycv_clkmgr_clock_set_parent(void *priv, struct clk *clk, 547 struct clk *clk_parent) 548{ 549 /* lookup clk in muxinfo table */ 550 /* if not found, parent is not settable */ 551 /* check if clk_parent can be a parent (by name) */ 552 /* beware of special case where there is only one parent in mux */ 553 /* enact reparenting h/w wise, update clk->parent */ 554 aprint_debug("%s: called and not implemented\n", __func__); 555 return EINVAL; 556} 557 558static struct clk * 559cycv_clkmgr_clock_get_parent(void *priv, struct clk *base_clk) 560{ 561 struct cycv_clkmgr_softc *sc = priv; 562 struct cycv_clk *clk = (struct cycv_clk *) base_clk; 563 struct cycv_clk_mux_info *mux; 564 struct cycv_clk *parent = clk->parent; 565 int parent_index; 566 uint32_t tmp; 567 568 if (parent != NULL) 569 goto update; 570 571 if (clk->parent_id != 0) { 572 parent = cycv_clkmgr_clock_lookup_by_id(sc, clk->parent_id); 573 goto update; 574 } 575 576 mux = cycv_clkmgr_get_mux_info(clk->base.name); 577 578 if (mux == NULL) 579 goto update; 580 581 if (mux->nparents == 1) 582 parent_index = 0; 583 else { 584 tmp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, mux->addr); 585 parent_index = __SHIFTOUT(tmp, mux->mask); 586 } 587 588 if (parent_index >= mux->nparents) { 589 aprint_error_dev(sc->sc_dev, 590 "clock %s parent has non existent index %d\n", 591 clk->base.name, parent_index); 592 goto update; 593 } 594 595 parent = cycv_clkmgr_clock_lookup_by_name(sc, 596 mux->parents[parent_index]); 597 598update: 599 clk->parent = parent; 600 return &parent->base; 601} 602 603/* 604 * Functions called during early startup, possibly before autoconfiguration. 605 */ 606 607uint32_t 608cycv_clkmgr_early_get_mpu_clk(void) 609{ 610 bus_space_tag_t bst = &armv7_generic_bs_tag; 611 bus_space_handle_t bsh; 612 uint32_t tmp; 613 uint64_t vco; 614 615 bus_space_map(bst, CYCV_CLKMGR_BASE, CYCV_CLKMGR_SIZE, 0, &bsh); 616 617 tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_VCO); 618 vco = (uint64_t) CYCV_CLOCK_OSC1 * 619 (__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1) / 620 (__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1); 621 tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_MPUCLK); 622 623 return vco / 2 / (__SHIFTOUT(tmp, CYCV_CLKMGR_MAIN_PLL_MPUCLK_CNT) + 1); 624} 625 626uint32_t 627cycv_clkmgr_early_get_l4_sp_clk(void) 628{ 629 bus_space_tag_t bst = &armv7_generic_bs_tag; 630 bus_space_handle_t bsh; 631 uint32_t tmp; 632 uint32_t res; 633 uint64_t vco; 634 635 bus_space_map(bst, CYCV_CLKMGR_BASE, CYCV_CLKMGR_SIZE, 0, &bsh); 636 637 tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_L4SRC); 638 if (__SHIFTOUT(tmp, CYCV_CLKMGR_MAIN_PLL_L4SRC_L4SP) == 0) { 639 /* L4 SP clock driven by main clock */ 640 vco = (uint64_t) CYCV_CLOCK_OSC1 * 641 (__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1) / 642 (__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1); 643 tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_MAINCLK); 644 tmp = __SHIFTOUT(tmp, CYCV_CLKMGR_MAIN_PLL_MAINCLK_CNT); 645 646 res = vco / 4 / (tmp + 1); 647 } else { 648 /* L4 SP clock driven by periph clock */ 649 vco = (uint64_t) CYCV_CLOCK_OSC1 * 650 (__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_NUMER) + 1) / 651 (__SHIFTOUT(tmp, CYCV_CLKMGR_PLL_VCO_DENOM) + 1); 652 tmp = bus_space_read_4(bst, bsh, 653 CYCV_CLKMGR_PERI_PLL_PERBASECLK); 654 tmp = __SHIFTOUT(tmp, CYCV_CLKMGR_PERI_PLL_PERBASECLK_CNT); 655 656 res = vco / (tmp + 1); 657 } 658 659 tmp = bus_space_read_4(bst, bsh, CYCV_CLKMGR_MAIN_PLL_MAINDIV); 660 tmp = __SHIFTOUT(tmp, CYCV_CLKMGR_MAIN_PLL_MAINDIV_L4SP); 661 662 printf("%s: returning %u\n", __func__, (uint32_t) 663 (res / (1 << tmp))); 664 return res / (1 << tmp); 665} 666