1// SPDX-License-Identifier: GPL-2.0 2/* 3 * (C) Copyright 2017-2019 Rockchip Electronics Co., Ltd 4 */ 5#include <common.h> 6#include <bitfield.h> 7#include <clk-uclass.h> 8#include <dm.h> 9#include <div64.h> 10#include <errno.h> 11#include <log.h> 12#include <malloc.h> 13#include <syscon.h> 14#include <asm/global_data.h> 15#include <asm/arch-rockchip/clock.h> 16#include <asm/arch-rockchip/cru_rk3308.h> 17#include <asm/arch-rockchip/hardware.h> 18#include <dm/device-internal.h> 19#include <dm/lists.h> 20#include <dt-bindings/clock/rk3308-cru.h> 21#include <linux/bitops.h> 22 23DECLARE_GLOBAL_DATA_PTR; 24 25enum { 26 VCO_MAX_HZ = 3200U * 1000000, 27 VCO_MIN_HZ = 800 * 1000000, 28 OUTPUT_MAX_HZ = 3200U * 1000000, 29 OUTPUT_MIN_HZ = 24 * 1000000, 30}; 31 32#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 33 34#define RK3308_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \ 35{ \ 36 .rate = _rate##U, \ 37 .aclk_div = _aclk_div, \ 38 .pclk_div = _pclk_div, \ 39} 40 41static struct rockchip_pll_rate_table rk3308_pll_rates[] = { 42 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ 43 RK3036_PLL_RATE(1300000000, 6, 325, 1, 1, 1, 0), 44 RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), 45 RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), 46 RK3036_PLL_RATE(748000000, 2, 187, 3, 1, 1, 0), 47}; 48 49static struct rockchip_cpu_rate_table rk3308_cpu_rates[] = { 50 RK3308_CPUCLK_RATE(1200000000, 1, 5), 51 RK3308_CPUCLK_RATE(1008000000, 1, 5), 52 RK3308_CPUCLK_RATE(816000000, 1, 3), 53 RK3308_CPUCLK_RATE(600000000, 1, 3), 54 RK3308_CPUCLK_RATE(408000000, 1, 1), 55}; 56 57static struct rockchip_pll_clock rk3308_pll_clks[] = { 58 [APLL] = PLL(pll_rk3328, PLL_APLL, RK3308_PLL_CON(0), 59 RK3308_MODE_CON, 0, 10, 0, rk3308_pll_rates), 60 [DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3308_PLL_CON(8), 61 RK3308_MODE_CON, 2, 10, 0, NULL), 62 [VPLL0] = PLL(pll_rk3328, PLL_VPLL0, RK3308_PLL_CON(16), 63 RK3308_MODE_CON, 4, 10, 0, NULL), 64 [VPLL1] = PLL(pll_rk3328, PLL_VPLL1, RK3308_PLL_CON(24), 65 RK3308_MODE_CON, 6, 10, 0, NULL), 66}; 67 68/* 69 * 70 * rational_best_approximation(31415, 10000, 71 * (1 << 8) - 1, (1 << 5) - 1, &n, &d); 72 * 73 * you may look at given_numerator as a fixed point number, 74 * with the fractional part size described in given_denominator. 75 * 76 * for theoretical background, see: 77 * http://en.wikipedia.org/wiki/Continued_fraction 78 */ 79static void rational_best_approximation(unsigned long given_numerator, 80 unsigned long given_denominator, 81 unsigned long max_numerator, 82 unsigned long max_denominator, 83 unsigned long *best_numerator, 84 unsigned long *best_denominator) 85{ 86 unsigned long n, d, n0, d0, n1, d1; 87 88 n = given_numerator; 89 d = given_denominator; 90 n0 = 0; 91 d1 = 0; 92 n1 = 1; 93 d0 = 1; 94 for (;;) { 95 unsigned long t, a; 96 97 if (n1 > max_numerator || d1 > max_denominator) { 98 n1 = n0; 99 d1 = d0; 100 break; 101 } 102 if (d == 0) 103 break; 104 t = d; 105 a = n / d; 106 d = n % d; 107 n = t; 108 t = n0 + a * n1; 109 n0 = n1; 110 n1 = t; 111 t = d0 + a * d1; 112 d0 = d1; 113 d1 = t; 114 } 115 *best_numerator = n1; 116 *best_denominator = d1; 117} 118 119static ulong rk3308_armclk_set_clk(struct rk3308_clk_priv *priv, ulong hz) 120{ 121 struct rk3308_cru *cru = priv->cru; 122 const struct rockchip_cpu_rate_table *rate; 123 ulong old_rate; 124 125 rate = rockchip_get_cpu_settings(rk3308_cpu_rates, hz); 126 if (!rate) { 127 printf("%s unsupport rate\n", __func__); 128 return -EINVAL; 129 } 130 131 /* 132 * select apll as cpu/core clock pll source and 133 * set up dependent divisors for PERI and ACLK clocks. 134 * core hz : apll = 1:1 135 */ 136 old_rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL], 137 priv->cru, APLL); 138 if (old_rate > hz) { 139 if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL], 140 priv->cru, APLL, hz)) 141 return -EINVAL; 142 rk_clrsetreg(&cru->clksel_con[0], 143 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | 144 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, 145 rate->aclk_div << CORE_ACLK_DIV_SHIFT | 146 rate->pclk_div << CORE_DBG_DIV_SHIFT | 147 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 148 0 << CORE_DIV_CON_SHIFT); 149 } else if (old_rate < hz) { 150 rk_clrsetreg(&cru->clksel_con[0], 151 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | 152 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, 153 rate->aclk_div << CORE_ACLK_DIV_SHIFT | 154 rate->pclk_div << CORE_DBG_DIV_SHIFT | 155 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 156 0 << CORE_DIV_CON_SHIFT); 157 if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL], 158 priv->cru, APLL, hz)) 159 return -EINVAL; 160 } 161 162 return rockchip_pll_get_rate(&rk3308_pll_clks[APLL], priv->cru, APLL); 163} 164 165static void rk3308_clk_get_pll_rate(struct rk3308_clk_priv *priv) 166{ 167 if (!priv->dpll_hz) 168 priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL], 169 priv->cru, DPLL); 170 if (!priv->vpll0_hz) 171 priv->vpll0_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0], 172 priv->cru, VPLL0); 173 if (!priv->vpll1_hz) 174 priv->vpll1_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1], 175 priv->cru, VPLL1); 176} 177 178static ulong rk3308_i2c_get_clk(struct clk *clk) 179{ 180 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 181 struct rk3308_cru *cru = priv->cru; 182 u32 div, con, con_id; 183 184 switch (clk->id) { 185 case SCLK_I2C0: 186 con_id = 25; 187 break; 188 case SCLK_I2C1: 189 con_id = 26; 190 break; 191 case SCLK_I2C2: 192 con_id = 27; 193 break; 194 case SCLK_I2C3: 195 con_id = 28; 196 break; 197 default: 198 printf("do not support this i2c bus\n"); 199 return -EINVAL; 200 } 201 202 con = readl(&cru->clksel_con[con_id]); 203 div = (con & CLK_I2C_DIV_CON_MASK) >> CLK_I2C_DIV_CON_SHIFT; 204 205 return DIV_TO_RATE(priv->dpll_hz, div); 206} 207 208static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz) 209{ 210 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 211 struct rk3308_cru *cru = priv->cru; 212 u32 src_clk_div, con_id; 213 214 src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz); 215 assert(src_clk_div - 1 <= 127); 216 217 switch (clk->id) { 218 case SCLK_I2C0: 219 con_id = 25; 220 break; 221 case SCLK_I2C1: 222 con_id = 26; 223 break; 224 case SCLK_I2C2: 225 con_id = 27; 226 break; 227 case SCLK_I2C3: 228 con_id = 28; 229 break; 230 default: 231 printf("do not support this i2c bus\n"); 232 return -EINVAL; 233 } 234 rk_clrsetreg(&cru->clksel_con[con_id], 235 CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK, 236 CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT | 237 (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT); 238 239 return rk3308_i2c_get_clk(clk); 240} 241 242static ulong rk3308_mac_set_clk(struct clk *clk, uint hz) 243{ 244 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 245 struct rk3308_cru *cru = priv->cru; 246 u32 con = readl(&cru->clksel_con[43]); 247 ulong pll_rate; 248 u8 div; 249 250 if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL0) 251 pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0], 252 priv->cru, VPLL0); 253 else if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL1) 254 pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1], 255 priv->cru, VPLL1); 256 else 257 pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL], 258 priv->cru, DPLL); 259 260 /*default set 50MHZ for gmac*/ 261 if (!hz) 262 hz = 50000000; 263 264 div = DIV_ROUND_UP(pll_rate, hz) - 1; 265 assert(div < 32); 266 rk_clrsetreg(&cru->clksel_con[43], MAC_DIV_MASK, 267 div << MAC_DIV_SHIFT); 268 269 return DIV_TO_RATE(pll_rate, div); 270} 271 272static int rk3308_mac_set_speed_clk(struct clk *clk, uint hz) 273{ 274 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 275 struct rk3308_cru *cru = priv->cru; 276 277 if (hz != 2500000 && hz != 25000000) { 278 debug("Unsupported mac speed:%d\n", hz); 279 return -EINVAL; 280 } 281 282 rk_clrsetreg(&cru->clksel_con[43], MAC_CLK_SPEED_SEL_MASK, 283 ((hz == 2500000) ? 0 : 1) << MAC_CLK_SPEED_SEL_SHIFT); 284 285 return 0; 286} 287 288static ulong rk3308_mmc_get_clk(struct clk *clk) 289{ 290 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 291 struct rk3308_cru *cru = priv->cru; 292 u32 div, con, con_id; 293 294 switch (clk->id) { 295 case HCLK_SDMMC: 296 case SCLK_SDMMC: 297 con_id = 39; 298 break; 299 case HCLK_EMMC: 300 case SCLK_EMMC: 301 case SCLK_EMMC_SAMPLE: 302 con_id = 41; 303 break; 304 default: 305 return -EINVAL; 306 } 307 308 con = readl(&cru->clksel_con[con_id]); 309 div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; 310 311 if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT 312 == EMMC_SEL_24M) 313 return DIV_TO_RATE(OSC_HZ, div) / 2; 314 else 315 return DIV_TO_RATE(priv->vpll0_hz, div) / 2; 316} 317 318static ulong rk3308_mmc_set_clk(struct clk *clk, ulong set_rate) 319{ 320 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 321 struct rk3308_cru *cru = priv->cru; 322 int src_clk_div; 323 u32 con_id; 324 325 switch (clk->id) { 326 case HCLK_SDMMC: 327 case SCLK_SDMMC: 328 con_id = 39; 329 break; 330 case HCLK_EMMC: 331 case SCLK_EMMC: 332 con_id = 41; 333 break; 334 default: 335 return -EINVAL; 336 } 337 /* Select clk_sdmmc/emmc source from VPLL0 by default */ 338 /* mmc clock defaulg div 2 internal, need provide double in cru */ 339 src_clk_div = DIV_ROUND_UP(priv->vpll0_hz / 2, set_rate); 340 341 if (src_clk_div > 127) { 342 /* use 24MHz source for 400KHz clock */ 343 src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate); 344 rk_clrsetreg(&cru->clksel_con[con_id], 345 EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK, 346 EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT | 347 EMMC_SEL_24M << EMMC_PLL_SHIFT | 348 (src_clk_div - 1) << EMMC_DIV_SHIFT); 349 } else { 350 rk_clrsetreg(&cru->clksel_con[con_id], 351 EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK, 352 EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT | 353 EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT | 354 (src_clk_div - 1) << EMMC_DIV_SHIFT); 355 } 356 357 return rk3308_mmc_get_clk(clk); 358} 359 360static ulong rk3308_saradc_get_clk(struct clk *clk) 361{ 362 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 363 struct rk3308_cru *cru = priv->cru; 364 u32 div, con; 365 366 con = readl(&cru->clksel_con[34]); 367 div = (con & CLK_SARADC_DIV_CON_MASK) >> CLK_SARADC_DIV_CON_SHIFT; 368 369 return DIV_TO_RATE(OSC_HZ, div); 370} 371 372static ulong rk3308_saradc_set_clk(struct clk *clk, uint hz) 373{ 374 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 375 struct rk3308_cru *cru = priv->cru; 376 int src_clk_div; 377 378 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz); 379 assert(src_clk_div - 1 <= 2047); 380 381 rk_clrsetreg(&cru->clksel_con[34], 382 CLK_SARADC_DIV_CON_MASK, 383 (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT); 384 385 return rk3308_saradc_get_clk(clk); 386} 387 388static ulong rk3308_tsadc_get_clk(struct clk *clk) 389{ 390 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 391 struct rk3308_cru *cru = priv->cru; 392 u32 div, con; 393 394 con = readl(&cru->clksel_con[33]); 395 div = (con & CLK_SARADC_DIV_CON_MASK) >> CLK_SARADC_DIV_CON_SHIFT; 396 397 return DIV_TO_RATE(OSC_HZ, div); 398} 399 400static ulong rk3308_tsadc_set_clk(struct clk *clk, uint hz) 401{ 402 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 403 struct rk3308_cru *cru = priv->cru; 404 int src_clk_div; 405 406 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz); 407 assert(src_clk_div - 1 <= 2047); 408 409 rk_clrsetreg(&cru->clksel_con[33], 410 CLK_SARADC_DIV_CON_MASK, 411 (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT); 412 413 return rk3308_tsadc_get_clk(clk); 414} 415 416static ulong rk3308_spi_get_clk(struct clk *clk) 417{ 418 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 419 struct rk3308_cru *cru = priv->cru; 420 u32 div, con, con_id; 421 422 switch (clk->id) { 423 case SCLK_SPI0: 424 con_id = 30; 425 break; 426 case SCLK_SPI1: 427 con_id = 31; 428 break; 429 case SCLK_SPI2: 430 con_id = 32; 431 break; 432 default: 433 printf("do not support this spi bus\n"); 434 return -EINVAL; 435 } 436 437 con = readl(&cru->clksel_con[con_id]); 438 div = (con & CLK_SPI_DIV_CON_MASK) >> CLK_SPI_DIV_CON_SHIFT; 439 440 return DIV_TO_RATE(priv->dpll_hz, div); 441} 442 443static ulong rk3308_spi_set_clk(struct clk *clk, uint hz) 444{ 445 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 446 struct rk3308_cru *cru = priv->cru; 447 u32 src_clk_div, con_id; 448 449 src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz); 450 assert(src_clk_div - 1 <= 127); 451 452 switch (clk->id) { 453 case SCLK_SPI0: 454 con_id = 30; 455 break; 456 case SCLK_SPI1: 457 con_id = 31; 458 break; 459 case SCLK_SPI2: 460 con_id = 32; 461 break; 462 default: 463 printf("do not support this spi bus\n"); 464 return -EINVAL; 465 } 466 467 rk_clrsetreg(&cru->clksel_con[con_id], 468 CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK, 469 CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT | 470 (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT); 471 472 return rk3308_spi_get_clk(clk); 473} 474 475static ulong rk3308_pwm_get_clk(struct clk *clk) 476{ 477 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 478 struct rk3308_cru *cru = priv->cru; 479 u32 div, con; 480 481 con = readl(&cru->clksel_con[29]); 482 div = (con & CLK_PWM_DIV_CON_MASK) >> CLK_PWM_DIV_CON_SHIFT; 483 484 return DIV_TO_RATE(priv->dpll_hz, div); 485} 486 487static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz) 488{ 489 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 490 struct rk3308_cru *cru = priv->cru; 491 int src_clk_div; 492 493 src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz); 494 assert(src_clk_div - 1 <= 127); 495 496 rk_clrsetreg(&cru->clksel_con[29], 497 CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK, 498 CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT | 499 (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT); 500 501 return rk3308_pwm_get_clk(clk); 502} 503 504static ulong rk3308_uart_get_clk(struct clk *clk) 505{ 506 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 507 struct rk3308_cru *cru = priv->cru; 508 u32 div, pll_sel, con, con_id, parent; 509 510 switch (clk->id) { 511 case SCLK_UART0: 512 con_id = 10; 513 break; 514 case SCLK_UART1: 515 con_id = 13; 516 break; 517 case SCLK_UART2: 518 con_id = 16; 519 break; 520 case SCLK_UART3: 521 con_id = 19; 522 break; 523 case SCLK_UART4: 524 con_id = 22; 525 break; 526 default: 527 printf("do not support this uart interface\n"); 528 return -EINVAL; 529 } 530 531 con = readl(&cru->clksel_con[con_id]); 532 pll_sel = (con & CLK_UART_PLL_SEL_MASK) >> CLK_UART_PLL_SEL_SHIFT; 533 div = (con & CLK_UART_DIV_CON_MASK) >> CLK_UART_DIV_CON_SHIFT; 534 535 switch (pll_sel) { 536 case CLK_UART_PLL_SEL_DPLL: 537 parent = priv->dpll_hz; 538 break; 539 case CLK_UART_PLL_SEL_VPLL0: 540 parent = priv->vpll0_hz; 541 break; 542 case CLK_UART_PLL_SEL_VPLL1: 543 parent = priv->vpll0_hz; 544 break; 545 case CLK_UART_PLL_SEL_24M: 546 parent = OSC_HZ; 547 break; 548 default: 549 printf("do not support this uart pll sel\n"); 550 return -EINVAL; 551 } 552 553 return DIV_TO_RATE(parent, div); 554} 555 556static ulong rk3308_vop_get_clk(struct clk *clk) 557{ 558 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 559 struct rk3308_cru *cru = priv->cru; 560 u32 div, pll_sel, vol_sel, con, parent; 561 562 con = readl(&cru->clksel_con[8]); 563 vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT; 564 pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT; 565 div = con & DCLK_VOP_DIV_MASK; 566 567 if (vol_sel == DCLK_VOP_SEL_24M) { 568 parent = OSC_HZ; 569 } else if (vol_sel == DCLK_VOP_SEL_DIVOUT) { 570 switch (pll_sel) { 571 case DCLK_VOP_PLL_SEL_DPLL: 572 parent = priv->dpll_hz; 573 break; 574 case DCLK_VOP_PLL_SEL_VPLL0: 575 parent = priv->vpll0_hz; 576 break; 577 case DCLK_VOP_PLL_SEL_VPLL1: 578 parent = priv->vpll0_hz; 579 break; 580 default: 581 printf("do not support this vop pll sel\n"); 582 return -EINVAL; 583 } 584 } else { 585 printf("do not support this vop sel\n"); 586 return -EINVAL; 587 } 588 589 return DIV_TO_RATE(parent, div); 590} 591 592static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz) 593{ 594 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 595 struct rk3308_cru *cru = priv->cru; 596 ulong pll_rate, now, best_rate = 0; 597 u32 i, div, best_div = 0, best_sel = 0; 598 599 for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) { 600 switch (i) { 601 case DCLK_VOP_PLL_SEL_DPLL: 602 pll_rate = priv->dpll_hz; 603 break; 604 case DCLK_VOP_PLL_SEL_VPLL0: 605 pll_rate = priv->vpll0_hz; 606 break; 607 case DCLK_VOP_PLL_SEL_VPLL1: 608 pll_rate = priv->vpll1_hz; 609 break; 610 default: 611 printf("do not support this vop pll sel\n"); 612 return -EINVAL; 613 } 614 615 div = DIV_ROUND_UP(pll_rate, hz); 616 if (div > 255) 617 continue; 618 now = pll_rate / div; 619 if (abs(hz - now) < abs(hz - best_rate)) { 620 best_rate = now; 621 best_div = div; 622 best_sel = i; 623 } 624 debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n", 625 pll_rate, best_rate, best_div, best_sel); 626 } 627 628 if (best_rate != hz && hz == OSC_HZ) { 629 rk_clrsetreg(&cru->clksel_con[8], 630 DCLK_VOP_SEL_MASK, 631 DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT); 632 } else if (best_rate) { 633 rk_clrsetreg(&cru->clksel_con[8], 634 DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK | 635 DCLK_VOP_DIV_MASK, 636 DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT | 637 best_sel << DCLK_VOP_PLL_SEL_SHIFT | 638 (best_div - 1) << DCLK_VOP_DIV_SHIFT); 639 } else { 640 printf("do not support this vop freq\n"); 641 return -EINVAL; 642 } 643 644 return rk3308_vop_get_clk(clk); 645} 646 647static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id) 648{ 649 struct rk3308_cru *cru = priv->cru; 650 u32 div, con, parent = priv->dpll_hz; 651 652 switch (clk_id) { 653 case ACLK_BUS: 654 con = readl(&cru->clksel_con[5]); 655 div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT; 656 break; 657 case HCLK_BUS: 658 con = readl(&cru->clksel_con[6]); 659 div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT; 660 break; 661 case PCLK_BUS: 662 case PCLK_WDT: 663 con = readl(&cru->clksel_con[6]); 664 div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT; 665 break; 666 default: 667 return -ENOENT; 668 } 669 670 return DIV_TO_RATE(parent, div); 671} 672 673static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id, 674 ulong hz) 675{ 676 struct rk3308_cru *cru = priv->cru; 677 int src_clk_div; 678 679 src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz); 680 assert(src_clk_div - 1 <= 31); 681 682 /* 683 * select dpll as pd_bus bus clock source and 684 * set up dependent divisors for PCLK/HCLK and ACLK clocks. 685 */ 686 switch (clk_id) { 687 case ACLK_BUS: 688 rk_clrsetreg(&cru->clksel_con[5], 689 BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, 690 BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT | 691 (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT); 692 break; 693 case HCLK_BUS: 694 rk_clrsetreg(&cru->clksel_con[6], 695 BUS_HCLK_DIV_MASK, 696 (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT); 697 break; 698 case PCLK_BUS: 699 rk_clrsetreg(&cru->clksel_con[6], 700 BUS_PCLK_DIV_MASK, 701 (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT); 702 break; 703 default: 704 printf("do not support this bus freq\n"); 705 return -EINVAL; 706 } 707 708 return rk3308_bus_get_clk(priv, clk_id); 709} 710 711static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id) 712{ 713 struct rk3308_cru *cru = priv->cru; 714 u32 div, con, parent = priv->dpll_hz; 715 716 switch (clk_id) { 717 case ACLK_PERI: 718 con = readl(&cru->clksel_con[36]); 719 div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT; 720 break; 721 case HCLK_PERI: 722 con = readl(&cru->clksel_con[37]); 723 div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT; 724 break; 725 case PCLK_PERI: 726 con = readl(&cru->clksel_con[37]); 727 div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT; 728 break; 729 default: 730 return -ENOENT; 731 } 732 733 return DIV_TO_RATE(parent, div); 734} 735 736static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id, 737 ulong hz) 738{ 739 struct rk3308_cru *cru = priv->cru; 740 int src_clk_div; 741 742 src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz); 743 assert(src_clk_div - 1 <= 31); 744 745 /* 746 * select dpll as pd_peri bus clock source and 747 * set up dependent divisors for PCLK/HCLK and ACLK clocks. 748 */ 749 switch (clk_id) { 750 case ACLK_PERI: 751 rk_clrsetreg(&cru->clksel_con[36], 752 PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK, 753 PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT | 754 (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT); 755 break; 756 case HCLK_PERI: 757 rk_clrsetreg(&cru->clksel_con[37], 758 PERI_HCLK_DIV_MASK, 759 (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT); 760 break; 761 case PCLK_PERI: 762 rk_clrsetreg(&cru->clksel_con[37], 763 PERI_PCLK_DIV_MASK, 764 (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT); 765 break; 766 default: 767 printf("do not support this peri freq\n"); 768 return -EINVAL; 769 } 770 771 return rk3308_peri_get_clk(priv, clk_id); 772} 773 774static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id) 775{ 776 struct rk3308_cru *cru = priv->cru; 777 u32 div, con, parent = priv->vpll0_hz; 778 779 switch (clk_id) { 780 case HCLK_AUDIO: 781 con = readl(&cru->clksel_con[45]); 782 div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT; 783 break; 784 case PCLK_AUDIO: 785 con = readl(&cru->clksel_con[45]); 786 div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT; 787 break; 788 default: 789 return -ENOENT; 790 } 791 792 return DIV_TO_RATE(parent, div); 793} 794 795static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id, 796 ulong hz) 797{ 798 struct rk3308_cru *cru = priv->cru; 799 int src_clk_div; 800 801 src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz); 802 assert(src_clk_div - 1 <= 31); 803 804 /* 805 * select vpll0 as audio bus clock source and 806 * set up dependent divisors for HCLK and PCLK clocks. 807 */ 808 switch (clk_id) { 809 case HCLK_AUDIO: 810 rk_clrsetreg(&cru->clksel_con[45], 811 AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK, 812 AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT | 813 (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT); 814 break; 815 case PCLK_AUDIO: 816 rk_clrsetreg(&cru->clksel_con[45], 817 AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK, 818 AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT | 819 (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT); 820 break; 821 default: 822 printf("do not support this audio freq\n"); 823 return -EINVAL; 824 } 825 826 return rk3308_peri_get_clk(priv, clk_id); 827} 828 829static ulong rk3308_crypto_get_clk(struct rk3308_clk_priv *priv, ulong clk_id) 830{ 831 struct rk3308_cru *cru = priv->cru; 832 u32 div, con, parent; 833 834 switch (clk_id) { 835 case SCLK_CRYPTO: 836 con = readl(&cru->clksel_con[7]); 837 div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT; 838 parent = priv->vpll0_hz; 839 break; 840 case SCLK_CRYPTO_APK: 841 con = readl(&cru->clksel_con[7]); 842 div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT; 843 parent = priv->vpll0_hz; 844 break; 845 default: 846 return -ENOENT; 847 } 848 849 return DIV_TO_RATE(parent, div); 850} 851 852static ulong rk3308_crypto_set_clk(struct rk3308_clk_priv *priv, ulong clk_id, 853 ulong hz) 854{ 855 struct rk3308_cru *cru = priv->cru; 856 int src_clk_div; 857 858 src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz); 859 assert(src_clk_div - 1 <= 31); 860 861 /* 862 * select gpll as crypto clock source and 863 * set up dependent divisors for crypto clocks. 864 */ 865 switch (clk_id) { 866 case SCLK_CRYPTO: 867 rk_clrsetreg(&cru->clksel_con[7], 868 CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK, 869 CRYPTO_PLL_SEL_VPLL0 << CRYPTO_PLL_SEL_SHIFT | 870 (src_clk_div - 1) << CRYPTO_DIV_SHIFT); 871 break; 872 case SCLK_CRYPTO_APK: 873 rk_clrsetreg(&cru->clksel_con[7], 874 CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK, 875 CRYPTO_PLL_SEL_VPLL0 << CRYPTO_APK_SEL_SHIFT | 876 (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT); 877 break; 878 default: 879 printf("do not support this peri freq\n"); 880 return -EINVAL; 881 } 882 883 return rk3308_crypto_get_clk(priv, clk_id); 884} 885 886static ulong rk3308_rtc32k_get_clk(struct rk3308_clk_priv *priv, ulong clk_id) 887{ 888 struct rk3308_cru *cru = priv->cru; 889 unsigned long m, n; 890 u32 con, fracdiv; 891 892 con = readl(&cru->clksel_con[2]); 893 if ((con & CLK_RTC32K_SEL_MASK) >> CLK_RTC32K_SEL_SHIFT != 894 CLK_RTC32K_FRAC_DIV) 895 return -EINVAL; 896 897 fracdiv = readl(&cru->clksel_con[3]); 898 m = fracdiv & CLK_RTC32K_FRAC_NUMERATOR_MASK; 899 m >>= CLK_RTC32K_FRAC_NUMERATOR_SHIFT; 900 n = fracdiv & CLK_RTC32K_FRAC_DENOMINATOR_MASK; 901 n >>= CLK_RTC32K_FRAC_DENOMINATOR_SHIFT; 902 903 return OSC_HZ * m / n; 904} 905 906static ulong rk3308_rtc32k_set_clk(struct rk3308_clk_priv *priv, ulong clk_id, 907 ulong hz) 908{ 909 struct rk3308_cru *cru = priv->cru; 910 unsigned long m, n, val; 911 912 rational_best_approximation(hz, OSC_HZ, 913 GENMASK(16 - 1, 0), 914 GENMASK(16 - 1, 0), 915 &m, &n); 916 val = m << CLK_RTC32K_FRAC_NUMERATOR_SHIFT | n; 917 writel(val, &cru->clksel_con[3]); 918 rk_clrsetreg(&cru->clksel_con[2], CLK_RTC32K_SEL_MASK, 919 CLK_RTC32K_FRAC_DIV << CLK_RTC32K_SEL_SHIFT); 920 921 return rk3308_rtc32k_get_clk(priv, clk_id); 922} 923 924static ulong rk3308_clk_get_rate(struct clk *clk) 925{ 926 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 927 ulong rate = 0; 928 929 debug("%s id:%ld\n", __func__, clk->id); 930 931 switch (clk->id) { 932 case PLL_APLL: 933 case ARMCLK: 934 rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL], 935 priv->cru, APLL); 936 break; 937 case PLL_DPLL: 938 rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL], 939 priv->cru, DPLL); 940 break; 941 case PLL_VPLL0: 942 rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0], 943 priv->cru, VPLL0); 944 break; 945 case PLL_VPLL1: 946 rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1], 947 priv->cru, VPLL1); 948 break; 949 case HCLK_SDMMC: 950 case HCLK_EMMC: 951 case SCLK_SDMMC: 952 case SCLK_EMMC: 953 case SCLK_EMMC_SAMPLE: 954 rate = rk3308_mmc_get_clk(clk); 955 break; 956 case SCLK_UART0: 957 case SCLK_UART1: 958 case SCLK_UART2: 959 case SCLK_UART3: 960 case SCLK_UART4: 961 rate = rk3308_uart_get_clk(clk); 962 break; 963 case SCLK_I2C0: 964 case SCLK_I2C1: 965 case SCLK_I2C2: 966 case SCLK_I2C3: 967 rate = rk3308_i2c_get_clk(clk); 968 break; 969 case SCLK_SARADC: 970 rate = rk3308_saradc_get_clk(clk); 971 break; 972 case SCLK_TSADC: 973 rate = rk3308_tsadc_get_clk(clk); 974 break; 975 case SCLK_SPI0: 976 case SCLK_SPI1: 977 rate = rk3308_spi_get_clk(clk); 978 break; 979 case SCLK_PWM0: 980 rate = rk3308_pwm_get_clk(clk); 981 break; 982 case DCLK_VOP: 983 rate = rk3308_vop_get_clk(clk); 984 break; 985 case ACLK_BUS: 986 case HCLK_BUS: 987 case PCLK_BUS: 988 case PCLK_WDT: 989 rate = rk3308_bus_get_clk(priv, clk->id); 990 break; 991 case ACLK_PERI: 992 case HCLK_PERI: 993 case PCLK_PERI: 994 rate = rk3308_peri_get_clk(priv, clk->id); 995 break; 996 case HCLK_AUDIO: 997 case PCLK_AUDIO: 998 rate = rk3308_audio_get_clk(priv, clk->id); 999 break; 1000 case SCLK_CRYPTO: 1001 case SCLK_CRYPTO_APK: 1002 rate = rk3308_crypto_get_clk(priv, clk->id); 1003 break; 1004 case SCLK_RTC32K: 1005 rate = rk3308_rtc32k_get_clk(priv, clk->id); 1006 break; 1007 default: 1008 return -ENOENT; 1009 } 1010 1011 return rate; 1012} 1013 1014static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate) 1015{ 1016 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 1017 ulong ret = 0; 1018 1019 debug("%s %ld %ld\n", __func__, clk->id, rate); 1020 1021 switch (clk->id) { 1022 case PLL_DPLL: 1023 ret = rockchip_pll_set_rate(&rk3308_pll_clks[DPLL], priv->cru, 1024 DPLL, rate); 1025 priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL], 1026 priv->cru, DPLL); 1027 break; 1028 case ARMCLK: 1029 if (priv->armclk_hz) 1030 rk3308_armclk_set_clk(priv, rate); 1031 priv->armclk_hz = rate; 1032 break; 1033 case HCLK_SDMMC: 1034 case HCLK_EMMC: 1035 case SCLK_SDMMC: 1036 case SCLK_EMMC: 1037 ret = rk3308_mmc_set_clk(clk, rate); 1038 break; 1039 case SCLK_I2C0: 1040 case SCLK_I2C1: 1041 case SCLK_I2C2: 1042 case SCLK_I2C3: 1043 ret = rk3308_i2c_set_clk(clk, rate); 1044 break; 1045 case SCLK_MAC: 1046 ret = rk3308_mac_set_clk(clk, rate); 1047 break; 1048 case SCLK_MAC_RMII: 1049 ret = rk3308_mac_set_speed_clk(clk, rate); 1050 break; 1051 case SCLK_SARADC: 1052 ret = rk3308_saradc_set_clk(clk, rate); 1053 break; 1054 case SCLK_TSADC: 1055 ret = rk3308_tsadc_set_clk(clk, rate); 1056 break; 1057 case SCLK_SPI0: 1058 case SCLK_SPI1: 1059 ret = rk3308_spi_set_clk(clk, rate); 1060 break; 1061 case SCLK_PWM0: 1062 ret = rk3308_pwm_set_clk(clk, rate); 1063 break; 1064 case DCLK_VOP: 1065 ret = rk3308_vop_set_clk(clk, rate); 1066 break; 1067 case ACLK_BUS: 1068 case HCLK_BUS: 1069 case PCLK_BUS: 1070 rate = rk3308_bus_set_clk(priv, clk->id, rate); 1071 break; 1072 case ACLK_PERI: 1073 case HCLK_PERI: 1074 case PCLK_PERI: 1075 rate = rk3308_peri_set_clk(priv, clk->id, rate); 1076 break; 1077 case HCLK_AUDIO: 1078 case PCLK_AUDIO: 1079 rate = rk3308_audio_set_clk(priv, clk->id, rate); 1080 break; 1081 case SCLK_CRYPTO: 1082 case SCLK_CRYPTO_APK: 1083 ret = rk3308_crypto_set_clk(priv, clk->id, rate); 1084 break; 1085 case SCLK_RTC32K: 1086 ret = rk3308_rtc32k_set_clk(priv, clk->id, rate); 1087 break; 1088 case USB480M: 1089 return 0; 1090 default: 1091 return -ENOENT; 1092 } 1093 1094 return ret; 1095} 1096 1097#if CONFIG_IS_ENABLED(OF_REAL) 1098static int __maybe_unused rk3308_mac_set_parent(struct clk *clk, struct clk *parent) 1099{ 1100 struct rk3308_clk_priv *priv = dev_get_priv(clk->dev); 1101 1102 /* 1103 * If the requested parent is in the same clock-controller and 1104 * the id is SCLK_MAC_SRC, switch to the internal clock. 1105 */ 1106 if (parent->id == SCLK_MAC_SRC) { 1107 debug("%s: switching RMII to SCLK_MAC\n", __func__); 1108 rk_clrreg(&priv->cru->clksel_con[43], BIT(14)); 1109 } else { 1110 debug("%s: switching RMII to CLKIN\n", __func__); 1111 rk_setreg(&priv->cru->clksel_con[43], BIT(14)); 1112 } 1113 1114 return 0; 1115} 1116 1117static int __maybe_unused rk3308_clk_set_parent(struct clk *clk, struct clk *parent) 1118{ 1119 switch (clk->id) { 1120 case SCLK_MAC: 1121 return rk3308_mac_set_parent(clk, parent); 1122 case USB480M: 1123 return 0; 1124 default: 1125 break; 1126 } 1127 1128 debug("%s: unsupported clk %ld\n", __func__, clk->id); 1129 return -ENOENT; 1130} 1131#endif 1132 1133static struct clk_ops rk3308_clk_ops = { 1134 .get_rate = rk3308_clk_get_rate, 1135 .set_rate = rk3308_clk_set_rate, 1136#if CONFIG_IS_ENABLED(OF_REAL) 1137 .set_parent = rk3308_clk_set_parent, 1138#endif 1139}; 1140 1141static void rk3308_clk_init(struct udevice *dev) 1142{ 1143 struct rk3308_clk_priv *priv = dev_get_priv(dev); 1144 int ret; 1145 1146 if (rockchip_pll_get_rate(&rk3308_pll_clks[APLL], 1147 priv->cru, APLL) != APLL_HZ) { 1148 ret = rk3308_armclk_set_clk(priv, APLL_HZ); 1149 if (ret < 0) 1150 printf("%s failed to set armclk rate\n", __func__); 1151 } 1152 1153 rk3308_clk_get_pll_rate(priv); 1154 1155 rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ); 1156 rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ); 1157 rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ); 1158 1159 rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ); 1160 rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ); 1161 rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ); 1162 1163 rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ); 1164 rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ); 1165} 1166 1167static int rk3308_clk_probe(struct udevice *dev) 1168{ 1169 int ret; 1170 1171 rk3308_clk_init(dev); 1172 1173 /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ 1174 ret = clk_set_defaults(dev, CLK_DEFAULTS_POST); 1175 if (ret) 1176 debug("%s clk_set_defaults failed %d\n", __func__, ret); 1177 1178 return ret; 1179} 1180 1181static int rk3308_clk_of_to_plat(struct udevice *dev) 1182{ 1183 struct rk3308_clk_priv *priv = dev_get_priv(dev); 1184 1185 priv->cru = dev_read_addr_ptr(dev); 1186 1187 return 0; 1188} 1189 1190static int rk3308_clk_bind(struct udevice *dev) 1191{ 1192 int ret; 1193 struct udevice *sys_child; 1194 struct sysreset_reg *priv; 1195 1196 /* The reset driver does not have a device node, so bind it here */ 1197 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 1198 &sys_child); 1199 if (ret) { 1200 debug("Warning: No sysreset driver: ret=%d\n", ret); 1201 } else { 1202 priv = malloc(sizeof(struct sysreset_reg)); 1203 priv->glb_srst_fst_value = offsetof(struct rk3308_cru, 1204 glb_srst_fst); 1205 priv->glb_srst_snd_value = offsetof(struct rk3308_cru, 1206 glb_srst_snd); 1207 dev_set_priv(sys_child, priv); 1208 } 1209 1210#if CONFIG_IS_ENABLED(RESET_ROCKCHIP) 1211 ret = offsetof(struct rk3308_cru, softrst_con[0]); 1212 ret = rockchip_reset_bind(dev, ret, 12); 1213 if (ret) 1214 debug("Warning: software reset driver bind failed\n"); 1215#endif 1216 1217 return 0; 1218} 1219 1220static const struct udevice_id rk3308_clk_ids[] = { 1221 { .compatible = "rockchip,rk3308-cru" }, 1222 { } 1223}; 1224 1225U_BOOT_DRIVER(rockchip_rk3308_cru) = { 1226 .name = "rockchip_rk3308_cru", 1227 .id = UCLASS_CLK, 1228 .of_match = rk3308_clk_ids, 1229 .priv_auto = sizeof(struct rk3308_clk_priv), 1230 .of_to_plat = rk3308_clk_of_to_plat, 1231 .ops = &rk3308_clk_ops, 1232 .bind = rk3308_clk_bind, 1233 .probe = rk3308_clk_probe, 1234}; 1235