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