1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2023 Rockchip Electronics Co., Ltd 4 * Author: Finley Xiao <finley.xiao@rock-chips.com> 5 */ 6 7 #include <common.h> 8 #include <clk-uclass.h> 9 #include <dm.h> 10 #include <syscon.h> 11 #include <asm/arch/clock.h> 12 #include <asm/arch/cru_rk3506.h> 13 #include <asm/arch/grf_rk3506.h> 14 #include <asm/arch/hardware.h> 15 #include <asm/io.h> 16 #include <dm/lists.h> 17 #include <dt-bindings/clock/rockchip,rk3506-cru.h> 18 19 DECLARE_GLOBAL_DATA_PTR; 20 21 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) 22 23 /* 24 * [FRAC PLL]: GPLL, V0PLL, V1PLL 25 * - VCO Frequency: 950MHz to 3800MHZ 26 * - Output Frequency: 19MHz to 3800MHZ 27 * - refdiv: 1 to 63 (Int Mode), 1 to 2 (Frac Mode) 28 * - fbdiv: 16 to 3800 (Int Mode), 20 to 380 (Frac Mode) 29 * - post1div: 1 to 7 30 * - post2div: 1 to 7 31 */ 32 static struct rockchip_pll_rate_table rk3506_pll_rates[] = { 33 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */ 34 RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0), 35 RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0), 36 RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0), 37 RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0), 38 RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0), 39 RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0), 40 RK3036_PLL_RATE(1350000000, 4, 225, 1, 1, 1, 0), 41 RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0), 42 RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0), 43 RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0), 44 RK3036_PLL_RATE(1179648000, 1, 49, 1, 1, 0, 2550137), 45 RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0), 46 RK3036_PLL_RATE(1000000000, 3, 125, 1, 1, 1, 0), 47 RK3036_PLL_RATE(993484800, 1, 41, 1, 1, 0, 6630355), 48 RK3036_PLL_RATE(983040000, 1, 40, 1, 1, 0, 16106127), 49 RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0), 50 RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0), 51 RK3036_PLL_RATE(903168000, 1, 75, 2, 1, 0, 4429185), 52 RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0), 53 RK3036_PLL_RATE(800000000, 3, 200, 2, 1, 1, 0), 54 RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0), 55 RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0), 56 RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0), 57 RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0), 58 RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0), 59 RK3036_PLL_RATE(96000000, 1, 48, 6, 2, 1, 0), 60 { /* sentinel */ }, 61 }; 62 63 static struct rockchip_pll_clock rk3506_pll_clks[] = { 64 [GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3506_PLL_CON(0), 65 RK3506_MODE_CON, 0, 10, 0, rk3506_pll_rates), 66 [V0PLL] = PLL(pll_rk3328, PLL_V0PLL, RK3506_PLL_CON(8), 67 RK3506_MODE_CON, 2, 10, 0, rk3506_pll_rates), 68 [V1PLL] = PLL(pll_rk3328, PLL_V1PLL, RK3506_PLL_CON(16), 69 RK3506_MODE_CON, 4, 10, 0, rk3506_pll_rates), 70 }; 71 72 #define RK3506_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg) \ 73 { \ 74 .rate = _rate##U, \ 75 .aclk_div = _aclk_m_core, \ 76 .pclk_div = _pclk_dbg, \ 77 } 78 79 /* SIGN-OFF: aclk_core: 500M, pclk_core: 125M, */ 80 static struct rockchip_cpu_rate_table rk3506_cpu_rates[] = { 81 RK3506_CPUCLK_RATE(1179648000, 1, 6), 82 RK3506_CPUCLK_RATE(903168000, 1, 5), 83 RK3506_CPUCLK_RATE(800000000, 1, 4), 84 RK3506_CPUCLK_RATE(589824000, 1, 3), 85 RK3506_CPUCLK_RATE(400000000, 1, 2), 86 RK3506_CPUCLK_RATE(200000000, 1, 1), 87 { /* sentinel */ }, 88 }; 89 90 #ifndef CONFIG_SPL_BUILD 91 #define RK3506_CLK_DUMP(_id, _name) \ 92 { \ 93 .id = _id, \ 94 .name = _name, \ 95 } 96 97 static const struct rk3506_clk_info clks_dump[] = { 98 RK3506_CLK_DUMP(PLL_GPLL, "gpll"), 99 RK3506_CLK_DUMP(PLL_V0PLL, "v0pll"), 100 RK3506_CLK_DUMP(PLL_V1PLL, "v1pll"), 101 RK3506_CLK_DUMP(CLK_GPLL_DIV, "clk_gpll_div"), 102 RK3506_CLK_DUMP(CLK_GPLL_DIV_100M, "clk_gpll_div_100m"), 103 RK3506_CLK_DUMP(CLK_V0PLL_DIV, "clk_v0pll_div"), 104 RK3506_CLK_DUMP(CLK_V1PLL_DIV, "clk_v1pll_div"), 105 RK3506_CLK_DUMP(ACLK_BUS_ROOT, "aclk_bus_root"), 106 RK3506_CLK_DUMP(HCLK_BUS_ROOT, "hclk_bus_root"), 107 RK3506_CLK_DUMP(PCLK_BUS_ROOT, "pclk_bus_root"), 108 RK3506_CLK_DUMP(ACLK_HSPERI_ROOT, "aclk_hsperi_root"), 109 RK3506_CLK_DUMP(HCLK_LSPERI_ROOT, "hclk_ksperi_root"), 110 }; 111 112 /** 113 * soc_clk_dump() - Print clock frequencies 114 * Returns zero on success 115 * 116 * Implementation for the clk dump command. 117 */ 118 int soc_clk_dump(void) 119 { 120 const struct rk3506_clk_info *clk_dump; 121 struct rk3506_clk_priv *priv; 122 struct udevice *cru_dev; 123 struct clk clk; 124 ulong clk_count = ARRAY_SIZE(clks_dump); 125 ulong rate; 126 int i, ret; 127 u32 sel; 128 129 ret = uclass_get_device_by_driver(UCLASS_CLK, 130 DM_GET_DRIVER(rockchip_rk3506_cru), 131 &cru_dev); 132 if (ret) { 133 printf("%s failed to get cru device\n", __func__); 134 return ret; 135 } 136 137 priv = dev_get_priv(cru_dev); 138 sel = (readl(&priv->cru->clksel_con[15]) & 139 CLK_CORE_SRC_PVTMUX_SEL_MASK) >> 140 CLK_CORE_SRC_PVTMUX_SEL_SHIFT; 141 if (sel == CLK_CORE_PVTPLL_SRC) 142 printf("CLK: (arm clk use pvtpll, rate = 1200M)\n"); 143 else 144 printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n", 145 priv->sync_kernel ? "sync kernel" : "uboot", 146 priv->armclk_enter_hz / 1000, 147 priv->armclk_init_hz / 1000, 148 priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0, 149 priv->set_armclk_rate ? " KHz" : "N/A"); 150 for (i = 0; i < clk_count; i++) { 151 clk_dump = &clks_dump[i]; 152 if (clk_dump->name) { 153 clk.id = clk_dump->id; 154 ret = clk_request(cru_dev, &clk); 155 if (ret < 0) 156 return ret; 157 158 rate = clk_get_rate(&clk); 159 clk_free(&clk); 160 if (i == 0) { 161 if (rate < 0) 162 printf(" %s %s\n", clk_dump->name, 163 "unknown"); 164 else 165 printf(" %s %lu KHz\n", clk_dump->name, 166 rate / 1000); 167 } else { 168 if (rate < 0) 169 printf(" %s %s\n", clk_dump->name, 170 "unknown"); 171 else 172 printf(" %s %lu KHz\n", clk_dump->name, 173 rate / 1000); 174 } 175 } 176 } 177 178 return 0; 179 } 180 #endif 181 182 static int rk3506_armclk_get_rate(struct rk3506_clk_priv *priv) 183 { 184 struct rk3506_cru *cru = priv->cru; 185 u32 sel, con, div; 186 ulong prate; 187 188 con = readl(&cru->clksel_con[15]); 189 sel = (con & CLK_CORE_SRC_SEL_MASK) >> CLK_CORE_SRC_SEL_SHIFT; 190 div = (con & CLK_CORE_SRC_DIV_MASK) >> CLK_CORE_SRC_DIV_SHIFT; 191 192 if (sel == CLK_CORE_SEL_GPLL) 193 prate = priv->gpll_hz; 194 else if (sel == CLK_CORE_SEL_V0PLL) 195 prate = priv->v0pll_hz; 196 else if (sel == CLK_CORE_SEL_V1PLL) 197 prate = priv->v1pll_hz; 198 else 199 return -EINVAL; 200 201 return DIV_TO_RATE(prate, div); 202 } 203 204 static int rk3506_armclk_set_rate(struct rk3506_clk_priv *priv, ulong new_rate) 205 { 206 const struct rockchip_cpu_rate_table *rate; 207 struct rk3506_cru *cru = priv->cru; 208 ulong old_rate, prate; 209 u32 con, sel, div, old_div; 210 211 rate = rockchip_get_cpu_settings(rk3506_cpu_rates, new_rate); 212 if (!rate) { 213 printf("%s unsupported rate\n", __func__); 214 return -EINVAL; 215 } 216 217 /* 218 * set up dependent divisors for PCLK and ACLK clocks. 219 */ 220 old_rate = rk3506_armclk_get_rate(priv); 221 if (new_rate >= old_rate) { 222 rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK, 223 rate->aclk_div << ACLK_CORE_DIV_SHIFT); 224 rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK, 225 rate->pclk_div << PCLK_CORE_DIV_SHIFT); 226 } 227 228 if (new_rate == 589824000 || new_rate == 1179648000) { 229 sel = CLK_CORE_SEL_V0PLL; 230 div = DIV_ROUND_UP(priv->v0pll_hz, new_rate); 231 prate = priv->v0pll_hz; 232 } else if (new_rate == 903168000) { 233 sel = CLK_CORE_SEL_V1PLL; 234 div = DIV_ROUND_UP(priv->v1pll_hz, new_rate); 235 prate = priv->v1pll_hz; 236 } else { 237 sel = CLK_CORE_SEL_GPLL; 238 div = DIV_ROUND_UP(priv->gpll_hz, new_rate); 239 prate = priv->gpll_hz; 240 } 241 assert(div - 1 <= 31); 242 243 con = readl(&cru->clksel_con[15]); 244 old_div = (con & CLK_CORE_SRC_DIV_MASK) >> CLK_CORE_SRC_DIV_SHIFT; 245 if (DIV_TO_RATE(prate, old_div) > new_rate) { 246 rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK, 247 (div - 1) << CLK_CORE_SRC_DIV_SHIFT); 248 rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK, 249 sel << CLK_CORE_SRC_SEL_SHIFT); 250 } else { 251 rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK, 252 sel << CLK_CORE_SRC_SEL_SHIFT); 253 rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK, 254 (div - 1) << CLK_CORE_SRC_DIV_SHIFT); 255 } 256 257 if (new_rate < old_rate) { 258 rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK, 259 rate->aclk_div << ACLK_CORE_DIV_SHIFT); 260 rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK, 261 rate->pclk_div << PCLK_CORE_DIV_SHIFT); 262 } 263 264 return 0; 265 } 266 267 static ulong rk3506_pll_div_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 268 { 269 struct rk3506_cru *cru = priv->cru; 270 u32 con, div; 271 ulong prate; 272 273 switch (clk_id) { 274 case CLK_GPLL_DIV: 275 con = readl(&cru->clksel_con[0]); 276 div = (con & CLK_GPLL_DIV_MASK) >> CLK_GPLL_DIV_SHIFT; 277 prate = priv->gpll_hz; 278 break; 279 case CLK_GPLL_DIV_100M: 280 con = readl(&cru->clksel_con[0]); 281 div = (con & CLK_GPLL_DIV_100M_MASK) >> CLK_GPLL_DIV_100M_SHIFT; 282 prate = priv->gpll_div_hz; 283 break; 284 case CLK_V0PLL_DIV: 285 con = readl(&cru->clksel_con[1]); 286 div = (con & CLK_V0PLL_DIV_MASK) >> CLK_V0PLL_DIV_SHIFT; 287 prate = priv->v0pll_hz; 288 break; 289 case CLK_V1PLL_DIV: 290 con = readl(&cru->clksel_con[1]); 291 div = (con & CLK_V1PLL_DIV_MASK) >> CLK_V1PLL_DIV_SHIFT; 292 prate = priv->v1pll_hz; 293 break; 294 default: 295 return -ENOENT; 296 } 297 298 return DIV_TO_RATE(prate, div); 299 } 300 301 static ulong rk3506_pll_div_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 302 ulong rate) 303 { 304 struct rk3506_cru *cru = priv->cru; 305 u32 div; 306 307 switch (clk_id) { 308 case CLK_GPLL_DIV: 309 div = DIV_ROUND_UP(priv->gpll_hz, rate); 310 assert(div - 1 <= 15); 311 rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_MASK, 312 ((div - 1) << CLK_GPLL_DIV_SHIFT)); 313 break; 314 case CLK_GPLL_DIV_100M: 315 div = DIV_ROUND_UP(priv->gpll_div_hz, rate); 316 assert(div - 1 <= 15); 317 rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_100M_MASK, 318 ((div - 1) << CLK_GPLL_DIV_100M_SHIFT)); 319 break; 320 case CLK_V0PLL_DIV: 321 div = DIV_ROUND_UP(priv->v0pll_hz, rate); 322 assert(div - 1 <= 15); 323 rk_clrsetreg(&cru->clksel_con[1], CLK_V0PLL_DIV_MASK, 324 ((div - 1) << CLK_V0PLL_DIV_SHIFT)); 325 break; 326 case CLK_V1PLL_DIV: 327 div = DIV_ROUND_UP(priv->v1pll_hz, rate); 328 assert(div - 1 <= 15); 329 rk_clrsetreg(&cru->clksel_con[1], CLK_V1PLL_DIV_MASK, 330 ((div - 1) << CLK_V1PLL_DIV_SHIFT)); 331 break; 332 default: 333 return -ENOENT; 334 } 335 336 return rk3506_pll_div_get_rate(priv, clk_id); 337 } 338 339 static ulong rk3506_bus_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 340 { 341 struct rk3506_cru *cru = priv->cru; 342 u32 sel, con, div; 343 ulong prate; 344 345 switch (clk_id) { 346 case ACLK_BUS_ROOT: 347 con = readl(&cru->clksel_con[21]); 348 sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT; 349 div = (con & ACLK_BUS_DIV_MASK) >> ACLK_BUS_DIV_SHIFT; 350 break; 351 case HCLK_BUS_ROOT: 352 con = readl(&cru->clksel_con[21]); 353 sel = (con & HCLK_BUS_SEL_MASK) >> HCLK_BUS_SEL_SHIFT; 354 div = (con & HCLK_BUS_DIV_MASK) >> HCLK_BUS_DIV_SHIFT; 355 break; 356 case PCLK_BUS_ROOT: 357 con = readl(&cru->clksel_con[22]); 358 sel = (con & PCLK_BUS_SEL_MASK) >> PCLK_BUS_SEL_SHIFT; 359 div = (con & PCLK_BUS_DIV_MASK) >> PCLK_BUS_DIV_SHIFT; 360 break; 361 default: 362 return -ENOENT; 363 } 364 365 if (sel == ACLK_BUS_SEL_GPLL_DIV) 366 prate = priv->gpll_div_hz; 367 else if (sel == ACLK_BUS_SEL_V0PLL_DIV) 368 prate = priv->v0pll_div_hz; 369 else if (sel == ACLK_BUS_SEL_V1PLL_DIV) 370 prate = priv->v1pll_div_hz; 371 else 372 return -EINVAL; 373 374 return DIV_TO_RATE(prate, div); 375 } 376 377 static ulong rk3506_bus_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 378 ulong rate) 379 { 380 struct rk3506_cru *cru = priv->cru; 381 u32 sel, div; 382 383 if (priv->v0pll_div_hz % rate == 0) { 384 sel = ACLK_BUS_SEL_V0PLL_DIV; 385 div = DIV_ROUND_UP(priv->v0pll_div_hz, rate); 386 } else if (priv->v1pll_div_hz % rate == 0) { 387 sel= ACLK_BUS_SEL_V1PLL_DIV; 388 div = DIV_ROUND_UP(priv->v1pll_div_hz, rate); 389 } else { 390 sel= ACLK_BUS_SEL_GPLL_DIV; 391 div = DIV_ROUND_UP(priv->gpll_div_hz, rate); 392 } 393 assert(div - 1 <= 31); 394 395 switch (clk_id) { 396 case ACLK_BUS_ROOT: 397 rk_clrsetreg(&cru->clksel_con[21], 398 ACLK_BUS_DIV_MASK | ACLK_BUS_SEL_MASK, 399 (sel << ACLK_BUS_SEL_SHIFT) | 400 ((div - 1) << ACLK_BUS_DIV_SHIFT)); 401 break; 402 case HCLK_BUS_ROOT: 403 rk_clrsetreg(&cru->clksel_con[21], 404 HCLK_BUS_SEL_MASK | HCLK_BUS_DIV_MASK, 405 (sel << HCLK_BUS_SEL_SHIFT) | 406 ((div - 1) << HCLK_BUS_DIV_SHIFT)); 407 break; 408 case PCLK_BUS_ROOT: 409 rk_clrsetreg(&cru->clksel_con[22], 410 PCLK_BUS_SEL_MASK | PCLK_BUS_DIV_MASK, 411 (sel << PCLK_BUS_SEL_SHIFT) | 412 ((div - 1) << PCLK_BUS_DIV_SHIFT)); 413 break; 414 default: 415 return -ENOENT; 416 } 417 418 return rk3506_bus_get_rate(priv, clk_id); 419 } 420 421 static ulong rk3506_peri_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 422 { 423 struct rk3506_cru *cru = priv->cru; 424 u32 sel, con, div; 425 ulong prate; 426 427 switch (clk_id) { 428 case ACLK_HSPERI_ROOT: 429 con = readl(&cru->clksel_con[49]); 430 sel = (con & ACLK_HSPERI_SEL_MASK) >> ACLK_HSPERI_SEL_SHIFT; 431 div = (con & ACLK_HSPERI_DIV_MASK) >> ACLK_HSPERI_DIV_SHIFT; 432 break; 433 case HCLK_LSPERI_ROOT: 434 con = readl(&cru->clksel_con[29]); 435 sel = (con & HCLK_LSPERI_SEL_MASK) >> HCLK_LSPERI_SEL_SHIFT; 436 div = (con & HCLK_LSPERI_DIV_MASK) >> HCLK_LSPERI_DIV_SHIFT; 437 break; 438 default: 439 return -ENOENT; 440 } 441 442 if (sel == ACLK_HSPERI_SEL_GPLL_DIV) 443 prate = priv->gpll_div_hz; 444 else if (sel == ACLK_HSPERI_SEL_V0PLL_DIV) 445 prate = priv->v0pll_div_hz; 446 else if (sel == ACLK_HSPERI_SEL_V1PLL_DIV) 447 prate = priv->v1pll_div_hz; 448 else 449 return -EINVAL; 450 451 return DIV_TO_RATE(prate, div); 452 } 453 454 static ulong rk3506_peri_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 455 ulong rate) 456 { 457 struct rk3506_cru *cru = priv->cru; 458 u32 sel, div; 459 460 if (priv->v0pll_div_hz % rate == 0) { 461 sel = ACLK_BUS_SEL_V0PLL_DIV; 462 div = DIV_ROUND_UP(priv->v0pll_div_hz, rate); 463 } else if (priv->v1pll_div_hz % rate == 0) { 464 sel = ACLK_BUS_SEL_V1PLL_DIV; 465 div = DIV_ROUND_UP(priv->v1pll_div_hz, rate); 466 } else { 467 sel = ACLK_BUS_SEL_GPLL_DIV; 468 div = DIV_ROUND_UP(priv->gpll_div_hz, rate); 469 } 470 assert(div - 1 <= 31); 471 472 switch (clk_id) { 473 case ACLK_HSPERI_ROOT: 474 rk_clrsetreg(&cru->clksel_con[49], 475 ACLK_HSPERI_SEL_MASK | ACLK_HSPERI_DIV_MASK, 476 (sel << ACLK_HSPERI_SEL_SHIFT) | 477 ((div - 1) << ACLK_HSPERI_DIV_SHIFT)); 478 break; 479 case HCLK_LSPERI_ROOT: 480 rk_clrsetreg(&cru->clksel_con[29], 481 HCLK_LSPERI_SEL_MASK | HCLK_LSPERI_DIV_MASK, 482 (sel << HCLK_LSPERI_SEL_SHIFT) | 483 ((div - 1) << HCLK_LSPERI_DIV_SHIFT)); 484 break; 485 default: 486 return -ENOENT; 487 } 488 489 return rk3506_peri_get_rate(priv, clk_id); 490 } 491 492 static ulong rk3506_sdmmc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 493 { 494 struct rk3506_cru *cru = priv->cru; 495 u32 sel, con, div; 496 ulong prate; 497 498 con = readl(&cru->clksel_con[49]); 499 sel = (con & CCLK_SDMMC_SEL_MASK) >> CCLK_SDMMC_SEL_SHIFT; 500 div = (con & CCLK_SDMMC_DIV_MASK) >> CCLK_SDMMC_DIV_SHIFT; 501 502 if (sel == CCLK_SDMMC_SEL_24M) 503 prate = OSC_HZ; 504 else if (sel == CCLK_SDMMC_SEL_GPLL) 505 prate = priv->gpll_hz; 506 else if (sel == CCLK_SDMMC_SEL_V0PLL) 507 prate = priv->v0pll_hz; 508 else if (sel == CCLK_SDMMC_SEL_V1PLL) 509 prate = priv->v1pll_hz; 510 else 511 return -EINVAL; 512 513 return DIV_TO_RATE(prate, div); 514 } 515 516 static ulong rk3506_sdmmc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 517 ulong rate) 518 { 519 struct rk3506_cru *cru = priv->cru; 520 u32 sel, div; 521 522 if (OSC_HZ % rate == 0) { 523 sel = CCLK_SDMMC_SEL_24M; 524 div = DIV_ROUND_UP(OSC_HZ, rate); 525 } else if (priv->v0pll_hz % rate == 0) { 526 sel = CCLK_SDMMC_SEL_V0PLL; 527 div = DIV_ROUND_UP(priv->v0pll_hz, rate); 528 } else if (priv->v1pll_hz % rate == 0) { 529 sel= CCLK_SDMMC_SEL_V1PLL; 530 div = DIV_ROUND_UP(priv->v1pll_hz, rate); 531 } else { 532 sel= CCLK_SDMMC_SEL_GPLL; 533 div = DIV_ROUND_UP(priv->gpll_hz, rate); 534 } 535 assert(div - 1 <= 63); 536 537 rk_clrsetreg(&cru->clksel_con[49], 538 CCLK_SDMMC_SEL_MASK | CCLK_SDMMC_DIV_MASK, 539 (sel << CCLK_SDMMC_SEL_SHIFT) | 540 ((div - 1) << CCLK_SDMMC_DIV_SHIFT)); 541 542 return rk3506_sdmmc_get_rate(priv, clk_id); 543 } 544 545 static ulong rk3506_saradc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 546 { 547 struct rk3506_cru *cru = priv->cru; 548 u32 div, con, sel; 549 ulong prate; 550 551 con = readl(&cru->clksel_con[54]); 552 div = (con & CLK_SARADC_DIV_MASK) >> CLK_SARADC_DIV_SHIFT; 553 sel = (con & CLK_SARADC_SEL_MASK) >> CLK_SARADC_SEL_SHIFT; 554 555 if (sel == CLK_SARADC_SEL_24M) 556 prate = OSC_HZ; 557 else if (sel == CLK_SARADC_SEL_400K) 558 prate = 400000; 559 else if (sel == CLK_SARADC_SEL_32K) 560 prate = 32000; 561 else 562 return -EINVAL; 563 564 return DIV_TO_RATE(prate, div); 565 } 566 567 static ulong rk3506_saradc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 568 ulong rate) 569 { 570 struct rk3506_cru *cru = priv->cru; 571 u32 div, sel; 572 573 if (32000 % rate == 0) { 574 sel = CLK_SARADC_SEL_32K; 575 div = 1; 576 } else if (400000 % rate == 0) { 577 sel = CLK_SARADC_SEL_400K; 578 div = 1; 579 } else { 580 sel= CLK_SARADC_SEL_24M; 581 div = DIV_ROUND_UP(OSC_HZ, rate); 582 } 583 assert(div - 1 <= 15); 584 585 rk_clrsetreg(&cru->clksel_con[54], 586 CLK_SARADC_SEL_MASK | CLK_SARADC_DIV_MASK, 587 (sel << CLK_SARADC_SEL_SHIFT) | 588 ((div - 1) << CLK_SARADC_DIV_SHIFT)); 589 590 return rk3506_saradc_get_rate(priv, clk_id); 591 } 592 593 static ulong rk3506_tsadc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 594 { 595 struct rk3506_cru *cru = priv->cru; 596 u32 div, con; 597 598 con = readl(&cru->clksel_con[61]); 599 switch (clk_id) { 600 case CLK_TSADC_TSEN: 601 div = (con & CLK_TSADC_TSEN_DIV_MASK) >> CLK_TSADC_TSEN_DIV_SHIFT; 602 break; 603 case CLK_TSADC: 604 div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT; 605 break; 606 default: 607 return -ENOENT; 608 } 609 610 return DIV_TO_RATE(OSC_HZ, div); 611 } 612 613 static ulong rk3506_tsadc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 614 ulong rate) 615 { 616 struct rk3506_cru *cru = priv->cru; 617 u32 div; 618 619 switch (clk_id) { 620 case CLK_TSADC_TSEN: 621 div = DIV_ROUND_UP(OSC_HZ, rate); 622 assert(div - 1 <= 7); 623 rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_TSEN_DIV_MASK, 624 (div - 1) << CLK_TSADC_TSEN_DIV_SHIFT); 625 break; 626 case CLK_TSADC: 627 div = DIV_ROUND_UP(OSC_HZ, rate); 628 assert(div - 1 <= 255); 629 rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_DIV_MASK, 630 (div - 1) << CLK_TSADC_DIV_SHIFT); 631 break; 632 default: 633 return -ENOENT; 634 } 635 636 637 return rk3506_tsadc_get_rate(priv, clk_id); 638 } 639 640 static ulong rk3506_i2c_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 641 { 642 struct rk3506_cru *cru = priv->cru; 643 u32 sel, con, div; 644 ulong prate; 645 646 switch (clk_id) { 647 case CLK_I2C0: 648 con = readl(&cru->clksel_con[32]); 649 sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT; 650 div = (con & CLK_I2C0_DIV_MASK) >> CLK_I2C0_DIV_SHIFT; 651 case CLK_I2C1: 652 con = readl(&cru->clksel_con[32]); 653 sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT; 654 div = (con & CLK_I2C1_DIV_MASK) >> CLK_I2C1_DIV_SHIFT; 655 case CLK_I2C2: 656 con = readl(&cru->clksel_con[33]); 657 sel = (con & CLK_I2C2_SEL_MASK) >> CLK_I2C2_SEL_SHIFT; 658 div = (con & CLK_I2C2_DIV_MASK) >> CLK_I2C2_DIV_SHIFT; 659 break; 660 default: 661 return -ENOENT; 662 } 663 664 if (sel == CLK_I2C_SEL_GPLL) 665 prate = priv->gpll_hz; 666 else if (sel == CLK_I2C_SEL_V0PLL) 667 prate = priv->v0pll_hz; 668 else if (sel == CLK_I2C_SEL_V1PLL) 669 prate = priv->v1pll_hz; 670 else 671 return -EINVAL; 672 673 return DIV_TO_RATE(prate, div); 674 } 675 676 static ulong rk3506_i2c_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 677 ulong rate) 678 { 679 struct rk3506_cru *cru = priv->cru; 680 u32 sel, div; 681 682 if (priv->v0pll_hz % rate == 0) { 683 sel = CLK_I2C_SEL_V0PLL; 684 div = DIV_ROUND_UP(priv->v0pll_hz, rate); 685 } else if (priv->v1pll_hz % rate == 0) { 686 sel = CLK_I2C_SEL_V1PLL; 687 div = DIV_ROUND_UP(priv->v1pll_hz, rate); 688 } else { 689 sel = CLK_I2C_SEL_GPLL; 690 div = DIV_ROUND_UP(priv->gpll_hz, rate); 691 } 692 assert(div - 1 <= 15); 693 694 switch (clk_id) { 695 case CLK_I2C0: 696 rk_clrsetreg(&cru->clksel_con[32], 697 CLK_I2C0_SEL_MASK | CLK_I2C0_DIV_MASK, 698 (sel << CLK_I2C0_SEL_SHIFT) | 699 ((div - 1) << CLK_I2C0_DIV_SHIFT)); 700 break; 701 case CLK_I2C1: 702 rk_clrsetreg(&cru->clksel_con[32], 703 CLK_I2C1_SEL_MASK | CLK_I2C1_DIV_MASK, 704 (sel << CLK_I2C1_SEL_SHIFT) | 705 ((div - 1) << CLK_I2C1_DIV_SHIFT)); 706 break; 707 case CLK_I2C2: 708 rk_clrsetreg(&cru->clksel_con[33], 709 CLK_I2C2_SEL_MASK | CLK_I2C2_DIV_MASK, 710 (sel << CLK_I2C2_SEL_SHIFT) | 711 ((div - 1) << CLK_I2C2_DIV_SHIFT)); 712 break; 713 default: 714 return -ENOENT; 715 } 716 717 718 return rk3506_i2c_get_rate(priv, clk_id); 719 } 720 721 static ulong rk3506_pwm_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 722 { 723 struct rk3506_cru *cru = priv->cru; 724 u32 sel, con, div; 725 ulong prate; 726 727 switch (clk_id) { 728 case CLK_PWM0: 729 con = readl(&cru->pmuclksel_con[0]); 730 div = (con & CLK_PWM0_DIV_MASK) >> CLK_PWM0_DIV_SHIFT; 731 prate = priv->gpll_div_100mhz; 732 break; 733 case CLK_PWM1: 734 con = readl(&cru->clksel_con[33]); 735 sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT; 736 div = (con & CLK_PWM1_DIV_MASK) >> CLK_PWM1_DIV_SHIFT; 737 if (sel == CLK_PWM1_SEL_GPLL_DIV) 738 prate = priv->gpll_div_hz; 739 else if (sel == CLK_PWM1_SEL_V0PLL_DIV) 740 prate = priv->v0pll_div_hz; 741 else if (sel == CLK_PWM1_SEL_V1PLL_DIV) 742 prate = priv->v1pll_div_hz; 743 else 744 return -EINVAL; 745 break; 746 default: 747 return -ENOENT; 748 } 749 750 return DIV_TO_RATE(prate, div); 751 } 752 753 static ulong rk3506_pwm_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 754 ulong rate) 755 { 756 struct rk3506_cru *cru = priv->cru; 757 u32 sel, div; 758 759 switch (clk_id) { 760 case CLK_PWM0: 761 div = DIV_ROUND_UP(priv->gpll_div_100mhz, rate); 762 assert(div - 1 <= 15); 763 rk_clrsetreg(&cru->pmuclksel_con[0], CLK_PWM0_DIV_MASK, 764 (div - 1) << CLK_PWM0_DIV_SHIFT); 765 break; 766 case CLK_PWM1: 767 if (priv->v0pll_hz % rate == 0) { 768 sel = CLK_PWM1_SEL_V0PLL_DIV; 769 div = DIV_ROUND_UP(priv->v0pll_div_hz, rate); 770 } else if (priv->v1pll_hz % rate == 0) { 771 sel = CLK_PWM1_SEL_V1PLL_DIV; 772 div = DIV_ROUND_UP(priv->v1pll_div_hz, rate); 773 } else { 774 sel = CLK_PWM1_SEL_GPLL_DIV; 775 div = DIV_ROUND_UP(priv->gpll_div_hz, rate); 776 } 777 assert(div - 1 <= 15); 778 rk_clrsetreg(&cru->clksel_con[33], 779 CLK_PWM1_SEL_MASK | CLK_PWM1_DIV_MASK, 780 (sel << CLK_PWM1_SEL_SHIFT) | 781 ((div - 1) << CLK_PWM1_DIV_SHIFT)); 782 break; 783 default: 784 return -ENOENT; 785 } 786 787 return rk3506_pwm_get_rate(priv, clk_id); 788 } 789 790 static ulong rk3506_spi_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 791 { 792 struct rk3506_cru *cru = priv->cru; 793 u32 sel, con, div; 794 ulong prate; 795 796 switch (clk_id) { 797 case CLK_SPI0: 798 con = readl(&cru->clksel_con[34]); 799 sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT; 800 div = (con & CLK_SPI0_DIV_MASK) >> CLK_SPI0_DIV_SHIFT; 801 break; 802 case CLK_SPI1: 803 con = readl(&cru->clksel_con[34]); 804 sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT; 805 div = (con & CLK_SPI1_DIV_MASK) >> CLK_SPI1_DIV_SHIFT; 806 break; 807 default: 808 return -ENOENT; 809 } 810 811 if (sel == CLK_SPI_SEL_24M) 812 prate = OSC_HZ; 813 else if (sel == CLK_SPI_SEL_GPLL_DIV) 814 prate = priv->gpll_div_hz; 815 else if (sel == CLK_SPI_SEL_V0PLL_DIV) 816 prate = priv->v0pll_div_hz; 817 else if (sel == CLK_SPI_SEL_V1PLL_DIV) 818 prate = priv->v1pll_div_hz; 819 else 820 return -EINVAL; 821 822 return DIV_TO_RATE(prate, div); 823 } 824 825 static ulong rk3506_spi_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 826 ulong rate) 827 { 828 struct rk3506_cru *cru = priv->cru; 829 u32 sel, div; 830 831 if (OSC_HZ % rate == 0) { 832 sel = CLK_SPI_SEL_24M; 833 div = DIV_ROUND_UP(OSC_HZ, rate); 834 } else if (priv->v0pll_div_hz % rate == 0) { 835 sel = CLK_SPI_SEL_V0PLL_DIV; 836 div = DIV_ROUND_UP(priv->v0pll_div_hz, rate); 837 } else if (priv->v1pll_div_hz % rate == 0) { 838 sel = CLK_SPI_SEL_V1PLL_DIV; 839 div = DIV_ROUND_UP(priv->v1pll_div_hz, rate); 840 } else { 841 sel = CLK_SPI_SEL_GPLL_DIV; 842 div = DIV_ROUND_UP(priv->gpll_div_hz, rate); 843 } 844 assert(div - 1 <= 15); 845 846 switch (clk_id) { 847 case CLK_SPI0: 848 rk_clrsetreg(&cru->clksel_con[34], 849 CLK_SPI0_SEL_MASK | CLK_SPI0_DIV_MASK, 850 (sel << CLK_SPI0_SEL_SHIFT) | 851 ((div - 1) << CLK_SPI0_DIV_SHIFT)); 852 break; 853 case CLK_SPI1: 854 rk_clrsetreg(&cru->clksel_con[34], 855 CLK_SPI1_SEL_MASK | CLK_SPI1_DIV_MASK, 856 (sel << CLK_SPI1_SEL_SHIFT) | 857 ((div - 1) << CLK_SPI1_DIV_SHIFT)); 858 break; 859 default: 860 return -ENOENT; 861 } 862 863 return rk3506_spi_get_rate(priv, clk_id); 864 } 865 866 static ulong rk3506_fspi_get_rate(struct rk3506_clk_priv *priv) 867 { 868 struct rk3506_cru *cru = priv->cru; 869 u32 div, sel, con, prate; 870 871 con = readl(&cru->clksel_con[50]); 872 div = (con & SCLK_FSPI_DIV_MASK) >> SCLK_FSPI_DIV_SHIFT; 873 sel = (con & SCLK_FSPI_SEL_MASK) >> SCLK_FSPI_SEL_SHIFT; 874 if (sel == SCLK_FSPI_SEL_24M) 875 prate = OSC_HZ; 876 else if (sel == SCLK_FSPI_SEL_GPLL) 877 prate = priv->gpll_hz; 878 else if (sel == SCLK_FSPI_SEL_V0PLL) 879 prate = priv->v0pll_hz; 880 else if (sel == SCLK_FSPI_SEL_V1PLL) 881 prate = priv->v1pll_hz; 882 else 883 return -EINVAL; 884 885 return DIV_TO_RATE(prate, div); 886 } 887 888 static ulong rk3506_fspi_set_rate(struct rk3506_clk_priv *priv, ulong rate) 889 { 890 struct rk3506_cru *cru = priv->cru; 891 int div, sel; 892 893 if (OSC_HZ % rate == 0) { 894 sel = SCLK_FSPI_SEL_24M; 895 div = DIV_ROUND_UP(OSC_HZ, rate); 896 } else if ((priv->v0pll_hz % rate) == 0) { 897 sel = SCLK_FSPI_SEL_V0PLL; 898 div = DIV_ROUND_UP(priv->v0pll_hz, rate); 899 } else if ((priv->v1pll_hz % rate) == 0) { 900 sel = SCLK_FSPI_SEL_V1PLL; 901 div = DIV_ROUND_UP(priv->v1pll_hz, rate); 902 } else { 903 sel = SCLK_FSPI_SEL_GPLL; 904 div = DIV_ROUND_UP(priv->gpll_hz, rate); 905 } 906 assert(div - 1 <= 31); 907 908 rk_clrsetreg(&cru->clksel_con[50], 909 SCLK_FSPI_SEL_MASK | SCLK_FSPI_DIV_MASK, 910 sel << SCLK_FSPI_SEL_SHIFT | 911 (div - 1) << SCLK_FSPI_DIV_SHIFT); 912 913 return rk3506_fspi_get_rate(priv); 914 } 915 916 static ulong rk3506_vop_dclk_get_rate(struct rk3506_clk_priv *priv) 917 { 918 struct rk3506_cru *cru = priv->cru; 919 u32 div, sel, con, prate; 920 921 con = readl(&cru->clksel_con[60]); 922 div = (con & DCLK_VOP_DIV_MASK) >> DCLK_VOP_DIV_SHIFT; 923 sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT; 924 925 if (sel == DCLK_VOP_SEL_24M) 926 prate = OSC_HZ; 927 else if (sel == DCLK_VOP_SEL_GPLL) 928 prate = priv->gpll_hz; 929 else if (sel == DCLK_VOP_SEL_V0PLL) 930 prate = priv->v0pll_hz; 931 else if (sel == DCLK_VOP_SEL_V1PLL) 932 prate = priv->v1pll_hz; 933 else 934 return -EINVAL; 935 936 return DIV_TO_RATE(prate, div); 937 } 938 939 static ulong rk3506_vop_dclk_set_rate(struct rk3506_clk_priv *priv, ulong rate) 940 { 941 struct rk3506_cru *cru = priv->cru; 942 int div, sel; 943 944 if (OSC_HZ % rate == 0) { 945 sel = DCLK_VOP_SEL_24M; 946 div = DIV_ROUND_UP(OSC_HZ, rate); 947 } else if ((priv->v0pll_hz % rate) == 0) { 948 sel = DCLK_VOP_SEL_V0PLL; 949 div = DIV_ROUND_UP(priv->v0pll_hz, rate); 950 } else if ((priv->v1pll_hz % rate) == 0) { 951 sel = DCLK_VOP_SEL_V1PLL; 952 div = DIV_ROUND_UP(priv->v1pll_hz, rate); 953 } else { 954 sel = DCLK_VOP_SEL_GPLL; 955 div = DIV_ROUND_UP(priv->gpll_hz, rate); 956 } 957 assert(div - 1 <= 255); 958 959 rk_clrsetreg(&cru->clksel_con[60], 960 DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK, 961 sel << DCLK_VOP_SEL_SHIFT | 962 (div - 1) << DCLK_VOP_DIV_SHIFT); 963 964 return rk3506_vop_dclk_get_rate(priv); 965 } 966 967 static ulong rk3506_mac_get_rate(struct rk3506_clk_priv *priv, ulong clk_id) 968 { 969 struct rk3506_cru *cru = priv->cru; 970 u32 div, con; 971 972 switch (clk_id) { 973 case CLK_MAC0: 974 case CLK_MAC1: 975 con = readl(&cru->clksel_con[50]); 976 div = (con & CLK_MAC_DIV_MASK) >> CLK_MAC_DIV_SHIFT; 977 break; 978 case CLK_MAC_OUT: 979 con = readl(&cru->pmuclksel_con[0]); 980 div = (con & CLK_MAC_OUT_DIV_MASK) >> CLK_MAC_OUT_DIV_SHIFT; 981 default: 982 return -ENOENT; 983 } 984 985 return DIV_TO_RATE(priv->gpll_hz, div); 986 } 987 988 static ulong rk3506_mac_set_rate(struct rk3506_clk_priv *priv, ulong clk_id, 989 ulong rate) 990 { 991 struct rk3506_cru *cru = priv->cru; 992 u32 div; 993 994 switch (clk_id) { 995 case CLK_MAC0: 996 case CLK_MAC1: 997 div = DIV_ROUND_UP(priv->gpll_hz, rate); 998 rk_clrsetreg(&cru->clksel_con[50], CLK_MAC_DIV_MASK, 999 ((div - 1) << CLK_MAC_DIV_SHIFT)); 1000 break; 1001 case CLK_MAC_OUT: 1002 div = DIV_ROUND_UP(priv->gpll_hz, rate); 1003 rk_clrsetreg(&cru->pmuclksel_con[0], CLK_MAC_OUT_DIV_MASK, 1004 ((div - 1) << CLK_MAC_OUT_DIV_SHIFT)); 1005 default: 1006 return -ENOENT; 1007 } 1008 1009 return rk3506_mac_get_rate(priv, clk_id); 1010 } 1011 1012 static ulong rk3506_clk_get_rate(struct clk *clk) 1013 { 1014 struct rk3506_clk_priv *priv = dev_get_priv(clk->dev); 1015 ulong rate = 0; 1016 1017 if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) { 1018 printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n", 1019 __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz); 1020 return -ENOENT; 1021 } 1022 1023 switch (clk->id) { 1024 case PLL_GPLL: 1025 rate = priv->gpll_hz; 1026 break; 1027 case PLL_V0PLL: 1028 rate = priv->v0pll_hz; 1029 break; 1030 case PLL_V1PLL: 1031 rate = priv->v1pll_hz; 1032 break; 1033 case ARMCLK: 1034 rate = rk3506_armclk_get_rate(priv); 1035 break; 1036 case CLK_GPLL_DIV: 1037 case CLK_GPLL_DIV_100M: 1038 case CLK_V0PLL_DIV: 1039 case CLK_V1PLL_DIV: 1040 rate = rk3506_pll_div_get_rate(priv, clk->id); 1041 break; 1042 case ACLK_BUS_ROOT: 1043 case HCLK_BUS_ROOT: 1044 case PCLK_BUS_ROOT: 1045 rate = rk3506_bus_get_rate(priv, clk->id); 1046 break; 1047 case ACLK_HSPERI_ROOT: 1048 case HCLK_LSPERI_ROOT: 1049 rate = rk3506_peri_get_rate(priv, clk->id); 1050 break; 1051 case HCLK_SDMMC: 1052 case CCLK_SRC_SDMMC: 1053 rate = rk3506_sdmmc_get_rate(priv, clk->id); 1054 break; 1055 case CLK_SARADC: 1056 rate = rk3506_saradc_get_rate(priv, clk->id); 1057 break; 1058 case CLK_TSADC: 1059 case CLK_TSADC_TSEN: 1060 rate = rk3506_tsadc_get_rate(priv, clk->id); 1061 break; 1062 case CLK_I2C0: 1063 case CLK_I2C1: 1064 case CLK_I2C2: 1065 rate = rk3506_i2c_get_rate(priv, clk->id); 1066 break; 1067 case CLK_PWM0: 1068 case CLK_PWM1: 1069 rate = rk3506_pwm_get_rate(priv, clk->id); 1070 break; 1071 case CLK_SPI0: 1072 case CLK_SPI1: 1073 rate = rk3506_spi_get_rate(priv, clk->id); 1074 break; 1075 case SCLK_FSPI: 1076 rate = rk3506_fspi_get_rate(priv); 1077 break; 1078 case DCLK_VOP: 1079 rate = rk3506_vop_dclk_get_rate(priv); 1080 break; 1081 case CLK_MAC0: 1082 case CLK_MAC1: 1083 case CLK_MAC_OUT: 1084 rate = rk3506_mac_get_rate(priv, clk->id); 1085 break; 1086 default: 1087 return -ENOENT; 1088 } 1089 1090 return rate; 1091 }; 1092 1093 static ulong rk3506_clk_set_rate(struct clk *clk, ulong rate) 1094 { 1095 struct rk3506_clk_priv *priv = dev_get_priv(clk->dev); 1096 ulong ret = 0; 1097 1098 if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) { 1099 printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n", 1100 __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz); 1101 return -ENOENT; 1102 } 1103 1104 debug("%s: id=%ld, rate=%ld\n", __func__, clk->id, rate); 1105 1106 switch (clk->id) { 1107 case ARMCLK: 1108 if (priv->armclk_hz) 1109 rk3506_armclk_set_rate(priv, rate); 1110 priv->armclk_hz = rate; 1111 break; 1112 case CLK_GPLL_DIV: 1113 case CLK_GPLL_DIV_100M: 1114 case CLK_V0PLL_DIV: 1115 case CLK_V1PLL_DIV: 1116 ret = rk3506_pll_div_set_rate(priv, clk->id, rate); 1117 break; 1118 case ACLK_BUS_ROOT: 1119 case HCLK_BUS_ROOT: 1120 case PCLK_BUS_ROOT: 1121 ret = rk3506_bus_set_rate(priv, clk->id, rate); 1122 break; 1123 case ACLK_HSPERI_ROOT: 1124 case HCLK_LSPERI_ROOT: 1125 ret = rk3506_peri_set_rate(priv, clk->id, rate); 1126 break; 1127 case HCLK_SDMMC: 1128 case CCLK_SRC_SDMMC: 1129 ret = rk3506_sdmmc_set_rate(priv, clk->id, rate); 1130 break; 1131 case CLK_SARADC: 1132 ret = rk3506_saradc_set_rate(priv, clk->id, rate); 1133 break; 1134 case CLK_TSADC: 1135 case CLK_TSADC_TSEN: 1136 ret = rk3506_tsadc_set_rate(priv, clk->id, rate); 1137 break; 1138 case CLK_I2C0: 1139 case CLK_I2C1: 1140 case CLK_I2C2: 1141 ret = rk3506_i2c_set_rate(priv, clk->id, rate); 1142 break; 1143 case CLK_PWM0: 1144 case CLK_PWM1: 1145 ret = rk3506_pwm_set_rate(priv, clk->id, rate); 1146 break; 1147 case CLK_SPI0: 1148 case CLK_SPI1: 1149 ret = rk3506_spi_set_rate(priv, clk->id, rate); 1150 break; 1151 case HCLK_FSPI: 1152 case SCLK_FSPI: 1153 ret = rk3506_fspi_set_rate(priv, rate); 1154 break; 1155 case DCLK_VOP: 1156 ret = rk3506_vop_dclk_set_rate(priv, rate); 1157 break; 1158 case CLK_MAC0: 1159 case CLK_MAC1: 1160 case CLK_MAC_OUT: 1161 ret = rk3506_mac_set_rate(priv, clk->id, rate); 1162 break; 1163 default: 1164 return -ENOENT; 1165 } 1166 1167 return ret; 1168 }; 1169 1170 static struct clk_ops rk3506_clk_ops = { 1171 .get_rate = rk3506_clk_get_rate, 1172 .set_rate = rk3506_clk_set_rate, 1173 }; 1174 1175 static void rk3506_clk_init(struct rk3506_clk_priv *priv) 1176 { 1177 priv->sync_kernel = false; 1178 1179 if (!priv->gpll_hz) { 1180 priv->gpll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[GPLL], 1181 priv->cru, GPLL); 1182 priv->gpll_hz = roundup(priv->gpll_hz, 1000); 1183 } 1184 if (!priv->v0pll_hz) { 1185 priv->v0pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V0PLL], 1186 priv->cru, V0PLL); 1187 priv->v0pll_hz = roundup(priv->v0pll_hz, 1000); 1188 } 1189 if (!priv->v1pll_hz) { 1190 priv->v1pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V1PLL], 1191 priv->cru, V1PLL); 1192 priv->v1pll_hz = roundup(priv->v1pll_hz, 1000); 1193 } 1194 if (!priv->gpll_div_hz) { 1195 priv->gpll_div_hz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV); 1196 priv->gpll_div_hz = roundup(priv->gpll_div_hz, 1000); 1197 } 1198 if (!priv->gpll_div_100mhz) { 1199 priv->gpll_div_100mhz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV_100M); 1200 priv->gpll_div_100mhz = roundup(priv->gpll_div_100mhz, 1000); 1201 } 1202 if (!priv->v0pll_div_hz) { 1203 priv->v0pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V0PLL_DIV); 1204 priv->v0pll_div_hz = roundup(priv->v0pll_div_hz, 1000); 1205 } 1206 if (!priv->v1pll_div_hz) { 1207 priv->v1pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V1PLL_DIV); 1208 priv->v1pll_div_hz = roundup(priv->v1pll_div_hz, 1000); 1209 } 1210 1211 if (!priv->armclk_enter_hz) { 1212 priv->armclk_enter_hz = rk3506_armclk_get_rate(priv); 1213 priv->armclk_init_hz = priv->armclk_enter_hz; 1214 } 1215 } 1216 1217 static int rk3506_clk_probe(struct udevice *dev) 1218 { 1219 struct rk3506_clk_priv *priv = dev_get_priv(dev); 1220 int ret; 1221 1222 rk3506_clk_init(priv); 1223 1224 /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */ 1225 ret = clk_set_defaults(dev); 1226 if (ret) 1227 debug("%s clk_set_defaults failed %d\n", __func__, ret); 1228 else 1229 priv->sync_kernel = true; 1230 1231 return 0; 1232 } 1233 1234 static int rk3506_clk_ofdata_to_platdata(struct udevice *dev) 1235 { 1236 struct rk3506_clk_priv *priv = dev_get_priv(dev); 1237 1238 priv->cru = dev_read_addr_ptr(dev); 1239 1240 return 0; 1241 } 1242 1243 static int rk3506_clk_bind(struct udevice *dev) 1244 { 1245 struct udevice *sys_child, *sf_child; 1246 struct softreset_reg *sf_priv; 1247 struct sysreset_reg *priv; 1248 int ret; 1249 1250 /* The reset driver does not have a device node, so bind it here */ 1251 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", 1252 &sys_child); 1253 if (ret) { 1254 debug("Warning: No sysreset driver: ret=%d\n", ret); 1255 } else { 1256 priv = malloc(sizeof(struct sysreset_reg)); 1257 priv->glb_srst_fst_value = offsetof(struct rk3506_cru, 1258 glb_srst_fst); 1259 priv->glb_srst_snd_value = offsetof(struct rk3506_cru, 1260 glb_srst_snd); 1261 sys_child->priv = priv; 1262 } 1263 1264 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset", 1265 dev_ofnode(dev), &sf_child); 1266 if (ret) { 1267 debug("Warning: No rockchip reset driver: ret=%d\n", ret); 1268 } else { 1269 sf_priv = malloc(sizeof(struct softreset_reg)); 1270 sf_priv->sf_reset_offset = offsetof(struct rk3506_cru, 1271 softrst_con[0]); 1272 sf_priv->sf_reset_num = 23; 1273 sf_child->priv = sf_priv; 1274 } 1275 1276 return 0; 1277 } 1278 1279 static const struct udevice_id rk3506_clk_ids[] = { 1280 { .compatible = "rockchip,rk3506-cru" }, 1281 { } 1282 }; 1283 1284 U_BOOT_DRIVER(rockchip_rk3506_cru) = { 1285 .name = "rockchip_rk3506_cru", 1286 .id = UCLASS_CLK, 1287 .of_match = rk3506_clk_ids, 1288 .priv_auto_alloc_size = sizeof(struct rk3506_clk_priv), 1289 .ofdata_to_platdata = rk3506_clk_ofdata_to_platdata, 1290 .ops = &rk3506_clk_ops, 1291 .bind = rk3506_clk_bind, 1292 .probe = rk3506_clk_probe, 1293 }; 1294