1 /* $OpenBSD: rkclock.c,v 1.53 2020/06/11 00:07:34 patrick Exp $ */ 2 /* 3 * Copyright (c) 2017, 2018 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/sysctl.h> 21 #include <sys/device.h> 22 23 #include <machine/intr.h> 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/ofw_clock.h> 29 #include <dev/ofw/ofw_misc.h> 30 #include <dev/ofw/fdt.h> 31 32 /* RK3288 registers */ 33 #define RK3288_CRU_APLL_CON(i) (0x0000 + (i) * 4) 34 #define RK3288_CRU_CPLL_CON(i) (0x0020 + (i) * 4) 35 #define RK3288_CRU_GPLL_CON(i) (0x0030 + (i) * 4) 36 #define RK3288_CRU_NPLL_CON(i) (0x0040 + (i) * 4) 37 #define RK3288_CRU_PLL_CLKR_MASK (0x3f << 8) 38 #define RK3288_CRU_PLL_CLKR_SHIFT 8 39 #define RK3288_CRU_PLL_CLKOD_MASK (0xf << 0) 40 #define RK3288_CRU_PLL_CLKOD_SHIFT 0 41 #define RK3288_CRU_PLL_CLKF_MASK (0x1fff << 0) 42 #define RK3288_CRU_PLL_CLKF_SHIFT 0 43 #define RK3288_CRU_PLL_RESET (1 << 5) 44 #define RK3288_CRU_MODE_CON 0x0050 45 #define RK3288_CRU_MODE_PLL_WORK_MODE_MASK 0x3 46 #define RK3288_CRU_MODE_PLL_WORK_MODE_SLOW 0x0 47 #define RK3288_CRU_MODE_PLL_WORK_MODE_NORMAL 0x1 48 #define RK3288_CRU_CLKSEL_CON(i) (0x0060 + (i) * 4) 49 #define RK3288_CRU_SOFTRST_CON(i) (0x01b8 + (i) * 4) 50 51 /* RK3328 registers */ 52 #define RK3328_CRU_APLL_CON(i) (0x0000 + (i) * 4) 53 #define RK3328_CRU_DPLL_CON(i) (0x0020 + (i) * 4) 54 #define RK3328_CRU_CPLL_CON(i) (0x0040 + (i) * 4) 55 #define RK3328_CRU_GPLL_CON(i) (0x0060 + (i) * 4) 56 #define RK3328_CRU_NPLL_CON(i) (0x00a0 + (i) * 4) 57 #define RK3328_CRU_PLL_POSTDIV1_MASK (0x7 << 12) 58 #define RK3328_CRU_PLL_POSTDIV1_SHIFT 12 59 #define RK3328_CRU_PLL_FBDIV_MASK (0xfff << 0) 60 #define RK3328_CRU_PLL_FBDIV_SHIFT 0 61 #define RK3328_CRU_PLL_DSMPD (1 << 12) 62 #define RK3328_CRU_PLL_PLL_LOCK (1 << 10) 63 #define RK3328_CRU_PLL_POSTDIV2_MASK (0x7 << 6) 64 #define RK3328_CRU_PLL_POSTDIV2_SHIFT 6 65 #define RK3328_CRU_PLL_REFDIV_MASK (0x3f << 0) 66 #define RK3328_CRU_PLL_REFDIV_SHIFT 0 67 #define RK3328_CRU_PLL_FRACDIV_MASK (0xffffff << 0) 68 #define RK3328_CRU_PLL_FRACDIV_SHIFT 0 69 #define RK3328_CRU_CRU_MODE 0x0080 70 #define RK3328_CRU_CRU_MODE_MASK 0x1 71 #define RK3328_CRU_CRU_MODE_SLOW 0x0 72 #define RK3328_CRU_CRU_MODE_NORMAL 0x1 73 #define RK3328_CRU_CLKSEL_CON(i) (0x0100 + (i) * 4) 74 #define RK3328_CRU_CORE_CLK_PLL_SEL_MASK (0x3 << 6) 75 #define RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT 6 76 #define RK3328_CRU_CLK_CORE_DIV_CON_MASK (0x1f << 0) 77 #define RK3328_CRU_CLK_CORE_DIV_CON_SHIFT 0 78 #define RK3328_CRU_ACLK_CORE_DIV_CON_MASK (0x7 << 4) 79 #define RK3328_CRU_ACLK_CORE_DIV_CON_SHIFT 4 80 #define RK3328_CRU_CLK_CORE_DBG_DIV_CON_MASK (0xf << 0) 81 #define RK3328_CRU_CLK_CORE_DBG_DIV_CON_SHIFT 0 82 #define RK3328_CRU_VOP_DCLK_SRC_SEL_MASK (0x1 << 1) 83 #define RK3328_CRU_VOP_DCLK_SRC_SEL_SHIFT 1 84 #define RK3328_CRU_CLKGATE_CON(i) (0x0200 + (i) * 4) 85 #define RK3328_CRU_SOFTRST_CON(i) (0x0300 + (i) * 4) 86 87 #define RK3328_GRF_SOC_CON4 0x0410 88 #define RK3328_GRF_GMAC2IO_MAC_CLK_OUTPUT_EN (1 << 14) 89 #define RK3328_GRF_MAC_CON1 0x0904 90 #define RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL (1 << 10) 91 92 /* RK3399 registers */ 93 #define RK3399_CRU_LPLL_CON(i) (0x0000 + (i) * 4) 94 #define RK3399_CRU_BPLL_CON(i) (0x0020 + (i) * 4) 95 #define RK3399_CRU_DPLL_CON(i) (0x0020 + (i) * 4) 96 #define RK3399_CRU_CPLL_CON(i) (0x0060 + (i) * 4) 97 #define RK3399_CRU_GPLL_CON(i) (0x0080 + (i) * 4) 98 #define RK3399_CRU_NPLL_CON(i) (0x00a0 + (i) * 4) 99 #define RK3399_CRU_VPLL_CON(i) (0x00c0 + (i) * 4) 100 #define RK3399_CRU_PLL_FBDIV_MASK (0xfff << 0) 101 #define RK3399_CRU_PLL_FBDIV_SHIFT 0 102 #define RK3399_CRU_PLL_POSTDIV2_MASK (0x7 << 12) 103 #define RK3399_CRU_PLL_POSTDIV2_SHIFT 12 104 #define RK3399_CRU_PLL_POSTDIV1_MASK (0x7 << 8) 105 #define RK3399_CRU_PLL_POSTDIV1_SHIFT 8 106 #define RK3399_CRU_PLL_REFDIV_MASK (0x3f << 0) 107 #define RK3399_CRU_PLL_REFDIV_SHIFT 0 108 #define RK3399_CRU_PLL_PLL_WORK_MODE_MASK (0x3 << 8) 109 #define RK3399_CRU_PLL_PLL_WORK_MODE_SLOW (0x0 << 8) 110 #define RK3399_CRU_PLL_PLL_WORK_MODE_NORMAL (0x1 << 8) 111 #define RK3399_CRU_PLL_PLL_WORK_MODE_DEEP_SLOW (0x2 << 8) 112 #define RK3399_CRU_PLL_PLL_LOCK (1U << 31) 113 #define RK3399_CRU_CLKSEL_CON(i) (0x0100 + (i) * 4) 114 #define RK3399_CRU_ACLKM_CORE_DIV_CON_MASK (0x1f << 8) 115 #define RK3399_CRU_ACLKM_CORE_DIV_CON_SHIFT 8 116 #define RK3399_CRU_CORE_PLL_SEL_MASK (0x3 << 6) 117 #define RK3399_CRU_CORE_PLL_SEL_APLL (0x0 << 6) 118 #define RK3399_CRU_CORE_PLL_SEL_BPLL (0x1 << 6) 119 #define RK3399_CRU_CORE_PLL_SEL_DPLL (0x2 << 6) 120 #define RK3399_CRU_CORE_PLL_SEL_GPLL (0x3 << 6) 121 #define RK3399_CRU_CORE_PLL_SEL_SHIFT 6 122 #define RK3399_CRU_CLK_CORE_DIV_CON_MASK (0x1f << 0) 123 #define RK3399_CRU_CLK_CORE_DIV_CON_SHIFT 0 124 #define RK3399_CRU_PCLK_DBG_DIV_CON_MASK (0x1f << 8) 125 #define RK3399_CRU_PCLK_DBG_DIV_CON_SHIFT 8 126 #define RK3399_CRU_ATCLK_CORE_DIV_CON_MASK (0x1f << 0) 127 #define RK3399_CRU_ATCLK_CORE_DIV_CON_SHIFT 0 128 #define RK3399_CRU_CLK_SD_PLL_SEL_MASK (0x7 << 8) 129 #define RK3399_CRU_CLK_SD_PLL_SEL_SHIFT 8 130 #define RK3399_CRU_CLK_SD_DIV_CON_MASK (0x7f << 0) 131 #define RK3399_CRU_CLK_SD_DIV_CON_SHIFT 0 132 #define RK3399_CRU_CLKGATE_CON(i) (0x0300 + (i) * 4) 133 #define RK3399_CRU_SOFTRST_CON(i) (0x0400 + (i) * 4) 134 #define RK3399_CRU_SDMMC_CON(i) (0x0580 + (i) * 4) 135 136 #define RK3399_PMUCRU_PPLL_CON(i) (0x0000 + (i) * 4) 137 #define RK3399_PMUCRU_CLKSEL_CON(i) (0x0080 + (i) * 4) 138 139 #include "rkclock_clocks.h" 140 141 struct rkclock { 142 uint16_t idx; 143 uint16_t reg; 144 uint16_t sel_mask; 145 uint16_t div_mask; 146 uint16_t parents[8]; 147 uint32_t flags; 148 }; 149 150 #define SEL(l, f) (((1 << (l - f + 1)) - 1) << f) 151 #define DIV(l, f) SEL(l, f) 152 153 #define FIXED_PARENT (1 << 0) 154 #define SET_PARENT (1 << 1) 155 156 #define HREAD4(sc, reg) \ 157 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 158 #define HWRITE4(sc, reg, val) \ 159 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 160 #define HSET4(sc, reg, bits) \ 161 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 162 #define HCLR4(sc, reg, bits) \ 163 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 164 165 struct rkclock_softc { 166 struct device sc_dev; 167 bus_space_tag_t sc_iot; 168 bus_space_handle_t sc_ioh; 169 struct regmap *sc_grf; 170 171 uint32_t sc_phandle; 172 struct rkclock *sc_clocks; 173 174 struct clock_device sc_cd; 175 struct reset_device sc_rd; 176 }; 177 178 int rkclock_match(struct device *, void *, void *); 179 void rkclock_attach(struct device *, struct device *, void *); 180 181 struct cfattach rkclock_ca = { 182 sizeof (struct rkclock_softc), rkclock_match, rkclock_attach 183 }; 184 185 struct cfdriver rkclock_cd = { 186 NULL, "rkclock", DV_DULL 187 }; 188 189 void rk3288_init(struct rkclock_softc *); 190 uint32_t rk3288_get_frequency(void *, uint32_t *); 191 int rk3288_set_frequency(void *, uint32_t *, uint32_t); 192 void rk3288_enable(void *, uint32_t *, int); 193 void rk3288_reset(void *, uint32_t *, int); 194 195 void rk3328_init(struct rkclock_softc *); 196 uint32_t rk3328_get_frequency(void *, uint32_t *); 197 int rk3328_set_frequency(void *, uint32_t *, uint32_t); 198 int rk3328_set_parent(void *, uint32_t *, uint32_t *); 199 void rk3328_enable(void *, uint32_t *, int); 200 void rk3328_reset(void *, uint32_t *, int); 201 202 void rk3399_init(struct rkclock_softc *); 203 uint32_t rk3399_get_frequency(void *, uint32_t *); 204 int rk3399_set_frequency(void *, uint32_t *, uint32_t); 205 void rk3399_enable(void *, uint32_t *, int); 206 void rk3399_reset(void *, uint32_t *, int); 207 208 void rk3399_pmu_init(struct rkclock_softc *); 209 uint32_t rk3399_pmu_get_frequency(void *, uint32_t *); 210 int rk3399_pmu_set_frequency(void *, uint32_t *, uint32_t); 211 void rk3399_pmu_enable(void *, uint32_t *, int); 212 void rk3399_pmu_reset(void *, uint32_t *, int); 213 214 struct rkclock_compat { 215 const char *compat; 216 int assign; 217 void (*init)(struct rkclock_softc *); 218 void (*enable)(void *, uint32_t *, int); 219 uint32_t (*get_frequency)(void *, uint32_t *); 220 int (*set_frequency)(void *, uint32_t *, uint32_t); 221 int (*set_parent)(void *, uint32_t *, uint32_t *); 222 void (*reset)(void *, uint32_t *, int); 223 }; 224 225 struct rkclock_compat rkclock_compat[] = { 226 { 227 "rockchip,rk3288-cru", 0, rk3288_init, 228 rk3288_enable, rk3288_get_frequency, 229 rk3288_set_frequency, NULL, 230 rk3288_reset 231 }, 232 { 233 "rockchip,rk3328-cru", 1, rk3328_init, 234 rk3328_enable, rk3328_get_frequency, 235 rk3328_set_frequency, rk3328_set_parent, 236 rk3328_reset 237 }, 238 { 239 "rockchip,rk3399-cru", 1, rk3399_init, 240 rk3399_enable, rk3399_get_frequency, 241 rk3399_set_frequency, NULL, 242 rk3399_reset 243 }, 244 { 245 "rockchip,rk3399-pmucru", 1, rk3399_pmu_init, 246 rk3399_pmu_enable, rk3399_pmu_get_frequency, 247 rk3399_pmu_set_frequency, NULL, 248 rk3399_pmu_reset 249 } 250 }; 251 252 int 253 rkclock_match(struct device *parent, void *match, void *aux) 254 { 255 struct fdt_attach_args *faa = aux; 256 int i; 257 258 for (i = 0; i < nitems(rkclock_compat); i++) { 259 if (OF_is_compatible(faa->fa_node, rkclock_compat[i].compat)) 260 return 10; 261 } 262 263 return 0; 264 } 265 266 void 267 rkclock_attach(struct device *parent, struct device *self, void *aux) 268 { 269 struct rkclock_softc *sc = (struct rkclock_softc *)self; 270 struct fdt_attach_args *faa = aux; 271 uint32_t grf; 272 int i; 273 274 if (faa->fa_nreg < 1) { 275 printf(": no registers\n"); 276 return; 277 } 278 279 sc->sc_iot = faa->fa_iot; 280 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 281 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 282 printf(": can't map registers\n"); 283 return; 284 } 285 286 grf = OF_getpropint(faa->fa_node, "rockchip,grf", 0); 287 sc->sc_grf = regmap_byphandle(grf); 288 289 printf("\n"); 290 291 sc->sc_phandle = OF_getpropint(faa->fa_node, "phandle", 0); 292 293 for (i = 0; i < nitems(rkclock_compat); i++) { 294 if (OF_is_compatible(faa->fa_node, rkclock_compat[i].compat)) { 295 break; 296 } 297 } 298 KASSERT(i < nitems(rkclock_compat)); 299 300 if (rkclock_compat[i].init) 301 rkclock_compat[i].init(sc); 302 303 sc->sc_cd.cd_node = faa->fa_node; 304 sc->sc_cd.cd_cookie = sc; 305 sc->sc_cd.cd_enable = rkclock_compat[i].enable; 306 sc->sc_cd.cd_get_frequency = rkclock_compat[i].get_frequency; 307 sc->sc_cd.cd_set_frequency = rkclock_compat[i].set_frequency; 308 sc->sc_cd.cd_set_parent = rkclock_compat[i].set_parent; 309 clock_register(&sc->sc_cd); 310 311 sc->sc_rd.rd_node = faa->fa_node; 312 sc->sc_rd.rd_cookie = sc; 313 sc->sc_rd.rd_reset = rkclock_compat[i].reset; 314 reset_register(&sc->sc_rd); 315 316 if (rkclock_compat[i].assign) 317 clock_set_assigned(faa->fa_node); 318 } 319 320 struct rkclock * 321 rkclock_lookup(struct rkclock_softc *sc, uint32_t idx) 322 { 323 struct rkclock *clk; 324 325 for (clk = sc->sc_clocks; clk->idx; clk++) { 326 if (clk->idx == idx) 327 return clk; 328 } 329 330 return NULL; 331 } 332 333 uint32_t 334 rkclock_div_con(struct rkclock_softc *sc, struct rkclock *clk, 335 uint32_t mux, uint32_t freq) 336 { 337 uint32_t parent_freq, div, div_con, max_div_con; 338 uint32_t idx = clk->parents[mux]; 339 340 /* Derive maximum value from mask. */ 341 max_div_con = clk->div_mask >> (ffs(clk->div_mask) - 1); 342 343 parent_freq = sc->sc_cd.cd_get_frequency(sc, &idx); 344 div = (parent_freq + freq - 1) / freq; 345 div_con = (div > 0 ? div - 1 : 0); 346 return (div_con < max_div_con) ? div_con : max_div_con; 347 } 348 349 uint32_t 350 rkclock_freq(struct rkclock_softc *sc, struct rkclock *clk, 351 uint32_t mux, uint32_t freq) 352 { 353 uint32_t parent_freq, div_con; 354 uint32_t idx = clk->parents[mux]; 355 356 parent_freq = sc->sc_cd.cd_get_frequency(sc, &idx); 357 div_con = rkclock_div_con(sc, clk, mux, freq); 358 return parent_freq / (div_con + 1); 359 } 360 361 uint32_t 362 rkclock_get_frequency(struct rkclock_softc *sc, uint32_t idx) 363 { 364 struct rkclock *clk; 365 uint32_t reg, mux, div_con; 366 int shift; 367 368 clk = rkclock_lookup(sc, idx); 369 if (clk == NULL) { 370 printf("%s: 0x%08x\n", __func__, idx); 371 return 0; 372 } 373 374 reg = HREAD4(sc, clk->reg); 375 shift = ffs(clk->sel_mask) - 1; 376 if (shift == -1) 377 mux = 0; 378 else 379 mux = (reg & clk->sel_mask) >> shift; 380 shift = ffs(clk->div_mask) - 1; 381 if (shift == -1) 382 div_con = 0; 383 else 384 div_con = (reg & clk->div_mask) >> shift; 385 386 if (clk->parents[mux] == 0) { 387 printf("%s: parent 0x%08x\n", __func__, idx); 388 return 0; 389 } 390 idx = clk->parents[mux]; 391 return sc->sc_cd.cd_get_frequency(sc, &idx) / (div_con + 1); 392 } 393 394 int 395 rkclock_set_frequency(struct rkclock_softc *sc, uint32_t idx, uint32_t freq) 396 { 397 struct rkclock *clk; 398 uint32_t reg, mux, div_con; 399 uint32_t best_freq, best_mux, f; 400 int sel_shift, div_shift, i; 401 402 clk = rkclock_lookup(sc, idx); 403 if (clk == NULL) { 404 printf("%s: 0x%08x\n", __func__, idx); 405 return -1; 406 } 407 408 reg = HREAD4(sc, clk->reg); 409 sel_shift = ffs(clk->sel_mask) - 1; 410 if (sel_shift == -1) 411 mux = sel_shift = 0; 412 else 413 mux = (reg & clk->sel_mask) >> sel_shift; 414 415 if (clk->parents[mux] == 0) { 416 printf("%s: parent 0x%08x\n", __func__, idx); 417 return 0; 418 } 419 420 if (clk->flags & SET_PARENT) { 421 idx = clk->parents[mux]; 422 sc->sc_cd.cd_set_frequency(sc, &idx, freq); 423 if (clk->div_mask == 0) 424 return 0; 425 } 426 427 if (clk->div_mask == 0) { 428 printf("%s: 0x%08x\n", __func__, idx); 429 return -1; 430 } 431 432 /* 433 * Start out with the current parent. This prevents 434 * unecessary switching to a different parent. 435 */ 436 best_freq = rkclock_freq(sc, clk, mux, freq); 437 best_mux = mux; 438 439 /* 440 * Find the parent that allows configuration of a frequency 441 * closest to the target frequency. 442 */ 443 if ((clk->flags & FIXED_PARENT) == 0) { 444 for (i = 0; i < nitems(clk->parents); i++) { 445 if (clk->parents[i] == 0) 446 continue; 447 f = rkclock_freq(sc, clk, i, freq); 448 if ((f > best_freq && f <= freq) || 449 (f < best_freq && f >= freq)) { 450 best_freq = f; 451 best_mux = i; 452 } 453 } 454 } 455 456 div_con = rkclock_div_con(sc, clk, best_mux, freq); 457 div_shift = ffs(clk->div_mask) - 1; 458 HWRITE4(sc, clk->reg, 459 clk->sel_mask << 16 | best_mux << sel_shift | 460 clk->div_mask << 16 | div_con << div_shift); 461 return 0; 462 } 463 464 int 465 rkclock_set_parent(struct rkclock_softc *sc, uint32_t idx, uint32_t parent) 466 { 467 struct rkclock *clk; 468 uint32_t mux; 469 int shift; 470 471 clk = rkclock_lookup(sc, idx); 472 if (clk == NULL || clk->sel_mask == 0) { 473 printf("%s: 0x%08x\n", __func__, idx); 474 return -1; 475 } 476 477 for (mux = 0; mux < nitems(clk->parents); mux++) { 478 if (clk->parents[mux] == parent) 479 break; 480 } 481 if (mux == nitems(clk->parents) || parent == 0) { 482 printf("%s: 0x%08x parent 0x%08x\n", __func__, idx, parent); 483 return -1; 484 } 485 486 shift = ffs(clk->sel_mask) - 1; 487 HWRITE4(sc, clk->reg, clk->sel_mask << 16 | mux << shift); 488 return 0; 489 } 490 491 /* 492 * Rockchip RK3288 493 */ 494 495 struct rkclock rk3288_clocks[] = { 496 { 497 RK3288_CLK_SDMMC, RK3288_CRU_CLKSEL_CON(11), 498 SEL(7, 6), DIV(5, 0), 499 { RK3288_PLL_CPLL, RK3288_PLL_GPLL, RK3288_XIN24M } 500 } 501 }; 502 503 void 504 rk3288_init(struct rkclock_softc *sc) 505 { 506 int node; 507 508 /* 509 * Since the hardware comes up with a really conservative CPU 510 * clock frequency, and U-Boot doesn't set it to a more 511 * reasonable default, try to do so here. These defaults were 512 * chosen assuming that the CPU voltage is at least 1.1 V. 513 * Only do this on the Tinker-RK3288 for now where this is 514 * likely to be true given the default voltages for the 515 * regulators on that board. 516 */ 517 node = OF_finddevice("/"); 518 if (OF_is_compatible(node, "rockchip,rk3288-tinker")) { 519 uint32_t idx; 520 521 /* Run at 1.2 GHz. */ 522 idx = RK3288_ARMCLK; 523 rk3288_set_frequency(sc, &idx, 1200000000); 524 } 525 526 sc->sc_clocks = rk3288_clocks; 527 } 528 529 uint32_t 530 rk3288_get_pll(struct rkclock_softc *sc, bus_size_t base) 531 { 532 uint32_t clkod, clkr, clkf; 533 uint32_t reg; 534 535 reg = HREAD4(sc, base); 536 clkod = (reg & RK3288_CRU_PLL_CLKOD_MASK) >> 537 RK3288_CRU_PLL_CLKOD_SHIFT; 538 clkr = (reg & RK3288_CRU_PLL_CLKR_MASK) >> 539 RK3288_CRU_PLL_CLKR_SHIFT; 540 reg = HREAD4(sc, base + 4); 541 clkf = (reg & RK3288_CRU_PLL_CLKF_MASK) >> 542 RK3288_CRU_PLL_CLKF_SHIFT; 543 return 24000000ULL * (clkf + 1) / (clkr + 1) / (clkod + 1); 544 } 545 546 int 547 rk3288_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 548 { 549 int shift = 4 * (base / RK3288_CRU_CPLL_CON(0)); 550 uint32_t no, nr, nf; 551 552 /* 553 * It is not clear whether all combinations of the clock 554 * dividers result in a stable clock. Therefore this function 555 * only supports a limited set of PLL clock rates. For now 556 * this set covers all the CPU frequencies supported by the 557 * Linux kernel. 558 */ 559 switch (freq) { 560 case 1800000000: 561 case 1704000000: 562 case 1608000000: 563 case 1512000000: 564 case 1488000000: 565 case 1416000000: 566 case 1200000000: 567 nr = no = 1; 568 break; 569 case 1008000000: 570 case 816000000: 571 case 696000000: 572 case 600000000: 573 nr = 1; no = 2; 574 break; 575 case 408000000: 576 case 312000000: 577 nr = 1; no = 4; 578 break; 579 case 216000000: 580 case 126000000: 581 nr = 1; no = 8; 582 break; 583 default: 584 printf("%s: %u Hz\n", __func__, freq); 585 return -1; 586 } 587 588 /* Calculate feedback divider. */ 589 nf = freq * nr * no / 24000000; 590 591 /* 592 * Select slow mode to guarantee a stable clock while we're 593 * adjusting the PLL. 594 */ 595 HWRITE4(sc, RK3288_CRU_MODE_CON, 596 (RK3288_CRU_MODE_PLL_WORK_MODE_MASK << 16 | 597 RK3288_CRU_MODE_PLL_WORK_MODE_SLOW) << shift); 598 599 /* Assert reset. */ 600 HWRITE4(sc, base + 0x000c, 601 RK3288_CRU_PLL_RESET << 16 | RK3288_CRU_PLL_RESET); 602 603 /* Set PLL rate. */ 604 HWRITE4(sc, base + 0x0000, 605 RK3288_CRU_PLL_CLKR_MASK << 16 | 606 (nr - 1) << RK3288_CRU_PLL_CLKR_SHIFT | 607 RK3288_CRU_PLL_CLKOD_MASK << 16 | 608 (no - 1) << RK3288_CRU_PLL_CLKOD_SHIFT); 609 HWRITE4(sc, base + 0x0004, 610 RK3288_CRU_PLL_CLKF_MASK << 16 | 611 (nf - 1) << RK3288_CRU_PLL_CLKF_SHIFT); 612 613 /* Deassert reset and wait. */ 614 HWRITE4(sc, base + 0x000c, 615 RK3288_CRU_PLL_RESET << 16); 616 delay((nr * 500 / 24) + 1); 617 618 /* Switch back to normal mode. */ 619 HWRITE4(sc, RK3288_CRU_MODE_CON, 620 (RK3288_CRU_MODE_PLL_WORK_MODE_MASK << 16 | 621 RK3288_CRU_MODE_PLL_WORK_MODE_NORMAL) << shift); 622 623 return 0; 624 } 625 626 uint32_t 627 rk3288_get_frequency(void *cookie, uint32_t *cells) 628 { 629 struct rkclock_softc *sc = cookie; 630 uint32_t idx = cells[0]; 631 uint32_t reg, mux, div_con, aclk_div_con; 632 633 switch (idx) { 634 case RK3288_PLL_APLL: 635 return rk3288_get_pll(sc, RK3288_CRU_APLL_CON(0)); 636 case RK3288_PLL_CPLL: 637 return rk3288_get_pll(sc, RK3288_CRU_CPLL_CON(0)); 638 case RK3288_PLL_GPLL: 639 return rk3288_get_pll(sc, RK3288_CRU_GPLL_CON(0)); 640 case RK3288_PLL_NPLL: 641 return rk3288_get_pll(sc, RK3288_CRU_NPLL_CON(0)); 642 case RK3288_ARMCLK: 643 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(0)); 644 mux = (reg >> 15) & 0x1; 645 div_con = (reg >> 8) & 0x1f; 646 idx = (mux == 0) ? RK3288_PLL_APLL : RK3288_PLL_GPLL; 647 return rk3288_get_frequency(sc, &idx) / (div_con + 1); 648 case RK3288_XIN24M: 649 return 24000000; 650 case RK3288_CLK_UART0: 651 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(13)); 652 mux = (reg >> 8) & 0x3; 653 div_con = reg & 0x7f; 654 if (mux == 2) 655 return 24000000 / (div_con + 1); 656 break; 657 case RK3288_CLK_UART1: 658 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(14)); 659 mux = (reg >> 8) & 0x3; 660 div_con = reg & 0x7f; 661 if (mux == 2) 662 return 24000000 / (div_con + 1); 663 break; 664 case RK3288_CLK_UART2: 665 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(15)); 666 mux = (reg >> 8) & 0x3; 667 div_con = reg & 0x7f; 668 if (mux == 2) 669 return 24000000 / (div_con + 1); 670 break; 671 case RK3288_CLK_UART3: 672 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(16)); 673 mux = (reg >> 8) & 0x3; 674 div_con = reg & 0x7f; 675 if (mux == 2) 676 return 24000000 / (div_con + 1); 677 break; 678 case RK3288_CLK_UART4: 679 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(3)); 680 mux = (reg >> 8) & 0x3; 681 div_con = reg & 0x7f; 682 if (mux == 2) 683 return 24000000 / (div_con + 1); 684 break; 685 case RK3288_CLK_MAC: 686 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(21)); 687 if (reg & 0x10) 688 return 125000000; 689 mux = (reg >> 0) & 0x3; 690 div_con = (reg >> 8) & 0x1f; 691 switch (mux) { 692 case 0: 693 idx = RK3288_PLL_NPLL; 694 break; 695 case 1: 696 idx = RK3288_PLL_CPLL; 697 break; 698 case 2: 699 idx = RK3288_PLL_GPLL; 700 break; 701 default: 702 return 0; 703 } 704 return rk3288_get_frequency(sc, &idx) / (div_con + 1); 705 case RK3288_PCLK_I2C0: 706 case RK3288_PCLK_I2C2: 707 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(1)); 708 mux = (reg >> 15) & 0x1; 709 /* pd_bus_pclk_div_con */ 710 div_con = (reg >> 12) & 0x7; 711 if (mux == 1) 712 idx = RK3288_PLL_GPLL; 713 else 714 idx = RK3288_PLL_CPLL; 715 return rk3288_get_frequency(sc, &idx) / (div_con + 1); 716 case RK3288_PCLK_I2C1: 717 case RK3288_PCLK_I2C3: 718 case RK3288_PCLK_I2C4: 719 case RK3288_PCLK_I2C5: 720 reg = HREAD4(sc, RK3288_CRU_CLKSEL_CON(10)); 721 mux = (reg >> 15) & 0x1; 722 /* peri_pclk_div_con */ 723 div_con = (reg >> 12) & 0x3; 724 /* peri_aclk_div_con */ 725 aclk_div_con = reg & 0xf; 726 if (mux == 1) 727 idx = RK3288_PLL_GPLL; 728 else 729 idx = RK3288_PLL_CPLL; 730 return (rk3288_get_frequency(sc, &idx) / (aclk_div_con + 1)) >> 731 div_con; 732 default: 733 break; 734 } 735 736 return rkclock_get_frequency(sc, idx); 737 } 738 739 int 740 rk3288_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 741 { 742 struct rkclock_softc *sc = cookie; 743 uint32_t idx = cells[0]; 744 int error; 745 746 switch (idx) { 747 case RK3288_PLL_APLL: 748 return rk3288_set_pll(sc, RK3288_CRU_APLL_CON(0), freq); 749 case RK3288_ARMCLK: 750 idx = RK3288_PLL_APLL; 751 error = rk3288_set_frequency(sc, &idx, freq); 752 if (error == 0) { 753 HWRITE4(sc, RK3288_CRU_CLKSEL_CON(0), 754 ((1 << 15) | (0x1f << 8)) << 16); 755 } 756 return error; 757 default: 758 break; 759 } 760 761 return rkclock_set_frequency(sc, idx, freq); 762 } 763 764 void 765 rk3288_enable(void *cookie, uint32_t *cells, int on) 766 { 767 uint32_t idx = cells[0]; 768 769 switch (idx) { 770 case RK3288_CLK_SDMMC: 771 case RK3288_CLK_TSADC: 772 case RK3288_CLK_UART0: 773 case RK3288_CLK_UART1: 774 case RK3288_CLK_UART2: 775 case RK3288_CLK_UART3: 776 case RK3288_CLK_UART4: 777 case RK3288_CLK_MAC_RX: 778 case RK3288_CLK_MAC_TX: 779 case RK3288_CLK_SDMMC_DRV: 780 case RK3288_CLK_SDMMC_SAMPLE: 781 case RK3288_CLK_MAC: 782 case RK3288_ACLK_GMAC: 783 case RK3288_PCLK_GMAC: 784 case RK3288_PCLK_I2C0: 785 case RK3288_PCLK_I2C1: 786 case RK3288_PCLK_I2C2: 787 case RK3288_PCLK_I2C3: 788 case RK3288_PCLK_I2C4: 789 case RK3288_PCLK_I2C5: 790 case RK3288_PCLK_TSADC: 791 case RK3288_HCLK_HOST0: 792 case RK3288_HCLK_SDMMC: 793 /* Enabled by default. */ 794 break; 795 default: 796 printf("%s: 0x%08x\n", __func__, idx); 797 break; 798 } 799 } 800 801 void 802 rk3288_reset(void *cookie, uint32_t *cells, int on) 803 { 804 struct rkclock_softc *sc = cookie; 805 uint32_t idx = cells[0]; 806 uint32_t mask = (1 << (idx % 16)); 807 808 HWRITE4(sc, RK3288_CRU_SOFTRST_CON(idx / 16), 809 mask << 16 | (on ? mask : 0)); 810 } 811 812 /* 813 * Rockchip RK3328 814 */ 815 816 struct rkclock rk3328_clocks[] = { 817 { 818 RK3328_CLK_RTC32K, RK3328_CRU_CLKSEL_CON(38), 819 SEL(15, 14), DIV(13, 0), 820 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_XIN24M } 821 }, 822 { 823 RK3328_CLK_SDMMC, RK3328_CRU_CLKSEL_CON(30), 824 SEL(9, 8), DIV(7, 0), 825 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_XIN24M, 826 RK3328_USB480M } 827 }, 828 { 829 RK3328_CLK_SDIO, RK3328_CRU_CLKSEL_CON(31), 830 SEL(9, 8), DIV(7, 0), 831 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_XIN24M, 832 RK3328_USB480M } 833 }, 834 { 835 RK3328_CLK_EMMC, RK3328_CRU_CLKSEL_CON(32), 836 SEL(9, 8), DIV(7, 0), 837 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_XIN24M, 838 RK3328_USB480M } 839 }, 840 { 841 RK3328_CLK_TSADC, RK3328_CRU_CLKSEL_CON(22), 842 0, DIV(9, 0), 843 { RK3328_CLK_24M } 844 }, 845 { 846 RK3328_CLK_UART0, RK3328_CRU_CLKSEL_CON(14), 847 SEL(9, 8), 0, 848 { 0, 0, RK3328_XIN24M, RK3328_XIN24M } 849 }, 850 { 851 RK3328_CLK_UART1, RK3328_CRU_CLKSEL_CON(16), 852 SEL(9, 8), 0, 853 { 0, 0, RK3328_XIN24M, RK3328_XIN24M } 854 }, 855 { 856 RK3328_CLK_UART2, RK3328_CRU_CLKSEL_CON(18), 857 SEL(9, 8), 0, 858 { 0, 0, RK3328_XIN24M, RK3328_XIN24M } 859 }, 860 { 861 RK3328_CLK_WIFI, RK3328_CRU_CLKSEL_CON(52), 862 SEL(7, 6), DIV(5, 0), 863 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_USB480M } 864 }, 865 { 866 RK3328_CLK_I2C0, RK3328_CRU_CLKSEL_CON(34), 867 SEL(7, 7), DIV(6, 0), 868 { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 869 }, 870 { 871 RK3328_CLK_I2C1, RK3328_CRU_CLKSEL_CON(34), 872 SEL(15, 15), DIV(14, 8), 873 { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 874 }, 875 { 876 RK3328_CLK_I2C2, RK3328_CRU_CLKSEL_CON(35), 877 SEL(7, 7), DIV(6, 0), 878 { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 879 }, 880 { 881 RK3328_CLK_I2C3, RK3328_CRU_CLKSEL_CON(35), 882 SEL(15, 15), DIV(14, 8), 883 { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 884 }, 885 { 886 RK3328_CLK_CRYPTO, RK3328_CRU_CLKSEL_CON(20), 887 SEL(7, 7), DIV(4, 0), 888 { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 889 }, 890 { 891 RK3328_CLK_PDM, RK3328_CRU_CLKSEL_CON(20), 892 SEL(15, 14), DIV(12, 8), 893 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_PLL_APLL }, 894 FIXED_PARENT | SET_PARENT 895 }, 896 { 897 RK3328_CLK_VDEC_CABAC, RK3328_CRU_CLKSEL_CON(48), 898 SEL(15, 14), DIV(12, 8), 899 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 900 RK3328_USB480M } 901 }, 902 { 903 RK3328_CLK_VDEC_CORE, RK3328_CRU_CLKSEL_CON(49), 904 SEL(7, 6), DIV(4, 0), 905 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 906 RK3328_USB480M } 907 }, 908 { 909 RK3328_CLK_VENC_DSP, RK3328_CRU_CLKSEL_CON(52), 910 SEL(15, 14), DIV(12, 8), 911 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 912 RK3328_USB480M } 913 }, 914 { 915 RK3328_CLK_VENC_CORE, RK3328_CRU_CLKSEL_CON(51), 916 SEL(15, 14), DIV(12, 8), 917 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 918 RK3328_USB480M } 919 }, 920 { 921 RK3328_CLK_TSP, RK3328_CRU_CLKSEL_CON(21), 922 SEL(15, 15), DIV(12, 8), 923 { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 924 }, 925 { 926 RK3328_CLK_MAC2IO_SRC, RK3328_CRU_CLKSEL_CON(27), 927 SEL(7, 7), DIV(4, 0), 928 { RK3328_PLL_CPLL, RK3328_PLL_GPLL } 929 }, 930 { 931 RK3328_DCLK_LCDC, RK3328_CRU_CLKSEL_CON(40), 932 SEL(1, 1), 0, 933 { RK3328_HDMIPHY, RK3328_DCLK_LCDC_SRC } 934 }, 935 { 936 RK3328_ACLK_VOP_PRE, RK3328_CRU_CLKSEL_CON(39), 937 SEL(7, 6), DIV(4, 0), 938 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 939 RK3328_USB480M } 940 }, 941 { 942 RK3328_ACLK_RGA_PRE, RK3328_CRU_CLKSEL_CON(36), 943 SEL(15, 14), DIV(12, 8), 944 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 945 RK3328_USB480M } 946 }, 947 { 948 RK3328_ACLK_BUS_PRE, RK3328_CRU_CLKSEL_CON(0), 949 SEL(14, 13), DIV(12, 8), 950 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY } 951 }, 952 { 953 RK3328_ACLK_PERI_PRE, RK3328_CRU_CLKSEL_CON(28), 954 SEL(7, 6), DIV(4, 0), 955 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY } 956 }, 957 { 958 RK3328_ACLK_RKVDEC_PRE, RK3328_CRU_CLKSEL_CON(48), 959 SEL(7, 6), DIV(4, 0), 960 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 961 RK3328_USB480M } 962 }, 963 { 964 RK3328_ACLK_RKVENC, RK3328_CRU_CLKSEL_CON(51), 965 SEL(7, 6), DIV(4, 0), 966 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 967 RK3328_USB480M } 968 }, 969 { 970 RK3328_ACLK_VPU_PRE, RK3328_CRU_CLKSEL_CON(50), 971 SEL(7, 6), DIV(4, 0), 972 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 973 RK3328_USB480M } 974 }, 975 { 976 RK3328_ACLK_VIO_PRE, RK3328_CRU_CLKSEL_CON(37), 977 SEL(7, 6), DIV(4, 0), 978 { RK3328_PLL_CPLL, RK3328_PLL_GPLL, RK3328_HDMIPHY, 979 RK3328_USB480M } 980 }, 981 { 982 RK3328_PCLK_BUS_PRE, RK3328_CRU_CLKSEL_CON(1), 983 0, DIV(14, 12), 984 { RK3328_ACLK_BUS_PRE } 985 }, 986 { 987 RK3328_HCLK_BUS_PRE, RK3328_CRU_CLKSEL_CON(1), 988 0, DIV(9, 8), 989 { RK3328_ACLK_BUS_PRE } 990 }, 991 { 992 RK3328_PCLK_PERI, RK3328_CRU_CLKSEL_CON(29), 993 0, DIV(6, 4), 994 { RK3328_ACLK_PERI_PRE } 995 }, 996 { 997 RK3328_HCLK_PERI, RK3328_CRU_CLKSEL_CON(29), 998 0, DIV(1, 0), 999 { RK3328_ACLK_PERI_PRE } 1000 }, 1001 { 1002 RK3328_CLK_24M, RK3328_CRU_CLKSEL_CON(2), 1003 0, DIV(12, 8), 1004 { RK3328_XIN24M } 1005 }, 1006 { 1007 /* Sentinel */ 1008 } 1009 }; 1010 1011 void 1012 rk3328_init(struct rkclock_softc *sc) 1013 { 1014 int i; 1015 1016 /* The code below assumes all clocks are enabled. Check this!. */ 1017 for (i = 0; i <= 28; i++) { 1018 if (HREAD4(sc, RK3328_CRU_CLKGATE_CON(i)) != 0x00000000) { 1019 printf("CRU_CLKGATE_CON%d: 0x%08x\n", i, 1020 HREAD4(sc, RK3328_CRU_CLKGATE_CON(i))); 1021 } 1022 } 1023 1024 sc->sc_clocks = rk3328_clocks; 1025 } 1026 1027 uint32_t 1028 rk3328_armclk_parent(uint32_t mux) 1029 { 1030 switch (mux) { 1031 case 0: 1032 return RK3328_PLL_APLL; 1033 case 1: 1034 return RK3328_PLL_GPLL; 1035 case 2: 1036 return RK3328_PLL_DPLL; 1037 case 3: 1038 return RK3328_PLL_NPLL; 1039 } 1040 1041 return 0; 1042 } 1043 1044 uint32_t 1045 rk3328_get_armclk(struct rkclock_softc *sc) 1046 { 1047 uint32_t reg, mux, div_con; 1048 uint32_t idx; 1049 1050 reg = HREAD4(sc, RK3328_CRU_CLKSEL_CON(0)); 1051 mux = (reg & RK3328_CRU_CORE_CLK_PLL_SEL_MASK) >> 1052 RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT; 1053 div_con = (reg & RK3328_CRU_CLK_CORE_DIV_CON_MASK) >> 1054 RK3328_CRU_CLK_CORE_DIV_CON_SHIFT; 1055 idx = rk3328_armclk_parent(mux); 1056 1057 return rk3328_get_frequency(sc, &idx) / (div_con + 1); 1058 } 1059 1060 int 1061 rk3328_set_armclk(struct rkclock_softc *sc, uint32_t freq) 1062 { 1063 uint32_t reg, mux; 1064 uint32_t old_freq, div; 1065 uint32_t idx; 1066 1067 old_freq = rk3328_get_armclk(sc); 1068 if (freq == old_freq) 1069 return 0; 1070 1071 reg = HREAD4(sc, RK3328_CRU_CLKSEL_CON(0)); 1072 mux = (reg & RK3328_CRU_CORE_CLK_PLL_SEL_MASK) >> 1073 RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT; 1074 1075 /* Keep the pclk_dbg clock at or below 300 MHz. */ 1076 div = 1; 1077 while (freq / (div + 1) > 300000000) 1078 div++; 1079 /* and make sure we use an odd divider. */ 1080 if ((div % 2) == 0) 1081 div++; 1082 1083 /* When ramping up, set clock dividers first. */ 1084 if (freq > old_freq) { 1085 HWRITE4(sc, RK3328_CRU_CLKSEL_CON(0), 1086 RK3328_CRU_CLK_CORE_DIV_CON_MASK << 16 | 1087 0 << RK3328_CRU_CLK_CORE_DIV_CON_SHIFT); 1088 HWRITE4(sc, RK3328_CRU_CLKSEL_CON(1), 1089 RK3328_CRU_ACLK_CORE_DIV_CON_MASK << 16 | 1090 1 << RK3328_CRU_ACLK_CORE_DIV_CON_SHIFT | 1091 RK3328_CRU_CLK_CORE_DBG_DIV_CON_MASK << 16 | 1092 div << RK3328_CRU_CLK_CORE_DBG_DIV_CON_SHIFT); 1093 } 1094 1095 /* We always use NPLL and force the switch below if needed. */ 1096 idx = RK3328_PLL_NPLL; 1097 rk3328_set_frequency(sc, &idx, freq); 1098 1099 /* When ramping down, set clock dividers last. */ 1100 if (freq < old_freq || mux != 3) { 1101 HWRITE4(sc, RK3328_CRU_CLKSEL_CON(0), 1102 RK3328_CRU_CORE_CLK_PLL_SEL_MASK << 16 | 1103 3 << RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT | 1104 RK3328_CRU_CLK_CORE_DIV_CON_MASK << 16 | 1105 0 << RK3328_CRU_CLK_CORE_DIV_CON_SHIFT); 1106 HWRITE4(sc, RK3328_CRU_CLKSEL_CON(1), 1107 RK3328_CRU_ACLK_CORE_DIV_CON_MASK << 16 | 1108 1 << RK3328_CRU_ACLK_CORE_DIV_CON_SHIFT | 1109 RK3328_CRU_CLK_CORE_DBG_DIV_CON_MASK << 16 | 1110 div << RK3328_CRU_CLK_CORE_DBG_DIV_CON_SHIFT); 1111 } 1112 1113 return 0; 1114 } 1115 1116 uint32_t 1117 rk3328_get_pll(struct rkclock_softc *sc, bus_size_t base) 1118 { 1119 uint32_t fbdiv, postdiv1, postdiv2, refdiv; 1120 uint32_t dsmpd, fracdiv; 1121 uint64_t frac = 0; 1122 uint32_t reg; 1123 1124 reg = HREAD4(sc, base + 0x0000); 1125 postdiv1 = (reg & RK3328_CRU_PLL_POSTDIV1_MASK) >> 1126 RK3328_CRU_PLL_POSTDIV1_SHIFT; 1127 fbdiv = (reg & RK3328_CRU_PLL_FBDIV_MASK) >> 1128 RK3328_CRU_PLL_FBDIV_SHIFT; 1129 reg = HREAD4(sc, base + 0x0004); 1130 dsmpd = (reg & RK3328_CRU_PLL_DSMPD); 1131 postdiv2 = (reg & RK3328_CRU_PLL_POSTDIV2_MASK) >> 1132 RK3328_CRU_PLL_POSTDIV2_SHIFT; 1133 refdiv = (reg & RK3328_CRU_PLL_REFDIV_MASK) >> 1134 RK3328_CRU_PLL_REFDIV_SHIFT; 1135 reg = HREAD4(sc, base + 0x0008); 1136 fracdiv = (reg & RK3328_CRU_PLL_FRACDIV_MASK) >> 1137 RK3328_CRU_PLL_FRACDIV_SHIFT; 1138 1139 if (dsmpd == 0) 1140 frac = (24000000ULL * fracdiv / refdiv) >> 24; 1141 return ((24000000ULL * fbdiv / refdiv) + frac) / postdiv1 / postdiv2; 1142 } 1143 1144 int 1145 rk3328_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 1146 { 1147 uint32_t fbdiv, postdiv1, postdiv2, refdiv; 1148 int mode_shift = -1; 1149 1150 switch (base) { 1151 case RK3328_CRU_APLL_CON(0): 1152 mode_shift = 0; 1153 break; 1154 case RK3328_CRU_DPLL_CON(0): 1155 mode_shift = 4; 1156 break; 1157 case RK3328_CRU_CPLL_CON(0): 1158 mode_shift = 8; 1159 break; 1160 case RK3328_CRU_GPLL_CON(0): 1161 mode_shift = 12; 1162 break; 1163 case RK3328_CRU_NPLL_CON(0): 1164 mode_shift = 1; 1165 break; 1166 } 1167 KASSERT(mode_shift != -1); 1168 1169 /* 1170 * It is not clear whether all combinations of the clock 1171 * dividers result in a stable clock. Therefore this function 1172 * only supports a limited set of PLL clock rates. For now 1173 * this set covers all the CPU frequencies supported by the 1174 * Linux kernel. 1175 */ 1176 switch (freq) { 1177 case 1800000000U: 1178 case 1704000000U: 1179 case 1608000000U: 1180 case 1512000000U: 1181 case 1488000000U: 1182 case 1416000000U: 1183 case 1392000000U: 1184 case 1296000000U: 1185 case 1200000000U: 1186 case 1104000000U: 1187 postdiv1 = postdiv2 = refdiv = 1; 1188 break; 1189 case 1008000000U: 1190 case 912000000U: 1191 case 816000000U: 1192 case 696000000U: 1193 postdiv1 = 2; postdiv2 = refdiv = 1; 1194 break; 1195 case 600000000U: 1196 postdiv1 = 3; postdiv2 = refdiv = 1; 1197 break; 1198 case 408000000U: 1199 case 312000000U: 1200 postdiv1 = postdiv2 = 2; refdiv = 1; 1201 break; 1202 case 216000000U: 1203 postdiv1 = 4; postdiv2 = 2; refdiv = 1; 1204 break; 1205 case 96000000U: 1206 postdiv1 = postdiv2 = 4; refdiv = 1; 1207 break; 1208 default: 1209 printf("%s: %u Hz\n", __func__, freq); 1210 return -1; 1211 } 1212 1213 /* Calculate feedback divider. */ 1214 fbdiv = freq * postdiv1 * postdiv2 * refdiv / 24000000; 1215 1216 /* 1217 * Select slow mode to guarantee a stable clock while we're 1218 * adjusting the PLL. 1219 */ 1220 HWRITE4(sc, RK3328_CRU_CRU_MODE, 1221 (RK3328_CRU_CRU_MODE_MASK << 16 | 1222 RK3328_CRU_CRU_MODE_SLOW) << mode_shift); 1223 1224 /* Set PLL rate. */ 1225 HWRITE4(sc, base + 0x0000, 1226 RK3328_CRU_PLL_POSTDIV1_MASK << 16 | 1227 postdiv1 << RK3328_CRU_PLL_POSTDIV1_SHIFT | 1228 RK3328_CRU_PLL_FBDIV_MASK << 16 | 1229 fbdiv << RK3328_CRU_PLL_FBDIV_SHIFT); 1230 HWRITE4(sc, base + 0x0004, 1231 RK3328_CRU_PLL_DSMPD << 16 | RK3328_CRU_PLL_DSMPD | 1232 RK3328_CRU_PLL_POSTDIV2_MASK << 16 | 1233 postdiv2 << RK3328_CRU_PLL_POSTDIV2_SHIFT | 1234 RK3328_CRU_PLL_REFDIV_MASK << 16 | 1235 refdiv << RK3328_CRU_PLL_REFDIV_SHIFT); 1236 1237 /* Wait for PLL to stabilize. */ 1238 while ((HREAD4(sc, base + 0x0004) & RK3328_CRU_PLL_PLL_LOCK) == 0) 1239 delay(10); 1240 1241 /* Switch back to normal mode. */ 1242 HWRITE4(sc, RK3328_CRU_CRU_MODE, 1243 (RK3328_CRU_CRU_MODE_MASK << 16 | 1244 RK3328_CRU_CRU_MODE_NORMAL) << mode_shift); 1245 1246 return 0; 1247 } 1248 1249 int 1250 rk3328_set_frac_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 1251 { 1252 uint32_t fbdiv, postdiv1, postdiv2, refdiv, fracdiv; 1253 int mode_shift = -1; 1254 uint32_t reg; 1255 1256 switch (base) { 1257 case RK3328_CRU_APLL_CON(0): 1258 mode_shift = 0; 1259 break; 1260 case RK3328_CRU_DPLL_CON(0): 1261 mode_shift = 4; 1262 break; 1263 case RK3328_CRU_CPLL_CON(0): 1264 mode_shift = 8; 1265 break; 1266 case RK3328_CRU_GPLL_CON(0): 1267 mode_shift = 12; 1268 break; 1269 case RK3328_CRU_NPLL_CON(0): 1270 mode_shift = 1; 1271 break; 1272 } 1273 KASSERT(mode_shift != -1); 1274 1275 /* 1276 * It is not clear whether all combinations of the clock 1277 * dividers result in a stable clock. Therefore this function 1278 * only supports a limited set of PLL clock rates. This set 1279 * set covers all the fractional PLL frequencies supported by 1280 * the Linux kernel. 1281 */ 1282 switch (freq) { 1283 case 1016064000U: 1284 postdiv1 = postdiv2 = 1; refdiv = 3; fracdiv = 134217; 1285 break; 1286 case 983040000U: 1287 postdiv1 = postdiv2 = 1; refdiv = 24; fracdiv = 671088; 1288 break; 1289 case 491520000U: 1290 postdiv1 = 2; postdiv2 = 1; refdiv = 24; fracdiv = 671088; 1291 break; 1292 case 61440000U: 1293 postdiv1 = 7; postdiv2 = 2; refdiv = 6; fracdiv = 671088; 1294 break; 1295 case 56448000U: 1296 postdiv1 = postdiv2 = 4; refdiv = 12; fracdiv = 9797894; 1297 break; 1298 case 40960000U: 1299 postdiv1 = 4; postdiv2 = 5; refdiv = 12; fracdiv = 10066239; 1300 break; 1301 default: 1302 printf("%s: %u Hz\n", __func__, freq); 1303 return -1; 1304 } 1305 1306 /* Calculate feedback divider. */ 1307 fbdiv = (uint64_t)freq * postdiv1 * postdiv2 * refdiv / 24000000; 1308 1309 /* 1310 * Select slow mode to guarantee a stable clock while we're 1311 * adjusting the PLL. 1312 */ 1313 HWRITE4(sc, RK3328_CRU_CRU_MODE, 1314 (RK3328_CRU_CRU_MODE_MASK << 16 | 1315 RK3328_CRU_CRU_MODE_SLOW) << mode_shift); 1316 1317 /* Set PLL rate. */ 1318 HWRITE4(sc, base + 0x0000, 1319 RK3328_CRU_PLL_POSTDIV1_MASK << 16 | 1320 postdiv1 << RK3328_CRU_PLL_POSTDIV1_SHIFT | 1321 RK3328_CRU_PLL_FBDIV_MASK << 16 | 1322 fbdiv << RK3328_CRU_PLL_FBDIV_SHIFT); 1323 HWRITE4(sc, base + 0x0004, 1324 RK3328_CRU_PLL_DSMPD << 16 | 1325 RK3328_CRU_PLL_POSTDIV2_MASK << 16 | 1326 postdiv2 << RK3328_CRU_PLL_POSTDIV2_SHIFT | 1327 RK3328_CRU_PLL_REFDIV_MASK << 16 | 1328 refdiv << RK3328_CRU_PLL_REFDIV_SHIFT); 1329 reg = HREAD4(sc, base + 0x0008); 1330 reg &= ~RK3328_CRU_PLL_FRACDIV_MASK; 1331 reg |= fracdiv << RK3328_CRU_PLL_FRACDIV_SHIFT; 1332 HWRITE4(sc, base + 0x0008, reg); 1333 1334 /* Wait for PLL to stabilize. */ 1335 while ((HREAD4(sc, base + 0x0004) & RK3328_CRU_PLL_PLL_LOCK) == 0) 1336 delay(10); 1337 1338 /* Switch back to normal mode. */ 1339 HWRITE4(sc, RK3328_CRU_CRU_MODE, 1340 (RK3328_CRU_CRU_MODE_MASK << 16 | 1341 RK3328_CRU_CRU_MODE_NORMAL) << mode_shift); 1342 1343 return 0; 1344 } 1345 1346 uint32_t 1347 rk3328_get_frequency(void *cookie, uint32_t *cells) 1348 { 1349 struct rkclock_softc *sc = cookie; 1350 uint32_t idx = cells[0]; 1351 uint32_t reg; 1352 1353 switch (idx) { 1354 case RK3328_PLL_APLL: 1355 return rk3328_get_pll(sc, RK3328_CRU_APLL_CON(0)); 1356 break; 1357 case RK3328_PLL_DPLL: 1358 return rk3328_get_pll(sc, RK3328_CRU_DPLL_CON(0)); 1359 break; 1360 case RK3328_PLL_CPLL: 1361 return rk3328_get_pll(sc, RK3328_CRU_CPLL_CON(0)); 1362 break; 1363 case RK3328_PLL_GPLL: 1364 return rk3328_get_pll(sc, RK3328_CRU_GPLL_CON(0)); 1365 break; 1366 case RK3328_PLL_NPLL: 1367 return rk3328_get_pll(sc, RK3328_CRU_NPLL_CON(0)); 1368 break; 1369 case RK3328_ARMCLK: 1370 return rk3328_get_armclk(sc); 1371 case RK3328_XIN24M: 1372 return 24000000; 1373 case RK3328_GMAC_CLKIN: 1374 return 125000000; 1375 /* 1376 * XXX The HDMIPHY and USB480M clocks are external. Returning 1377 * zero here will cause them to be ignored for reparenting 1378 * purposes. 1379 */ 1380 case RK3328_HDMIPHY: 1381 return 0; 1382 case RK3328_USB480M: 1383 return 0; 1384 case RK3328_CLK_MAC2IO: 1385 reg = regmap_read_4(sc->sc_grf, RK3328_GRF_MAC_CON1); 1386 if (reg & RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL) 1387 idx = RK3328_GMAC_CLKIN; 1388 else 1389 idx = RK3328_CLK_MAC2IO_SRC; 1390 return rk3328_get_frequency(sc, &idx); 1391 default: 1392 break; 1393 } 1394 1395 return rkclock_get_frequency(sc, idx); 1396 } 1397 1398 int 1399 rk3328_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 1400 { 1401 struct rkclock_softc *sc = cookie; 1402 uint32_t idx = cells[0]; 1403 uint32_t reg, mux; 1404 1405 switch (idx) { 1406 case RK3328_PLL_APLL: 1407 return rk3328_set_frac_pll(sc, RK3328_CRU_APLL_CON(0), freq); 1408 case RK3328_PLL_DPLL: 1409 return rk3328_set_pll(sc, RK3328_CRU_DPLL_CON(0), freq); 1410 case RK3328_PLL_CPLL: 1411 return rk3328_set_pll(sc, RK3328_CRU_CPLL_CON(0), freq); 1412 case RK3328_PLL_GPLL: 1413 return rk3328_set_frac_pll(sc, RK3328_CRU_GPLL_CON(0), freq); 1414 case RK3328_PLL_NPLL: 1415 return rk3328_set_pll(sc, RK3328_CRU_NPLL_CON(0), freq); 1416 case RK3328_ARMCLK: 1417 return rk3328_set_armclk(sc, freq); 1418 case RK3328_CLK_UART0: 1419 case RK3328_CLK_UART1: 1420 case RK3328_CLK_UART2: 1421 if (freq == rk3328_get_frequency(sc, &idx)) 1422 return 0; 1423 break; 1424 case RK3328_DCLK_LCDC: 1425 reg = HREAD4(sc, RK3328_CRU_CLKSEL_CON(40)); 1426 mux = (reg & RK3328_CRU_VOP_DCLK_SRC_SEL_MASK) >> 1427 RK3328_CRU_VOP_DCLK_SRC_SEL_SHIFT; 1428 idx = (mux == 0) ? RK3328_HDMIPHY : RK3328_DCLK_LCDC_SRC; 1429 return rk3328_set_frequency(sc, &idx, freq); 1430 case RK3328_HCLK_CRYPTO_SLV: 1431 idx = RK3328_HCLK_BUS_PRE; 1432 return rk3328_set_frequency(sc, &idx, freq); 1433 default: 1434 break; 1435 } 1436 1437 return rkclock_set_frequency(sc, idx, freq); 1438 } 1439 1440 int 1441 rk3328_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells) 1442 { 1443 struct rkclock_softc *sc = cookie; 1444 uint32_t idx = cells[0]; 1445 uint32_t parent; 1446 1447 if (pcells[0] == sc->sc_phandle) 1448 parent = pcells[1]; 1449 else { 1450 char name[32]; 1451 int node; 1452 1453 node = OF_getnodebyphandle(pcells[0]); 1454 if (node == 0) 1455 return -1; 1456 name[0] = 0; 1457 OF_getprop(node, "clock-output-names", name, sizeof(name)); 1458 name[sizeof(name) - 1] = 0; 1459 if (strcmp(name, "xin24m") == 0) 1460 parent = RK3328_XIN24M; 1461 else if (strcmp(name, "gmac_clkin") == 0) 1462 parent = RK3328_GMAC_CLKIN; 1463 else 1464 return -1; 1465 } 1466 1467 switch (idx) { 1468 case RK3328_CLK_MAC2IO: 1469 if (parent == RK3328_GMAC_CLKIN) { 1470 regmap_write_4(sc->sc_grf, RK3328_GRF_MAC_CON1, 1471 RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL << 16 | 1472 RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL); 1473 } else { 1474 regmap_write_4(sc->sc_grf, RK3328_GRF_MAC_CON1, 1475 RK3328_GRF_GMAC2IO_RMII_EXTCLK_SEL << 16); 1476 } 1477 return 0; 1478 case RK3328_CLK_MAC2IO_EXT: 1479 if (parent == RK3328_GMAC_CLKIN) { 1480 regmap_write_4(sc->sc_grf, RK3328_GRF_SOC_CON4, 1481 RK3328_GRF_GMAC2IO_MAC_CLK_OUTPUT_EN << 16 | 1482 RK3328_GRF_GMAC2IO_MAC_CLK_OUTPUT_EN); 1483 } else { 1484 regmap_write_4(sc->sc_grf, RK3328_GRF_SOC_CON4, 1485 RK3328_GRF_GMAC2IO_MAC_CLK_OUTPUT_EN << 16); 1486 } 1487 return 0; 1488 } 1489 1490 return rkclock_set_parent(sc, idx, parent); 1491 } 1492 1493 void 1494 rk3328_enable(void *cookie, uint32_t *cells, int on) 1495 { 1496 uint32_t idx = cells[0]; 1497 1498 /* 1499 * All clocks are enabled by default, so there is nothing for 1500 * us to do until we start disabling clocks. 1501 */ 1502 if (!on) 1503 printf("%s: 0x%08x\n", __func__, idx); 1504 } 1505 1506 void 1507 rk3328_reset(void *cookie, uint32_t *cells, int on) 1508 { 1509 struct rkclock_softc *sc = cookie; 1510 uint32_t idx = cells[0]; 1511 uint32_t mask = (1 << (idx % 16)); 1512 1513 HWRITE4(sc, RK3328_CRU_SOFTRST_CON(idx / 16), 1514 mask << 16 | (on ? mask : 0)); 1515 } 1516 1517 /* 1518 * Rockchip RK3399 1519 */ 1520 1521 struct rkclock rk3399_clocks[] = { 1522 { 1523 RK3399_CLK_I2C1, RK3399_CRU_CLKSEL_CON(61), 1524 SEL(7, 7), DIV(6, 0), 1525 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1526 }, 1527 { 1528 RK3399_CLK_I2C2, RK3399_CRU_CLKSEL_CON(62), 1529 SEL(7, 7), DIV(6, 0), 1530 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1531 }, 1532 { 1533 RK3399_CLK_I2C3, RK3399_CRU_CLKSEL_CON(63), 1534 SEL(7, 7), DIV(6, 0), 1535 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1536 }, 1537 { 1538 RK3399_CLK_I2C5, RK3399_CRU_CLKSEL_CON(61), 1539 SEL(15, 15), DIV(14, 8), 1540 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1541 }, 1542 { 1543 RK3399_CLK_I2C6, RK3399_CRU_CLKSEL_CON(62), 1544 SEL(15, 15), DIV(14, 8), 1545 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1546 }, 1547 { 1548 RK3399_CLK_I2C7, RK3399_CRU_CLKSEL_CON(63), 1549 SEL(15, 15), DIV(14, 8), 1550 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1551 }, 1552 { 1553 RK3399_CLK_SDMMC, RK3399_CRU_CLKSEL_CON(16), 1554 SEL(10, 8), DIV(6, 0), 1555 { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL, 1556 /* RK3399_PLL_PPLL */ 0, /* RK3399_USB_480M */ 0, 1557 RK3399_XIN24M } 1558 }, 1559 { 1560 RK3399_CLK_SDIO, RK3399_CRU_CLKSEL_CON(15), 1561 SEL(10, 8), DIV(6, 0), 1562 { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL, 1563 /* RK3399_PLL_PPLL */ 0, /* RK3399_USB_480M */ 0, 1564 RK3399_XIN24M } 1565 }, 1566 { 1567 RK3399_CLK_EMMC, RK3399_CRU_CLKSEL_CON(22), 1568 SEL(10, 8), DIV(6, 0), 1569 { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL, 1570 /* RK3399_USB_480M */ 0, RK3399_XIN24M } 1571 }, 1572 { 1573 RK3399_CLK_TSADC, RK3399_CRU_CLKSEL_CON(27), 1574 SEL(15, 15), DIV(9, 0), 1575 { RK3399_XIN24M, RK3399_CLK_32K } 1576 }, 1577 { 1578 RK3399_CLK_UART0, RK3399_CRU_CLKSEL_CON(33), 1579 SEL(9, 8), 0, 1580 { 0, 0, RK3399_XIN24M } 1581 }, 1582 { 1583 RK3399_CLK_UART1, RK3399_CRU_CLKSEL_CON(34), 1584 SEL(9, 8), 0, 1585 { 0, 0, RK3399_XIN24M } 1586 }, 1587 { 1588 RK3399_CLK_UART2, RK3399_CRU_CLKSEL_CON(35), 1589 SEL(9, 8), 0, 1590 { 0, 0, RK3399_XIN24M } 1591 }, 1592 { 1593 RK3399_CLK_UART3, RK3399_CRU_CLKSEL_CON(36), 1594 SEL(9, 8), 0, 1595 { 0, 0, RK3399_XIN24M } 1596 }, 1597 { 1598 RK3399_CLK_I2S0_8CH, RK3399_CRU_CLKSEL_CON(28), 1599 SEL(9, 8), 0, 1600 { RK3399_CLK_I2S0_DIV, 0, 0, RK3399_XIN12M }, 1601 SET_PARENT 1602 }, 1603 { 1604 RK3399_CLK_I2S1_8CH, RK3399_CRU_CLKSEL_CON(29), 1605 SEL(9, 8), 0, 1606 { RK3399_CLK_I2S1_DIV, 0, 0, RK3399_XIN12M }, 1607 SET_PARENT 1608 }, 1609 { 1610 RK3399_CLK_I2S2_8CH, RK3399_CRU_CLKSEL_CON(30), 1611 SEL(9, 8), 0, 1612 { RK3399_CLK_I2S2_DIV, 0, 0, RK3399_XIN12M }, 1613 SET_PARENT 1614 }, 1615 { 1616 RK3399_CLK_I2S_8CH_OUT, RK3399_CRU_CLKSEL_CON(31), 1617 SEL(2, 2), 0, 1618 { RK3399_CLK_I2SOUT_SRC, RK3399_XIN12M }, 1619 SET_PARENT 1620 }, 1621 { 1622 RK3399_CLK_MAC, RK3399_CRU_CLKSEL_CON(20), 1623 SEL(15, 14), DIV(12, 8), 1624 { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL } 1625 }, 1626 { 1627 RK3399_DCLK_VOP0, RK3399_CRU_CLKSEL_CON(49), 1628 SEL(11, 11), 0, 1629 { RK3399_DCLK_VOP0_DIV, RK3399_DCLK_VOP0_FRAC }, 1630 SET_PARENT 1631 }, 1632 { 1633 RK3399_DCLK_VOP1, RK3399_CRU_CLKSEL_CON(50), 1634 SEL(11, 11), 0, 1635 { RK3399_DCLK_VOP1_DIV, RK3399_DCLK_VOP1_FRAC }, 1636 SET_PARENT 1637 }, 1638 { 1639 RK3399_DCLK_VOP0_DIV, RK3399_CRU_CLKSEL_CON(49), 1640 SEL(9, 8), DIV(7, 0), 1641 { RK3399_PLL_VPLL, RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1642 }, 1643 { 1644 RK3399_DCLK_VOP1_DIV, RK3399_CRU_CLKSEL_CON(50), 1645 SEL(9, 8), DIV(7, 0), 1646 { RK3399_PLL_VPLL, RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1647 }, 1648 { 1649 RK3399_ACLK_PERIPH, RK3399_CRU_CLKSEL_CON(14), 1650 SEL(7, 7), DIV(4, 0), 1651 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1652 }, 1653 { 1654 RK3399_ACLK_PERILP0, RK3399_CRU_CLKSEL_CON(23), 1655 SEL(7, 7), DIV(4, 0), 1656 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1657 }, 1658 { 1659 RK3399_ACLK_VIO, RK3399_CRU_CLKSEL_CON(42), 1660 SEL(7, 6), DIV(4, 0), 1661 { RK3399_PLL_CPLL, RK3399_PLL_GPLL, /* RK3399_PLL_PPLL */ } 1662 }, 1663 { 1664 RK3399_ACLK_CCI, RK3399_CRU_CLKSEL_CON(5), 1665 SEL(7, 6), DIV(4, 0), 1666 { RK3399_PLL_CPLL, RK3399_PLL_GPLL, RK3399_PLL_NPLL, 1667 RK3399_PLL_VPLL } 1668 }, 1669 { 1670 RK3399_ACLK_VOP0, RK3399_CRU_CLKSEL_CON(47), 1671 SEL(7, 6), DIV(4, 0), 1672 { RK3399_PLL_VPLL, RK3399_PLL_CPLL, RK3399_PLL_GPLL, 1673 RK3399_PLL_NPLL } 1674 }, 1675 { 1676 RK3399_ACLK_VOP1, RK3399_CRU_CLKSEL_CON(48), 1677 SEL(7, 6), DIV(4, 0), 1678 { RK3399_PLL_VPLL, RK3399_PLL_CPLL, RK3399_PLL_GPLL, 1679 RK3399_PLL_NPLL } 1680 }, 1681 { 1682 RK3399_ACLK_HDCP, RK3399_CRU_CLKSEL_CON(42), 1683 SEL(15, 14), DIV(12, 8), 1684 { RK3399_PLL_CPLL, RK3399_PLL_GPLL, /* RK3399_PLL_PPLL */ } 1685 }, 1686 { 1687 RK3399_ACLK_GIC_PRE, RK3399_CRU_CLKSEL_CON(56), 1688 SEL(15, 15), DIV(12, 8), 1689 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1690 }, 1691 { 1692 RK3399_PCLK_PERIPH, RK3399_CRU_CLKSEL_CON(14), 1693 0, DIV(14, 12), 1694 { RK3399_ACLK_PERIPH } 1695 }, 1696 { 1697 RK3399_PCLK_PERILP0, RK3399_CRU_CLKSEL_CON(23), 1698 0, DIV(14, 12), 1699 { RK3399_ACLK_PERILP0 } 1700 }, 1701 { 1702 RK3399_PCLK_PERILP1, RK3399_CRU_CLKSEL_CON(25), 1703 0, DIV(10, 8), 1704 { RK3399_HCLK_PERILP1 } 1705 }, 1706 { 1707 RK3399_PCLK_DDR, RK3399_CRU_CLKSEL_CON(6), 1708 SEL(15, 15), DIV(12, 8), 1709 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1710 }, 1711 { 1712 RK3399_HCLK_PERIPH, RK3399_CRU_CLKSEL_CON(14), 1713 0, DIV(9, 8), 1714 { RK3399_ACLK_PERIPH } 1715 }, 1716 { 1717 RK3399_HCLK_PERILP0, RK3399_CRU_CLKSEL_CON(23), 1718 0, DIV(9, 8), 1719 { RK3399_ACLK_PERILP0 } 1720 }, 1721 { 1722 RK3399_HCLK_PERILP1, RK3399_CRU_CLKSEL_CON(25), 1723 SEL(7, 7), DIV(4, 0), 1724 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1725 }, 1726 { 1727 RK3399_HCLK_SDMMC, RK3399_CRU_CLKSEL_CON(13), 1728 SEL(15, 15), DIV(12, 8), 1729 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1730 }, 1731 { 1732 RK3399_HCLK_VOP0, RK3399_CRU_CLKSEL_CON(47), 1733 0, DIV(12, 8), 1734 { RK3399_ACLK_VOP0 } 1735 }, 1736 { 1737 RK3399_HCLK_VOP1, RK3399_CRU_CLKSEL_CON(48), 1738 0, DIV(12, 8), 1739 { RK3399_ACLK_VOP1 } 1740 }, 1741 { 1742 RK3399_CLK_I2S0_DIV, RK3399_CRU_CLKSEL_CON(28), 1743 SEL(7, 7), DIV(6, 0), 1744 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1745 }, 1746 { 1747 RK3399_CLK_I2S1_DIV, RK3399_CRU_CLKSEL_CON(29), 1748 SEL(7, 7), DIV(6, 0), 1749 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1750 }, 1751 { 1752 RK3399_CLK_I2S2_DIV, RK3399_CRU_CLKSEL_CON(30), 1753 SEL(7, 7), DIV(6, 0), 1754 { RK3399_PLL_CPLL, RK3399_PLL_GPLL } 1755 }, 1756 { 1757 RK3399_CLK_I2SOUT_SRC, RK3399_CRU_CLKSEL_CON(31), 1758 SEL(1, 0), 0, 1759 { RK3399_CLK_I2S0_8CH, RK3399_CLK_I2S1_8CH, 1760 RK3399_CLK_I2S2_8CH }, 1761 SET_PARENT 1762 }, 1763 { 1764 /* Sentinel */ 1765 } 1766 }; 1767 1768 /* Some of our parent clocks live in the PMUCRU. */ 1769 struct rkclock_softc *rk3399_pmucru_sc; 1770 1771 void 1772 rk3399_init(struct rkclock_softc *sc) 1773 { 1774 int i; 1775 1776 /* PMUCRU instance should attach before us. */ 1777 KASSERT(rk3399_pmucru_sc != NULL); 1778 1779 /* 1780 * The U-Boot shipped on the Theobroma Systems RK3399-Q7 1781 * module is buggy and sets the parent of the clock for the 1782 * "big" cluster to LPLL. Undo that mistake here such that 1783 * the clocks of both clusters are independent. 1784 */ 1785 HWRITE4(sc, RK3399_CRU_CLKSEL_CON(2), 1786 RK3399_CRU_CORE_PLL_SEL_MASK << 16 | 1787 RK3399_CRU_CORE_PLL_SEL_BPLL); 1788 1789 /* The code below assumes all clocks are enabled. Check this!. */ 1790 for (i = 0; i <= 34; i++) { 1791 if (HREAD4(sc, RK3399_CRU_CLKGATE_CON(i)) != 0x00000000) { 1792 printf("CRU_CLKGATE_CON%d: 0x%08x\n", i, 1793 HREAD4(sc, RK3399_CRU_CLKGATE_CON(i))); 1794 } 1795 } 1796 1797 sc->sc_clocks = rk3399_clocks; 1798 } 1799 1800 uint32_t 1801 rk3399_get_pll(struct rkclock_softc *sc, bus_size_t base) 1802 { 1803 uint32_t fbdiv, postdiv1, postdiv2, refdiv; 1804 uint32_t pll_work_mode; 1805 uint32_t reg; 1806 1807 reg = HREAD4(sc, base + 0x000c); 1808 pll_work_mode = reg & RK3399_CRU_PLL_PLL_WORK_MODE_MASK; 1809 if (pll_work_mode == RK3399_CRU_PLL_PLL_WORK_MODE_SLOW) 1810 return 24000000; 1811 if (pll_work_mode == RK3399_CRU_PLL_PLL_WORK_MODE_DEEP_SLOW) 1812 return 32768; 1813 1814 reg = HREAD4(sc, base + 0x0000); 1815 fbdiv = (reg & RK3399_CRU_PLL_FBDIV_MASK) >> 1816 RK3399_CRU_PLL_FBDIV_SHIFT; 1817 reg = HREAD4(sc, base + 0x0004); 1818 postdiv2 = (reg & RK3399_CRU_PLL_POSTDIV2_MASK) >> 1819 RK3399_CRU_PLL_POSTDIV2_SHIFT; 1820 postdiv1 = (reg & RK3399_CRU_PLL_POSTDIV1_MASK) >> 1821 RK3399_CRU_PLL_POSTDIV1_SHIFT; 1822 refdiv = (reg & RK3399_CRU_PLL_REFDIV_MASK) >> 1823 RK3399_CRU_PLL_REFDIV_SHIFT; 1824 return 24000000ULL * fbdiv / refdiv / postdiv1 / postdiv2; 1825 } 1826 1827 int 1828 rk3399_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq) 1829 { 1830 uint32_t fbdiv, postdiv1, postdiv2, refdiv; 1831 1832 /* 1833 * It is not clear whether all combinations of the clock 1834 * dividers result in a stable clock. Therefore this function 1835 * only supports a limited set of PLL clock rates. For now 1836 * this set covers all the CPU frequencies supported by the 1837 * Linux kernel. 1838 */ 1839 switch (freq) { 1840 case 2208000000U: 1841 case 2184000000U: 1842 case 2088000000U: 1843 case 2040000000U: 1844 case 2016000000U: 1845 case 1992000000U: 1846 case 1896000000U: 1847 case 1800000000U: 1848 case 1704000000U: 1849 case 1608000000U: 1850 case 1512000000U: 1851 case 1488000000U: 1852 case 1416000000U: 1853 case 1200000000U: 1854 postdiv1 = postdiv2 = refdiv = 1; 1855 break; 1856 case 1008000000U: 1857 case 816000000U: 1858 case 696000000U: 1859 postdiv1 = 2; postdiv2 = refdiv = 1; 1860 break; 1861 case 676000000U: 1862 postdiv1 = 2; postdiv2 = 1; refdiv = 3; 1863 break; 1864 case 1000000000U: 1865 case 800000000U: 1866 case 600000000U: 1867 postdiv1 = 3; postdiv2 = refdiv = 1; 1868 break; 1869 case 594000000U: 1870 postdiv1 = 4; postdiv2 = refdiv = 1; 1871 break; 1872 case 408000000U: 1873 postdiv1 = postdiv2 = 2; refdiv = 1; 1874 break; 1875 case 297000000U: 1876 case 216000000U: 1877 postdiv1 = 4; postdiv2 = 2; refdiv = 1; 1878 break; 1879 case 148500000U: 1880 case 96000000U: 1881 postdiv1 = postdiv2 = 4; refdiv = 1; 1882 break; 1883 case 74250000U: 1884 postdiv1 = postdiv2 = 4; refdiv = 2; 1885 break; 1886 case 65000000U: 1887 case 54000000U: 1888 case 27000000U: 1889 postdiv1 = 6; postdiv2 = 4; refdiv = 1; 1890 break; 1891 default: 1892 printf("%s: %d Hz\n", __func__, freq); 1893 return -1; 1894 } 1895 1896 /* Calculate feedback divider. */ 1897 fbdiv = freq * postdiv1 * postdiv2 * refdiv / 24000000; 1898 1899 /* 1900 * Select slow mode to guarantee a stable clock while we're 1901 * adjusting the PLL. 1902 */ 1903 HWRITE4(sc, base + 0x000c, 1904 RK3399_CRU_PLL_PLL_WORK_MODE_MASK << 16 | 1905 RK3399_CRU_PLL_PLL_WORK_MODE_SLOW); 1906 1907 /* Set PLL rate. */ 1908 HWRITE4(sc, base + 0x0000, 1909 RK3399_CRU_PLL_FBDIV_MASK << 16 | 1910 fbdiv << RK3399_CRU_PLL_FBDIV_SHIFT); 1911 HWRITE4(sc, base + 0x0004, 1912 RK3399_CRU_PLL_POSTDIV2_MASK << 16 | 1913 postdiv2 << RK3399_CRU_PLL_POSTDIV2_SHIFT | 1914 RK3399_CRU_PLL_POSTDIV1_MASK << 16 | 1915 postdiv1 << RK3399_CRU_PLL_POSTDIV1_SHIFT | 1916 RK3399_CRU_PLL_REFDIV_MASK << 16 | 1917 refdiv << RK3399_CRU_PLL_REFDIV_SHIFT); 1918 1919 /* Wait for PLL to stabilize. */ 1920 while ((HREAD4(sc, base + 0x0008) & RK3399_CRU_PLL_PLL_LOCK) == 0) 1921 delay(10); 1922 1923 /* Switch back to normal mode. */ 1924 HWRITE4(sc, base + 0x000c, 1925 RK3399_CRU_PLL_PLL_WORK_MODE_MASK << 16 | 1926 RK3399_CRU_PLL_PLL_WORK_MODE_NORMAL); 1927 1928 return 0; 1929 } 1930 1931 uint32_t 1932 rk3399_armclk_parent(uint32_t mux) 1933 { 1934 switch (mux) { 1935 case 0: 1936 return RK3399_PLL_ALPLL; 1937 case 1: 1938 return RK3399_PLL_ABPLL; 1939 case 2: 1940 return RK3399_PLL_DPLL; 1941 case 3: 1942 return RK3399_PLL_GPLL; 1943 } 1944 1945 return 0; 1946 } 1947 1948 uint32_t 1949 rk3399_get_armclk(struct rkclock_softc *sc, bus_size_t clksel) 1950 { 1951 uint32_t reg, mux, div_con; 1952 uint32_t idx; 1953 1954 reg = HREAD4(sc, clksel); 1955 mux = (reg & RK3399_CRU_CORE_PLL_SEL_MASK) >> 1956 RK3399_CRU_CORE_PLL_SEL_SHIFT; 1957 div_con = (reg & RK3399_CRU_CLK_CORE_DIV_CON_MASK) >> 1958 RK3399_CRU_CLK_CORE_DIV_CON_SHIFT; 1959 idx = rk3399_armclk_parent(mux); 1960 1961 return rk3399_get_frequency(sc, &idx) / (div_con + 1); 1962 } 1963 1964 int 1965 rk3399_set_armclk(struct rkclock_softc *sc, bus_size_t clksel, uint32_t freq) 1966 { 1967 uint32_t reg, mux; 1968 uint32_t old_freq, div; 1969 uint32_t idx; 1970 1971 old_freq = rk3399_get_armclk(sc, clksel); 1972 if (freq == old_freq) 1973 return 0; 1974 1975 reg = HREAD4(sc, clksel); 1976 mux = (reg & RK3399_CRU_CORE_PLL_SEL_MASK) >> 1977 RK3399_CRU_CORE_PLL_SEL_SHIFT; 1978 idx = rk3399_armclk_parent(mux); 1979 1980 /* Keep the atclk_core and pclk_dbg clocks at or below 200 MHz. */ 1981 div = 1; 1982 while (freq / (div + 1) > 200000000) 1983 div++; 1984 1985 /* When ramping up, set clock dividers first. */ 1986 if (freq > old_freq) { 1987 HWRITE4(sc, clksel, 1988 RK3399_CRU_CLK_CORE_DIV_CON_MASK << 16 | 1989 0 << RK3399_CRU_CLK_CORE_DIV_CON_SHIFT | 1990 RK3399_CRU_ACLKM_CORE_DIV_CON_MASK << 16 | 1991 1 << RK3399_CRU_ACLKM_CORE_DIV_CON_SHIFT); 1992 HWRITE4(sc, clksel + 0x0004, 1993 RK3399_CRU_PCLK_DBG_DIV_CON_MASK << 16 | 1994 div << RK3399_CRU_PCLK_DBG_DIV_CON_SHIFT | 1995 RK3399_CRU_ATCLK_CORE_DIV_CON_MASK << 16 | 1996 div << RK3399_CRU_ATCLK_CORE_DIV_CON_SHIFT); 1997 } 1998 1999 rk3399_set_frequency(sc, &idx, freq); 2000 2001 /* When ramping down, set clock dividers last. */ 2002 if (freq < old_freq) { 2003 HWRITE4(sc, clksel, 2004 RK3399_CRU_CLK_CORE_DIV_CON_MASK << 16 | 2005 0 << RK3399_CRU_CLK_CORE_DIV_CON_SHIFT | 2006 RK3399_CRU_ACLKM_CORE_DIV_CON_MASK << 16 | 2007 1 << RK3399_CRU_ACLKM_CORE_DIV_CON_SHIFT); 2008 HWRITE4(sc, clksel + 0x0004, 2009 RK3399_CRU_PCLK_DBG_DIV_CON_MASK << 16 | 2010 div << RK3399_CRU_PCLK_DBG_DIV_CON_SHIFT | 2011 RK3399_CRU_ATCLK_CORE_DIV_CON_MASK << 16 | 2012 div << RK3399_CRU_ATCLK_CORE_DIV_CON_SHIFT); 2013 } 2014 2015 return 0; 2016 } 2017 2018 uint32_t 2019 rk3399_get_frequency(void *cookie, uint32_t *cells) 2020 { 2021 struct rkclock_softc *sc = cookie; 2022 uint32_t idx = cells[0]; 2023 2024 switch (idx) { 2025 case RK3399_PLL_ALPLL: 2026 return rk3399_get_pll(sc, RK3399_CRU_LPLL_CON(0)); 2027 case RK3399_PLL_ABPLL: 2028 return rk3399_get_pll(sc, RK3399_CRU_BPLL_CON(0)); 2029 case RK3399_PLL_DPLL: 2030 return rk3399_get_pll(sc, RK3399_CRU_DPLL_CON(0)); 2031 case RK3399_PLL_CPLL: 2032 return rk3399_get_pll(sc, RK3399_CRU_CPLL_CON(0)); 2033 case RK3399_PLL_GPLL: 2034 return rk3399_get_pll(sc, RK3399_CRU_GPLL_CON(0)); 2035 case RK3399_PLL_NPLL: 2036 return rk3399_get_pll(sc, RK3399_CRU_NPLL_CON(0)); 2037 case RK3399_PLL_VPLL: 2038 return rk3399_get_pll(sc, RK3399_CRU_VPLL_CON(0)); 2039 case RK3399_ARMCLKL: 2040 return rk3399_get_armclk(sc, RK3399_CRU_CLKSEL_CON(0)); 2041 case RK3399_ARMCLKB: 2042 return rk3399_get_armclk(sc, RK3399_CRU_CLKSEL_CON(2)); 2043 case RK3399_XIN24M: 2044 return 24000000; 2045 case RK3399_CLK_32K: 2046 return 32768; 2047 case RK3399_XIN12M: 2048 return 12000000; 2049 default: 2050 break; 2051 } 2052 2053 return rkclock_get_frequency(sc, idx); 2054 } 2055 2056 int 2057 rk3399_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 2058 { 2059 struct rkclock_softc *sc = cookie; 2060 uint32_t idx = cells[0]; 2061 2062 switch (idx) { 2063 case RK3399_PLL_ALPLL: 2064 return rk3399_set_pll(sc, RK3399_CRU_LPLL_CON(0), freq); 2065 case RK3399_PLL_ABPLL: 2066 return rk3399_set_pll(sc, RK3399_CRU_BPLL_CON(0), freq); 2067 case RK3399_PLL_CPLL: 2068 return rk3399_set_pll(sc, RK3399_CRU_CPLL_CON(0), freq); 2069 case RK3399_PLL_GPLL: 2070 return rk3399_set_pll(sc, RK3399_CRU_GPLL_CON(0), freq); 2071 case RK3399_PLL_NPLL: 2072 return rk3399_set_pll(sc, RK3399_CRU_NPLL_CON(0), freq); 2073 case RK3399_PLL_VPLL: 2074 return rk3399_set_pll(sc, RK3399_CRU_VPLL_CON(0), freq); 2075 case RK3399_ARMCLKL: 2076 return rk3399_set_armclk(sc, RK3399_CRU_CLKSEL_CON(0), freq); 2077 case RK3399_ARMCLKB: 2078 return rk3399_set_armclk(sc, RK3399_CRU_CLKSEL_CON(2), freq); 2079 case RK3399_XIN12M: 2080 if (freq / (1000 * 1000) != 12) 2081 return -1; 2082 return 0; 2083 default: 2084 break; 2085 } 2086 2087 return rkclock_set_frequency(sc, idx, freq); 2088 } 2089 2090 void 2091 rk3399_enable(void *cookie, uint32_t *cells, int on) 2092 { 2093 uint32_t idx = cells[0]; 2094 2095 /* 2096 * All clocks are enabled by default, so there is nothing for 2097 * us to do until we start disabling clocks. 2098 */ 2099 if (!on) 2100 printf("%s: 0x%08x\n", __func__, idx); 2101 } 2102 2103 void 2104 rk3399_reset(void *cookie, uint32_t *cells, int on) 2105 { 2106 struct rkclock_softc *sc = cookie; 2107 uint32_t idx = cells[0]; 2108 uint32_t mask = (1 << (idx % 16)); 2109 2110 HWRITE4(sc, RK3399_CRU_SOFTRST_CON(idx / 16), 2111 mask << 16 | (on ? mask : 0)); 2112 } 2113 2114 /* PMUCRU */ 2115 2116 struct rkclock rk3399_pmu_clocks[] = { 2117 { 2118 RK3399_CLK_I2C0, RK3399_PMUCRU_CLKSEL_CON(2), 2119 0, DIV(6, 0), 2120 { RK3399_PLL_PPLL } 2121 }, 2122 { 2123 RK3399_CLK_I2C4, RK3399_PMUCRU_CLKSEL_CON(3), 2124 0, DIV(6, 0), 2125 { RK3399_PLL_PPLL } 2126 }, 2127 { 2128 RK3399_CLK_I2C8, RK3399_PMUCRU_CLKSEL_CON(2), 2129 0, DIV(14, 8), 2130 { RK3399_PLL_PPLL } 2131 }, 2132 { 2133 RK3399_PCLK_RKPWM, RK3399_PMUCRU_CLKSEL_CON(0), 2134 0, DIV(6, 0), 2135 { RK3399_PLL_PPLL } 2136 }, 2137 { 2138 /* Sentinel */ 2139 } 2140 }; 2141 2142 void 2143 rk3399_pmu_init(struct rkclock_softc *sc) 2144 { 2145 sc->sc_clocks = rk3399_pmu_clocks; 2146 rk3399_pmucru_sc = sc; 2147 } 2148 2149 uint32_t 2150 rk3399_pmu_get_frequency(void *cookie, uint32_t *cells) 2151 { 2152 struct rkclock_softc *sc = cookie; 2153 uint32_t idx = cells[0]; 2154 2155 switch (idx) { 2156 case RK3399_PLL_PPLL: 2157 return rk3399_get_pll(sc, RK3399_PMUCRU_PPLL_CON(0)); 2158 default: 2159 break; 2160 } 2161 2162 return rkclock_get_frequency(sc, idx); 2163 } 2164 2165 int 2166 rk3399_pmu_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 2167 { 2168 struct rkclock_softc *sc = cookie; 2169 uint32_t idx = cells[0]; 2170 2171 switch (idx) { 2172 case RK3399_PLL_PPLL: 2173 return rk3399_set_pll(sc, RK3399_PMUCRU_PPLL_CON(0), freq); 2174 break; 2175 default: 2176 break; 2177 } 2178 2179 return rkclock_set_frequency(sc, idx, freq); 2180 } 2181 2182 void 2183 rk3399_pmu_enable(void *cookie, uint32_t *cells, int on) 2184 { 2185 uint32_t idx = cells[0]; 2186 2187 switch (idx) { 2188 case RK3399_CLK_I2C0: 2189 case RK3399_CLK_I2C4: 2190 case RK3399_CLK_I2C8: 2191 case RK3399_PCLK_I2C0: 2192 case RK3399_PCLK_I2C4: 2193 case RK3399_PCLK_I2C8: 2194 case RK3399_PCLK_RKPWM: 2195 /* Enabled by default. */ 2196 break; 2197 default: 2198 printf("%s: 0x%08x\n", __func__, idx); 2199 break; 2200 } 2201 } 2202 2203 void 2204 rk3399_pmu_reset(void *cookie, uint32_t *cells, int on) 2205 { 2206 uint32_t idx = cells[0]; 2207 2208 printf("%s: 0x%08x\n", __func__, idx); 2209 } 2210