1 /* 2 * (C) Copyright 2015 Google, Inc 3 * (C) Copyright 2016 Heiko Stuebner <heiko@sntech.de> 4 * 5 * SPDX-License-Identifier: GPL-2.0 6 */ 7 8 #include <common.h> 9 #include <clk-uclass.h> 10 #include <dm.h> 11 #include <dt-structs.h> 12 #include <errno.h> 13 #include <mapmem.h> 14 #include <syscon.h> 15 #include <asm/io.h> 16 #include <asm/arch/clock.h> 17 #include <asm/arch/cru_rk3066.h> 18 #include <asm/arch/grf_rk3066.h> 19 #include <asm/arch/hardware.h> 20 #include <dt-bindings/clock/rk3066a-cru.h> 21 #include <dm/device-internal.h> 22 #include <dm/lists.h> 23 #include <dm/uclass-internal.h> 24 #include <linux/log2.h> 25 26 DECLARE_GLOBAL_DATA_PTR; 27 28 enum rk3066_clk_type { 29 RK3066_CRU, 30 RK3066A_CRU, 31 }; 32 33 struct rk3066_clk_plat { 34 #if CONFIG_IS_ENABLED(OF_PLATDATA) 35 struct dtd_rockchip_rk3066a_cru dtd; 36 #endif 37 }; 38 39 #ifndef CONFIG_SPL_BUILD 40 #define RK3066_CLK_DUMP(_id, _name, _iscru) \ 41 { \ 42 .id = _id, \ 43 .name = _name, \ 44 .is_cru = _iscru, \ 45 } 46 47 static const struct rk3066_clk_info clks_dump[] = { 48 RK3066_CLK_DUMP(PLL_APLL, "apll", true), 49 RK3066_CLK_DUMP(PLL_DPLL, "dpll", true), 50 RK3066_CLK_DUMP(PLL_GPLL, "gpll", true), 51 RK3066_CLK_DUMP(PLL_CPLL, "cpll", true), 52 }; 53 #endif 54 55 struct pll_div { 56 u32 nr; 57 u32 nf; 58 u32 no; 59 }; 60 61 enum { 62 VCO_MAX_HZ = 1416U * 1000000, 63 VCO_MIN_HZ = 300 * 1000000, 64 OUTPUT_MAX_HZ = 1416U * 1000000, 65 OUTPUT_MIN_HZ = 30 * 1000000, 66 FREF_MAX_HZ = 1416U * 1000000, 67 FREF_MIN_HZ = 30 * 1000, 68 }; 69 70 enum { 71 /* PLL CON0 */ 72 PLL_OD_MASK = 0x0f, 73 74 /* PLL CON1 */ 75 PLL_NF_MASK = 0x1fff, 76 77 /* PLL CON2 */ 78 PLL_BWADJ_MASK = 0x0fff, 79 80 /* PLL CON3 */ 81 PLL_RESET_SHIFT = 5, 82 83 /* GRF_SOC_STATUS0 */ 84 SOCSTS_DPLL_LOCK = 1 << 4, 85 SOCSTS_APLL_LOCK = 1 << 5, 86 SOCSTS_CPLL_LOCK = 1 << 6, 87 SOCSTS_GPLL_LOCK = 1 << 7, 88 }; 89 90 #define RATE_TO_DIV(input_rate, output_rate) \ 91 ((input_rate) / (output_rate) - 1); 92 93 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 94 95 #define PLL_DIVISORS(hz, _nr, _no) {\ 96 .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\ 97 _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\ 98 (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\ 99 "divisors on line " __stringify(__LINE__)); 100 101 /* Keep divisors as low as possible to reduce jitter and power usage */ 102 #ifdef CONFIG_TPL_BUILD 103 static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2); 104 static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2); 105 #endif 106 107 static int rkclk_set_pll(struct rk3066_cru *cru, enum rk_clk_id clk_id, 108 const struct pll_div *div, bool has_bwadj) 109 { 110 int pll_id = rk_pll_id(clk_id); 111 struct rk3066_pll *pll = &cru->pll[pll_id]; 112 /* All PLLs have same VCO and output frequency range restrictions. */ 113 uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000; 114 uint output_hz = vco_hz / div->no; 115 116 debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n", 117 (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz); 118 assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ && 119 output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ && 120 (div->no == 1 || !(div->no % 2))); 121 122 /* enter reset */ 123 rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT); 124 125 rk_clrsetreg(&pll->con0, 126 CLKR_MASK | PLL_OD_MASK, 127 ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1)); 128 rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1); 129 130 if (has_bwadj) 131 rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1); 132 133 udelay(10); 134 135 /* return from reset */ 136 rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT); 137 138 return 0; 139 } 140 141 static int rkclk_configure_ddr(struct rk3066_cru *cru, struct rk3066_grf *grf, 142 unsigned int hz, bool has_bwadj) 143 { 144 static const struct pll_div dpll_cfg[] = { 145 {.nf = 25, .nr = 2, .no = 1}, 146 {.nf = 400, .nr = 9, .no = 2}, 147 {.nf = 500, .nr = 9, .no = 2}, 148 {.nf = 100, .nr = 3, .no = 1}, 149 }; 150 int cfg; 151 152 switch (hz) { 153 case 300000000: 154 cfg = 0; 155 break; 156 case 533000000: /* actually 533.3P MHz */ 157 cfg = 1; 158 break; 159 case 666000000: /* actually 666.6P MHz */ 160 cfg = 2; 161 break; 162 case 800000000: 163 cfg = 3; 164 break; 165 default: 166 debug("Unsupported SDRAM frequency"); 167 return -EINVAL; 168 } 169 170 /* pll enter slow-mode */ 171 rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, 172 DPLL_MODE_SLOW << DPLL_MODE_SHIFT); 173 174 rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg], has_bwadj); 175 176 /* wait for pll lock */ 177 while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK)) 178 udelay(1); 179 180 /* PLL enter normal-mode */ 181 rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK, 182 DPLL_MODE_NORMAL << DPLL_MODE_SHIFT); 183 184 return 0; 185 } 186 187 static int rkclk_configure_cpu(struct rk3066_cru *cru, struct rk3066_grf *grf, 188 unsigned int hz, bool has_bwadj) 189 { 190 static const struct pll_div apll_cfg[] = { 191 {.nf = 50, .nr = 1, .no = 2}, 192 {.nf = 59, .nr = 1, .no = 1}, 193 }; 194 int div_core_peri, div_aclk_core, cfg; 195 196 /* 197 * We support two possible frequencies, the safe 600MHz 198 * which will work with default pmic settings and will 199 * be set to get away from the 24MHz default and 200 * the maximum of 1.416Ghz, which boards can set if they 201 * were able to get pmic support for it. 202 */ 203 switch (hz) { 204 case APLL_SAFE_HZ: 205 cfg = 0; 206 div_core_peri = 1; 207 div_aclk_core = 3; 208 break; 209 case APLL_HZ: 210 cfg = 1; 211 div_core_peri = 2; 212 div_aclk_core = 3; 213 break; 214 default: 215 debug("Unsupported ARMCLK frequency"); 216 return -EINVAL; 217 } 218 219 /* pll enter slow-mode */ 220 rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK, 221 APLL_MODE_SLOW << APLL_MODE_SHIFT); 222 223 rkclk_set_pll(cru, CLK_ARM, &apll_cfg[cfg], has_bwadj); 224 225 /* waiting for pll lock */ 226 while (!(readl(&grf->soc_status0) & SOCSTS_APLL_LOCK)) 227 udelay(1); 228 229 /* Set divider for peripherals attached to the cpu core. */ 230 rk_clrsetreg(&cru->cru_clksel_con[0], 231 CORE_PERI_DIV_MASK, 232 div_core_peri << CORE_PERI_DIV_SHIFT); 233 234 /* set up dependent divisor for aclk_core */ 235 rk_clrsetreg(&cru->cru_clksel_con[1], 236 CORE_ACLK_DIV_MASK, 237 div_aclk_core << CORE_ACLK_DIV_SHIFT); 238 239 /* PLL enter normal-mode */ 240 rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK, 241 APLL_MODE_NORMAL << APLL_MODE_SHIFT); 242 243 return hz; 244 } 245 246 /* Get pll rate by id */ 247 static uint32_t rkclk_pll_get_rate(struct rk3066_cru *cru, 248 enum rk_clk_id clk_id) 249 { 250 uint32_t nr, no, nf; 251 uint32_t con; 252 int pll_id = rk_pll_id(clk_id); 253 struct rk3066_pll *pll = &cru->pll[pll_id]; 254 static u8 clk_shift[CLK_COUNT] = { 255 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT, 256 GPLL_MODE_SHIFT 257 }; 258 uint shift; 259 260 con = readl(&cru->cru_mode_con); 261 shift = clk_shift[clk_id]; 262 switch ((con >> shift) & APLL_MODE_MASK >> APLL_MODE_SHIFT) { 263 case APLL_MODE_SLOW: 264 return OSC_HZ; 265 case APLL_MODE_NORMAL: 266 /* normal mode */ 267 con = readl(&pll->con0); 268 no = ((con >> CLKOD_SHIFT) & (CLKOD_MASK >> CLKOD_SHIFT)) + 1; 269 nr = ((con >> CLKR_SHIFT) & (CLKR_MASK >> CLKR_SHIFT)) + 1; 270 con = readl(&pll->con1); 271 nf = ((con >> CLKF_SHIFT) & (CLKF_MASK >> CLKF_SHIFT)) + 1; 272 273 return (24 * nf / (nr * no)) * 1000000; 274 case APLL_MODE_DEEP: 275 default: 276 return 32768; 277 } 278 } 279 280 static ulong rockchip_mmc_get_clk(struct rk3066_cru *cru, uint gclk_rate, 281 int periph) 282 { 283 uint div; 284 u32 con; 285 286 switch (periph) { 287 case HCLK_EMMC: 288 con = readl(&cru->cru_clksel_con[12]); 289 div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK >> EMMC_DIV_SHIFT; 290 break; 291 case HCLK_SDMMC: 292 con = readl(&cru->cru_clksel_con[11]); 293 div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK >> MMC0_DIV_SHIFT; 294 break; 295 case HCLK_SDIO: 296 con = readl(&cru->cru_clksel_con[12]); 297 div = (con >> SDIO_DIV_SHIFT) & SDIO_DIV_MASK >> SDIO_DIV_SHIFT; 298 break; 299 default: 300 return -EINVAL; 301 } 302 303 return DIV_TO_RATE(gclk_rate, div); 304 } 305 306 static ulong rockchip_mmc_set_clk(struct rk3066_cru *cru, uint gclk_rate, 307 int periph, uint freq) 308 { 309 int src_clk_div; 310 311 debug("%s: gclk_rate=%u\n", __func__, gclk_rate); 312 src_clk_div = RATE_TO_DIV(gclk_rate, freq); 313 if (src_clk_div > 0x3f) 314 src_clk_div = 0x3f; 315 316 switch (periph) { 317 case HCLK_EMMC: 318 rk_clrsetreg(&cru->cru_clksel_con[12], 319 EMMC_DIV_MASK, 320 src_clk_div << EMMC_DIV_SHIFT); 321 break; 322 case HCLK_SDMMC: 323 rk_clrsetreg(&cru->cru_clksel_con[11], 324 MMC0_DIV_MASK, 325 src_clk_div << MMC0_DIV_SHIFT); 326 break; 327 case HCLK_SDIO: 328 rk_clrsetreg(&cru->cru_clksel_con[12], 329 SDIO_DIV_MASK, 330 src_clk_div << SDIO_DIV_SHIFT); 331 break; 332 default: 333 return -EINVAL; 334 } 335 336 return rockchip_mmc_get_clk(cru, gclk_rate, periph); 337 } 338 339 static ulong rockchip_spi_get_clk(struct rk3066_cru *cru, uint gclk_rate, 340 int periph) 341 { 342 uint div; 343 u32 con; 344 345 switch (periph) { 346 case SCLK_SPI0: 347 con = readl(&cru->cru_clksel_con[25]); 348 div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK >> SPI0_DIV_SHIFT; 349 break; 350 case SCLK_SPI1: 351 con = readl(&cru->cru_clksel_con[25]); 352 div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK >> SPI1_DIV_SHIFT; 353 break; 354 default: 355 return -EINVAL; 356 } 357 358 return DIV_TO_RATE(gclk_rate, div); 359 } 360 361 static ulong rockchip_spi_set_clk(struct rk3066_cru *cru, uint gclk_rate, 362 int periph, uint freq) 363 { 364 int src_clk_div = RATE_TO_DIV(gclk_rate, freq); 365 366 switch (periph) { 367 case SCLK_SPI0: 368 assert(src_clk_div <= SPI0_DIV_MASK >> SPI0_DIV_SHIFT); 369 rk_clrsetreg(&cru->cru_clksel_con[25], 370 SPI0_DIV_MASK, 371 src_clk_div << SPI0_DIV_SHIFT); 372 break; 373 case SCLK_SPI1: 374 assert(src_clk_div <= SPI1_DIV_MASK >> SPI1_DIV_SHIFT); 375 rk_clrsetreg(&cru->cru_clksel_con[25], 376 SPI1_DIV_MASK, 377 src_clk_div << SPI1_DIV_SHIFT); 378 break; 379 default: 380 return -EINVAL; 381 } 382 383 return rockchip_spi_get_clk(cru, gclk_rate, periph); 384 } 385 #ifdef CONFIG_TPL_BUILD 386 static void rkclk_init(struct rk3066_cru *cru, struct rk3066_grf *grf, 387 bool has_bwadj) 388 { 389 u32 aclk_div, hclk_div, pclk_div, h2p_div; 390 391 /* pll enter slow-mode */ 392 rk_clrsetreg(&cru->cru_mode_con, 393 GPLL_MODE_MASK | 394 CPLL_MODE_MASK, 395 GPLL_MODE_SLOW << GPLL_MODE_SHIFT | 396 CPLL_MODE_SLOW << CPLL_MODE_SHIFT); 397 398 /* init pll */ 399 rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg, has_bwadj); 400 rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg, has_bwadj); 401 402 /* waiting for pll lock */ 403 while ((readl(&grf->soc_status0) & 404 (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) != 405 (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) 406 udelay(1); 407 408 /* 409 * cpu clock pll source selection and 410 * reparent aclk_cpu_pre from apll to gpll 411 * set up dependent divisors for PCLK/HCLK and ACLK clocks. 412 */ 413 aclk_div = RATE_TO_DIV(GPLL_HZ, CPU_ACLK_HZ); 414 assert((aclk_div + 1) * CPU_ACLK_HZ <= GPLL_HZ && aclk_div < 0x1f); 415 416 rk_clrsetreg(&cru->cru_clksel_con[0], 417 CPU_ACLK_PLL_MASK | 418 A9_CPU_DIV_MASK, 419 CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT | 420 aclk_div << A9_CPU_DIV_SHIFT); 421 422 hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ); 423 assert((1 << hclk_div) * CPU_HCLK_HZ <= CPU_ACLK_HZ && hclk_div < 0x3); 424 pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ); 425 assert((1 << pclk_div) * CPU_PCLK_HZ <= CPU_ACLK_HZ && pclk_div < 0x4); 426 h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ); 427 assert((1 << h2p_div) * CPU_H2P_HZ <= CPU_HCLK_HZ && pclk_div < 0x3); 428 429 rk_clrsetreg(&cru->cru_clksel_con[1], 430 AHB2APB_DIV_MASK | 431 CPU_PCLK_DIV_MASK | 432 CPU_HCLK_DIV_MASK, 433 h2p_div << AHB2APB_DIV_SHIFT | 434 pclk_div << CPU_PCLK_DIV_SHIFT | 435 hclk_div << CPU_HCLK_DIV_SHIFT); 436 437 /* 438 * peri clock pll source selection and 439 * set up dependent divisors for PCLK/HCLK and ACLK clocks. 440 */ 441 aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1; 442 assert((aclk_div + 1) * PERI_ACLK_HZ <= GPLL_HZ && aclk_div < 0x1f); 443 444 hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ); 445 assert((1 << hclk_div) * PERI_HCLK_HZ <= 446 PERI_ACLK_HZ && (hclk_div < 0x4)); 447 448 pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ); 449 assert((1 << pclk_div) * PERI_PCLK_HZ <= 450 PERI_ACLK_HZ && (pclk_div < 0x4)); 451 452 rk_clrsetreg(&cru->cru_clksel_con[10], 453 PERI_PCLK_DIV_MASK | 454 PERI_HCLK_DIV_MASK | 455 PERI_ACLK_DIV_MASK, 456 PERI_SEL_GPLL << PERI_SEL_PLL_SHIFT | 457 pclk_div << PERI_PCLK_DIV_SHIFT | 458 hclk_div << PERI_HCLK_DIV_SHIFT | 459 aclk_div << PERI_ACLK_DIV_SHIFT); 460 461 /* PLL enter normal-mode */ 462 rk_clrsetreg(&cru->cru_mode_con, 463 GPLL_MODE_MASK | 464 CPLL_MODE_MASK, 465 GPLL_MODE_NORMAL << GPLL_MODE_SHIFT | 466 CPLL_MODE_NORMAL << CPLL_MODE_SHIFT); 467 468 rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000); 469 } 470 #endif 471 472 static ulong rk3066_clk_get_rate(struct clk *clk) 473 { 474 struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); 475 ulong new_rate, gclk_rate; 476 477 gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL); 478 switch (clk->id) { 479 case 1 ... 4: 480 new_rate = rkclk_pll_get_rate(priv->cru, clk->id); 481 break; 482 case HCLK_EMMC: 483 case HCLK_SDMMC: 484 case HCLK_SDIO: 485 new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ, 486 clk->id); 487 break; 488 case SCLK_SPI0: 489 case SCLK_SPI1: 490 new_rate = rockchip_spi_get_clk(priv->cru, PERI_PCLK_HZ, 491 clk->id); 492 break; 493 case PCLK_I2C0: 494 case PCLK_I2C1: 495 case PCLK_I2C2: 496 case PCLK_I2C3: 497 case PCLK_I2C4: 498 return gclk_rate; 499 default: 500 return -ENOENT; 501 } 502 503 return new_rate; 504 } 505 506 static ulong rk3066_clk_set_rate(struct clk *clk, ulong rate) 507 { 508 struct rk3066_clk_priv *priv = dev_get_priv(clk->dev); 509 struct rk3066_cru *cru = priv->cru; 510 ulong new_rate; 511 512 switch (clk->id) { 513 case PLL_APLL: 514 new_rate = rkclk_configure_cpu(priv->cru, priv->grf, rate, 515 priv->has_bwadj); 516 break; 517 case CLK_DDR: 518 new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate, 519 priv->has_bwadj); 520 break; 521 case HCLK_EMMC: 522 case HCLK_SDMMC: 523 case HCLK_SDIO: 524 new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, 525 clk->id, rate); 526 break; 527 case SCLK_SPI0: 528 case SCLK_SPI1: 529 new_rate = rockchip_spi_set_clk(cru, PERI_PCLK_HZ, 530 clk->id, rate); 531 break; 532 default: 533 return -ENOENT; 534 } 535 536 return new_rate; 537 } 538 539 static struct clk_ops rk3066_clk_ops = { 540 .get_rate = rk3066_clk_get_rate, 541 .set_rate = rk3066_clk_set_rate, 542 }; 543 544 static int rk3066_clk_ofdata_to_platdata(struct udevice *dev) 545 { 546 #if !CONFIG_IS_ENABLED(OF_PLATDATA) 547 struct rk3066_clk_priv *priv = dev_get_priv(dev); 548 549 priv->cru = dev_read_addr_ptr(dev); 550 #endif 551 552 return 0; 553 } 554 555 static int rk3066_clk_probe(struct udevice *dev) 556 { 557 struct rk3066_clk_priv *priv = dev_get_priv(dev); 558 559 priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); 560 if (IS_ERR(priv->grf)) 561 return PTR_ERR(priv->grf); 562 563 #ifdef CONFIG_TPL_BUILD 564 #if CONFIG_IS_ENABLED(OF_PLATDATA) 565 struct rk3066_clk_plat *plat = dev_get_platdata(dev); 566 567 priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]); 568 #endif 569 priv->sync_kernel = false; 570 if (!priv->armclk_enter_hz) 571 priv->armclk_enter_hz = rkclk_pll_get_rate(priv->cru, 572 CLK_ARM); 573 rkclk_init(priv->cru, priv->grf, 1); 574 if (!priv->armclk_init_hz) 575 priv->armclk_init_hz = rkclk_pll_get_rate(priv->cru, 576 CLK_ARM); 577 #endif 578 return 0; 579 } 580 581 static int rk3066_clk_bind(struct udevice *dev) 582 { 583 int ret; 584 struct udevice *sys_child, *sf_child; 585 struct sysreset_reg *priv; 586 struct softreset_reg *sf_priv; 587 588 /* The reset driver does not have a device node, so bind it here */ 589 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 590 &sys_child); 591 if (ret) { 592 debug("Warning: No sysreset driver: ret=%d\n", ret); 593 } else { 594 priv = malloc(sizeof(struct sysreset_reg)); 595 priv->glb_srst_fst_value = offsetof(struct rk3066_cru, 596 cru_glb_srst_fst_value); 597 priv->glb_srst_snd_value = offsetof(struct rk3066_cru, 598 cru_glb_srst_snd_value); 599 sys_child->priv = priv; 600 } 601 602 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 603 dev_ofnode(dev), &sf_child); 604 if (ret) { 605 debug("Warning: No rockchip reset driver: ret=%d\n", ret); 606 } else { 607 sf_priv = malloc(sizeof(struct softreset_reg)); 608 sf_priv->sf_reset_offset = offsetof(struct rk3066_cru, 609 cru_softrst_con[0]); 610 sf_priv->sf_reset_num = 9; 611 sf_child->priv = sf_priv; 612 } 613 614 return 0; 615 } 616 617 static const struct udevice_id rk3066_clk_ids[] = { 618 { .compatible = "rockchip,rk3066a-cru" }, 619 { } 620 }; 621 622 U_BOOT_DRIVER(rockchip_rk3066a_cru) = { 623 .name = "rockchip_rk3066a_cru", 624 .id = UCLASS_CLK, 625 .of_match = rk3066_clk_ids, 626 .priv_auto_alloc_size = sizeof(struct rk3066_clk_priv), 627 .platdata_auto_alloc_size = sizeof(struct rk3066_clk_plat), 628 .ops = &rk3066_clk_ops, 629 .bind = rk3066_clk_bind, 630 .ofdata_to_platdata = rk3066_clk_ofdata_to_platdata, 631 .probe = rk3066_clk_probe, 632 }; 633 634 #ifndef CONFIG_SPL_BUILD 635 /** 636 * soc_clk_dump() - Print clock frequencies 637 * Returns zero on success 638 * 639 * Implementation for the clk dump command. 640 */ 641 int soc_clk_dump(void) 642 { 643 struct udevice *cru_dev; 644 struct rk3066_clk_priv *priv; 645 const struct rk3066_clk_info *clk_dump; 646 struct clk clk; 647 unsigned long clk_count = ARRAY_SIZE(clks_dump); 648 unsigned long rate; 649 int i, ret; 650 651 ret = uclass_get_device_by_driver(UCLASS_CLK, 652 DM_GET_DRIVER(rockchip_rk3066a_cru), 653 &cru_dev); 654 if (ret) { 655 printf("%s failed to get cru device\n", __func__); 656 return ret; 657 } 658 659 priv = dev_get_priv(cru_dev); 660 printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n", 661 priv->sync_kernel ? "sync kernel" : "uboot", 662 priv->armclk_enter_hz / 1000, 663 priv->armclk_init_hz / 1000, 664 priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0, 665 priv->set_armclk_rate ? " KHz" : "N/A"); 666 for (i = 0; i < clk_count; i++) { 667 clk_dump = &clks_dump[i]; 668 if (clk_dump->name) { 669 clk.id = clk_dump->id; 670 if (clk_dump->is_cru) 671 ret = clk_request(cru_dev, &clk); 672 if (ret < 0) 673 return ret; 674 675 rate = clk_get_rate(&clk); 676 clk_free(&clk); 677 if (i == 0) { 678 if (rate < 0) 679 printf(" %s %s\n", clk_dump->name, 680 "unknown"); 681 else 682 printf(" %s %lu KHz\n", clk_dump->name, 683 rate / 1000); 684 } else { 685 if (rate < 0) 686 printf(" %s %s\n", clk_dump->name, 687 "unknown"); 688 else 689 printf(" %s %lu KHz\n", clk_dump->name, 690 rate / 1000); 691 } 692 } 693 } 694 695 return 0; 696 } 697 #endif 698 699