1 /* 2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd 3 * 4 * SPDX-License-Identifier: GPL-2.0 5 */ 6 7 #include <common.h> 8 #include <clk-uclass.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <syscon.h> 12 #include <asm/io.h> 13 #include <asm/arch/clock.h> 14 #include <asm/arch/cru_rk322x.h> 15 #include <asm/arch/hardware.h> 16 #include <dm/lists.h> 17 #include <dt-bindings/clock/rk3228-cru.h> 18 #include <linux/log2.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 23 24 #ifndef CONFIG_SPL_BUILD 25 #define RK322x_CLK_DUMP(_id, _name, _iscru) \ 26 { \ 27 .id = _id, \ 28 .name = _name, \ 29 .is_cru = _iscru, \ 30 } 31 #endif 32 33 static struct rockchip_pll_rate_table rk322x_pll_rates[] = { 34 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ 35 RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), 36 #ifndef CONFIG_SPL_BUILD 37 RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), 38 RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), 39 #endif 40 RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), 41 RK3036_PLL_RATE(800000000, 1, 100, 3, 1, 1, 0), 42 RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0), 43 #ifndef CONFIG_SPL_BUILD 44 RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), 45 RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0), 46 RK3036_PLL_RATE(400000000, 1, 50, 3, 1, 1, 0), 47 #endif 48 { /* sentinel */ }, 49 }; 50 51 #define RK322x_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \ 52 { \ 53 .rate = _rate##U, \ 54 .aclk_div = _aclk_div, \ 55 .pclk_div = _pclk_div, \ 56 } 57 58 static struct rockchip_cpu_rate_table rk322x_cpu_rates[] = { 59 RK322x_CPUCLK_RATE(1200000000, 1, 5), 60 RK322x_CPUCLK_RATE(1008000000, 1, 5), 61 RK322x_CPUCLK_RATE(816000000, 1, 3), 62 RK322x_CPUCLK_RATE(600000000, 1, 3), 63 }; 64 65 #ifndef CONFIG_SPL_BUILD 66 static const struct rk322x_clk_info clks_dump[] = { 67 RK322x_CLK_DUMP(PLL_APLL, "apll", true), 68 RK322x_CLK_DUMP(PLL_DPLL, "dpll", true), 69 RK322x_CLK_DUMP(PLL_CPLL, "cpll", true), 70 RK322x_CLK_DUMP(PLL_GPLL, "gpll", true), 71 RK322x_CLK_DUMP(ARMCLK, "armclk", true), 72 RK322x_CLK_DUMP(ACLK_CPU, "aclk_bus", true), 73 RK322x_CLK_DUMP(HCLK_CPU, "hclk_bus", true), 74 RK322x_CLK_DUMP(PCLK_CPU, "pclk_bus", true), 75 RK322x_CLK_DUMP(ACLK_PERI, "aclk_peri", true), 76 RK322x_CLK_DUMP(HCLK_PERI, "hclk_peri", true), 77 RK322x_CLK_DUMP(PCLK_PERI, "pclk_peri", true), 78 }; 79 #endif 80 81 static struct rockchip_pll_clock rk322x_pll_clks[] = { 82 [APLL] = PLL(pll_rk3036, PLL_APLL, RK2928_PLL_CON(0), 83 RK2928_MODE_CON, 0, 10, 0, rk322x_pll_rates), 84 [DPLL] = PLL(pll_rk3036, PLL_DPLL, RK2928_PLL_CON(3), 85 RK2928_MODE_CON, 4, 10, 0, rk322x_pll_rates), 86 [CPLL] = PLL(pll_rk3036, PLL_CPLL, RK2928_PLL_CON(6), 87 RK2928_MODE_CON, 8, 10, 0, rk322x_pll_rates), 88 [GPLL] = PLL(pll_rk3036, PLL_GPLL, RK2928_PLL_CON(9), 89 RK2928_MODE_CON, 12, 10, 0, rk322x_pll_rates), 90 }; 91 92 static ulong rk322x_armclk_set_clk(struct rk322x_clk_priv *priv, ulong hz) 93 { 94 struct rk322x_cru *cru = priv->cru; 95 const struct rockchip_cpu_rate_table *rate; 96 ulong old_rate; 97 98 rate = rockchip_get_cpu_settings(rk322x_cpu_rates, hz); 99 if (!rate) { 100 printf("%s unsupported rate\n", __func__); 101 return -EINVAL; 102 } 103 104 /* 105 * select apll as cpu/core clock pll source and 106 * set up dependent divisors for PERI and ACLK clocks. 107 * core hz : apll = 1:1 108 */ 109 old_rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL], 110 priv->cru, APLL); 111 if (old_rate > hz) { 112 if (rockchip_pll_set_rate(&rk322x_pll_clks[APLL], 113 priv->cru, APLL, hz)) 114 return -EINVAL; 115 rk_clrsetreg(&cru->cru_clksel_con[0], 116 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK, 117 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 118 0 << CORE_DIV_CON_SHIFT); 119 rk_clrsetreg(&cru->cru_clksel_con[1], 120 CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK, 121 rate->aclk_div << CORE_ACLK_DIV_SHIFT | 122 rate->pclk_div << CORE_PERI_DIV_SHIFT); 123 } else if (old_rate < hz) { 124 rk_clrsetreg(&cru->cru_clksel_con[1], 125 CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK, 126 rate->aclk_div << CORE_ACLK_DIV_SHIFT | 127 rate->pclk_div << CORE_PERI_DIV_SHIFT); 128 rk_clrsetreg(&cru->cru_clksel_con[0], 129 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK, 130 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 131 0 << CORE_DIV_CON_SHIFT); 132 if (rockchip_pll_set_rate(&rk322x_pll_clks[APLL], 133 priv->cru, APLL, hz)) 134 return -EINVAL; 135 } 136 137 return rockchip_pll_get_rate(&rk322x_pll_clks[APLL], priv->cru, APLL); 138 } 139 140 static ulong rk322x_mmc_get_clk(struct rk322x_clk_priv *priv, 141 int periph) 142 { 143 struct rk322x_cru *cru = priv->cru; 144 uint src_rate; 145 uint div, mux; 146 u32 con; 147 148 switch (periph) { 149 case HCLK_EMMC: 150 case SCLK_EMMC: 151 case SCLK_EMMC_SAMPLE: 152 con = readl(&cru->cru_clksel_con[11]); 153 mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT; 154 con = readl(&cru->cru_clksel_con[12]); 155 div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; 156 break; 157 case HCLK_SDMMC: 158 case SCLK_SDMMC: 159 case SCLK_SDMMC_SAMPLE: 160 con = readl(&cru->cru_clksel_con[11]); 161 mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT; 162 div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT; 163 break; 164 case SCLK_SDIO: 165 case SCLK_SDIO_SAMPLE: 166 con = readl(&cru->cru_clksel_con[11]); 167 mux = (con & SDIO_PLL_MASK) >> SDIO_PLL_SHIFT; 168 con = readl(&cru->cru_clksel_con[12]); 169 div = (con & SDIO_DIV_MASK) >> SDIO_DIV_SHIFT; 170 break; 171 default: 172 return -EINVAL; 173 } 174 175 src_rate = mux == EMMC_SEL_24M ? OSC_HZ : priv->gpll_hz; 176 return DIV_TO_RATE(src_rate, div) / 2; 177 } 178 179 #ifndef CONFIG_SPL_BUILD 180 static ulong rk322x_mac_set_clk(struct rk322x_clk_priv *priv, uint freq) 181 { 182 struct rk322x_cru *cru = priv->cru; 183 ulong ret; 184 185 /* 186 * The gmac clock can be derived either from an external clock 187 * or can be generated from internally by a divider from SCLK_MAC. 188 */ 189 if (readl(&cru->cru_clksel_con[5]) & BIT(5)) { 190 /* An external clock will always generate the right rate... */ 191 ret = freq; 192 } else { 193 u32 con = readl(&cru->cru_clksel_con[5]); 194 ulong pll_rate; 195 u8 div; 196 197 if ((con >> MAC_PLL_SEL_SHIFT) & MAC_PLL_SEL_MASK) 198 pll_rate = priv->gpll_hz; 199 else 200 /* CPLL is not set */ 201 return -EPERM; 202 203 div = DIV_ROUND_UP(pll_rate, freq) - 1; 204 if (div <= 0x1f) 205 rk_clrsetreg(&cru->cru_clksel_con[5], CLK_MAC_DIV_MASK, 206 div << CLK_MAC_DIV_SHIFT); 207 else 208 debug("Unsupported div for gmac:%d\n", div); 209 210 return DIV_TO_RATE(pll_rate, div); 211 } 212 213 return ret; 214 } 215 #endif 216 217 static ulong rk322x_mmc_set_clk(struct rk322x_clk_priv *priv, 218 int periph, uint freq) 219 { 220 struct rk322x_cru *cru = priv->cru; 221 int src_clk_div; 222 int mux; 223 224 /* mmc clock defaulg div 2 internal, need provide double in cru */ 225 src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, freq); 226 227 if (src_clk_div > 128) { 228 src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq); 229 assert(src_clk_div - 1 < 128); 230 mux = EMMC_SEL_24M; 231 } else { 232 mux = EMMC_SEL_GPLL; 233 } 234 235 switch (periph) { 236 case HCLK_EMMC: 237 case SCLK_EMMC: 238 case SCLK_EMMC_SAMPLE: 239 rk_clrsetreg(&cru->cru_clksel_con[11], 240 EMMC_PLL_MASK, 241 mux << EMMC_PLL_SHIFT); 242 rk_clrsetreg(&cru->cru_clksel_con[12], 243 EMMC_DIV_MASK, 244 (src_clk_div - 1) << EMMC_DIV_SHIFT); 245 break; 246 case HCLK_SDMMC: 247 case SCLK_SDMMC: 248 case SCLK_SDMMC_SAMPLE: 249 rk_clrsetreg(&cru->cru_clksel_con[11], 250 MMC0_PLL_MASK | MMC0_DIV_MASK, 251 mux << MMC0_PLL_SHIFT | 252 (src_clk_div - 1) << MMC0_DIV_SHIFT); 253 break; 254 case SCLK_SDIO: 255 case SCLK_SDIO_SAMPLE: 256 rk_clrsetreg(&cru->cru_clksel_con[11], 257 SDIO_PLL_MASK, 258 mux << SDIO_PLL_SHIFT); 259 rk_clrsetreg(&cru->cru_clksel_con[12], 260 SDIO_DIV_MASK, 261 (src_clk_div - 1) << SDIO_DIV_SHIFT); 262 break; 263 default: 264 return -EINVAL; 265 } 266 267 return rk322x_mmc_get_clk(priv, periph); 268 } 269 270 static ulong rk322x_bus_get_clk(struct rk322x_clk_priv *priv, ulong clk_id) 271 { 272 struct rk322x_cru *cru = priv->cru; 273 u32 div, con, parent; 274 275 switch (clk_id) { 276 case ACLK_CPU: 277 con = readl(&cru->cru_clksel_con[0]); 278 div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT; 279 parent = priv->gpll_hz; 280 break; 281 case HCLK_CPU: 282 con = readl(&cru->cru_clksel_con[1]); 283 div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT; 284 parent = rk322x_bus_get_clk(priv, ACLK_CPU); 285 break; 286 case PCLK_CPU: 287 case PCLK_I2C0: 288 case PCLK_I2C1: 289 case PCLK_I2C2: 290 case PCLK_I2C3: 291 case PCLK_PWM: 292 con = readl(&cru->cru_clksel_con[1]); 293 div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT; 294 parent = rk322x_bus_get_clk(priv, ACLK_CPU); 295 break; 296 default: 297 return -ENOENT; 298 } 299 300 return DIV_TO_RATE(parent, div); 301 } 302 303 static ulong rk322x_bus_set_clk(struct rk322x_clk_priv *priv, 304 ulong clk_id, ulong hz) 305 { 306 struct rk322x_cru *cru = priv->cru; 307 int src_clk_div; 308 309 /* 310 * select gpll as pd_bus bus clock source and 311 * set up dependent divisors for PCLK/HCLK and ACLK clocks. 312 */ 313 switch (clk_id) { 314 case ACLK_CPU: 315 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 316 assert(src_clk_div - 1 < 32); 317 rk_clrsetreg(&cru->cru_clksel_con[0], 318 BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK, 319 BUS_ACLK_PLL_SEL_GPLL << BUS_ACLK_PLL_SEL_SHIFT | 320 (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT); 321 break; 322 case HCLK_CPU: 323 src_clk_div = DIV_ROUND_UP(rk322x_bus_get_clk(priv, 324 ACLK_CPU), 325 hz); 326 assert(src_clk_div - 1 < 4); 327 rk_clrsetreg(&cru->cru_clksel_con[1], 328 BUS_HCLK_DIV_MASK, 329 (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT); 330 break; 331 case PCLK_CPU: 332 src_clk_div = DIV_ROUND_UP(rk322x_bus_get_clk(priv, 333 ACLK_CPU), 334 hz); 335 assert(src_clk_div - 1 < 8); 336 rk_clrsetreg(&cru->cru_clksel_con[1], 337 BUS_PCLK_DIV_MASK, 338 (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT); 339 break; 340 default: 341 printf("do not support this bus freq\n"); 342 return -EINVAL; 343 } 344 345 return rk322x_bus_get_clk(priv, clk_id); 346 } 347 348 static ulong rk322x_peri_get_clk(struct rk322x_clk_priv *priv, ulong clk_id) 349 { 350 struct rk322x_cru *cru = priv->cru; 351 u32 div, con, parent; 352 353 switch (clk_id) { 354 case ACLK_PERI: 355 con = readl(&cru->cru_clksel_con[10]); 356 div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT; 357 parent = priv->gpll_hz; 358 break; 359 case HCLK_PERI: 360 con = readl(&cru->cru_clksel_con[10]); 361 div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT; 362 parent = rk322x_peri_get_clk(priv, ACLK_PERI); 363 break; 364 case PCLK_PERI: 365 con = readl(&cru->cru_clksel_con[10]); 366 div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT; 367 parent = rk322x_peri_get_clk(priv, ACLK_PERI); 368 break; 369 default: 370 return -ENOENT; 371 } 372 373 return DIV_TO_RATE(parent, div); 374 } 375 376 static ulong rk322x_peri_set_clk(struct rk322x_clk_priv *priv, 377 ulong clk_id, ulong hz) 378 { 379 struct rk322x_cru *cru = priv->cru; 380 int src_clk_div; 381 382 /* 383 * select gpll as pd_bus bus clock source and 384 * set up dependent divisors for PCLK/HCLK and ACLK clocks. 385 */ 386 switch (clk_id) { 387 case ACLK_PERI: 388 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 389 assert(src_clk_div - 1 < 32); 390 rk_clrsetreg(&cru->cru_clksel_con[10], 391 PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK, 392 PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT | 393 (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT); 394 break; 395 case HCLK_PERI: 396 src_clk_div = DIV_ROUND_UP(rk322x_peri_get_clk(priv, 397 ACLK_PERI), 398 hz); 399 assert(src_clk_div - 1 < 4); 400 rk_clrsetreg(&cru->cru_clksel_con[10], 401 PERI_HCLK_DIV_MASK, 402 (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT); 403 break; 404 case PCLK_PERI: 405 src_clk_div = DIV_ROUND_UP(rk322x_peri_get_clk(priv, 406 ACLK_PERI), 407 hz); 408 assert(src_clk_div - 1 < 8); 409 rk_clrsetreg(&cru->cru_clksel_con[10], 410 PERI_PCLK_DIV_MASK, 411 (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT); 412 break; 413 default: 414 printf("do not support this bus freq\n"); 415 return -EINVAL; 416 } 417 418 return rk322x_peri_get_clk(priv, clk_id); 419 } 420 421 #ifndef CONFIG_SPL_BUILD 422 static ulong rk322x_vop_get_clk(struct rk322x_clk_priv *priv, ulong clk_id) 423 { 424 struct rk322x_cru *cru = priv->cru; 425 u32 div, con, sel, parent; 426 427 switch (clk_id) { 428 case ACLK_VOP: 429 con = readl(&cru->cru_clksel_con[33]); 430 div = (con & ACLK_VOP_DIV_CON_MASK) >> ACLK_VOP_DIV_CON_SHIFT; 431 parent = priv->gpll_hz; 432 break; 433 case DCLK_VOP: 434 con = readl(&cru->cru_clksel_con[27]); 435 con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT; 436 if (con) { 437 sel = readl(&cru->cru_clksel_con[27]); 438 sel = (sel & DCLK_LCDC_PLL_SEL_MASK) >> 439 DCLK_LCDC_PLL_SEL_SHIFT; 440 if (sel) 441 parent = priv->cpll_hz; 442 else 443 parent = priv->gpll_hz; 444 445 con = readl(&cru->cru_clksel_con[27]); 446 div = (con & DCLK_LCDC_DIV_CON_MASK) >> 447 DCLK_LCDC_DIV_CON_SHIFT; 448 } else { 449 parent = priv->cpll_hz; 450 div = 1; 451 } 452 break; 453 default: 454 return -ENOENT; 455 } 456 457 return DIV_TO_RATE(parent, div); 458 } 459 460 static ulong rk322x_vop_set_clk(struct rk322x_clk_priv *priv, 461 ulong clk_id, uint hz) 462 { 463 struct rk322x_cru *cru = priv->cru; 464 int src_clk_div; 465 u32 con, parent; 466 467 switch (clk_id) { 468 case ACLK_VOP: 469 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 470 assert(src_clk_div - 1 < 32); 471 rk_clrsetreg(&cru->cru_clksel_con[33], 472 ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK, 473 ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT | 474 (src_clk_div - 1) << ACLK_VOP_DIV_CON_SHIFT); 475 break; 476 case DCLK_VOP: 477 con = readl(&cru->cru_clksel_con[27]); 478 con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT; 479 if (con) { 480 parent = readl(&cru->cru_clksel_con[27]); 481 parent = (parent & DCLK_LCDC_PLL_SEL_MASK) >> 482 DCLK_LCDC_PLL_SEL_SHIFT; 483 if (parent) 484 src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz); 485 else 486 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 487 488 assert(src_clk_div - 1 < 256); 489 rk_clrsetreg(&cru->cru_clksel_con[27], 490 DCLK_LCDC_DIV_CON_MASK, 491 (src_clk_div - 1) << 492 DCLK_LCDC_DIV_CON_SHIFT); 493 } 494 break; 495 default: 496 printf("do not support this vop freq\n"); 497 return -EINVAL; 498 } 499 500 return rk322x_vop_get_clk(priv, clk_id); 501 } 502 503 static ulong rk322x_crypto_get_clk(struct rk322x_clk_priv *priv, ulong clk_id) 504 { 505 struct rk322x_cru *cru = priv->cru; 506 u32 div, con, parent; 507 508 switch (clk_id) { 509 case SCLK_CRYPTO: 510 con = readl(&cru->cru_clksel_con[24]); 511 div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT; 512 parent = priv->gpll_hz; 513 break; 514 default: 515 return -ENOENT; 516 } 517 518 return DIV_TO_RATE(parent, div); 519 } 520 521 static ulong rk322x_crypto_set_clk(struct rk322x_clk_priv *priv, ulong clk_id, 522 ulong hz) 523 { 524 struct rk322x_cru *cru = priv->cru; 525 int src_clk_div; 526 527 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 528 assert(src_clk_div - 1 <= 31); 529 530 /* 531 * select gpll as crypto clock source and 532 * set up dependent divisors for crypto clocks. 533 */ 534 switch (clk_id) { 535 case SCLK_CRYPTO: 536 rk_clrsetreg(&cru->cru_clksel_con[24], 537 CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK, 538 CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT | 539 (src_clk_div - 1) << CRYPTO_DIV_SHIFT); 540 break; 541 default: 542 printf("do not support this peri freq\n"); 543 return -EINVAL; 544 } 545 546 return rk322x_crypto_get_clk(priv, clk_id); 547 } 548 #endif 549 550 static ulong rk322x_clk_get_rate(struct clk *clk) 551 { 552 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 553 ulong rate; 554 555 switch (clk->id) { 556 case PLL_APLL: 557 case PLL_DPLL: 558 case PLL_CPLL: 559 case PLL_GPLL: 560 rate = rockchip_pll_get_rate(&rk322x_pll_clks[clk->id - 1], 561 priv->cru, clk->id - 1); 562 break; 563 case ARMCLK: 564 rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL], 565 priv->cru, APLL); 566 break; 567 case HCLK_EMMC: 568 case SCLK_EMMC: 569 case SCLK_EMMC_SAMPLE: 570 case HCLK_SDMMC: 571 case SCLK_SDMMC: 572 case SCLK_SDMMC_SAMPLE: 573 case SCLK_SDIO: 574 case SCLK_SDIO_SAMPLE: 575 rate = rk322x_mmc_get_clk(priv, clk->id); 576 break; 577 case ACLK_CPU: 578 case HCLK_CPU: 579 case PCLK_CPU: 580 case PCLK_I2C0: 581 case PCLK_I2C1: 582 case PCLK_I2C2: 583 case PCLK_I2C3: 584 case PCLK_PWM: 585 rate = rk322x_bus_get_clk(priv, clk->id); 586 break; 587 case ACLK_PERI: 588 case HCLK_PERI: 589 case PCLK_PERI: 590 rate = rk322x_peri_get_clk(priv, clk->id); 591 break; 592 #ifndef CONFIG_SPL_BUILD 593 case DCLK_VOP: 594 case ACLK_VOP: 595 rate = rk322x_vop_get_clk(priv, clk->id); 596 break; 597 case SCLK_CRYPTO: 598 rate = rk322x_crypto_get_clk(priv, clk->id); 599 break; 600 #endif 601 default: 602 return -ENOENT; 603 } 604 605 return rate; 606 } 607 608 static ulong rk322x_clk_set_rate(struct clk *clk, ulong rate) 609 { 610 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 611 ulong ret; 612 613 switch (clk->id) { 614 case PLL_APLL: 615 case PLL_DPLL: 616 ret = rockchip_pll_set_rate(&rk322x_pll_clks[clk->id - 1], 617 priv->cru, clk->id - 1, rate); 618 break; 619 case PLL_CPLL: 620 ret = rockchip_pll_set_rate(&rk322x_pll_clks[CPLL], 621 priv->cru, CPLL, rate); 622 priv->cpll_hz = rate; 623 break; 624 case PLL_GPLL: 625 ret = rockchip_pll_set_rate(&rk322x_pll_clks[GPLL], 626 priv->cru, GPLL, rate); 627 priv->gpll_hz = rate; 628 break; 629 case ARMCLK: 630 ret = rk322x_armclk_set_clk(priv, rate); 631 break; 632 case HCLK_EMMC: 633 case SCLK_EMMC: 634 case SCLK_EMMC_SAMPLE: 635 case HCLK_SDMMC: 636 case SCLK_SDMMC: 637 case SCLK_SDMMC_SAMPLE: 638 case SCLK_SDIO: 639 case SCLK_SDIO_SAMPLE: 640 ret = rk322x_mmc_set_clk(priv, clk->id, rate); 641 break; 642 case SCLK_DDRC: 643 ret = rockchip_pll_set_rate(&rk322x_pll_clks[DPLL], 644 priv->cru, DPLL, rate); 645 break; 646 case ACLK_CPU: 647 case HCLK_CPU: 648 case PCLK_CPU: 649 ret = rk322x_bus_set_clk(priv, clk->id, rate); 650 break; 651 case ACLK_PERI: 652 case HCLK_PERI: 653 case PCLK_PERI: 654 ret = rk322x_peri_set_clk(priv, clk->id, rate); 655 break; 656 #ifndef CONFIG_SPL_BUILD 657 case SCLK_MAC: 658 ret = rk322x_mac_set_clk(priv, rate); 659 break; 660 case DCLK_VOP: 661 case ACLK_VOP: 662 ret = rk322x_vop_set_clk(priv, clk->id, rate); 663 break; 664 case SCLK_CRYPTO: 665 ret = rk322x_crypto_set_clk(priv, clk->id, rate); 666 break; 667 #endif 668 default: 669 return -ENOENT; 670 } 671 672 return ret; 673 } 674 675 #ifndef CONFIG_SPL_BUILD 676 static int rk322x_gmac_set_parent(struct clk *clk, struct clk *parent) 677 { 678 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 679 struct rk322x_cru *cru = priv->cru; 680 681 /* 682 * If the requested parent is in the same clock-controller and the id 683 * is SCLK_MAC_SRC ("sclk_gmac_src"), switch to the internal clock. 684 */ 685 if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_SRC)) { 686 debug("%s: switching RGMII to SCLK_MAC_SRC\n", __func__); 687 rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), 0); 688 return 0; 689 } 690 691 /* 692 * If the requested parent is in the same clock-controller and the id 693 * is SCLK_MAC_EXTCLK (sclk_mac_extclk), switch to the external clock. 694 */ 695 if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_EXTCLK)) { 696 debug("%s: switching RGMII to SCLK_MAC_EXTCLK\n", __func__); 697 rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), BIT(5)); 698 return 0; 699 } 700 701 return -EINVAL; 702 } 703 704 static int rk322x_gmac_extclk_set_parent(struct clk *clk, struct clk *parent) 705 { 706 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 707 const char *clock_output_name; 708 struct rk322x_cru *cru = priv->cru; 709 int ret; 710 711 ret = dev_read_string_index(parent->dev, "clock-output-names", 712 parent->id, &clock_output_name); 713 if (ret < 0) 714 return -ENODATA; 715 716 if (!strcmp(clock_output_name, "ext_gmac")) { 717 debug("%s: switching gmac extclk to ext_gmac\n", __func__); 718 rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), 0); 719 return 0; 720 } else if (!strcmp(clock_output_name, "phy_50m_out")) { 721 debug("%s: switching gmac extclk to phy_50m_out\n", __func__); 722 rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), BIT(10)); 723 return 0; 724 } 725 726 return -EINVAL; 727 } 728 729 static int rk322x_lcdc_set_parent(struct clk *clk, struct clk *parent) 730 { 731 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 732 733 if (parent->id == HDMIPHY) 734 rk_clrsetreg(&priv->cru->cru_clksel_con[27], 735 DCLK_LCDC_SEL_MASK, 736 DCLK_LCDC_SEL_HDMIPHY << DCLK_LCDC_SEL_SHIFT); 737 else if (parent->id == PLL_CPLL) 738 rk_clrsetreg(&priv->cru->cru_clksel_con[27], 739 DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK, 740 (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) | 741 (DCLK_LCDC_PLL_SEL_CPLL << 742 DCLK_LCDC_PLL_SEL_SHIFT)); 743 else 744 rk_clrsetreg(&priv->cru->cru_clksel_con[27], 745 DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK, 746 (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) | 747 (DCLK_LCDC_PLL_SEL_GPLL << 748 DCLK_LCDC_PLL_SEL_SHIFT)); 749 750 return 0; 751 } 752 #endif 753 754 static int rk322x_clk_set_parent(struct clk *clk, struct clk *parent) 755 { 756 switch (clk->id) { 757 #ifndef CONFIG_SPL_BUILD 758 case SCLK_MAC: 759 return rk322x_gmac_set_parent(clk, parent); 760 case SCLK_MAC_EXTCLK: 761 return rk322x_gmac_extclk_set_parent(clk, parent); 762 case DCLK_VOP: 763 return rk322x_lcdc_set_parent(clk, parent); 764 #endif 765 } 766 767 debug("%s: unsupported clk %ld\n", __func__, clk->id); 768 return -ENOENT; 769 } 770 771 #define ROCKCHIP_MMC_DELAY_SEL BIT(10) 772 #define ROCKCHIP_MMC_DEGREE_MASK 0x3 773 #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 774 #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) 775 776 #define PSECS_PER_SEC 1000000000000LL 777 /* 778 * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to 779 * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. 780 */ 781 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 782 783 int rk322x_mmc_get_phase(struct clk *clk) 784 { 785 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 786 struct rk322x_cru *cru = priv->cru; 787 u32 raw_value, delay_num; 788 u16 degrees = 0; 789 ulong rate; 790 791 rate = rk322x_clk_get_rate(clk); 792 793 if (rate < 0) 794 return rate; 795 796 if (clk->id == SCLK_EMMC_SAMPLE) 797 raw_value = readl(&cru->cru_emmc_con[1]); 798 else if (clk->id == SCLK_SDMMC_SAMPLE) 799 raw_value = readl(&cru->cru_sdmmc_con[1]); 800 else 801 raw_value = readl(&cru->cru_sdio_con[1]); 802 803 raw_value >>= 1; 804 degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; 805 806 if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { 807 /* degrees/delaynum * 10000 */ 808 unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * 809 36 * (rate / 1000000); 810 811 delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); 812 delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; 813 degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000); 814 } 815 816 return degrees % 360; 817 } 818 819 int rk322x_mmc_set_phase(struct clk *clk, u32 degrees) 820 { 821 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 822 struct rk322x_cru *cru = priv->cru; 823 u8 nineties, remainder, delay_num; 824 u32 raw_value, delay; 825 ulong rate; 826 827 rate = rk322x_clk_get_rate(clk); 828 829 if (rate < 0) 830 return rate; 831 832 nineties = degrees / 90; 833 remainder = (degrees % 90); 834 835 /* 836 * Convert to delay; do a little extra work to make sure we 837 * don't overflow 32-bit / 64-bit numbers. 838 */ 839 delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ 840 delay *= remainder; 841 delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * 842 (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); 843 844 delay_num = (u8)min_t(u32, delay, 255); 845 846 raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; 847 raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; 848 raw_value |= nineties; 849 850 raw_value <<= 1; 851 if (clk->id == SCLK_EMMC_SAMPLE) 852 writel(raw_value | 0xffff0000, &cru->cru_emmc_con[1]); 853 else if (clk->id == SCLK_SDMMC_SAMPLE) 854 writel(raw_value | 0xffff0000, &cru->cru_sdmmc_con[1]); 855 else 856 writel(raw_value | 0xffff0000, &cru->cru_sdio_con[1]); 857 858 debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n", 859 degrees, delay_num, raw_value, rk322x_mmc_get_phase(clk)); 860 861 return 0; 862 } 863 864 static int rk322x_clk_get_phase(struct clk *clk) 865 { 866 int ret; 867 868 debug("%s %ld\n", __func__, clk->id); 869 switch (clk->id) { 870 case SCLK_EMMC_SAMPLE: 871 case SCLK_SDMMC_SAMPLE: 872 case SCLK_SDIO_SAMPLE: 873 ret = rk322x_mmc_get_phase(clk); 874 break; 875 default: 876 return -ENOENT; 877 } 878 879 return ret; 880 } 881 882 static int rk322x_clk_set_phase(struct clk *clk, int degrees) 883 { 884 int ret; 885 886 debug("%s %ld\n", __func__, clk->id); 887 switch (clk->id) { 888 case SCLK_EMMC_SAMPLE: 889 case SCLK_SDMMC_SAMPLE: 890 case SCLK_SDIO_SAMPLE: 891 ret = rk322x_mmc_set_phase(clk, degrees); 892 break; 893 default: 894 return -ENOENT; 895 } 896 897 return ret; 898 } 899 900 static struct clk_ops rk322x_clk_ops = { 901 .get_rate = rk322x_clk_get_rate, 902 .set_rate = rk322x_clk_set_rate, 903 .set_parent = rk322x_clk_set_parent, 904 .get_phase = rk322x_clk_get_phase, 905 .set_phase = rk322x_clk_set_phase, 906 }; 907 908 static int rk322x_clk_ofdata_to_platdata(struct udevice *dev) 909 { 910 struct rk322x_clk_priv *priv = dev_get_priv(dev); 911 912 priv->cru = dev_read_addr_ptr(dev); 913 914 return 0; 915 } 916 917 #ifndef CONFIG_TPL_BUILD 918 static void rkclk_init(struct rk322x_clk_priv *priv) 919 { 920 struct rk322x_cru *cru = priv->cru; 921 922 if (rockchip_pll_get_rate(&rk322x_pll_clks[APLL], 923 priv->cru, APLL) != APLL_HZ) 924 rk322x_armclk_set_clk(priv, APLL_HZ); 925 926 priv->gpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[GPLL], 927 priv->cru, GPLL); 928 priv->cpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[CPLL], 929 priv->cru, CPLL); 930 931 /* before set pll set child div first */ 932 rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ / 4); 933 rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ / 4); 934 rk322x_mmc_set_clk(priv, SCLK_EMMC, 50000000); 935 rk322x_mmc_set_clk(priv, SCLK_SDMMC, 50000000); 936 rk322x_mmc_set_clk(priv, SCLK_SDIO, 50000000); 937 rk_clrsetreg(&cru->cru_clksel_con[2], (0x1 << 14) | 938 (0x1f << 8), (1 << 14) | (0xb << 8)); 939 rk_clrsetreg(&cru->cru_clksel_con[23], (0x1f << 0) | (0x1f << 8), 940 (0x1f << 0) | (5 << 8)); 941 rk_clrsetreg(&cru->cru_clksel_con[33], 942 ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK, 943 ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT | 944 3 << ACLK_VOP_DIV_CON_SHIFT); 945 rk_clrsetreg(&cru->cru_clksel_con[22], 0x1f << 0, 5 << 0); 946 rk_clrsetreg(&cru->cru_clksel_con[24], 0x1f << 0, 0xb << 0); 947 rk_clrsetreg(&cru->cru_clksel_con[28], (0x1f << 8) | (0x1f << 0), 948 (5 << 8) | (5 << 0)); 949 rk_clrsetreg(&cru->cru_clksel_con[31], (0x1f << 8) | (0x1f << 0), 950 (5 << 8) | (5 << 0)); 951 rk_clrsetreg(&cru->cru_clksel_con[32], 0x1f << 0, 5 << 0); 952 rk_clrsetreg(&cru->cru_clksel_con[33], (0x1f << 8) | (0x1f << 0), 953 (5 << 8) | (5 << 0)); 954 rk_clrsetreg(&cru->cru_clksel_con[34], (0x1f << 8) | (0x1f << 0), 955 (5 << 8) | (3 << 0)); 956 957 rockchip_pll_set_rate(&rk322x_pll_clks[GPLL], 958 priv->cru, GPLL, GPLL_HZ); 959 priv->gpll_hz = GPLL_HZ; 960 961 rockchip_pll_set_rate(&rk322x_pll_clks[CPLL], 962 priv->cru, CPLL, CPLL_HZ); 963 priv->cpll_hz = CPLL_HZ; 964 965 rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ); 966 rk322x_bus_set_clk(priv, HCLK_CPU, ACLK_BUS_HZ / 2); 967 rk322x_bus_set_clk(priv, PCLK_CPU, ACLK_BUS_HZ / 2); 968 rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ); 969 rk322x_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2); 970 rk322x_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2); 971 /*rk322x_mmc_set_clk(priv, SCLK_EMMC, rate);*/ 972 973 /* set usbphy and hdmiphy from phy */ 974 rk_clrsetreg(&cru->cru_misc_con, (0x1 << 13) | 975 (0x1 << 15), (0 << 15) | (0 << 13)); 976 } 977 #endif 978 979 static int rk322x_clk_probe(struct udevice *dev) 980 { 981 #ifndef CONFIG_TPL_BUILD 982 struct rk322x_clk_priv *priv = dev_get_priv(dev); 983 int ret = 0; 984 985 rkclk_init(priv); 986 ret = clk_set_defaults(dev); 987 if (ret) 988 debug("%s clk_set_defaults failed %d\n", __func__, ret); 989 #endif 990 return 0; 991 } 992 993 static int rk322x_clk_bind(struct udevice *dev) 994 { 995 int ret; 996 struct udevice *sys_child, *sf_child; 997 struct sysreset_reg *priv; 998 struct softreset_reg *sf_priv; 999 1000 /* The reset driver does not have a device node, so bind it here */ 1001 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 1002 &sys_child); 1003 if (ret) { 1004 debug("Warning: No sysreset driver: ret=%d\n", ret); 1005 } else { 1006 priv = malloc(sizeof(struct sysreset_reg)); 1007 priv->glb_srst_fst_value = offsetof(struct rk322x_cru, 1008 cru_glb_srst_fst_value); 1009 priv->glb_srst_snd_value = offsetof(struct rk322x_cru, 1010 cru_glb_srst_snd_value); 1011 sys_child->priv = priv; 1012 } 1013 1014 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 1015 dev_ofnode(dev), &sf_child); 1016 if (ret) { 1017 debug("Warning: No rockchip reset driver: ret=%d\n", ret); 1018 } else { 1019 sf_priv = malloc(sizeof(struct softreset_reg)); 1020 sf_priv->sf_reset_offset = offsetof(struct rk322x_cru, 1021 cru_softrst_con[0]); 1022 sf_priv->sf_reset_num = 9; 1023 sf_child->priv = sf_priv; 1024 } 1025 1026 return 0; 1027 } 1028 1029 static const struct udevice_id rk322x_clk_ids[] = { 1030 { .compatible = "rockchip,rk3228-cru" }, 1031 { } 1032 }; 1033 1034 U_BOOT_DRIVER(rockchip_rk322x_cru) = { 1035 .name = "clk_rk322x", 1036 .id = UCLASS_CLK, 1037 .of_match = rk322x_clk_ids, 1038 .priv_auto_alloc_size = sizeof(struct rk322x_clk_priv), 1039 .ofdata_to_platdata = rk322x_clk_ofdata_to_platdata, 1040 .ops = &rk322x_clk_ops, 1041 .bind = rk322x_clk_bind, 1042 .probe = rk322x_clk_probe, 1043 }; 1044 1045 #ifndef CONFIG_SPL_BUILD 1046 /** 1047 * soc_clk_dump() - Print clock frequencies 1048 * Returns zero on success 1049 * 1050 * Implementation for the clk dump command. 1051 */ 1052 int soc_clk_dump(void) 1053 { 1054 struct udevice *cru_dev; 1055 const struct rk322x_clk_info *clk_dump; 1056 struct clk clk; 1057 unsigned long clk_count = ARRAY_SIZE(clks_dump); 1058 unsigned long rate; 1059 int i, ret; 1060 1061 ret = uclass_get_device_by_driver(UCLASS_CLK, 1062 DM_GET_DRIVER(rockchip_rk322x_cru), 1063 &cru_dev); 1064 if (ret) { 1065 printf("%s failed to get cru device\n", __func__); 1066 return ret; 1067 } 1068 1069 printf("CLK:"); 1070 for (i = 0; i < clk_count; i++) { 1071 clk_dump = &clks_dump[i]; 1072 if (clk_dump->name) { 1073 clk.id = clk_dump->id; 1074 if (clk_dump->is_cru) 1075 ret = clk_request(cru_dev, &clk); 1076 if (ret < 0) 1077 return ret; 1078 1079 rate = clk_get_rate(&clk); 1080 clk_free(&clk); 1081 if (i == 0) { 1082 if (rate < 0) 1083 printf("%10s%20s\n", clk_dump->name, 1084 "unknown"); 1085 else 1086 printf("%10s%20lu Hz\n", clk_dump->name, 1087 rate); 1088 } else { 1089 if (rate < 0) 1090 printf("%14s%20s\n", clk_dump->name, 1091 "unknown"); 1092 else 1093 printf("%14s%20lu Hz\n", clk_dump->name, 1094 rate); 1095 } 1096 } 1097 } 1098 1099 return 0; 1100 } 1101 #endif 1102 1103