1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2018 Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 6 #include <common.h> 7 #include <bitfield.h> 8 #include <clk-uclass.h> 9 #include <dm.h> 10 #include <errno.h> 11 #include <syscon.h> 12 #include <clk.h> 13 #include <asm/arch/clock.h> 14 #include <asm/arch/cru_rk1808.h> 15 #include <asm/arch/hardware.h> 16 #include <asm/io.h> 17 #include <dm/lists.h> 18 #include <dt-bindings/clock/rk1808-cru.h> 19 #include <div64.h> 20 21 DECLARE_GLOBAL_DATA_PTR; 22 23 #define RK1808_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \ 24 { \ 25 .rate = _rate##U, \ 26 .aclk_div = _aclk_div, \ 27 .pclk_div = _pclk_div, \ 28 } 29 30 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 31 32 static struct rockchip_pll_rate_table rk1808_pll_rates[] = { 33 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ 34 RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), 35 RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0), 36 RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0), 37 RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), 38 RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0), 39 RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), 40 RK3036_PLL_RATE(800000000, 6, 400, 2, 1, 1, 0), 41 RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0), 42 RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), 43 RK3036_PLL_RATE(500000000, 6, 250, 2, 1, 1, 0), 44 RK3036_PLL_RATE(200000000, 1, 200, 6, 4, 1, 0), 45 { /* sentinel */ }, 46 }; 47 48 #ifndef CONFIG_SPL_BUILD 49 #define RK1808_CLK_DUMP(_id, _name, _iscru) \ 50 { \ 51 .id = _id, \ 52 .name = _name, \ 53 .is_cru = _iscru, \ 54 } 55 56 static const struct rk1808_clk_info clks_dump[] = { 57 RK1808_CLK_DUMP(PLL_APLL, "apll", true), 58 RK1808_CLK_DUMP(PLL_DPLL, "dpll", true), 59 RK1808_CLK_DUMP(PLL_CPLL, "cpll", true), 60 RK1808_CLK_DUMP(PLL_GPLL, "gpll", true), 61 RK1808_CLK_DUMP(PLL_NPLL, "npll", true), 62 RK1808_CLK_DUMP(PLL_PPLL, "ppll", true), 63 RK1808_CLK_DUMP(HSCLK_BUS_PRE, "hsclk_bus", true), 64 RK1808_CLK_DUMP(MSCLK_BUS_PRE, "msclk_bus", true), 65 RK1808_CLK_DUMP(LSCLK_BUS_PRE, "lsclk_bus", true), 66 RK1808_CLK_DUMP(MSCLK_PERI, "msclk_peri", true), 67 RK1808_CLK_DUMP(LSCLK_PERI, "lsclk_peri", true), 68 }; 69 #endif 70 71 static struct rockchip_cpu_rate_table rk1808_cpu_rates[] = { 72 RK1808_CPUCLK_RATE(1200000000, 1, 5), 73 RK1808_CPUCLK_RATE(1008000000, 1, 5), 74 RK1808_CPUCLK_RATE(816000000, 1, 3), 75 RK1808_CPUCLK_RATE(600000000, 1, 3), 76 }; 77 78 static struct rockchip_pll_clock rk1808_pll_clks[] = { 79 [APLL] = PLL(pll_rk3036, PLL_APLL, RK1808_PLL_CON(0), 80 RK1808_MODE_CON, 0, 10, 0, rk1808_pll_rates), 81 [DPLL] = PLL(pll_rk3036, PLL_DPLL, RK1808_PLL_CON(8), 82 RK1808_MODE_CON, 2, 10, 0, NULL), 83 [CPLL] = PLL(pll_rk3036, PLL_CPLL, RK1808_PLL_CON(16), 84 RK1808_MODE_CON, 4, 10, 0, rk1808_pll_rates), 85 [GPLL] = PLL(pll_rk3036, PLL_GPLL, RK1808_PLL_CON(24), 86 RK1808_MODE_CON, 6, 10, 0, rk1808_pll_rates), 87 [NPLL] = PLL(pll_rk3036, PLL_NPLL, RK1808_PLL_CON(24), 88 RK1808_MODE_CON, 8, 10, 0, rk1808_pll_rates), 89 [PPLL] = PLL(pll_rk3036, PLL_PPLL, RK1808_PMU_PLL_CON(0), 90 RK1808_PMU_MODE_CON, 0, 10, 0, rk1808_pll_rates), 91 }; 92 93 #ifndef CONFIG_SPL_BUILD 94 static ulong rk1808_i2c_get_clk(struct rk1808_clk_priv *priv, ulong clk_id) 95 { 96 struct rk1808_cru *cru = priv->cru; 97 u32 div, con; 98 99 switch (clk_id) { 100 case SCLK_PMU_I2C0: 101 con = readl(&cru->pmu_clksel_con[7]); 102 div = (con & CLK_I2C0_DIV_CON_MASK) >> CLK_I2C0_DIV_CON_SHIFT; 103 break; 104 case SCLK_I2C1: 105 con = readl(&cru->clksel_con[59]); 106 div = (con & CLK_I2C1_DIV_CON_MASK) >> CLK_I2C1_DIV_CON_SHIFT; 107 break; 108 case SCLK_I2C2: 109 con = readl(&cru->clksel_con[59]); 110 div = (con & CLK_I2C2_DIV_CON_MASK) >> CLK_I2C2_DIV_CON_SHIFT; 111 break; 112 case SCLK_I2C3: 113 con = readl(&cru->clksel_con[60]); 114 div = (con & CLK_I2C3_DIV_CON_MASK) >> CLK_I2C3_DIV_CON_SHIFT; 115 break; 116 case SCLK_I2C4: 117 con = readl(&cru->clksel_con[71]); 118 div = (con & CLK_I2C4_DIV_CON_MASK) >> CLK_I2C4_DIV_CON_SHIFT; 119 break; 120 case SCLK_I2C5: 121 con = readl(&cru->clksel_con[71]); 122 div = (con & CLK_I2C5_DIV_CON_MASK) >> CLK_I2C5_DIV_CON_SHIFT; 123 break; 124 default: 125 printf("do not support this i2c bus\n"); 126 return -EINVAL; 127 } 128 129 return DIV_TO_RATE(priv->gpll_hz, div); 130 } 131 132 static ulong rk1808_i2c_set_clk(struct rk1808_clk_priv *priv, 133 ulong clk_id, uint hz) 134 { 135 struct rk1808_cru *cru = priv->cru; 136 int src_clk_div; 137 138 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 139 assert(src_clk_div - 1 < 127); 140 141 switch (clk_id) { 142 case SCLK_PMU_I2C0: 143 rk_clrsetreg(&cru->pmu_clksel_con[7], 144 CLK_I2C0_DIV_CON_MASK | CLK_I2C0_PLL_SEL_MASK, 145 (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT | 146 CLK_I2C0_PLL_SEL_PPLL << CLK_I2C0_PLL_SEL_SHIFT); 147 break; 148 case SCLK_I2C1: 149 rk_clrsetreg(&cru->clksel_con[59], 150 CLK_I2C1_DIV_CON_MASK | CLK_I2C1_PLL_SEL_MASK, 151 (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT | 152 CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT); 153 break; 154 case SCLK_I2C2: 155 rk_clrsetreg(&cru->clksel_con[59], 156 CLK_I2C2_DIV_CON_MASK | CLK_I2C2_PLL_SEL_MASK, 157 (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT | 158 CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT); 159 break; 160 case SCLK_I2C3: 161 rk_clrsetreg(&cru->clksel_con[60], 162 CLK_I2C3_DIV_CON_MASK | CLK_I2C3_PLL_SEL_MASK, 163 (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT | 164 CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT); 165 break; 166 case SCLK_I2C4: 167 rk_clrsetreg(&cru->clksel_con[71], 168 CLK_I2C4_DIV_CON_MASK | CLK_I2C4_PLL_SEL_MASK, 169 (src_clk_div - 1) << CLK_I2C4_DIV_CON_SHIFT | 170 CLK_I2C_PLL_SEL_GPLL << CLK_I2C4_PLL_SEL_SHIFT); 171 break; 172 case SCLK_I2C5: 173 rk_clrsetreg(&cru->clksel_con[71], 174 CLK_I2C5_DIV_CON_MASK | CLK_I2C5_PLL_SEL_MASK, 175 (src_clk_div - 1) << CLK_I2C5_DIV_CON_SHIFT | 176 CLK_I2C_PLL_SEL_GPLL << CLK_I2C5_PLL_SEL_SHIFT); 177 break; 178 default: 179 printf("do not support this i2c bus\n"); 180 return -EINVAL; 181 } 182 183 return rk1808_i2c_get_clk(priv, clk_id); 184 } 185 #endif 186 187 static ulong rk1808_mmc_get_clk(struct rk1808_clk_priv *priv, uint clk_id) 188 { 189 struct rk1808_cru *cru = priv->cru; 190 u32 div, con, con_id; 191 192 switch (clk_id) { 193 case HCLK_SDMMC: 194 case SCLK_SDMMC: 195 con_id = 20; 196 break; 197 case HCLK_SDIO: 198 case SCLK_SDIO: 199 con_id = 22; 200 break; 201 case HCLK_EMMC: 202 case SCLK_EMMC: 203 case SCLK_EMMC_SAMPLE: 204 con_id = 24; 205 break; 206 default: 207 return -EINVAL; 208 } 209 210 con = readl(&cru->clksel_con[con_id]); 211 div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT; 212 213 if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT 214 == EMMC_SEL_24M) 215 return DIV_TO_RATE(OSC_HZ, div) / 2; 216 else 217 return DIV_TO_RATE(priv->gpll_hz, div) / 2; 218 } 219 220 static ulong rk1808_mmc_set_clk(struct rk1808_clk_priv *priv, 221 ulong clk_id, ulong set_rate) 222 { 223 struct rk1808_cru *cru = priv->cru; 224 int src_clk_div; 225 u32 con_id; 226 227 switch (clk_id) { 228 case HCLK_SDMMC: 229 case SCLK_SDMMC: 230 con_id = 20; 231 break; 232 case HCLK_SDIO: 233 case SCLK_SDIO: 234 con_id = 22; 235 break; 236 case HCLK_EMMC: 237 case SCLK_EMMC: 238 con_id = 24; 239 break; 240 default: 241 return -EINVAL; 242 } 243 244 /* Select clk_sdmmc/emmc source from GPLL by default */ 245 /* mmc clock defaulg div 2 internal, need provide double in cru */ 246 src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate); 247 248 if (src_clk_div > 127) { 249 /* use 24MHz source for 400KHz clock */ 250 src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate); 251 rk_clrsetreg(&cru->clksel_con[con_id], 252 EMMC_PLL_MASK | EMMC_DIV_MASK, 253 EMMC_SEL_24M << EMMC_PLL_SHIFT | 254 (src_clk_div - 1) << EMMC_DIV_SHIFT); 255 } else { 256 rk_clrsetreg(&cru->clksel_con[con_id], 257 EMMC_PLL_MASK | EMMC_DIV_MASK, 258 EMMC_SEL_GPLL << EMMC_PLL_SHIFT | 259 (src_clk_div - 1) << EMMC_DIV_SHIFT); 260 } 261 rk_clrsetreg(&cru->clksel_con[con_id + 1], EMMC_CLK_SEL_MASK, 262 EMMC_CLK_SEL_EMMC); 263 264 return rk1808_mmc_get_clk(priv, clk_id); 265 } 266 267 #ifndef CONFIG_SPL_BUILD 268 static ulong rk1808_pwm_get_clk(struct rk1808_clk_priv *priv, ulong clk_id) 269 { 270 struct rk1808_cru *cru = priv->cru; 271 u32 div, con; 272 273 switch (clk_id) { 274 case SCLK_PWM0: 275 con = readl(&cru->clksel_con[69]); 276 div = (con & CLK_PWM0_DIV_CON_MASK) >> CLK_PWM0_DIV_CON_SHIFT; 277 break; 278 case SCLK_PWM1: 279 con = readl(&cru->clksel_con[69]); 280 div = (con & CLK_PWM1_DIV_CON_MASK) >> CLK_PWM1_DIV_CON_SHIFT; 281 break; 282 case SCLK_PWM2: 283 con = readl(&cru->clksel_con[70]); 284 div = (con & CLK_PWM2_DIV_CON_MASK) >> CLK_PWM2_DIV_CON_SHIFT; 285 break; 286 default: 287 printf("do not support this pwm bus\n"); 288 return -EINVAL; 289 } 290 291 return DIV_TO_RATE(priv->gpll_hz, div); 292 } 293 294 static ulong rk1808_pwm_set_clk(struct rk1808_clk_priv *priv, 295 ulong clk_id, uint hz) 296 { 297 struct rk1808_cru *cru = priv->cru; 298 int src_clk_div; 299 300 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 301 assert(src_clk_div - 1 < 127); 302 303 switch (clk_id) { 304 case SCLK_PWM0: 305 rk_clrsetreg(&cru->clksel_con[69], 306 CLK_PWM0_DIV_CON_MASK | CLK_PWM0_PLL_SEL_MASK, 307 (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT | 308 CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT); 309 break; 310 case SCLK_PWM1: 311 rk_clrsetreg(&cru->clksel_con[69], 312 CLK_PWM1_DIV_CON_MASK | CLK_PWM1_PLL_SEL_MASK, 313 (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT | 314 CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT); 315 break; 316 case SCLK_PWM2: 317 rk_clrsetreg(&cru->clksel_con[70], 318 CLK_PWM2_DIV_CON_MASK | CLK_PWM2_PLL_SEL_MASK, 319 (src_clk_div - 1) << CLK_PWM2_DIV_CON_SHIFT | 320 CLK_PWM_PLL_SEL_GPLL << CLK_PWM2_PLL_SEL_SHIFT); 321 break; 322 default: 323 printf("do not support this pwm bus\n"); 324 return -EINVAL; 325 } 326 327 return rk1808_pwm_get_clk(priv, clk_id); 328 } 329 330 static ulong rk1808_saradc_get_clk(struct rk1808_clk_priv *priv) 331 { 332 struct rk1808_cru *cru = priv->cru; 333 u32 div, con; 334 335 con = readl(&cru->clksel_con[63]); 336 div = con & CLK_SARADC_DIV_CON_MASK; 337 338 return DIV_TO_RATE(OSC_HZ, div); 339 } 340 341 static ulong rk1808_saradc_set_clk(struct rk1808_clk_priv *priv, uint hz) 342 { 343 struct rk1808_cru *cru = priv->cru; 344 int src_clk_div; 345 346 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz); 347 assert(src_clk_div - 1 < 2047); 348 349 rk_clrsetreg(&cru->clksel_con[63], 350 CLK_SARADC_DIV_CON_MASK, 351 (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT); 352 353 return rk1808_saradc_get_clk(priv); 354 } 355 356 static ulong rk1808_spi_get_clk(struct rk1808_clk_priv *priv, ulong clk_id) 357 { 358 struct rk1808_cru *cru = priv->cru; 359 u32 div, con; 360 361 switch (clk_id) { 362 case SCLK_SPI0: 363 con = readl(&cru->clksel_con[60]); 364 div = (con & CLK_SPI0_DIV_CON_MASK) >> CLK_SPI0_DIV_CON_SHIFT; 365 break; 366 case SCLK_SPI1: 367 con = readl(&cru->clksel_con[61]); 368 div = (con & CLK_SPI1_DIV_CON_MASK) >> CLK_SPI1_DIV_CON_SHIFT; 369 break; 370 case SCLK_SPI2: 371 con = readl(&cru->clksel_con[61]); 372 div = (con & CLK_SPI2_DIV_CON_MASK) >> CLK_SPI2_DIV_CON_SHIFT; 373 break; 374 default: 375 printf("do not support this pwm bus\n"); 376 return -EINVAL; 377 } 378 379 return DIV_TO_RATE(priv->gpll_hz, div); 380 } 381 382 static ulong rk1808_spi_set_clk(struct rk1808_clk_priv *priv, 383 ulong clk_id, uint hz) 384 { 385 struct rk1808_cru *cru = priv->cru; 386 int src_clk_div; 387 388 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 389 assert(src_clk_div - 1 < 127); 390 391 switch (clk_id) { 392 case SCLK_SPI0: 393 rk_clrsetreg(&cru->clksel_con[60], 394 CLK_SPI0_DIV_CON_MASK | CLK_SPI0_PLL_SEL_MASK, 395 (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT | 396 CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT); 397 break; 398 case SCLK_SPI1: 399 rk_clrsetreg(&cru->clksel_con[61], 400 CLK_SPI1_DIV_CON_MASK | CLK_SPI1_PLL_SEL_MASK, 401 (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT | 402 CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_PLL_SEL_SHIFT); 403 break; 404 case SCLK_SPI2: 405 rk_clrsetreg(&cru->clksel_con[61], 406 CLK_SPI2_DIV_CON_MASK | CLK_SPI2_PLL_SEL_MASK, 407 (src_clk_div - 1) << CLK_SPI2_DIV_CON_SHIFT | 408 CLK_SPI_PLL_SEL_GPLL << CLK_SPI2_PLL_SEL_SHIFT); 409 break; 410 default: 411 printf("do not support this pwm bus\n"); 412 return -EINVAL; 413 } 414 415 return rk1808_spi_get_clk(priv, clk_id); 416 } 417 418 #define RK1808_VOP_PLL_LIMIT_FREQ 600 * 1000000 419 static ulong rk1808_vop_get_clk(struct rk1808_clk_priv *priv, ulong clk_id) 420 { 421 struct rk1808_cru *cru = priv->cru; 422 u32 div, con, parent; 423 424 switch (clk_id) { 425 case ACLK_VOPRAW: 426 case ACLK_VOPLITE: 427 con = readl(&cru->clksel_con[4]); 428 div = (con & ACLK_VOP_DIV_CON_MASK) >> ACLK_VOP_DIV_CON_SHIFT; 429 parent = priv->gpll_hz; 430 break; 431 case HCLK_VOPRAW: 432 case HCLK_VOPLITE: 433 parent = rk1808_vop_get_clk(priv, ACLK_VOPRAW); 434 con = readl(&cru->clksel_con[4]); 435 div = (con & HCLK_VOP_DIV_CON_MASK) >> HCLK_VOP_DIV_CON_SHIFT; 436 break; 437 case DCLK_VOPRAW: 438 con = readl(&cru->clksel_con[5]); 439 div = con & DCLK_VOPRAW_DIV_CON_MASK; 440 parent = rockchip_pll_get_rate(&rk1808_pll_clks[NPLL], 441 priv->cru, NPLL); 442 break; 443 case DCLK_VOPLITE: 444 con = readl(&cru->clksel_con[7]); 445 div = con & DCLK_VOPLITE_DIV_CON_MASK; 446 parent = (con & DCLK_VOPLITE_PLL_SEL_MASK) >> 447 DCLK_VOPLITE_PLL_SEL_SHIFT; 448 if (parent == DCLK_VOPLITE_PLL_SEL_NPLL) 449 parent = rockchip_pll_get_rate(&rk1808_pll_clks[NPLL], 450 priv->cru, NPLL); 451 else if (parent == DCLK_VOPLITE_PLL_SEL_CPLL) 452 parent = priv->cpll_hz; 453 else 454 parent = priv->gpll_hz; 455 break; 456 default: 457 return -ENOENT; 458 } 459 460 return DIV_TO_RATE(parent, div); 461 } 462 463 static ulong rk1808_vop_set_clk(struct rk1808_clk_priv *priv, 464 ulong clk_id, uint hz) 465 { 466 struct rk1808_cru *cru = priv->cru; 467 int src_clk_div, parent; 468 469 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 470 assert(src_clk_div - 1 < 31); 471 472 switch (clk_id) { 473 case ACLK_VOPRAW: 474 case ACLK_VOPLITE: 475 rk_clrsetreg(&cru->clksel_con[4], 476 ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK, 477 ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT | 478 (src_clk_div - 1) << ACLK_VOP_DIV_CON_SHIFT); 479 break; 480 case HCLK_VOPRAW: 481 case HCLK_VOPLITE: 482 src_clk_div = 483 DIV_ROUND_UP(rk1808_vop_get_clk(priv, ACLK_VOPRAW), hz); 484 assert(src_clk_div - 1 < 15); 485 rk_clrsetreg(&cru->clksel_con[4], 486 HCLK_VOP_DIV_CON_MASK, 487 (src_clk_div - 1) << HCLK_VOP_DIV_CON_SHIFT); 488 break; 489 case DCLK_VOPRAW: 490 /* 491 * vopb dclk source from npll, and equals to 492 */ 493 src_clk_div = DIV_ROUND_UP(RK1808_VOP_PLL_LIMIT_FREQ, hz); 494 rockchip_pll_set_rate(&rk1808_pll_clks[NPLL], 495 priv->cru, NPLL, src_clk_div * hz); 496 rk_clrsetreg(&cru->clksel_con[5], 497 DCLK_VOPRAW_SEL_MASK | 498 DCLK_VOPRAW_PLL_SEL_MASK | 499 DCLK_VOPRAW_DIV_CON_MASK, 500 DCLK_VOPRAW_SEL_VOPRAW << 501 DCLK_VOPRAW_SEL_SHIFT | 502 DCLK_VOPRAW_PLL_SEL_NPLL << 503 DCLK_VOPRAW_PLL_SEL_SHIFT | 504 (src_clk_div - 1) << DCLK_VOPRAW_DIV_CON_SHIFT); 505 break; 506 case DCLK_VOPLITE: 507 /* 508 * vopl dclk source from cpll, and equals to 509 */ 510 if (!(priv->npll_hz % hz)) { 511 parent = DCLK_VOPLITE_PLL_SEL_NPLL; 512 src_clk_div = do_div(priv->npll_hz, hz); 513 } else if (!(priv->cpll_hz % hz)) { 514 parent = DCLK_VOPLITE_PLL_SEL_CPLL; 515 src_clk_div = do_div(priv->cpll_hz, hz); 516 } else { 517 parent = DCLK_VOPLITE_PLL_SEL_GPLL; 518 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 519 } 520 rk_clrsetreg(&cru->clksel_con[7], 521 DCLK_VOPLITE_SEL_MASK | DCLK_VOPLITE_PLL_SEL_MASK | 522 DCLK_VOPLITE_DIV_CON_MASK, 523 DCLK_VOPLITE_SEL_VOPRAW << DCLK_VOPLITE_SEL_SHIFT | 524 parent << DCLK_VOPLITE_PLL_SEL_SHIFT | 525 (src_clk_div - 1) << DCLK_VOPLITE_DIV_CON_SHIFT); 526 break; 527 default: 528 printf("do not support this vop freq\n"); 529 return -EINVAL; 530 } 531 532 return rk1808_vop_get_clk(priv, clk_id); 533 } 534 #endif 535 536 static ulong rk1808_bus_get_clk(struct rk1808_clk_priv *priv, ulong clk_id) 537 { 538 struct rk1808_cru *cru = priv->cru; 539 u32 div, con, parent; 540 541 switch (clk_id) { 542 case HSCLK_BUS_PRE: 543 con = readl(&cru->clksel_con[27]); 544 div = (con & HSCLK_BUS_DIV_CON_MASK) >> HSCLK_BUS_DIV_CON_SHIFT; 545 parent = priv->gpll_hz; 546 break; 547 case MSCLK_BUS_PRE: 548 con = readl(&cru->clksel_con[28]); 549 div = (con & MSCLK_BUS_DIV_CON_MASK) >> MSCLK_BUS_DIV_CON_SHIFT; 550 parent = priv->gpll_hz; 551 break; 552 case LSCLK_BUS_PRE: 553 con = readl(&cru->clksel_con[28]); 554 div = (con & LSCLK_BUS_DIV_CON_MASK) >> LSCLK_BUS_DIV_CON_SHIFT; 555 parent = priv->gpll_hz; 556 break; 557 default: 558 return -ENOENT; 559 } 560 561 return DIV_TO_RATE(parent, div); 562 } 563 564 static ulong rk1808_bus_set_clk(struct rk1808_clk_priv *priv, 565 ulong clk_id, ulong hz) 566 { 567 struct rk1808_cru *cru = priv->cru; 568 int src_clk_div; 569 570 /* 571 * select gpll as pd_bus bus clock source and 572 * set up dependent divisors for PCLK/HCLK and ACLK clocks. 573 */ 574 switch (clk_id) { 575 case HSCLK_BUS_PRE: 576 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 577 assert(src_clk_div - 1 < 31); 578 rk_clrsetreg(&cru->clksel_con[27], 579 CLK_BUS_PLL_SEL_MASK | HSCLK_BUS_DIV_CON_MASK, 580 CLK_BUS_PLL_SEL_GPLL << CLK_BUS_PLL_SEL_SHIFT | 581 (src_clk_div - 1) << HSCLK_BUS_DIV_CON_SHIFT); 582 break; 583 case MSCLK_BUS_PRE: 584 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 585 assert(src_clk_div - 1 < 31); 586 rk_clrsetreg(&cru->clksel_con[28], 587 CLK_BUS_PLL_SEL_MASK | MSCLK_BUS_DIV_CON_MASK, 588 CLK_BUS_PLL_SEL_GPLL << CLK_BUS_PLL_SEL_SHIFT | 589 (src_clk_div - 1) << MSCLK_BUS_DIV_CON_SHIFT); 590 break; 591 case LSCLK_BUS_PRE: 592 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 593 assert(src_clk_div - 1 < 31); 594 rk_clrsetreg(&cru->clksel_con[28], 595 CLK_BUS_PLL_SEL_MASK | LSCLK_BUS_DIV_CON_MASK, 596 CLK_BUS_PLL_SEL_GPLL << CLK_BUS_PLL_SEL_SHIFT | 597 (src_clk_div - 1) << LSCLK_BUS_DIV_CON_SHIFT); 598 break; 599 default: 600 printf("do not support this bus freq\n"); 601 return -EINVAL; 602 } 603 604 return rk1808_bus_get_clk(priv, clk_id); 605 } 606 607 static ulong rk1808_peri_get_clk(struct rk1808_clk_priv *priv, ulong clk_id) 608 { 609 struct rk1808_cru *cru = priv->cru; 610 u32 div, con, parent; 611 612 switch (clk_id) { 613 case MSCLK_PERI: 614 con = readl(&cru->clksel_con[19]); 615 div = (con & MSCLK_PERI_DIV_CON_MASK) >> 616 MSCLK_PERI_DIV_CON_SHIFT; 617 parent = priv->gpll_hz; 618 break; 619 case LSCLK_PERI: 620 con = readl(&cru->clksel_con[19]); 621 div = (con & LSCLK_PERI_DIV_CON_MASK) >> 622 LSCLK_PERI_DIV_CON_SHIFT; 623 parent = priv->gpll_hz; 624 break; 625 default: 626 return -ENOENT; 627 } 628 629 return DIV_TO_RATE(parent, div); 630 } 631 632 static ulong rk1808_peri_set_clk(struct rk1808_clk_priv *priv, 633 ulong clk_id, ulong hz) 634 { 635 struct rk1808_cru *cru = priv->cru; 636 int src_clk_div; 637 638 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz); 639 assert(src_clk_div - 1 < 31); 640 641 /* 642 * select gpll as pd_peri bus clock source and 643 * set up dependent divisors for HCLK and ACLK clocks. 644 */ 645 switch (clk_id) { 646 case MSCLK_PERI: 647 rk_clrsetreg(&cru->clksel_con[19], 648 CLK_PERI_PLL_SEL_MASK | MSCLK_PERI_DIV_CON_MASK, 649 CLK_PERI_PLL_SEL_GPLL << CLK_PERI_PLL_SEL_SHIFT | 650 (src_clk_div - 1) << MSCLK_PERI_DIV_CON_SHIFT); 651 break; 652 case LSCLK_PERI: 653 rk_clrsetreg(&cru->clksel_con[19], 654 CLK_PERI_PLL_SEL_MASK | LSCLK_PERI_DIV_CON_MASK, 655 CLK_PERI_PLL_SEL_GPLL << CLK_PERI_PLL_SEL_SHIFT | 656 (src_clk_div - 1) << LSCLK_PERI_DIV_CON_SHIFT); 657 break; 658 default: 659 printf("do not support this peri freq\n"); 660 return -EINVAL; 661 } 662 663 return rk1808_peri_get_clk(priv, clk_id); 664 } 665 666 static ulong rk1808_armclk_set_clk(struct rk1808_clk_priv *priv, ulong hz) 667 { 668 struct rk1808_cru *cru = priv->cru; 669 const struct rockchip_cpu_rate_table *rate; 670 ulong old_rate; 671 672 rate = rockchip_get_cpu_settings(rk1808_cpu_rates, hz); 673 if (!rate) { 674 printf("%s unsupported rate\n", __func__); 675 return -EINVAL; 676 } 677 678 /* 679 * select apll as cpu/core clock pll source and 680 * set up dependent divisors for PERI and ACLK clocks. 681 * core hz : apll = 1:1 682 */ 683 old_rate = rockchip_pll_get_rate(&rk1808_pll_clks[APLL], 684 priv->cru, APLL); 685 if (old_rate > hz) { 686 if (rockchip_pll_set_rate(&rk1808_pll_clks[APLL], 687 priv->cru, APLL, hz)) 688 return -EINVAL; 689 rk_clrsetreg(&cru->clksel_con[0], 690 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | 691 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, 692 rate->aclk_div << CORE_ACLK_DIV_SHIFT | 693 rate->pclk_div << CORE_DBG_DIV_SHIFT | 694 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 695 0 << CORE_DIV_CON_SHIFT); 696 } else if (old_rate < hz) { 697 rk_clrsetreg(&cru->clksel_con[0], 698 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK | 699 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK, 700 rate->aclk_div << CORE_ACLK_DIV_SHIFT | 701 rate->pclk_div << CORE_DBG_DIV_SHIFT | 702 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT | 703 0 << CORE_DIV_CON_SHIFT); 704 if (rockchip_pll_set_rate(&rk1808_pll_clks[APLL], 705 priv->cru, APLL, hz)) 706 return -EINVAL; 707 } 708 709 return rockchip_pll_get_rate(&rk1808_pll_clks[APLL], priv->cru, APLL); 710 } 711 712 static ulong rk1808_clk_get_rate(struct clk *clk) 713 { 714 struct rk1808_clk_priv *priv = dev_get_priv(clk->dev); 715 ulong rate = 0; 716 717 debug("%s %ld\n", __func__, clk->id); 718 switch (clk->id) { 719 case PLL_APLL: 720 case PLL_DPLL: 721 case PLL_CPLL: 722 case PLL_GPLL: 723 case PLL_NPLL: 724 case PLL_PPLL: 725 rate = rockchip_pll_get_rate(&rk1808_pll_clks[clk->id - 1], 726 priv->cru, clk->id - 1); 727 break; 728 case ARMCLK: 729 rate = rockchip_pll_get_rate(&rk1808_pll_clks[APLL], 730 priv->cru, APLL); 731 break; 732 case HCLK_SDMMC: 733 case HCLK_EMMC: 734 case HCLK_SDIO: 735 case SCLK_SDMMC: 736 case SCLK_EMMC: 737 case SCLK_EMMC_SAMPLE: 738 case SCLK_SDIO: 739 rate = rk1808_mmc_get_clk(priv, clk->id); 740 break; 741 #ifndef CONFIG_SPL_BUILD 742 case SCLK_PMU_I2C0: 743 case SCLK_I2C1: 744 case SCLK_I2C2: 745 case SCLK_I2C3: 746 case SCLK_I2C4: 747 case SCLK_I2C5: 748 rate = rk1808_i2c_get_clk(priv, clk->id); 749 break; 750 case SCLK_PWM0: 751 case SCLK_PWM1: 752 case SCLK_PWM2: 753 rate = rk1808_pwm_get_clk(priv, clk->id); 754 break; 755 case SCLK_SARADC: 756 rate = rk1808_saradc_get_clk(priv); 757 break; 758 case SCLK_SPI0: 759 case SCLK_SPI1: 760 case SCLK_SPI2: 761 rate = rk1808_spi_get_clk(priv, clk->id); 762 break; 763 case ACLK_VOPRAW: 764 case DCLK_VOPRAW: 765 case ACLK_VOPLITE: 766 case DCLK_VOPLITE: 767 rate = rk1808_vop_get_clk(priv, clk->id); 768 break; 769 #endif 770 case HSCLK_BUS_PRE: 771 case MSCLK_BUS_PRE: 772 case LSCLK_BUS_PRE: 773 rate = rk1808_bus_get_clk(priv, clk->id); 774 break; 775 case MSCLK_PERI: 776 case LSCLK_PERI: 777 rate = rk1808_peri_get_clk(priv, clk->id); 778 break; 779 default: 780 return -ENOENT; 781 } 782 783 return rate; 784 } 785 786 static ulong rk1808_clk_set_rate(struct clk *clk, ulong rate) 787 { 788 struct rk1808_clk_priv *priv = dev_get_priv(clk->dev); 789 ulong ret = 0; 790 791 debug("%s %ld %ld\n", __func__, clk->id, rate); 792 switch (clk->id) { 793 case PLL_APLL: 794 case PLL_DPLL: 795 case PLL_PPLL: 796 ret = rockchip_pll_set_rate(&rk1808_pll_clks[clk->id - 1], 797 priv->cru, clk->id - 1, rate); 798 break; 799 case PLL_CPLL: 800 ret = rockchip_pll_set_rate(&rk1808_pll_clks[CPLL], 801 priv->cru, CPLL, rate); 802 if (ret == 0) 803 priv->cpll_hz = rate; 804 break; 805 case PLL_GPLL: 806 ret = rockchip_pll_set_rate(&rk1808_pll_clks[GPLL], 807 priv->cru, GPLL, rate); 808 if (ret == 0) 809 priv->gpll_hz = rate; 810 break; 811 case PLL_NPLL: 812 ret = rockchip_pll_set_rate(&rk1808_pll_clks[NPLL], 813 priv->cru, NPLL, rate); 814 if (ret == 0) 815 priv->npll_hz = rate; 816 break; 817 case ARMCLK: 818 if (priv->armclk_hz) 819 rk1808_armclk_set_clk(priv, rate); 820 priv->armclk_hz = rate; 821 break; 822 case HCLK_SDMMC: 823 case HCLK_EMMC: 824 case HCLK_SDIO: 825 case SCLK_SDMMC: 826 case SCLK_EMMC: 827 case SCLK_SDIO: 828 ret = rk1808_mmc_set_clk(priv, clk->id, rate); 829 break; 830 #ifndef CONFIG_SPL_BUILD 831 case SCLK_PMU_I2C0: 832 case SCLK_I2C1: 833 case SCLK_I2C2: 834 case SCLK_I2C3: 835 case SCLK_I2C4: 836 case SCLK_I2C5: 837 ret = rk1808_i2c_set_clk(priv, clk->id, rate); 838 break; 839 case SCLK_PWM0: 840 case SCLK_PWM1: 841 case SCLK_PWM2: 842 ret = rk1808_pwm_set_clk(priv, clk->id, rate); 843 break; 844 case SCLK_SARADC: 845 ret = rk1808_saradc_set_clk(priv, rate); 846 break; 847 case SCLK_SPI0: 848 case SCLK_SPI1: 849 case SCLK_SPI2: 850 ret = rk1808_spi_set_clk(priv, clk->id, rate); 851 break; 852 case ACLK_VOPRAW: 853 case DCLK_VOPRAW: 854 case ACLK_VOPLITE: 855 case DCLK_VOPLITE: 856 ret = rk1808_vop_set_clk(priv, clk->id, rate); 857 break; 858 #endif 859 case HSCLK_BUS_PRE: 860 case MSCLK_BUS_PRE: 861 case LSCLK_BUS_PRE: 862 ret = rk1808_bus_set_clk(priv, clk->id, rate); 863 break; 864 case MSCLK_PERI: 865 case LSCLK_PERI: 866 ret = rk1808_peri_set_clk(priv, clk->id, rate); 867 break; 868 default: 869 return -ENOENT; 870 } 871 872 return ret; 873 } 874 875 #define ROCKCHIP_MMC_DELAY_SEL BIT(10) 876 #define ROCKCHIP_MMC_DEGREE_MASK 0x3 877 #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2 878 #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET) 879 880 #define PSECS_PER_SEC 1000000000000LL 881 /* 882 * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to 883 * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg. 884 */ 885 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60 886 887 int rk1808_mmc_get_phase(struct clk *clk) 888 { 889 struct rk1808_clk_priv *priv = dev_get_priv(clk->dev); 890 struct rk1808_cru *cru = priv->cru; 891 u32 raw_value, delay_num; 892 u16 degrees = 0; 893 ulong rate; 894 895 rate = rk1808_clk_get_rate(clk); 896 897 if (rate < 0) 898 return rate; 899 900 if (clk->id == SCLK_EMMC_SAMPLE) 901 raw_value = readl(&cru->emmc_con[1]); 902 else if (clk->id == SCLK_SDMMC_SAMPLE) 903 raw_value = readl(&cru->sdmmc_con[1]); 904 else 905 raw_value = readl(&cru->sdio_con[1]); 906 907 raw_value >>= 1; 908 degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90; 909 910 if (raw_value & ROCKCHIP_MMC_DELAY_SEL) { 911 /* degrees/delaynum * 10000 */ 912 unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) * 913 36 * (rate / 1000000); 914 915 delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK); 916 delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET; 917 degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000); 918 } 919 920 return degrees % 360; 921 } 922 923 int rk1808_mmc_set_phase(struct clk *clk, u32 degrees) 924 { 925 struct rk1808_clk_priv *priv = dev_get_priv(clk->dev); 926 struct rk1808_cru *cru = priv->cru; 927 u8 nineties, remainder, delay_num; 928 u32 raw_value, delay; 929 ulong rate; 930 931 rate = rk1808_clk_get_rate(clk); 932 933 if (rate < 0) 934 return rate; 935 936 nineties = degrees / 90; 937 remainder = (degrees % 90); 938 939 /* 940 * Convert to delay; do a little extra work to make sure we 941 * don't overflow 32-bit / 64-bit numbers. 942 */ 943 delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */ 944 delay *= remainder; 945 delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 * 946 (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10)); 947 948 delay_num = (u8)min_t(u32, delay, 255); 949 950 raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0; 951 raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET; 952 raw_value |= nineties; 953 954 raw_value <<= 1; 955 if (clk->id == SCLK_EMMC_SAMPLE) 956 writel(raw_value | 0xffff0000, &cru->emmc_con[1]); 957 else if (clk->id == SCLK_SDMMC_SAMPLE) 958 writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]); 959 else 960 writel(raw_value | 0xffff0000, &cru->sdio_con[1]); 961 962 debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n", 963 degrees, delay_num, raw_value, rk1808_mmc_get_phase(clk)); 964 965 return 0; 966 } 967 968 static int rk1808_clk_get_phase(struct clk *clk) 969 { 970 int ret; 971 972 debug("%s %ld\n", __func__, clk->id); 973 switch (clk->id) { 974 case SCLK_EMMC_SAMPLE: 975 case SCLK_SDMMC_SAMPLE: 976 case SCLK_SDIO_SAMPLE: 977 ret = rk1808_mmc_get_phase(clk); 978 break; 979 default: 980 return -ENOENT; 981 } 982 983 return ret; 984 } 985 986 static int rk1808_clk_set_phase(struct clk *clk, int degrees) 987 { 988 int ret; 989 990 debug("%s %ld\n", __func__, clk->id); 991 switch (clk->id) { 992 case SCLK_EMMC_SAMPLE: 993 case SCLK_SDMMC_SAMPLE: 994 case SCLK_SDIO_SAMPLE: 995 ret = rk1808_mmc_set_phase(clk, degrees); 996 break; 997 default: 998 return -ENOENT; 999 } 1000 1001 return ret; 1002 } 1003 1004 static struct clk_ops rk1808_clk_ops = { 1005 .get_rate = rk1808_clk_get_rate, 1006 .set_rate = rk1808_clk_set_rate, 1007 .get_phase = rk1808_clk_get_phase, 1008 .set_phase = rk1808_clk_set_phase, 1009 }; 1010 1011 static int rk1808_clk_probe(struct udevice *dev) 1012 { 1013 struct rk1808_clk_priv *priv = dev_get_priv(dev); 1014 int ret; 1015 1016 if (rockchip_pll_get_rate(&rk1808_pll_clks[APLL], 1017 priv->cru, APLL) != APLL_HZ) { 1018 ret = rk1808_armclk_set_clk(priv, APLL_HZ); 1019 if (ret < 0) 1020 printf("%s failed to set armclk rate\n", __func__); 1021 } 1022 1023 priv->cpll_hz = rockchip_pll_get_rate(&rk1808_pll_clks[CPLL], 1024 priv->cru, CPLL); 1025 priv->gpll_hz = rockchip_pll_get_rate(&rk1808_pll_clks[GPLL], 1026 priv->cru, GPLL); 1027 1028 /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ 1029 ret = clk_set_defaults(dev); 1030 if (ret) 1031 debug("%s clk_set_defaults failed %d\n", __func__, ret); 1032 1033 return 0; 1034 } 1035 1036 static int rk1808_clk_ofdata_to_platdata(struct udevice *dev) 1037 { 1038 struct rk1808_clk_priv *priv = dev_get_priv(dev); 1039 1040 priv->cru = dev_read_addr_ptr(dev); 1041 1042 return 0; 1043 } 1044 1045 static int rk1808_clk_bind(struct udevice *dev) 1046 { 1047 int ret; 1048 struct udevice *sys_child, *sf_child; 1049 struct sysreset_reg *priv; 1050 struct softreset_reg *sf_priv; 1051 1052 /* The reset driver does not have a device node, so bind it here */ 1053 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 1054 &sys_child); 1055 if (ret) { 1056 debug("Warning: No sysreset driver: ret=%d\n", ret); 1057 } else { 1058 priv = malloc(sizeof(struct sysreset_reg)); 1059 priv->glb_srst_fst_value = offsetof(struct rk1808_cru, 1060 glb_srst_fst); 1061 priv->glb_srst_snd_value = offsetof(struct rk1808_cru, 1062 glb_srst_snd); 1063 sys_child->priv = priv; 1064 } 1065 1066 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 1067 dev_ofnode(dev), &sf_child); 1068 if (ret) { 1069 debug("Warning: No rockchip reset driver: ret=%d\n", ret); 1070 } else { 1071 sf_priv = malloc(sizeof(struct softreset_reg)); 1072 sf_priv->sf_reset_offset = offsetof(struct rk1808_cru, 1073 softrst_con[0]); 1074 sf_priv->sf_reset_num = 16; 1075 sf_child->priv = sf_priv; 1076 } 1077 1078 return 0; 1079 } 1080 1081 static const struct udevice_id rk1808_clk_ids[] = { 1082 { .compatible = "rockchip,rk1808-cru" }, 1083 { } 1084 }; 1085 1086 U_BOOT_DRIVER(rockchip_rk1808_cru) = { 1087 .name = "rockchip_rk1808_cru", 1088 .id = UCLASS_CLK, 1089 .of_match = rk1808_clk_ids, 1090 .priv_auto_alloc_size = sizeof(struct rk1808_clk_priv), 1091 .ofdata_to_platdata = rk1808_clk_ofdata_to_platdata, 1092 .ops = &rk1808_clk_ops, 1093 .bind = rk1808_clk_bind, 1094 .probe = rk1808_clk_probe, 1095 }; 1096 1097 #ifndef CONFIG_SPL_BUILD 1098 /** 1099 * soc_clk_dump() - Print clock frequencies 1100 * Returns zero on success 1101 * 1102 * Implementation for the clk dump command. 1103 */ 1104 int soc_clk_dump(void) 1105 { 1106 struct udevice *cru_dev; 1107 const struct rk1808_clk_info *clk_dump; 1108 struct clk clk; 1109 unsigned long clk_count = ARRAY_SIZE(clks_dump); 1110 unsigned long rate; 1111 int i, ret; 1112 1113 ret = uclass_get_device_by_driver(UCLASS_CLK, 1114 DM_GET_DRIVER(rockchip_rk1808_cru), 1115 &cru_dev); 1116 if (ret) { 1117 printf("%s failed to get cru device\n", __func__); 1118 return ret; 1119 } 1120 1121 printf("CLK:"); 1122 for (i = 0; i < clk_count; i++) { 1123 clk_dump = &clks_dump[i]; 1124 if (clk_dump->name) { 1125 clk.id = clk_dump->id; 1126 if (clk_dump->is_cru) 1127 ret = clk_request(cru_dev, &clk); 1128 if (ret < 0) 1129 return ret; 1130 1131 rate = clk_get_rate(&clk); 1132 clk_free(&clk); 1133 if (i == 0) { 1134 if (rate < 0) 1135 printf("%s %s\n", clk_dump->name, 1136 "unknown"); 1137 else 1138 printf("%s %lu KHz\n", clk_dump->name, 1139 rate / 1000); 1140 } else { 1141 if (rate < 0) 1142 printf("%s %s\n", clk_dump->name, 1143 "unknown"); 1144 else 1145 printf("%s %lu KHz\n", clk_dump->name, 1146 rate / 1000); 1147 } 1148 } 1149 } 1150 1151 return 0; 1152 } 1153 #endif 1154