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