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_rk3128.h> 15 #include <asm/arch/hardware.h> 16 #include <bitfield.h> 17 #include <dm/lists.h> 18 #include <dt-bindings/clock/rk3128-cru.h> 19 #include <linux/log2.h> 20 21 DECLARE_GLOBAL_DATA_PTR; 22 23 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 24 25 #ifndef CONFIG_SPL_BUILD 26 #define RK3128_CLK_DUMP(_id, _name, _iscru) \ 27 { \ 28 .id = _id, \ 29 .name = _name, \ 30 .is_cru = _iscru, \ 31 } 32 #endif 33 34 static struct rockchip_pll_rate_table rk3128_pll_rates[] = { 35 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ 36 #ifndef CONFIG_SPL_BUILD 37 RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), 38 RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), 39 RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), 40 #endif 41 RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), 42 RK3036_PLL_RATE(800000000, 1, 200, 6, 1, 1, 0), 43 RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0), 44 RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0), 45 RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0), 46 { /* sentinel */ }, 47 }; 48 49 #define RK3128_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \ 50 { \ 51 .rate = _rate##U, \ 52 .aclk_div = _aclk_div, \ 53 .pclk_div = _pclk_div, \ 54 } 55 56 static struct rockchip_cpu_rate_table rk3128_cpu_rates[] = { 57 RK3128_CPUCLK_RATE(1200000000, 1, 5), 58 RK3128_CPUCLK_RATE(1008000000, 1, 5), 59 RK3128_CPUCLK_RATE(816000000, 1, 3), 60 RK3128_CPUCLK_RATE(600000000, 1, 3), 61 }; 62 63 #ifndef CONFIG_SPL_BUILD 64 static const struct rk3128_clk_info clks_dump[] = { 65 RK3128_CLK_DUMP(PLL_APLL, "apll", true), 66 RK3128_CLK_DUMP(PLL_DPLL, "dpll", true), 67 RK3128_CLK_DUMP(PLL_CPLL, "cpll", true), 68 RK3128_CLK_DUMP(PLL_GPLL, "gpll", true), 69 RK3128_CLK_DUMP(ARMCLK, "armclk", true), 70 RK3128_CLK_DUMP(ACLK_CPU, "aclk_cpu", true), 71 RK3128_CLK_DUMP(HCLK_CPU, "hclk_cpu", true), 72 RK3128_CLK_DUMP(PCLK_CPU, "pclk_cpu", true), 73 RK3128_CLK_DUMP(ACLK_PERI, "aclk_peri", true), 74 RK3128_CLK_DUMP(HCLK_PERI, "hclk_peri", true), 75 RK3128_CLK_DUMP(PCLK_PERI, "pclk_peri", true), 76 }; 77 #endif 78 79 static struct rockchip_pll_clock rk3128_pll_clks[] = { 80 [APLL] = PLL(pll_rk3036, PLL_APLL, RK2928_PLL_CON(0), 81 RK2928_MODE_CON, 0, 10, 0, rk3128_pll_rates), 82 [DPLL] = PLL(pll_rk3036, PLL_DPLL, RK2928_PLL_CON(4), 83 RK2928_MODE_CON, 4, 10, 0, NULL), 84 [CPLL] = PLL(pll_rk3036, PLL_CPLL, RK2928_PLL_CON(8), 85 RK2928_MODE_CON, 8, 10, 0, rk3128_pll_rates), 86 [GPLL] = PLL(pll_rk3036, PLL_GPLL, RK2928_PLL_CON(12), 87 RK2928_MODE_CON, 12, 10, 0, rk3128_pll_rates), 88 }; 89 90 static ulong rk3128_armclk_set_clk(struct rk3128_clk_priv *priv, ulong hz) 91 { 92 struct rk3128_cru *cru = priv->cru; 93 const struct rockchip_cpu_rate_table *rate; 94 ulong old_rate; 95 96 rate = rockchip_get_cpu_settings(rk3128_cpu_rates, hz); 97 if (!rate) { 98 printf("%s unsupported rate\n", __func__); 99 return -EINVAL; 100 } 101 102 /* 103 * select apll as cpu/core clock pll source and 104 * set up dependent divisors for PERI and ACLK clocks. 105 * core hz : apll = 1:1 106 */ 107 old_rate = rockchip_pll_get_rate(&rk3128_pll_clks[APLL], 108 priv->cru, APLL); 109 if (old_rate > hz) { 110 if (rockchip_pll_set_rate(&rk3128_pll_clks[APLL], 111 priv->cru, APLL, hz)) 112 return -EINVAL; 113 rk_clrsetreg(&cru->cru_clksel_con[0], 114 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK, 115 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 116 0 << CORE_DIV_CON_SHIFT); 117 rk_clrsetreg(&cru->cru_clksel_con[1], 118 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, 119 rate->aclk_div << CORE_ACLK_DIV_SHIFT | 120 rate->pclk_div << CORE_DBG_DIV_SHIFT); 121 } else if (old_rate < hz) { 122 rk_clrsetreg(&cru->cru_clksel_con[1], 123 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, 124 rate->aclk_div << CORE_ACLK_DIV_SHIFT | 125 rate->pclk_div << CORE_DBG_DIV_SHIFT); 126 rk_clrsetreg(&cru->cru_clksel_con[0], 127 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK, 128 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 129 0 << CORE_DIV_CON_SHIFT); 130 if (rockchip_pll_set_rate(&rk3128_pll_clks[APLL], 131 priv->cru, APLL, hz)) 132 return -EINVAL; 133 } 134 135 return rockchip_pll_get_rate(&rk3128_pll_clks[APLL], priv->cru, APLL); 136 } 137 138 static ulong rockchip_mmc_get_clk(struct rk3128_clk_priv *priv, 139 int periph) 140 { 141 struct rk3128_cru *cru = priv->cru; 142 uint src_rate; 143 uint div, mux; 144 u32 con; 145 146 switch (periph) { 147 case HCLK_EMMC: 148 case SCLK_EMMC: 149 case SCLK_EMMC_SAMPLE: 150 con = readl(&cru->cru_clksel_con[12]); 151 mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT; 152 div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; 153 break; 154 case HCLK_SDMMC: 155 case SCLK_SDMMC: 156 case SCLK_SDMMC_SAMPLE: 157 con = readl(&cru->cru_clksel_con[11]); 158 mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT; 159 div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT; 160 break; 161 case HCLK_SDIO: 162 case SCLK_SDIO: 163 case SCLK_SDIO_SAMPLE: 164 con = readl(&cru->cru_clksel_con[12]); 165 mux = (con & SDIO_PLL_MASK) >> SDIO_PLL_SHIFT; 166 div = (con & SDIO_DIV_MASK) >> SDIO_DIV_SHIFT; 167 break; 168 default: 169 return -EINVAL; 170 } 171 172 src_rate = mux == EMMC_SEL_24M ? OSC_HZ : priv->gpll_hz; 173 return DIV_TO_RATE(src_rate, div); 174 } 175 176 static ulong rockchip_mmc_set_clk(struct rk3128_clk_priv *priv, 177 int periph, uint freq) 178 { 179 struct rk3128_cru *cru = priv->cru; 180 int src_clk_div; 181 int mux; 182 183 /* mmc clock defaulg div 2 internal, need provide double in cru */ 184 src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, freq); 185 186 if (src_clk_div > 128) { 187 src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq); 188 mux = EMMC_SEL_24M; 189 } else { 190 mux = EMMC_SEL_GPLL; 191 } 192 193 switch (periph) { 194 case HCLK_EMMC: 195 case SCLK_EMMC: 196 rk_clrsetreg(&cru->cru_clksel_con[12], 197 EMMC_PLL_MASK | EMMC_DIV_MASK, 198 mux << EMMC_PLL_SHIFT | 199 (src_clk_div - 1) << EMMC_DIV_SHIFT); 200 break; 201 case HCLK_SDMMC: 202 case SCLK_SDMMC: 203 rk_clrsetreg(&cru->cru_clksel_con[11], 204 MMC0_PLL_MASK | MMC0_DIV_MASK, 205 mux << MMC0_PLL_SHIFT | 206 (src_clk_div - 1) << MMC0_DIV_SHIFT); 207 break; 208 case HCLK_SDIO: 209 case SCLK_SDIO: 210 rk_clrsetreg(&cru->cru_clksel_con[12], 211 SDIO_PLL_MASK | SDIO_DIV_MASK, 212 mux << SDIO_PLL_SHIFT | 213 (src_clk_div - 1) << SDIO_DIV_SHIFT); 214 break; 215 default: 216 return -EINVAL; 217 } 218 219 return rockchip_mmc_get_clk(priv, periph); 220 } 221 222 static ulong rk3128_peri_get_clk(struct rk3128_clk_priv *priv, ulong clk_id) 223 { 224 struct rk3128_cru *cru = priv->cru; 225 u32 div, con, parent; 226 227 switch (clk_id) { 228 case ACLK_PERI: 229 con = readl(&cru->cru_clksel_con[10]); 230 div = (con & ACLK_PERI_DIV_MASK) >> ACLK_PERI_DIV_SHIFT; 231 parent = priv->gpll_hz; 232 break; 233 case PCLK_PERI: 234 case PCLK_I2C0: 235 case PCLK_I2C1: 236 case PCLK_I2C2: 237 case PCLK_I2C3: 238 case PCLK_PWM: 239 con = readl(&cru->cru_clksel_con[10]); 240 div = (con & PCLK_PERI_DIV_MASK) >> PCLK_PERI_DIV_SHIFT; 241 parent = rk3128_peri_get_clk(priv, ACLK_PERI); 242 break; 243 case HCLK_PERI: 244 con = readl(&cru->cru_clksel_con[10]); 245 div = (con & HCLK_PERI_DIV_MASK) >> HCLK_PERI_DIV_SHIFT; 246 parent = rk3128_peri_get_clk(priv, ACLK_PERI); 247 break; 248 default: 249 printf("do not support this peripheral bus\n"); 250 return -EINVAL; 251 } 252 253 return DIV_TO_RATE(parent, div); 254 } 255 256 static ulong rk3128_peri_set_clk(struct rk3128_clk_priv *priv, 257 ulong clk_id, uint hz) 258 { 259 struct rk3128_cru *cru = priv->cru; 260 int src_clk_div; 261 262 switch (clk_id) { 263 case ACLK_PERI: 264 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 265 assert(src_clk_div - 1 < 32); 266 rk_clrsetreg(&cru->cru_clksel_con[10], 267 PERI_PLL_SEL_MASK | ACLK_PERI_DIV_MASK, 268 PERI_PLL_SEL_GPLL << PERI_PLL_SEL_SHIFT | 269 (src_clk_div - 1) << ACLK_PERI_DIV_SHIFT); 270 break; 271 case PCLK_I2C0: 272 case PCLK_I2C1: 273 case PCLK_I2C2: 274 case PCLK_I2C3: 275 case PCLK_PWM: 276 case PCLK_PERI: 277 src_clk_div = DIV_ROUND_UP(rk3128_peri_get_clk(priv, 278 ACLK_PERI), 279 hz); 280 assert(src_clk_div - 1 < 3); 281 rk_clrsetreg(&cru->cru_clksel_con[10], 282 PCLK_PERI_DIV_MASK, 283 (src_clk_div - 1) << PCLK_PERI_DIV_SHIFT); 284 break; 285 case HCLK_PERI: 286 src_clk_div = DIV_ROUND_UP(rk3128_peri_get_clk(priv, 287 ACLK_PERI), 288 hz); 289 assert(src_clk_div - 1 < 7); 290 rk_clrsetreg(&cru->cru_clksel_con[10], 291 HCLK_PERI_DIV_MASK, 292 (src_clk_div - 1) << HCLK_PERI_DIV_SHIFT); 293 break; 294 default: 295 printf("do not support this peripheral bus\n"); 296 return -EINVAL; 297 } 298 299 return rk3128_peri_get_clk(priv, clk_id); 300 } 301 302 static ulong rk3128_bus_get_clk(struct rk3128_clk_priv *priv, ulong clk_id) 303 { 304 struct rk3128_cru *cru = priv->cru; 305 u32 div, con, parent; 306 307 switch (clk_id) { 308 case ACLK_CPU: 309 con = readl(&cru->cru_clksel_con[0]); 310 div = (con & ACLK_BUS_DIV_MASK) >> ACLK_BUS_DIV_SHIFT; 311 parent = priv->gpll_hz; 312 break; 313 case PCLK_CPU: 314 con = readl(&cru->cru_clksel_con[1]); 315 div = (con & PCLK_BUS_DIV_MASK) >> PCLK_BUS_DIV_SHIFT; 316 parent = rk3128_bus_get_clk(priv, ACLK_CPU); 317 break; 318 case HCLK_CPU: 319 con = readl(&cru->cru_clksel_con[1]); 320 div = (con & HCLK_BUS_DIV_MASK) >> HCLK_BUS_DIV_SHIFT; 321 parent = rk3128_bus_get_clk(priv, ACLK_CPU); 322 break; 323 default: 324 printf("do not support this peripheral bus\n"); 325 return -EINVAL; 326 } 327 328 return DIV_TO_RATE(parent, div); 329 } 330 331 static ulong rk3128_bus_set_clk(struct rk3128_clk_priv *priv, 332 ulong clk_id, uint hz) 333 { 334 struct rk3128_cru *cru = priv->cru; 335 int src_clk_div; 336 337 switch (clk_id) { 338 case ACLK_CPU: 339 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 340 assert(src_clk_div - 1 < 32); 341 rk_clrsetreg(&cru->cru_clksel_con[0], 342 BUS_PLL_SEL_MASK | ACLK_BUS_DIV_MASK, 343 BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT | 344 (src_clk_div - 1) << ACLK_BUS_DIV_SHIFT); 345 break; 346 case PCLK_CPU: 347 src_clk_div = DIV_ROUND_UP(rk3128_bus_get_clk(priv, 348 ACLK_CPU), 349 hz); 350 assert(src_clk_div - 1 < 3); 351 rk_clrsetreg(&cru->cru_clksel_con[1], 352 PCLK_BUS_DIV_MASK, 353 (src_clk_div - 1) << PCLK_BUS_DIV_SHIFT); 354 break; 355 case HCLK_CPU: 356 src_clk_div = DIV_ROUND_UP(rk3128_bus_get_clk(priv, 357 ACLK_CPU), 358 hz); 359 assert(src_clk_div - 1 < 7); 360 rk_clrsetreg(&cru->cru_clksel_con[1], 361 HCLK_BUS_DIV_MASK, 362 (src_clk_div - 1) << HCLK_BUS_DIV_SHIFT); 363 break; 364 default: 365 printf("do not support this peripheral bus\n"); 366 return -EINVAL; 367 } 368 369 return rk3128_bus_get_clk(priv, clk_id); 370 } 371 372 #ifndef CONFIG_SPL_BUILD 373 static ulong rk3128_saradc_get_clk(struct rk3128_clk_priv *priv) 374 { 375 struct rk3128_cru *cru = priv->cru; 376 u32 div, val; 377 378 val = readl(&cru->cru_clksel_con[24]); 379 div = bitfield_extract(val, SARADC_DIV_CON_SHIFT, 380 SARADC_DIV_CON_WIDTH); 381 382 return DIV_TO_RATE(OSC_HZ, div); 383 } 384 385 static ulong rk3128_saradc_set_clk(struct rk3128_clk_priv *priv, uint hz) 386 { 387 struct rk3128_cru *cru = priv->cru; 388 int src_clk_div; 389 390 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; 391 assert(src_clk_div < 128); 392 393 rk_clrsetreg(&cru->cru_clksel_con[24], 394 SARADC_DIV_CON_MASK, 395 src_clk_div << SARADC_DIV_CON_SHIFT); 396 397 return rk3128_saradc_get_clk(priv); 398 } 399 400 #define RK3128_LCDC_PLL_LIMIT 600000000 401 402 static ulong rk3128_vop_set_clk(struct rk3128_clk_priv *priv, 403 ulong clk_id, uint hz) 404 { 405 struct rk3128_cru *cru = priv->cru; 406 int src_clk_div; 407 408 src_clk_div = GPLL_HZ / hz; 409 assert(src_clk_div - 1 < 31); 410 411 switch (clk_id) { 412 case ACLK_LCDC0: 413 case ACLK_VIO0: 414 rk_clrsetreg(&cru->cru_clksel_con[31], 415 VIO0_PLL_MASK | VIO0_DIV_MASK, 416 VIO0_SEL_GPLL << VIO0_PLL_SHIFT | 417 (src_clk_div - 1) << VIO0_DIV_SHIFT); 418 break; 419 case ACLK_VIO1: 420 rk_clrsetreg(&cru->cru_clksel_con[31], 421 VIO1_PLL_MASK | VIO1_DIV_MASK, 422 VIO1_SEL_GPLL << VIO1_PLL_SHIFT | 423 (src_clk_div - 1) << VIO1_DIV_SHIFT); 424 break; 425 case DCLK_VOP: 426 src_clk_div = DIV_ROUND_UP(RK3128_LCDC_PLL_LIMIT, hz); 427 rockchip_pll_set_rate(&rk3128_pll_clks[CPLL], 428 priv->cru, CPLL, src_clk_div * hz); 429 rk_clrsetreg(&cru->cru_clksel_con[27], 430 DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_CON_MASK, 431 DCLK_VOP_PLL_SEL_CPLL << DCLK_VOP_SEL_SHIFT | 432 (src_clk_div - 1) << DCLK_VOP_DIV_CON_SHIFT); 433 break; 434 default: 435 printf("do not support this vop freq\n"); 436 return -EINVAL; 437 } 438 439 return hz; 440 } 441 442 static ulong rk3128_vop_get_rate(struct rk3128_clk_priv *priv, ulong clk_id) 443 { 444 struct rk3128_cru *cru = priv->cru; 445 u32 div, con, parent; 446 447 switch (clk_id) { 448 case ACLK_LCDC0: 449 case ACLK_VIO0: 450 con = readl(&cru->cru_clksel_con[31]); 451 div = con & 0x1f; 452 parent = GPLL_HZ; 453 break; 454 case ACLK_VIO1: 455 con = readl(&cru->cru_clksel_con[31]); 456 div = (con >> 8) & 0x1f; 457 parent = GPLL_HZ; 458 break; 459 case DCLK_VOP: 460 con = readl(&cru->cru_clksel_con[27]); 461 div = (con & DCLK_VOP_DIV_CON_MASK) >> DCLK_VOP_DIV_CON_SHIFT; 462 parent = rockchip_pll_get_rate(&rk3128_pll_clks[CPLL], 463 priv->cru, CPLL); 464 break; 465 default: 466 return -ENOENT; 467 } 468 return DIV_TO_RATE(parent, div); 469 } 470 #endif 471 472 static ulong rk3128_clk_get_rate(struct clk *clk) 473 { 474 struct rk3128_clk_priv *priv = dev_get_priv(clk->dev); 475 ulong rate = 0; 476 477 switch (clk->id) { 478 case PLL_APLL: 479 case PLL_DPLL: 480 case PLL_CPLL: 481 case PLL_GPLL: 482 rate = rockchip_pll_get_rate(&rk3128_pll_clks[clk->id - 1], 483 priv->cru, clk->id - 1); 484 break; 485 case ARMCLK: 486 rate = rockchip_pll_get_rate(&rk3128_pll_clks[APLL], 487 priv->cru, APLL); 488 break; 489 case HCLK_EMMC: 490 case SCLK_EMMC: 491 case HCLK_SDMMC: 492 case SCLK_SDMMC: 493 case HCLK_SDIO: 494 case SCLK_SDIO: 495 rate = rockchip_mmc_get_clk(priv, clk->id); 496 break; 497 case ACLK_PERI: 498 case HCLK_PERI: 499 case PCLK_PERI: 500 case PCLK_I2C0: 501 case PCLK_I2C1: 502 case PCLK_I2C2: 503 case PCLK_I2C3: 504 case PCLK_PWM: 505 rate = rk3128_peri_get_clk(priv, clk->id); 506 break; 507 case ACLK_CPU: 508 case HCLK_CPU: 509 case PCLK_CPU: 510 rate = rk3128_bus_get_clk(priv, clk->id); 511 break; 512 #ifndef CONFIG_SPL_BUILD 513 case SCLK_SARADC: 514 rate = rk3128_saradc_get_clk(priv); 515 break; 516 case DCLK_VOP: 517 case ACLK_VIO0: 518 case ACLK_VIO1: 519 case ACLK_LCDC0: 520 rate = rk3128_vop_get_rate(priv, clk->id); 521 break; 522 #endif 523 default: 524 return -ENOENT; 525 } 526 return rate; 527 } 528 529 static ulong rk3128_clk_set_rate(struct clk *clk, ulong rate) 530 { 531 struct rk3128_clk_priv *priv = dev_get_priv(clk->dev); 532 ulong ret; 533 534 switch (clk->id) { 535 case PLL_APLL: 536 case PLL_DPLL: 537 case PLL_CPLL: 538 ret = rockchip_pll_set_rate(&rk3128_pll_clks[clk->id - 1], 539 priv->cru, clk->id - 1, rate); 540 case PLL_GPLL: 541 ret = rockchip_pll_set_rate(&rk3128_pll_clks[GPLL], 542 priv->cru, GPLL, rate); 543 priv->gpll_hz = rate; 544 break; 545 case ARMCLK: 546 ret = rk3128_armclk_set_clk(priv, rate); 547 break; 548 case HCLK_EMMC: 549 case SCLK_EMMC: 550 case SCLK_EMMC_SAMPLE: 551 case HCLK_SDMMC: 552 case SCLK_SDMMC: 553 case SCLK_SDMMC_SAMPLE: 554 case HCLK_SDIO: 555 case SCLK_SDIO: 556 case SCLK_SDIO_SAMPLE: 557 ret = rockchip_mmc_set_clk(priv, clk->id, rate); 558 break; 559 case ACLK_PERI: 560 case PCLK_PERI: 561 case HCLK_PERI: 562 case PCLK_I2C0: 563 case PCLK_I2C1: 564 case PCLK_I2C2: 565 case PCLK_I2C3: 566 case PCLK_PWM: 567 ret = rk3128_peri_set_clk(priv, clk->id, rate); 568 break; 569 case ACLK_CPU: 570 case HCLK_CPU: 571 case PCLK_CPU: 572 ret = rk3128_bus_set_clk(priv, clk->id, rate); 573 break; 574 #ifndef CONFIG_SPL_BUILD 575 case SCLK_SARADC: 576 ret = rk3128_saradc_set_clk(priv, rate); 577 break; 578 case DCLK_VOP: 579 case ACLK_VIO0: 580 case ACLK_VIO1: 581 case ACLK_LCDC0: 582 ret = rk3128_vop_set_clk(priv, clk->id, rate); 583 break; 584 #endif 585 default: 586 return -ENOENT; 587 } 588 return ret; 589 } 590 591 static struct clk_ops rk3128_clk_ops = { 592 .get_rate = rk3128_clk_get_rate, 593 .set_rate = rk3128_clk_set_rate, 594 }; 595 596 static int rk3128_clk_ofdata_to_platdata(struct udevice *dev) 597 { 598 struct rk3128_clk_priv *priv = dev_get_priv(dev); 599 600 priv->cru = dev_read_addr_ptr(dev); 601 602 return 0; 603 } 604 605 static void rkclk_init(struct rk3128_clk_priv *priv) 606 { 607 if (rockchip_pll_get_rate(&rk3128_pll_clks[APLL], 608 priv->cru, APLL) != APLL_HZ) 609 rk3128_armclk_set_clk(priv, APLL_HZ); 610 611 priv->gpll_hz = rockchip_pll_get_rate(&rk3128_pll_clks[GPLL], 612 priv->cru, GPLL); 613 rk3128_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ / 2); 614 rk3128_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ / 2); 615 rockchip_pll_set_rate(&rk3128_pll_clks[GPLL], 616 priv->cru, GPLL, GPLL_HZ); 617 priv->gpll_hz = GPLL_HZ; 618 rk_clrsetreg(&priv->cru->cru_clksel_con[2], 619 NANDC_PLL_SEL_MASK | NANDC_CLK_DIV_MASK, 620 NANDC_PLL_SEL_GPLL << NANDC_PLL_SEL_SHIFT | 621 3 << NANDC_CLK_DIV_SHIFT); 622 rk3128_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ); 623 rk3128_bus_set_clk(priv, HCLK_CPU, ACLK_BUS_HZ / 2); 624 rk3128_bus_set_clk(priv, PCLK_CPU, ACLK_BUS_HZ / 2); 625 rk3128_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ); 626 rk3128_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2); 627 rk3128_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2); 628 } 629 630 static int rk3128_clk_probe(struct udevice *dev) 631 { 632 struct rk3128_clk_priv *priv = dev_get_priv(dev); 633 634 rkclk_init(priv); 635 636 return 0; 637 } 638 639 static int rk3128_clk_bind(struct udevice *dev) 640 { 641 int ret; 642 struct udevice *sys_child, *sf_child; 643 struct sysreset_reg *priv; 644 struct softreset_reg *sf_priv; 645 646 /* The reset driver does not have a device node, so bind it here */ 647 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 648 &sys_child); 649 if (ret) { 650 debug("Warning: No sysreset driver: ret=%d\n", ret); 651 } else { 652 priv = malloc(sizeof(struct sysreset_reg)); 653 priv->glb_srst_fst_value = offsetof(struct rk3128_cru, 654 cru_glb_srst_fst_value); 655 priv->glb_srst_snd_value = offsetof(struct rk3128_cru, 656 cru_glb_srst_snd_value); 657 sys_child->priv = priv; 658 } 659 660 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 661 dev_ofnode(dev), &sf_child); 662 if (ret) { 663 debug("Warning: No rockchip reset driver: ret=%d\n", ret); 664 } else { 665 sf_priv = malloc(sizeof(struct softreset_reg)); 666 sf_priv->sf_reset_offset = offsetof(struct rk3128_cru, 667 cru_softrst_con[0]); 668 sf_priv->sf_reset_num = 9; 669 sf_child->priv = sf_priv; 670 } 671 672 return 0; 673 } 674 675 static const struct udevice_id rk3128_clk_ids[] = { 676 { .compatible = "rockchip,rk3128-cru" }, 677 { .compatible = "rockchip,rk3126-cru" }, 678 { } 679 }; 680 681 U_BOOT_DRIVER(rockchip_rk3128_cru) = { 682 .name = "clk_rk3128", 683 .id = UCLASS_CLK, 684 .of_match = rk3128_clk_ids, 685 .priv_auto_alloc_size = sizeof(struct rk3128_clk_priv), 686 .ofdata_to_platdata = rk3128_clk_ofdata_to_platdata, 687 .ops = &rk3128_clk_ops, 688 .bind = rk3128_clk_bind, 689 .probe = rk3128_clk_probe, 690 }; 691 692 #ifndef CONFIG_SPL_BUILD 693 /** 694 * soc_clk_dump() - Print clock frequencies 695 * Returns zero on success 696 * 697 * Implementation for the clk dump command. 698 */ 699 int soc_clk_dump(void) 700 { 701 struct udevice *cru_dev; 702 const struct rk3128_clk_info *clk_dump; 703 struct clk clk; 704 unsigned long clk_count = ARRAY_SIZE(clks_dump); 705 unsigned long rate; 706 int i, ret; 707 708 ret = uclass_get_device_by_driver(UCLASS_CLK, 709 DM_GET_DRIVER(rockchip_rk3128_cru), 710 &cru_dev); 711 if (ret) { 712 printf("%s failed to get cru device\n", __func__); 713 return ret; 714 } 715 716 printf("CLK:"); 717 for (i = 0; i < clk_count; i++) { 718 clk_dump = &clks_dump[i]; 719 if (clk_dump->name) { 720 clk.id = clk_dump->id; 721 if (clk_dump->is_cru) 722 ret = clk_request(cru_dev, &clk); 723 if (ret < 0) 724 return ret; 725 726 rate = clk_get_rate(&clk); 727 clk_free(&clk); 728 if (i == 0) { 729 if (rate < 0) 730 printf("%10s%20s\n", clk_dump->name, 731 "unknown"); 732 else 733 printf("%10s%20lu Hz\n", clk_dump->name, 734 rate); 735 } else { 736 if (rate < 0) 737 printf("%14s%20s\n", clk_dump->name, 738 "unknown"); 739 else 740 printf("%14s%20lu Hz\n", clk_dump->name, 741 rate); 742 } 743 } 744 } 745 746 return 0; 747 } 748 #endif 749 750