1// SPDX-License-Identifier: GPL-2.0 2/* 3 * (C) Copyright 2018-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 <errno.h> 10#include <log.h> 11#include <asm/arch-rockchip/clock.h> 12#include <asm/arch-rockchip/hardware.h> 13#include <div64.h> 14#include <linux/delay.h> 15 16static struct rockchip_pll_rate_table rockchip_auto_table; 17 18#define PLL_MODE_MASK 0x3 19#define PLL_RK3328_MODE_MASK 0x1 20 21#define RK3036_PLLCON0_FBDIV_MASK 0xfff 22#define RK3036_PLLCON0_FBDIV_SHIFT 0 23#define RK3036_PLLCON0_POSTDIV1_MASK 0x7 << 12 24#define RK3036_PLLCON0_POSTDIV1_SHIFT 12 25#define RK3036_PLLCON1_REFDIV_MASK 0x3f 26#define RK3036_PLLCON1_REFDIV_SHIFT 0 27#define RK3036_PLLCON1_POSTDIV2_MASK 0x7 << 6 28#define RK3036_PLLCON1_POSTDIV2_SHIFT 6 29#define RK3036_PLLCON1_DSMPD_MASK 0x1 << 12 30#define RK3036_PLLCON1_DSMPD_SHIFT 12 31#define RK3036_PLLCON2_FRAC_MASK 0xffffff 32#define RK3036_PLLCON2_FRAC_SHIFT 0 33#define RK3036_PLLCON1_PWRDOWN_SHIFT 13 34 35#define MHZ 1000000 36#define KHZ 1000 37enum { 38 OSC_HZ = 24 * 1000000, 39 VCO_MAX_HZ = 3200U * 1000000, 40 VCO_MIN_HZ = 800 * 1000000, 41 OUTPUT_MAX_HZ = 3200U * 1000000, 42 OUTPUT_MIN_HZ = 24 * 1000000, 43}; 44 45#define MIN_FOUTVCO_FREQ (800 * MHZ) 46#define MAX_FOUTVCO_FREQ (2000 * MHZ) 47#define RK3588_VCO_MIN_HZ (2250UL * MHZ) 48#define RK3588_VCO_MAX_HZ (4500UL * MHZ) 49#define RK3588_FOUT_MIN_HZ (37UL * MHZ) 50#define RK3588_FOUT_MAX_HZ (4500UL * MHZ) 51 52int gcd(int m, int n) 53{ 54 int t; 55 56 while (m > 0) { 57 if (n > m) { 58 t = m; 59 m = n; 60 n = t; 61 } /* swap */ 62 m -= n; 63 } 64 return n; 65} 66 67/* 68 * How to calculate the PLL(from TRM V0.3 Part 1 Page 63): 69 * Formulas also embedded within the Fractional PLL Verilog model: 70 * If DSMPD = 1 (DSM is disabled, "integer mode") 71 * FOUTVCO = FREF / REFDIV * FBDIV 72 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 73 * Where: 74 * FOUTVCO = Fractional PLL non-divided output frequency 75 * FOUTPOSTDIV = Fractional PLL divided output frequency 76 * (output of second post divider) 77 * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input) 78 * REFDIV = Fractional PLL input reference clock divider 79 * FBDIV = Integer value programmed into feedback divide 80 * 81 */ 82 83static int rockchip_pll_clk_set_postdiv(ulong fout_hz, 84 u32 *postdiv1, 85 u32 *postdiv2, 86 u32 *foutvco) 87{ 88 ulong freq; 89 90 if (fout_hz < MIN_FOUTVCO_FREQ) { 91 for (*postdiv1 = 1; *postdiv1 <= 7; (*postdiv1)++) { 92 for (*postdiv2 = 1; *postdiv2 <= 7; (*postdiv2)++) { 93 freq = fout_hz * (*postdiv1) * (*postdiv2); 94 if (freq >= MIN_FOUTVCO_FREQ && 95 freq <= MAX_FOUTVCO_FREQ) { 96 *foutvco = freq; 97 return 0; 98 } 99 } 100 } 101 printf("Can't FIND postdiv1/2 to make fout=%lu in 800~2000M.\n", 102 fout_hz); 103 } else { 104 *postdiv1 = 1; 105 *postdiv2 = 1; 106 } 107 return 0; 108} 109 110static struct rockchip_pll_rate_table * 111rockchip_pll_clk_set_by_auto(ulong fin_hz, 112 ulong fout_hz) 113{ 114 struct rockchip_pll_rate_table *rate_table = &rockchip_auto_table; 115 /* FIXME set postdiv1/2 always 1*/ 116 u32 foutvco = fout_hz; 117 ulong fin_64, frac_64; 118 u32 f_frac, postdiv1, postdiv2; 119 ulong clk_gcd = 0; 120 121 if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz) 122 return NULL; 123 124 rockchip_pll_clk_set_postdiv(fout_hz, &postdiv1, &postdiv2, &foutvco); 125 rate_table->postdiv1 = postdiv1; 126 rate_table->postdiv2 = postdiv2; 127 rate_table->dsmpd = 1; 128 129 if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) { 130 fin_hz /= MHZ; 131 foutvco /= MHZ; 132 clk_gcd = gcd(fin_hz, foutvco); 133 rate_table->refdiv = fin_hz / clk_gcd; 134 rate_table->fbdiv = foutvco / clk_gcd; 135 136 rate_table->frac = 0; 137 138 debug("fin = %ld, fout = %ld, clk_gcd = %ld,\n", 139 fin_hz, fout_hz, clk_gcd); 140 debug("refdiv= %d,fbdiv= %d,postdiv1= %d,postdiv2= %d\n", 141 rate_table->refdiv, 142 rate_table->fbdiv, rate_table->postdiv1, 143 rate_table->postdiv2); 144 } else { 145 debug("frac div,fin_hz = %ld,fout_hz = %ld\n", 146 fin_hz, fout_hz); 147 debug("frac get postdiv1 = %d, postdiv2 = %d, foutvco = %d\n", 148 rate_table->postdiv1, rate_table->postdiv2, foutvco); 149 clk_gcd = gcd(fin_hz / MHZ, foutvco / MHZ); 150 rate_table->refdiv = fin_hz / MHZ / clk_gcd; 151 rate_table->fbdiv = foutvco / MHZ / clk_gcd; 152 debug("frac get refdiv = %d, fbdiv = %d\n", 153 rate_table->refdiv, rate_table->fbdiv); 154 155 rate_table->frac = 0; 156 157 f_frac = (foutvco % MHZ); 158 fin_64 = fin_hz; 159 fin_64 = fin_64 / rate_table->refdiv; 160 frac_64 = f_frac << 24; 161 frac_64 = frac_64 / fin_64; 162 rate_table->frac = frac_64; 163 if (rate_table->frac > 0) 164 rate_table->dsmpd = 0; 165 debug("frac = %x\n", rate_table->frac); 166 } 167 return rate_table; 168} 169 170static u32 171rockchip_rk3588_pll_k_get(u32 m, u32 p, u32 s, u64 fin_hz, u64 fvco) 172{ 173 u64 fref, fout, ffrac; 174 u32 k = 0; 175 176 fref = fin_hz / p; 177 ffrac = fvco - (m * fref); 178 fout = ffrac * 65536; 179 k = fout / fref; 180 if (k > 32767) { 181 fref = fin_hz / p; 182 ffrac = ((m + 1) * fref) - fvco; 183 fout = ffrac * 65536; 184 k = ((fout * 10 / fref) + 7) / 10; 185 if (k > 32767) 186 k = 0; 187 else 188 k = ~k + 1; 189 } 190 return k; 191} 192 193static struct rockchip_pll_rate_table * 194rockchip_rk3588_pll_frac_by_auto(unsigned long fin_hz, unsigned long fout_hz) 195{ 196 struct rockchip_pll_rate_table *rate_table = &rockchip_auto_table; 197 u32 p, m, s, k; 198 u64 fvco; 199 200 for (s = 0; s <= 6; s++) { 201 fvco = (u64)fout_hz << s; 202 if (fvco < RK3588_VCO_MIN_HZ || fvco > RK3588_VCO_MAX_HZ) 203 continue; 204 for (p = 1; p <= 4; p++) { 205 for (m = 64; m <= 1023; m++) { 206 if ((fvco >= m * fin_hz / p) && 207 (fvco < (m + 1) * fin_hz / p)) { 208 k = rockchip_rk3588_pll_k_get(m, p, s, 209 fin_hz, 210 fvco); 211 if (!k) 212 continue; 213 rate_table->p = p; 214 rate_table->s = s; 215 rate_table->k = k; 216 if (k > 32767) 217 rate_table->m = m + 1; 218 else 219 rate_table->m = m; 220 return rate_table; 221 } 222 } 223 } 224 } 225 return NULL; 226} 227 228static struct rockchip_pll_rate_table * 229rk3588_pll_clk_set_by_auto(unsigned long fin_hz, 230 unsigned long fout_hz) 231{ 232 struct rockchip_pll_rate_table *rate_table = &rockchip_auto_table; 233 u32 p, m, s; 234 ulong fvco; 235 236 if (fin_hz == 0 || fout_hz == 0 || fout_hz == fin_hz) 237 return NULL; 238 239 if (fout_hz > RK3588_FOUT_MAX_HZ || fout_hz < RK3588_FOUT_MIN_HZ) 240 return NULL; 241 242 if (fin_hz / MHZ * MHZ == fin_hz && fout_hz / MHZ * MHZ == fout_hz) { 243 for (s = 0; s <= 6; s++) { 244 fvco = fout_hz << s; 245 if (fvco < RK3588_VCO_MIN_HZ || 246 fvco > RK3588_VCO_MAX_HZ) 247 continue; 248 for (p = 2; p <= 4; p++) { 249 for (m = 64; m <= 1023; m++) { 250 if (fvco == m * fin_hz / p) { 251 rate_table->p = p; 252 rate_table->m = m; 253 rate_table->s = s; 254 rate_table->k = 0; 255 return rate_table; 256 } 257 } 258 } 259 } 260 pr_err("CANNOT FIND Fout by auto,fout = %lu\n", fout_hz); 261 } else { 262 rate_table = rockchip_rk3588_pll_frac_by_auto(fin_hz, fout_hz); 263 if (!rate_table) 264 pr_err("CANNOT FIND Fout by auto,fout = %lu\n", 265 fout_hz); 266 else 267 return rate_table; 268 } 269 return NULL; 270} 271 272static const struct rockchip_pll_rate_table * 273rockchip_get_pll_settings(struct rockchip_pll_clock *pll, ulong rate) 274{ 275 struct rockchip_pll_rate_table *rate_table = pll->rate_table; 276 277 while (rate_table->rate) { 278 if (rate_table->rate == rate) 279 break; 280 rate_table++; 281 } 282 if (rate_table->rate != rate) { 283 if (pll->type == pll_rk3588) 284 return rk3588_pll_clk_set_by_auto(24 * MHZ, rate); 285 else 286 return rockchip_pll_clk_set_by_auto(24 * MHZ, rate); 287 } else { 288 return rate_table; 289 } 290} 291 292static int rk3036_pll_set_rate(struct rockchip_pll_clock *pll, 293 void __iomem *base, ulong pll_id, 294 ulong drate) 295{ 296 const struct rockchip_pll_rate_table *rate; 297 298 rate = rockchip_get_pll_settings(pll, drate); 299 if (!rate) { 300 printf("%s unsupport rate\n", __func__); 301 return -EINVAL; 302 } 303 304 debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d\n", 305 __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv); 306 debug("%s: rate settings for %lu postdiv2: %d, dsmpd: %d, frac: %d\n", 307 __func__, rate->rate, rate->postdiv2, rate->dsmpd, rate->frac); 308 309 /* 310 * When power on or changing PLL setting, 311 * we must force PLL into slow mode to ensure output stable clock. 312 */ 313 rk_clrsetreg(base + pll->mode_offset, 314 pll->mode_mask << pll->mode_shift, 315 RKCLK_PLL_MODE_SLOW << pll->mode_shift); 316 317 /* Power down */ 318 rk_setreg(base + pll->con_offset + 0x4, 319 1 << RK3036_PLLCON1_PWRDOWN_SHIFT); 320 321 rk_clrsetreg(base + pll->con_offset, 322 (RK3036_PLLCON0_POSTDIV1_MASK | 323 RK3036_PLLCON0_FBDIV_MASK), 324 (rate->postdiv1 << RK3036_PLLCON0_POSTDIV1_SHIFT) | 325 rate->fbdiv); 326 rk_clrsetreg(base + pll->con_offset + 0x4, 327 (RK3036_PLLCON1_POSTDIV2_MASK | 328 RK3036_PLLCON1_REFDIV_MASK), 329 (rate->postdiv2 << RK3036_PLLCON1_POSTDIV2_SHIFT | 330 rate->refdiv << RK3036_PLLCON1_REFDIV_SHIFT)); 331 if (!rate->dsmpd) { 332 rk_clrsetreg(base + pll->con_offset + 0x4, 333 RK3036_PLLCON1_DSMPD_MASK, 334 rate->dsmpd << RK3036_PLLCON1_DSMPD_SHIFT); 335 writel((readl(base + pll->con_offset + 0x8) & 336 (~RK3036_PLLCON2_FRAC_MASK)) | 337 (rate->frac << RK3036_PLLCON2_FRAC_SHIFT), 338 base + pll->con_offset + 0x8); 339 } 340 341 /* Power Up */ 342 rk_clrreg(base + pll->con_offset + 0x4, 343 1 << RK3036_PLLCON1_PWRDOWN_SHIFT); 344 345 /* waiting for pll lock */ 346 while (!(readl(base + pll->con_offset + 0x4) & (1 << pll->lock_shift))) 347 udelay(1); 348 349 rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift, 350 RKCLK_PLL_MODE_NORMAL << pll->mode_shift); 351 debug("PLL at %p: con0=%x con1= %x con2= %x mode= %x\n", 352 pll, readl(base + pll->con_offset), 353 readl(base + pll->con_offset + 0x4), 354 readl(base + pll->con_offset + 0x8), 355 readl(base + pll->mode_offset)); 356 357 return 0; 358} 359 360static ulong rk3036_pll_get_rate(struct rockchip_pll_clock *pll, 361 void __iomem *base, ulong pll_id) 362{ 363 u32 refdiv, fbdiv, postdiv1, postdiv2, dsmpd, frac; 364 u32 con = 0, shift, mask; 365 ulong rate; 366 367 con = readl(base + pll->mode_offset); 368 shift = pll->mode_shift; 369 mask = pll->mode_mask << shift; 370 371 switch ((con & mask) >> shift) { 372 case RKCLK_PLL_MODE_SLOW: 373 return OSC_HZ; 374 case RKCLK_PLL_MODE_NORMAL: 375 /* normal mode */ 376 con = readl(base + pll->con_offset); 377 postdiv1 = (con & RK3036_PLLCON0_POSTDIV1_MASK) >> 378 RK3036_PLLCON0_POSTDIV1_SHIFT; 379 fbdiv = (con & RK3036_PLLCON0_FBDIV_MASK) >> 380 RK3036_PLLCON0_FBDIV_SHIFT; 381 con = readl(base + pll->con_offset + 0x4); 382 postdiv2 = (con & RK3036_PLLCON1_POSTDIV2_MASK) >> 383 RK3036_PLLCON1_POSTDIV2_SHIFT; 384 refdiv = (con & RK3036_PLLCON1_REFDIV_MASK) >> 385 RK3036_PLLCON1_REFDIV_SHIFT; 386 dsmpd = (con & RK3036_PLLCON1_DSMPD_MASK) >> 387 RK3036_PLLCON1_DSMPD_SHIFT; 388 con = readl(base + pll->con_offset + 0x8); 389 frac = (con & RK3036_PLLCON2_FRAC_MASK) >> 390 RK3036_PLLCON2_FRAC_SHIFT; 391 rate = (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000; 392 if (dsmpd == 0) { 393 u64 frac_rate = OSC_HZ * (u64)frac; 394 395 do_div(frac_rate, refdiv); 396 frac_rate >>= 24; 397 do_div(frac_rate, postdiv1); 398 do_div(frac_rate, postdiv1); 399 rate += frac_rate; 400 } 401 return rate; 402 case RKCLK_PLL_MODE_DEEP: 403 default: 404 return 32768; 405 } 406} 407 408#define RK3588_PLLCON(i) ((i) * 0x4) 409#define RK3588_PLLCON0_M_MASK 0x3ff << 0 410#define RK3588_PLLCON0_M_SHIFT 0 411#define RK3588_PLLCON1_P_MASK 0x3f << 0 412#define RK3588_PLLCON1_P_SHIFT 0 413#define RK3588_PLLCON1_S_MASK 0x7 << 6 414#define RK3588_PLLCON1_S_SHIFT 6 415#define RK3588_PLLCON2_K_MASK 0xffff 416#define RK3588_PLLCON2_K_SHIFT 0 417#define RK3588_PLLCON1_PWRDOWN BIT(13) 418#define RK3588_PLLCON6_LOCK_STATUS BIT(15) 419#define RK3588_B0PLL_CLKSEL_CON(i) ((i) * 0x4 + 0x50000 + 0x300) 420#define RK3588_B1PLL_CLKSEL_CON(i) ((i) * 0x4 + 0x52000 + 0x300) 421#define RK3588_LPLL_CLKSEL_CON(i) ((i) * 0x4 + 0x58000 + 0x300) 422#define RK3588_CORE_DIV_MASK 0x1f 423#define RK3588_CORE_L02_DIV_SHIFT 0 424#define RK3588_CORE_L13_DIV_SHIFT 7 425#define RK3588_CORE_B02_DIV_SHIFT 8 426#define RK3588_CORE_B13_DIV_SHIFT 0 427 428static int rk3588_pll_set_rate(struct rockchip_pll_clock *pll, 429 void __iomem *base, ulong pll_id, 430 ulong drate) 431{ 432 const struct rockchip_pll_rate_table *rate; 433 434 rate = rockchip_get_pll_settings(pll, drate); 435 if (!rate) { 436 printf("%s unsupported rate\n", __func__); 437 return -EINVAL; 438 } 439 440 debug("%s: rate settings for %lu p: %d, m: %d, s: %d, k: %d\n", 441 __func__, rate->rate, rate->p, rate->m, rate->s, rate->k); 442 443 /* 444 * When power on or changing PLL setting, 445 * we must force PLL into slow mode to ensure output stable clock. 446 */ 447 if (pll_id == 3) 448 rk_clrsetreg(base + 0x84c, 0x1 << 1, 0x1 << 1); 449 450 rk_clrsetreg(base + pll->mode_offset, 451 pll->mode_mask << pll->mode_shift, 452 RKCLK_PLL_MODE_SLOW << pll->mode_shift); 453 if (pll_id == 0) 454 rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(0), 455 pll->mode_mask << 6, 456 RKCLK_PLL_MODE_SLOW << 6); 457 else if (pll_id == 1) 458 rk_clrsetreg(base + RK3588_B1PLL_CLKSEL_CON(0), 459 pll->mode_mask << 6, 460 RKCLK_PLL_MODE_SLOW << 6); 461 else if (pll_id == 2) 462 rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(5), 463 pll->mode_mask << 14, 464 RKCLK_PLL_MODE_SLOW << 14); 465 466 /* Power down */ 467 rk_setreg(base + pll->con_offset + RK3588_PLLCON(1), 468 RK3588_PLLCON1_PWRDOWN); 469 470 rk_clrsetreg(base + pll->con_offset, 471 RK3588_PLLCON0_M_MASK, 472 (rate->m << RK3588_PLLCON0_M_SHIFT)); 473 rk_clrsetreg(base + pll->con_offset + RK3588_PLLCON(1), 474 (RK3588_PLLCON1_P_MASK | 475 RK3588_PLLCON1_S_MASK), 476 (rate->p << RK3588_PLLCON1_P_SHIFT | 477 rate->s << RK3588_PLLCON1_S_SHIFT)); 478 if (rate->k) { 479 rk_clrsetreg(base + pll->con_offset + RK3588_PLLCON(2), 480 RK3588_PLLCON2_K_MASK, 481 rate->k << RK3588_PLLCON2_K_SHIFT); 482 } 483 /* Power up */ 484 rk_clrreg(base + pll->con_offset + RK3588_PLLCON(1), 485 RK3588_PLLCON1_PWRDOWN); 486 487 /* waiting for pll lock */ 488 while (!(readl(base + pll->con_offset + RK3588_PLLCON(6)) & 489 RK3588_PLLCON6_LOCK_STATUS)) { 490 udelay(1); 491 debug("%s: wait pll lock, pll_id=%ld\n", __func__, pll_id); 492 } 493 494 rk_clrsetreg(base + pll->mode_offset, pll->mode_mask << pll->mode_shift, 495 RKCLK_PLL_MODE_NORMAL << pll->mode_shift); 496 if (pll_id == 0) { 497 rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(0), 498 pll->mode_mask << 6, 499 2 << 6); 500 rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(0), 501 RK3588_CORE_DIV_MASK << RK3588_CORE_B02_DIV_SHIFT, 502 0 << RK3588_CORE_B02_DIV_SHIFT); 503 rk_clrsetreg(base + RK3588_B0PLL_CLKSEL_CON(1), 504 RK3588_CORE_DIV_MASK << RK3588_CORE_B13_DIV_SHIFT, 505 0 << RK3588_CORE_B13_DIV_SHIFT); 506 } else if (pll_id == 1) { 507 rk_clrsetreg(base + RK3588_B1PLL_CLKSEL_CON(0), 508 pll->mode_mask << 6, 509 2 << 6); 510 rk_clrsetreg(base + RK3588_B1PLL_CLKSEL_CON(0), 511 RK3588_CORE_DIV_MASK << RK3588_CORE_B02_DIV_SHIFT, 512 0 << RK3588_CORE_B02_DIV_SHIFT); 513 rk_clrsetreg(base + RK3588_B1PLL_CLKSEL_CON(1), 514 RK3588_CORE_DIV_MASK << RK3588_CORE_B13_DIV_SHIFT, 515 0 << RK3588_CORE_B13_DIV_SHIFT); 516 } else if (pll_id == 2) { 517 rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(5), 518 pll->mode_mask << 14, 519 2 << 14); 520 rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(6), 521 RK3588_CORE_DIV_MASK << RK3588_CORE_L13_DIV_SHIFT, 522 0 << RK3588_CORE_L13_DIV_SHIFT); 523 rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(6), 524 RK3588_CORE_DIV_MASK << RK3588_CORE_L02_DIV_SHIFT, 525 0 << RK3588_CORE_L02_DIV_SHIFT); 526 rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(7), 527 RK3588_CORE_DIV_MASK << RK3588_CORE_L13_DIV_SHIFT, 528 0 << RK3588_CORE_L13_DIV_SHIFT); 529 rk_clrsetreg(base + RK3588_LPLL_CLKSEL_CON(7), 530 RK3588_CORE_DIV_MASK << RK3588_CORE_L02_DIV_SHIFT, 531 0 << RK3588_CORE_L02_DIV_SHIFT); 532 } 533 534 if (pll_id == 3) 535 rk_clrsetreg(base + 0x84c, 0x1 << 1, 0); 536 537 debug("PLL at %p: con0=%x con1= %x con2= %x mode= %x\n", 538 pll, readl(base + pll->con_offset), 539 readl(base + pll->con_offset + 0x4), 540 readl(base + pll->con_offset + 0x8), 541 readl(base + pll->mode_offset)); 542 543 return 0; 544} 545 546static ulong rk3588_pll_get_rate(struct rockchip_pll_clock *pll, 547 void __iomem *base, ulong pll_id) 548{ 549 u32 m, p, s, k; 550 u32 con = 0, shift, mode; 551 u64 rate, postdiv; 552 553 con = readl(base + pll->mode_offset); 554 shift = pll->mode_shift; 555 if (pll_id == 8) 556 mode = RKCLK_PLL_MODE_NORMAL; 557 else 558 mode = (con & (pll->mode_mask << shift)) >> shift; 559 switch (mode) { 560 case RKCLK_PLL_MODE_SLOW: 561 return OSC_HZ; 562 case RKCLK_PLL_MODE_NORMAL: 563 /* normal mode */ 564 con = readl(base + pll->con_offset); 565 m = (con & RK3588_PLLCON0_M_MASK) >> 566 RK3588_PLLCON0_M_SHIFT; 567 con = readl(base + pll->con_offset + RK3588_PLLCON(1)); 568 p = (con & RK3588_PLLCON1_P_MASK) >> 569 RK3036_PLLCON0_FBDIV_SHIFT; 570 s = (con & RK3588_PLLCON1_S_MASK) >> 571 RK3588_PLLCON1_S_SHIFT; 572 con = readl(base + pll->con_offset + RK3588_PLLCON(2)); 573 k = (con & RK3588_PLLCON2_K_MASK) >> 574 RK3588_PLLCON2_K_SHIFT; 575 576 rate = OSC_HZ / p; 577 rate *= m; 578 if (k & BIT(15)) { 579 /* fractional mode */ 580 u64 frac_rate64; 581 582 k = (~(k - 1)) & RK3588_PLLCON2_K_MASK; 583 frac_rate64 = OSC_HZ * k; 584 postdiv = p; 585 postdiv *= 65536; 586 do_div(frac_rate64, postdiv); 587 rate -= frac_rate64; 588 } else { 589 /* fractional mode */ 590 u64 frac_rate64 = OSC_HZ * k; 591 592 postdiv = p; 593 postdiv *= 65536; 594 do_div(frac_rate64, postdiv); 595 rate += frac_rate64; 596 } 597 rate = rate >> s; 598 return rate; 599 case RKCLK_PLL_MODE_DEEP: 600 default: 601 return 32768; 602 } 603} 604 605ulong rockchip_pll_get_rate(struct rockchip_pll_clock *pll, 606 void __iomem *base, 607 ulong pll_id) 608{ 609 ulong rate = 0; 610 611 switch (pll->type) { 612 case pll_rk3036: 613 pll->mode_mask = PLL_MODE_MASK; 614 rate = rk3036_pll_get_rate(pll, base, pll_id); 615 break; 616 case pll_rk3328: 617 pll->mode_mask = PLL_RK3328_MODE_MASK; 618 rate = rk3036_pll_get_rate(pll, base, pll_id); 619 break; 620 case pll_rk3588: 621 pll->mode_mask = PLL_MODE_MASK; 622 rate = rk3588_pll_get_rate(pll, base, pll_id); 623 break; 624 default: 625 printf("%s: Unknown pll type for pll clk %ld\n", 626 __func__, pll_id); 627 } 628 return rate; 629} 630 631int rockchip_pll_set_rate(struct rockchip_pll_clock *pll, 632 void __iomem *base, ulong pll_id, 633 ulong drate) 634{ 635 int ret = 0; 636 637 if (rockchip_pll_get_rate(pll, base, pll_id) == drate) 638 return 0; 639 640 switch (pll->type) { 641 case pll_rk3036: 642 pll->mode_mask = PLL_MODE_MASK; 643 ret = rk3036_pll_set_rate(pll, base, pll_id, drate); 644 break; 645 case pll_rk3328: 646 pll->mode_mask = PLL_RK3328_MODE_MASK; 647 ret = rk3036_pll_set_rate(pll, base, pll_id, drate); 648 break; 649 case pll_rk3588: 650 pll->mode_mask = PLL_MODE_MASK; 651 ret = rk3588_pll_set_rate(pll, base, pll_id, drate); 652 break; 653 default: 654 printf("%s: Unknown pll type for pll clk %ld\n", 655 __func__, pll_id); 656 } 657 return ret; 658} 659 660const struct rockchip_cpu_rate_table * 661rockchip_get_cpu_settings(struct rockchip_cpu_rate_table *cpu_table, 662 ulong rate) 663{ 664 struct rockchip_cpu_rate_table *ps = cpu_table; 665 666 while (ps->rate) { 667 if (ps->rate == rate) 668 break; 669 ps++; 670 } 671 if (ps->rate != rate) 672 return NULL; 673 else 674 return ps; 675} 676