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 < 31); 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 < 3); 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 < 7); 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 < 31); 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 < 3); 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 < 7); 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 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 468 assert(src_clk_div - 1 < 31); 469 470 switch (clk_id) { 471 case ACLK_VOP: 472 rk_clrsetreg(&cru->cru_clksel_con[33], 473 ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK, 474 ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT | 475 (src_clk_div - 1) << ACLK_VOP_DIV_CON_SHIFT); 476 break; 477 case DCLK_VOP: 478 con = readl(&cru->cru_clksel_con[27]); 479 con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT; 480 if (con) { 481 parent = readl(&cru->cru_clksel_con[27]); 482 parent = (parent & DCLK_LCDC_PLL_SEL_MASK) >> 483 DCLK_LCDC_PLL_SEL_SHIFT; 484 if (parent) 485 src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz); 486 else 487 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 488 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 #endif 503 504 static ulong rk322x_clk_get_rate(struct clk *clk) 505 { 506 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 507 ulong rate; 508 509 switch (clk->id) { 510 case PLL_APLL: 511 case PLL_DPLL: 512 case PLL_CPLL: 513 case PLL_GPLL: 514 rate = rockchip_pll_get_rate(&rk322x_pll_clks[clk->id - 1], 515 priv->cru, clk->id - 1); 516 break; 517 case ARMCLK: 518 rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL], 519 priv->cru, APLL); 520 break; 521 case HCLK_EMMC: 522 case SCLK_EMMC: 523 case SCLK_EMMC_SAMPLE: 524 case HCLK_SDMMC: 525 case SCLK_SDMMC: 526 case SCLK_SDMMC_SAMPLE: 527 case SCLK_SDIO: 528 case SCLK_SDIO_SAMPLE: 529 rate = rk322x_mmc_get_clk(priv, clk->id); 530 break; 531 case ACLK_CPU: 532 case HCLK_CPU: 533 case PCLK_CPU: 534 case PCLK_I2C0: 535 case PCLK_I2C1: 536 case PCLK_I2C2: 537 case PCLK_I2C3: 538 case PCLK_PWM: 539 rate = rk322x_bus_get_clk(priv, clk->id); 540 break; 541 case ACLK_PERI: 542 case HCLK_PERI: 543 case PCLK_PERI: 544 rate = rk322x_peri_get_clk(priv, clk->id); 545 break; 546 #ifndef CONFIG_SPL_BUILD 547 case DCLK_VOP: 548 case ACLK_VOP: 549 rate = rk322x_vop_get_clk(priv, clk->id); 550 break; 551 #endif 552 default: 553 return -ENOENT; 554 } 555 556 return rate; 557 } 558 559 static ulong rk322x_clk_set_rate(struct clk *clk, ulong rate) 560 { 561 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 562 ulong ret; 563 564 switch (clk->id) { 565 case PLL_APLL: 566 case PLL_DPLL: 567 ret = rockchip_pll_set_rate(&rk322x_pll_clks[clk->id - 1], 568 priv->cru, clk->id - 1, rate); 569 break; 570 case PLL_CPLL: 571 ret = rockchip_pll_set_rate(&rk322x_pll_clks[CPLL], 572 priv->cru, CPLL, rate); 573 priv->cpll_hz = rate; 574 break; 575 case PLL_GPLL: 576 ret = rockchip_pll_set_rate(&rk322x_pll_clks[GPLL], 577 priv->cru, GPLL, rate); 578 priv->gpll_hz = rate; 579 break; 580 case ARMCLK: 581 ret = rk322x_armclk_set_clk(priv, rate); 582 break; 583 case HCLK_EMMC: 584 case SCLK_EMMC: 585 case SCLK_EMMC_SAMPLE: 586 case HCLK_SDMMC: 587 case SCLK_SDMMC: 588 case SCLK_SDMMC_SAMPLE: 589 case SCLK_SDIO: 590 case SCLK_SDIO_SAMPLE: 591 ret = rk322x_mmc_set_clk(priv, clk->id, rate); 592 break; 593 case SCLK_DDRC: 594 ret = rockchip_pll_set_rate(&rk322x_pll_clks[DPLL], 595 priv->cru, DPLL, rate); 596 break; 597 case ACLK_CPU: 598 case HCLK_CPU: 599 case PCLK_CPU: 600 ret = rk322x_bus_set_clk(priv, clk->id, rate); 601 break; 602 case ACLK_PERI: 603 case HCLK_PERI: 604 case PCLK_PERI: 605 ret = rk322x_peri_set_clk(priv, clk->id, rate); 606 break; 607 #ifndef CONFIG_SPL_BUILD 608 case SCLK_MAC: 609 ret = rk322x_mac_set_clk(priv, rate); 610 break; 611 case DCLK_VOP: 612 case ACLK_VOP: 613 ret = rk322x_vop_set_clk(priv, clk->id, rate); 614 break; 615 #endif 616 default: 617 return -ENOENT; 618 } 619 620 return ret; 621 } 622 623 #ifndef CONFIG_SPL_BUILD 624 static int rk322x_gmac_set_parent(struct clk *clk, struct clk *parent) 625 { 626 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 627 struct rk322x_cru *cru = priv->cru; 628 629 /* 630 * If the requested parent is in the same clock-controller and the id 631 * is SCLK_MAC_SRC ("sclk_gmac_src"), switch to the internal clock. 632 */ 633 if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_SRC)) { 634 debug("%s: switching RGMII to SCLK_MAC_SRC\n", __func__); 635 rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), 0); 636 return 0; 637 } 638 639 /* 640 * If the requested parent is in the same clock-controller and the id 641 * is SCLK_MAC_EXTCLK (sclk_mac_extclk), switch to the external clock. 642 */ 643 if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_EXTCLK)) { 644 debug("%s: switching RGMII to SCLK_MAC_EXTCLK\n", __func__); 645 rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), BIT(5)); 646 return 0; 647 } 648 649 return -EINVAL; 650 } 651 652 static int rk322x_gmac_extclk_set_parent(struct clk *clk, struct clk *parent) 653 { 654 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 655 const char *clock_output_name; 656 struct rk322x_cru *cru = priv->cru; 657 int ret; 658 659 ret = dev_read_string_index(parent->dev, "clock-output-names", 660 parent->id, &clock_output_name); 661 if (ret < 0) 662 return -ENODATA; 663 664 if (!strcmp(clock_output_name, "ext_gmac")) { 665 debug("%s: switching gmac extclk to ext_gmac\n", __func__); 666 rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), 0); 667 return 0; 668 } else if (!strcmp(clock_output_name, "phy_50m_out")) { 669 debug("%s: switching gmac extclk to phy_50m_out\n", __func__); 670 rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), BIT(10)); 671 return 0; 672 } 673 674 return -EINVAL; 675 } 676 677 static int rk322x_lcdc_set_parent(struct clk *clk, struct clk *parent) 678 { 679 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 680 681 if (parent->id == HDMIPHY) 682 rk_clrsetreg(&priv->cru->cru_clksel_con[27], 683 DCLK_LCDC_SEL_MASK, 684 DCLK_LCDC_SEL_HDMIPHY << DCLK_LCDC_SEL_SHIFT); 685 else if (parent->id == PLL_CPLL) 686 rk_clrsetreg(&priv->cru->cru_clksel_con[27], 687 DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK, 688 (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) | 689 (DCLK_LCDC_PLL_SEL_CPLL << 690 DCLK_LCDC_PLL_SEL_SHIFT)); 691 else 692 rk_clrsetreg(&priv->cru->cru_clksel_con[27], 693 DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK, 694 (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) | 695 (DCLK_LCDC_PLL_SEL_GPLL << 696 DCLK_LCDC_PLL_SEL_SHIFT)); 697 698 return 0; 699 } 700 #endif 701 702 static int rk322x_clk_set_parent(struct clk *clk, struct clk *parent) 703 { 704 switch (clk->id) { 705 #ifndef CONFIG_SPL_BUILD 706 case SCLK_MAC: 707 return rk322x_gmac_set_parent(clk, parent); 708 case SCLK_MAC_EXTCLK: 709 return rk322x_gmac_extclk_set_parent(clk, parent); 710 case DCLK_VOP: 711 return rk322x_lcdc_set_parent(clk, parent); 712 #endif 713 } 714 715 debug("%s: unsupported clk %ld\n", __func__, clk->id); 716 return -ENOENT; 717 } 718 719 #define ROCKCHIP_MMC_DELAY_SEL BIT(10) 720 #define ROCKCHIP_MMC_DEGREE_MASK 0x3 721 #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 722 #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) 723 724 #define PSECS_PER_SEC 1000000000000LL 725 /* 726 * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to 727 * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. 728 */ 729 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 730 731 int rk322x_mmc_get_phase(struct clk *clk) 732 { 733 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 734 struct rk322x_cru *cru = priv->cru; 735 u32 raw_value, delay_num; 736 u16 degrees = 0; 737 ulong rate; 738 739 rate = rk322x_clk_get_rate(clk); 740 741 if (rate < 0) 742 return rate; 743 744 if (clk->id == SCLK_EMMC_SAMPLE) 745 raw_value = readl(&cru->cru_emmc_con[1]); 746 else if (clk->id == SCLK_SDMMC_SAMPLE) 747 raw_value = readl(&cru->cru_sdmmc_con[1]); 748 else 749 raw_value = readl(&cru->cru_sdio_con[1]); 750 751 raw_value >>= 1; 752 degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; 753 754 if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { 755 /* degrees/delaynum * 10000 */ 756 unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * 757 36 * (rate / 1000000); 758 759 delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); 760 delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; 761 degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000); 762 } 763 764 return degrees % 360; 765 } 766 767 int rk322x_mmc_set_phase(struct clk *clk, u32 degrees) 768 { 769 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev); 770 struct rk322x_cru *cru = priv->cru; 771 u8 nineties, remainder, delay_num; 772 u32 raw_value, delay; 773 ulong rate; 774 775 rate = rk322x_clk_get_rate(clk); 776 777 if (rate < 0) 778 return rate; 779 780 nineties = degrees / 90; 781 remainder = (degrees % 90); 782 783 /* 784 * Convert to delay; do a little extra work to make sure we 785 * don't overflow 32-bit / 64-bit numbers. 786 */ 787 delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ 788 delay *= remainder; 789 delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * 790 (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); 791 792 delay_num = (u8)min_t(u32, delay, 255); 793 794 raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; 795 raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; 796 raw_value |= nineties; 797 798 raw_value <<= 1; 799 if (clk->id == SCLK_EMMC_SAMPLE) 800 writel(raw_value | 0xffff0000, &cru->cru_emmc_con[1]); 801 else if (clk->id == SCLK_SDMMC_SAMPLE) 802 writel(raw_value | 0xffff0000, &cru->cru_sdmmc_con[1]); 803 else 804 writel(raw_value | 0xffff0000, &cru->cru_sdio_con[1]); 805 806 debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n", 807 degrees, delay_num, raw_value, rk322x_mmc_get_phase(clk)); 808 809 return 0; 810 } 811 812 static int rk322x_clk_get_phase(struct clk *clk) 813 { 814 int ret; 815 816 debug("%s %ld\n", __func__, clk->id); 817 switch (clk->id) { 818 case SCLK_EMMC_SAMPLE: 819 case SCLK_SDMMC_SAMPLE: 820 case SCLK_SDIO_SAMPLE: 821 ret = rk322x_mmc_get_phase(clk); 822 break; 823 default: 824 return -ENOENT; 825 } 826 827 return ret; 828 } 829 830 static int rk322x_clk_set_phase(struct clk *clk, int degrees) 831 { 832 int ret; 833 834 debug("%s %ld\n", __func__, clk->id); 835 switch (clk->id) { 836 case SCLK_EMMC_SAMPLE: 837 case SCLK_SDMMC_SAMPLE: 838 case SCLK_SDIO_SAMPLE: 839 ret = rk322x_mmc_set_phase(clk, degrees); 840 break; 841 default: 842 return -ENOENT; 843 } 844 845 return ret; 846 } 847 848 static struct clk_ops rk322x_clk_ops = { 849 .get_rate = rk322x_clk_get_rate, 850 .set_rate = rk322x_clk_set_rate, 851 .set_parent = rk322x_clk_set_parent, 852 .get_phase = rk322x_clk_get_phase, 853 .set_phase = rk322x_clk_set_phase, 854 }; 855 856 static int rk322x_clk_ofdata_to_platdata(struct udevice *dev) 857 { 858 struct rk322x_clk_priv *priv = dev_get_priv(dev); 859 860 priv->cru = dev_read_addr_ptr(dev); 861 862 return 0; 863 } 864 865 static void rkclk_init(struct rk322x_clk_priv *priv) 866 { 867 struct rk322x_cru *cru = priv->cru; 868 869 if (rockchip_pll_get_rate(&rk322x_pll_clks[APLL], 870 priv->cru, APLL) != APLL_HZ) 871 rk322x_armclk_set_clk(priv, APLL_HZ); 872 873 priv->gpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[GPLL], 874 priv->cru, GPLL); 875 priv->cpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[CPLL], 876 priv->cru, CPLL); 877 878 /* before set pll set child div first */ 879 rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ / 4); 880 rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ / 4); 881 rk322x_mmc_set_clk(priv, SCLK_EMMC, 50000000); 882 rk322x_mmc_set_clk(priv, SCLK_SDMMC, 50000000); 883 rk322x_mmc_set_clk(priv, SCLK_SDIO, 50000000); 884 rk_clrsetreg(&cru->cru_clksel_con[2], (0x1 << 14) | 885 (0x1f << 8), (1 << 14) | (0xb << 8)); 886 rk_clrsetreg(&cru->cru_clksel_con[23], (0x1f << 0) | (0x1f << 8), 887 (0x1f << 0) | (5 << 8)); 888 rk_clrsetreg(&cru->cru_clksel_con[33], 889 ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK, 890 ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT | 891 3 << ACLK_VOP_DIV_CON_SHIFT); 892 rk_clrsetreg(&cru->cru_clksel_con[22], 0x1f << 0, 5 << 0); 893 rk_clrsetreg(&cru->cru_clksel_con[24], 0x1f << 0, 0xb << 0); 894 rk_clrsetreg(&cru->cru_clksel_con[28], (0x1f << 8) | (0x1f << 0), 895 (5 << 8) | (5 << 0)); 896 rk_clrsetreg(&cru->cru_clksel_con[31], (0x1f << 8) | (0x1f << 0), 897 (5 << 8) | (5 << 0)); 898 rk_clrsetreg(&cru->cru_clksel_con[32], 0x1f << 0, 5 << 0); 899 rk_clrsetreg(&cru->cru_clksel_con[33], (0x1f << 8) | (0x1f << 0), 900 (5 << 8) | (5 << 0)); 901 rk_clrsetreg(&cru->cru_clksel_con[34], (0x1f << 8) | (0x1f << 0), 902 (5 << 8) | (3 << 0)); 903 904 rockchip_pll_set_rate(&rk322x_pll_clks[GPLL], 905 priv->cru, GPLL, GPLL_HZ); 906 priv->gpll_hz = GPLL_HZ; 907 908 rockchip_pll_set_rate(&rk322x_pll_clks[CPLL], 909 priv->cru, CPLL, CPLL_HZ); 910 priv->cpll_hz = CPLL_HZ; 911 912 rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ); 913 rk322x_bus_set_clk(priv, HCLK_CPU, ACLK_BUS_HZ / 2); 914 rk322x_bus_set_clk(priv, PCLK_CPU, ACLK_BUS_HZ / 2); 915 rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ); 916 rk322x_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2); 917 rk322x_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2); 918 /*rk322x_mmc_set_clk(priv, SCLK_EMMC, rate);*/ 919 920 /* set usbphy and hdmiphy from phy */ 921 rk_clrsetreg(&cru->cru_misc_con, (0x1 << 13) | 922 (0x1 << 15), (0 << 15) | (0 << 13)); 923 } 924 925 static int rk322x_clk_probe(struct udevice *dev) 926 { 927 struct rk322x_clk_priv *priv = dev_get_priv(dev); 928 929 rkclk_init(priv); 930 931 return 0; 932 } 933 934 static int rk322x_clk_bind(struct udevice *dev) 935 { 936 int ret; 937 struct udevice *sys_child, *sf_child; 938 struct sysreset_reg *priv; 939 struct softreset_reg *sf_priv; 940 941 /* The reset driver does not have a device node, so bind it here */ 942 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 943 &sys_child); 944 if (ret) { 945 debug("Warning: No sysreset driver: ret=%d\n", ret); 946 } else { 947 priv = malloc(sizeof(struct sysreset_reg)); 948 priv->glb_srst_fst_value = offsetof(struct rk322x_cru, 949 cru_glb_srst_fst_value); 950 priv->glb_srst_snd_value = offsetof(struct rk322x_cru, 951 cru_glb_srst_snd_value); 952 sys_child->priv = priv; 953 } 954 955 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 956 dev_ofnode(dev), &sf_child); 957 if (ret) { 958 debug("Warning: No rockchip reset driver: ret=%d\n", ret); 959 } else { 960 sf_priv = malloc(sizeof(struct softreset_reg)); 961 sf_priv->sf_reset_offset = offsetof(struct rk322x_cru, 962 cru_softrst_con[0]); 963 sf_priv->sf_reset_num = 9; 964 sf_child->priv = sf_priv; 965 } 966 967 return 0; 968 } 969 970 static const struct udevice_id rk322x_clk_ids[] = { 971 { .compatible = "rockchip,rk3228-cru" }, 972 { } 973 }; 974 975 U_BOOT_DRIVER(rockchip_rk322x_cru) = { 976 .name = "clk_rk322x", 977 .id = UCLASS_CLK, 978 .of_match = rk322x_clk_ids, 979 .priv_auto_alloc_size = sizeof(struct rk322x_clk_priv), 980 .ofdata_to_platdata = rk322x_clk_ofdata_to_platdata, 981 .ops = &rk322x_clk_ops, 982 .bind = rk322x_clk_bind, 983 .probe = rk322x_clk_probe, 984 }; 985 986 #ifndef CONFIG_SPL_BUILD 987 /** 988 * soc_clk_dump() - Print clock frequencies 989 * Returns zero on success 990 * 991 * Implementation for the clk dump command. 992 */ 993 int soc_clk_dump(void) 994 { 995 struct udevice *cru_dev; 996 const struct rk322x_clk_info *clk_dump; 997 struct clk clk; 998 unsigned long clk_count = ARRAY_SIZE(clks_dump); 999 unsigned long rate; 1000 int i, ret; 1001 1002 ret = uclass_get_device_by_driver(UCLASS_CLK, 1003 DM_GET_DRIVER(rockchip_rk322x_cru), 1004 &cru_dev); 1005 if (ret) { 1006 printf("%s failed to get cru device\n", __func__); 1007 return ret; 1008 } 1009 1010 printf("CLK:"); 1011 for (i = 0; i < clk_count; i++) { 1012 clk_dump = &clks_dump[i]; 1013 if (clk_dump->name) { 1014 clk.id = clk_dump->id; 1015 if (clk_dump->is_cru) 1016 ret = clk_request(cru_dev, &clk); 1017 if (ret < 0) 1018 return ret; 1019 1020 rate = clk_get_rate(&clk); 1021 clk_free(&clk); 1022 if (i == 0) { 1023 if (rate < 0) 1024 printf("%10s%20s\n", clk_dump->name, 1025 "unknown"); 1026 else 1027 printf("%10s%20lu Hz\n", clk_dump->name, 1028 rate); 1029 } else { 1030 if (rate < 0) 1031 printf("%14s%20s\n", clk_dump->name, 1032 "unknown"); 1033 else 1034 printf("%14s%20lu Hz\n", clk_dump->name, 1035 rate); 1036 } 1037 } 1038 } 1039 1040 return 0; 1041 } 1042 #endif 1043 1044