1 /*
2 * (C) Copyright 2015 Google, Inc
3 * (C) Copyright 2016 Heiko Stuebner <heiko@sntech.de>
4 *
5 * SPDX-License-Identifier: GPL-2.0
6 */
7
8 #include <common.h>
9 #include <clk-uclass.h>
10 #include <dm.h>
11 #include <dt-structs.h>
12 #include <errno.h>
13 #include <mapmem.h>
14 #include <syscon.h>
15 #include <asm/io.h>
16 #include <asm/arch/clock.h>
17 #include <asm/arch/cru_rk3066.h>
18 #include <asm/arch/grf_rk3066.h>
19 #include <asm/arch/hardware.h>
20 #include <dt-bindings/clock/rk3066a-cru.h>
21 #include <dm/device-internal.h>
22 #include <dm/lists.h>
23 #include <dm/uclass-internal.h>
24 #include <linux/log2.h>
25
26 DECLARE_GLOBAL_DATA_PTR;
27
28 enum rk3066_clk_type {
29 RK3066_CRU,
30 RK3066A_CRU,
31 };
32
33 struct rk3066_clk_plat {
34 #if CONFIG_IS_ENABLED(OF_PLATDATA)
35 struct dtd_rockchip_rk3066a_cru dtd;
36 #endif
37 };
38
39 #ifndef CONFIG_SPL_BUILD
40 #define RK3066_CLK_DUMP(_id, _name, _iscru) \
41 { \
42 .id = _id, \
43 .name = _name, \
44 .is_cru = _iscru, \
45 }
46
47 static const struct rk3066_clk_info clks_dump[] = {
48 RK3066_CLK_DUMP(PLL_APLL, "apll", true),
49 RK3066_CLK_DUMP(PLL_DPLL, "dpll", true),
50 RK3066_CLK_DUMP(PLL_GPLL, "gpll", true),
51 RK3066_CLK_DUMP(PLL_CPLL, "cpll", true),
52 };
53 #endif
54
55 struct pll_div {
56 u32 nr;
57 u32 nf;
58 u32 no;
59 };
60
61 enum {
62 VCO_MAX_HZ = 1416U * 1000000,
63 VCO_MIN_HZ = 300 * 1000000,
64 OUTPUT_MAX_HZ = 1416U * 1000000,
65 OUTPUT_MIN_HZ = 30 * 1000000,
66 FREF_MAX_HZ = 1416U * 1000000,
67 FREF_MIN_HZ = 30 * 1000,
68 };
69
70 enum {
71 /* PLL CON0 */
72 PLL_OD_MASK = 0x0f,
73
74 /* PLL CON1 */
75 PLL_NF_MASK = 0x1fff,
76
77 /* PLL CON2 */
78 PLL_BWADJ_MASK = 0x0fff,
79
80 /* PLL CON3 */
81 PLL_RESET_SHIFT = 5,
82
83 /* GRF_SOC_STATUS0 */
84 SOCSTS_DPLL_LOCK = 1 << 4,
85 SOCSTS_APLL_LOCK = 1 << 5,
86 SOCSTS_CPLL_LOCK = 1 << 6,
87 SOCSTS_GPLL_LOCK = 1 << 7,
88 };
89
90 #define RATE_TO_DIV(input_rate, output_rate) \
91 ((input_rate) / (output_rate) - 1);
92
93 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
94
95 #define PLL_DIVISORS(hz, _nr, _no) {\
96 .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\
97 _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
98 (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\
99 "divisors on line " __stringify(__LINE__));
100
101 /* Keep divisors as low as possible to reduce jitter and power usage */
102 #ifdef CONFIG_TPL_BUILD
103 static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2);
104 static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2);
105 #endif
106
rkclk_set_pll(struct rk3066_cru * cru,enum rk_clk_id clk_id,const struct pll_div * div,bool has_bwadj)107 static int rkclk_set_pll(struct rk3066_cru *cru, enum rk_clk_id clk_id,
108 const struct pll_div *div, bool has_bwadj)
109 {
110 int pll_id = rk_pll_id(clk_id);
111 struct rk3066_pll *pll = &cru->pll[pll_id];
112 /* All PLLs have same VCO and output frequency range restrictions. */
113 uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
114 uint output_hz = vco_hz / div->no;
115
116 debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
117 (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz);
118 assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
119 output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ &&
120 (div->no == 1 || !(div->no % 2)));
121
122 /* enter reset */
123 rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT);
124
125 rk_clrsetreg(&pll->con0,
126 CLKR_MASK | PLL_OD_MASK,
127 ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1));
128 rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1);
129
130 if (has_bwadj)
131 rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1);
132
133 udelay(10);
134
135 /* return from reset */
136 rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT);
137
138 return 0;
139 }
140
rkclk_configure_ddr(struct rk3066_cru * cru,struct rk3066_grf * grf,unsigned int hz,bool has_bwadj)141 static int rkclk_configure_ddr(struct rk3066_cru *cru, struct rk3066_grf *grf,
142 unsigned int hz, bool has_bwadj)
143 {
144 static const struct pll_div dpll_cfg[] = {
145 {.nf = 25, .nr = 2, .no = 1},
146 {.nf = 400, .nr = 9, .no = 2},
147 {.nf = 500, .nr = 9, .no = 2},
148 {.nf = 100, .nr = 3, .no = 1},
149 };
150 int cfg;
151
152 switch (hz) {
153 case 300000000:
154 cfg = 0;
155 break;
156 case 533000000: /* actually 533.3P MHz */
157 cfg = 1;
158 break;
159 case 666000000: /* actually 666.6P MHz */
160 cfg = 2;
161 break;
162 case 800000000:
163 cfg = 3;
164 break;
165 default:
166 debug("Unsupported SDRAM frequency");
167 return -EINVAL;
168 }
169
170 /* pll enter slow-mode */
171 rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
172 DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
173
174 rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg], has_bwadj);
175
176 /* wait for pll lock */
177 while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK))
178 udelay(1);
179
180 /* PLL enter normal-mode */
181 rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
182 DPLL_MODE_NORMAL << DPLL_MODE_SHIFT);
183
184 return 0;
185 }
186
rkclk_configure_cpu(struct rk3066_cru * cru,struct rk3066_grf * grf,unsigned int hz,bool has_bwadj)187 static int rkclk_configure_cpu(struct rk3066_cru *cru, struct rk3066_grf *grf,
188 unsigned int hz, bool has_bwadj)
189 {
190 static const struct pll_div apll_cfg[] = {
191 {.nf = 50, .nr = 1, .no = 2},
192 {.nf = 59, .nr = 1, .no = 1},
193 };
194 int div_core_peri, div_aclk_core, cfg;
195
196 /*
197 * We support two possible frequencies, the safe 600MHz
198 * which will work with default pmic settings and will
199 * be set to get away from the 24MHz default and
200 * the maximum of 1.416Ghz, which boards can set if they
201 * were able to get pmic support for it.
202 */
203 switch (hz) {
204 case APLL_SAFE_HZ:
205 cfg = 0;
206 div_core_peri = 1;
207 div_aclk_core = 3;
208 break;
209 case APLL_HZ:
210 cfg = 1;
211 div_core_peri = 2;
212 div_aclk_core = 3;
213 break;
214 default:
215 debug("Unsupported ARMCLK frequency");
216 return -EINVAL;
217 }
218
219 /* pll enter slow-mode */
220 rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
221 APLL_MODE_SLOW << APLL_MODE_SHIFT);
222
223 rkclk_set_pll(cru, CLK_ARM, &apll_cfg[cfg], has_bwadj);
224
225 /* waiting for pll lock */
226 while (!(readl(&grf->soc_status0) & SOCSTS_APLL_LOCK))
227 udelay(1);
228
229 /* Set divider for peripherals attached to the cpu core. */
230 rk_clrsetreg(&cru->cru_clksel_con[0],
231 CORE_PERI_DIV_MASK,
232 div_core_peri << CORE_PERI_DIV_SHIFT);
233
234 /* set up dependent divisor for aclk_core */
235 rk_clrsetreg(&cru->cru_clksel_con[1],
236 CORE_ACLK_DIV_MASK,
237 div_aclk_core << CORE_ACLK_DIV_SHIFT);
238
239 /* PLL enter normal-mode */
240 rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
241 APLL_MODE_NORMAL << APLL_MODE_SHIFT);
242
243 return hz;
244 }
245
246 /* Get pll rate by id */
rkclk_pll_get_rate(struct rk3066_cru * cru,enum rk_clk_id clk_id)247 static uint32_t rkclk_pll_get_rate(struct rk3066_cru *cru,
248 enum rk_clk_id clk_id)
249 {
250 uint32_t nr, no, nf;
251 uint32_t con;
252 int pll_id = rk_pll_id(clk_id);
253 struct rk3066_pll *pll = &cru->pll[pll_id];
254 static u8 clk_shift[CLK_COUNT] = {
255 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT,
256 GPLL_MODE_SHIFT
257 };
258 uint shift;
259
260 con = readl(&cru->cru_mode_con);
261 shift = clk_shift[clk_id];
262 switch ((con >> shift) & APLL_MODE_MASK >> APLL_MODE_SHIFT) {
263 case APLL_MODE_SLOW:
264 return OSC_HZ;
265 case APLL_MODE_NORMAL:
266 /* normal mode */
267 con = readl(&pll->con0);
268 no = ((con >> CLKOD_SHIFT) & (CLKOD_MASK >> CLKOD_SHIFT)) + 1;
269 nr = ((con >> CLKR_SHIFT) & (CLKR_MASK >> CLKR_SHIFT)) + 1;
270 con = readl(&pll->con1);
271 nf = ((con >> CLKF_SHIFT) & (CLKF_MASK >> CLKF_SHIFT)) + 1;
272
273 return (24 * nf / (nr * no)) * 1000000;
274 case APLL_MODE_DEEP:
275 default:
276 return 32768;
277 }
278 }
279
rockchip_mmc_get_clk(struct rk3066_cru * cru,uint gclk_rate,int periph)280 static ulong rockchip_mmc_get_clk(struct rk3066_cru *cru, uint gclk_rate,
281 int periph)
282 {
283 uint div;
284 u32 con;
285
286 switch (periph) {
287 case HCLK_EMMC:
288 con = readl(&cru->cru_clksel_con[12]);
289 div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK >> EMMC_DIV_SHIFT;
290 break;
291 case HCLK_SDMMC:
292 con = readl(&cru->cru_clksel_con[11]);
293 div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK >> MMC0_DIV_SHIFT;
294 break;
295 case HCLK_SDIO:
296 con = readl(&cru->cru_clksel_con[12]);
297 div = (con >> SDIO_DIV_SHIFT) & SDIO_DIV_MASK >> SDIO_DIV_SHIFT;
298 break;
299 default:
300 return -EINVAL;
301 }
302
303 return DIV_TO_RATE(gclk_rate, div);
304 }
305
rockchip_mmc_set_clk(struct rk3066_cru * cru,uint gclk_rate,int periph,uint freq)306 static ulong rockchip_mmc_set_clk(struct rk3066_cru *cru, uint gclk_rate,
307 int periph, uint freq)
308 {
309 int src_clk_div;
310
311 debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
312 src_clk_div = RATE_TO_DIV(gclk_rate, freq);
313 if (src_clk_div > 0x3f)
314 src_clk_div = 0x3f;
315
316 switch (periph) {
317 case HCLK_EMMC:
318 rk_clrsetreg(&cru->cru_clksel_con[12],
319 EMMC_DIV_MASK,
320 src_clk_div << EMMC_DIV_SHIFT);
321 break;
322 case HCLK_SDMMC:
323 rk_clrsetreg(&cru->cru_clksel_con[11],
324 MMC0_DIV_MASK,
325 src_clk_div << MMC0_DIV_SHIFT);
326 break;
327 case HCLK_SDIO:
328 rk_clrsetreg(&cru->cru_clksel_con[12],
329 SDIO_DIV_MASK,
330 src_clk_div << SDIO_DIV_SHIFT);
331 break;
332 default:
333 return -EINVAL;
334 }
335
336 return rockchip_mmc_get_clk(cru, gclk_rate, periph);
337 }
338
rockchip_spi_get_clk(struct rk3066_cru * cru,uint gclk_rate,int periph)339 static ulong rockchip_spi_get_clk(struct rk3066_cru *cru, uint gclk_rate,
340 int periph)
341 {
342 uint div;
343 u32 con;
344
345 switch (periph) {
346 case SCLK_SPI0:
347 con = readl(&cru->cru_clksel_con[25]);
348 div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK >> SPI0_DIV_SHIFT;
349 break;
350 case SCLK_SPI1:
351 con = readl(&cru->cru_clksel_con[25]);
352 div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK >> SPI1_DIV_SHIFT;
353 break;
354 default:
355 return -EINVAL;
356 }
357
358 return DIV_TO_RATE(gclk_rate, div);
359 }
360
rockchip_spi_set_clk(struct rk3066_cru * cru,uint gclk_rate,int periph,uint freq)361 static ulong rockchip_spi_set_clk(struct rk3066_cru *cru, uint gclk_rate,
362 int periph, uint freq)
363 {
364 int src_clk_div = RATE_TO_DIV(gclk_rate, freq);
365
366 switch (periph) {
367 case SCLK_SPI0:
368 assert(src_clk_div <= SPI0_DIV_MASK >> SPI0_DIV_SHIFT);
369 rk_clrsetreg(&cru->cru_clksel_con[25],
370 SPI0_DIV_MASK,
371 src_clk_div << SPI0_DIV_SHIFT);
372 break;
373 case SCLK_SPI1:
374 assert(src_clk_div <= SPI1_DIV_MASK >> SPI1_DIV_SHIFT);
375 rk_clrsetreg(&cru->cru_clksel_con[25],
376 SPI1_DIV_MASK,
377 src_clk_div << SPI1_DIV_SHIFT);
378 break;
379 default:
380 return -EINVAL;
381 }
382
383 return rockchip_spi_get_clk(cru, gclk_rate, periph);
384 }
385 #ifdef CONFIG_TPL_BUILD
rkclk_init(struct rk3066_cru * cru,struct rk3066_grf * grf,bool has_bwadj)386 static void rkclk_init(struct rk3066_cru *cru, struct rk3066_grf *grf,
387 bool has_bwadj)
388 {
389 u32 aclk_div, hclk_div, pclk_div, h2p_div;
390
391 /* pll enter slow-mode */
392 rk_clrsetreg(&cru->cru_mode_con,
393 GPLL_MODE_MASK |
394 CPLL_MODE_MASK,
395 GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
396 CPLL_MODE_SLOW << CPLL_MODE_SHIFT);
397
398 /* init pll */
399 rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg, has_bwadj);
400 rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg, has_bwadj);
401
402 /* waiting for pll lock */
403 while ((readl(&grf->soc_status0) &
404 (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) !=
405 (SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK))
406 udelay(1);
407
408 /*
409 * cpu clock pll source selection and
410 * reparent aclk_cpu_pre from apll to gpll
411 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
412 */
413 aclk_div = RATE_TO_DIV(GPLL_HZ, CPU_ACLK_HZ);
414 assert((aclk_div + 1) * CPU_ACLK_HZ <= GPLL_HZ && aclk_div < 0x1f);
415
416 rk_clrsetreg(&cru->cru_clksel_con[0],
417 CPU_ACLK_PLL_MASK |
418 A9_CPU_DIV_MASK,
419 CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT |
420 aclk_div << A9_CPU_DIV_SHIFT);
421
422 hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ);
423 assert((1 << hclk_div) * CPU_HCLK_HZ <= CPU_ACLK_HZ && hclk_div < 0x3);
424 pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ);
425 assert((1 << pclk_div) * CPU_PCLK_HZ <= CPU_ACLK_HZ && pclk_div < 0x4);
426 h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ);
427 assert((1 << h2p_div) * CPU_H2P_HZ <= CPU_HCLK_HZ && pclk_div < 0x3);
428
429 rk_clrsetreg(&cru->cru_clksel_con[1],
430 AHB2APB_DIV_MASK |
431 CPU_PCLK_DIV_MASK |
432 CPU_HCLK_DIV_MASK,
433 h2p_div << AHB2APB_DIV_SHIFT |
434 pclk_div << CPU_PCLK_DIV_SHIFT |
435 hclk_div << CPU_HCLK_DIV_SHIFT);
436
437 /*
438 * peri clock pll source selection and
439 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
440 */
441 aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
442 assert((aclk_div + 1) * PERI_ACLK_HZ <= GPLL_HZ && aclk_div < 0x1f);
443
444 hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ);
445 assert((1 << hclk_div) * PERI_HCLK_HZ <=
446 PERI_ACLK_HZ && (hclk_div < 0x4));
447
448 pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ);
449 assert((1 << pclk_div) * PERI_PCLK_HZ <=
450 PERI_ACLK_HZ && (pclk_div < 0x4));
451
452 rk_clrsetreg(&cru->cru_clksel_con[10],
453 PERI_PCLK_DIV_MASK |
454 PERI_HCLK_DIV_MASK |
455 PERI_ACLK_DIV_MASK,
456 PERI_SEL_GPLL << PERI_SEL_PLL_SHIFT |
457 pclk_div << PERI_PCLK_DIV_SHIFT |
458 hclk_div << PERI_HCLK_DIV_SHIFT |
459 aclk_div << PERI_ACLK_DIV_SHIFT);
460
461 /* PLL enter normal-mode */
462 rk_clrsetreg(&cru->cru_mode_con,
463 GPLL_MODE_MASK |
464 CPLL_MODE_MASK,
465 GPLL_MODE_NORMAL << GPLL_MODE_SHIFT |
466 CPLL_MODE_NORMAL << CPLL_MODE_SHIFT);
467
468 rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000);
469 }
470 #endif
471
rk3066_clk_get_rate(struct clk * clk)472 static ulong rk3066_clk_get_rate(struct clk *clk)
473 {
474 struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
475 ulong new_rate, gclk_rate;
476
477 gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
478 switch (clk->id) {
479 case 1 ... 4:
480 new_rate = rkclk_pll_get_rate(priv->cru, clk->id);
481 break;
482 case HCLK_EMMC:
483 case HCLK_SDMMC:
484 case HCLK_SDIO:
485 new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ,
486 clk->id);
487 break;
488 case SCLK_SPI0:
489 case SCLK_SPI1:
490 new_rate = rockchip_spi_get_clk(priv->cru, PERI_PCLK_HZ,
491 clk->id);
492 break;
493 case PCLK_I2C0:
494 case PCLK_I2C1:
495 case PCLK_I2C2:
496 case PCLK_I2C3:
497 case PCLK_I2C4:
498 return gclk_rate;
499 default:
500 return -ENOENT;
501 }
502
503 return new_rate;
504 }
505
rk3066_clk_set_rate(struct clk * clk,ulong rate)506 static ulong rk3066_clk_set_rate(struct clk *clk, ulong rate)
507 {
508 struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
509 struct rk3066_cru *cru = priv->cru;
510 ulong new_rate;
511
512 switch (clk->id) {
513 case PLL_APLL:
514 new_rate = rkclk_configure_cpu(priv->cru, priv->grf, rate,
515 priv->has_bwadj);
516 break;
517 case CLK_DDR:
518 new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate,
519 priv->has_bwadj);
520 break;
521 case HCLK_EMMC:
522 case HCLK_SDMMC:
523 case HCLK_SDIO:
524 new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ,
525 clk->id, rate);
526 break;
527 case SCLK_SPI0:
528 case SCLK_SPI1:
529 new_rate = rockchip_spi_set_clk(cru, PERI_PCLK_HZ,
530 clk->id, rate);
531 break;
532 default:
533 return -ENOENT;
534 }
535
536 return new_rate;
537 }
538
539 static struct clk_ops rk3066_clk_ops = {
540 .get_rate = rk3066_clk_get_rate,
541 .set_rate = rk3066_clk_set_rate,
542 };
543
rk3066_clk_ofdata_to_platdata(struct udevice * dev)544 static int rk3066_clk_ofdata_to_platdata(struct udevice *dev)
545 {
546 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
547 struct rk3066_clk_priv *priv = dev_get_priv(dev);
548
549 priv->cru = dev_read_addr_ptr(dev);
550 #endif
551
552 return 0;
553 }
554
rk3066_clk_probe(struct udevice * dev)555 static int rk3066_clk_probe(struct udevice *dev)
556 {
557 struct rk3066_clk_priv *priv = dev_get_priv(dev);
558
559 priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
560 if (IS_ERR(priv->grf))
561 return PTR_ERR(priv->grf);
562
563 #ifdef CONFIG_TPL_BUILD
564 #if CONFIG_IS_ENABLED(OF_PLATDATA)
565 struct rk3066_clk_plat *plat = dev_get_platdata(dev);
566
567 priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
568 #endif
569 priv->sync_kernel = false;
570 if (!priv->armclk_enter_hz)
571 priv->armclk_enter_hz = rkclk_pll_get_rate(priv->cru,
572 CLK_ARM);
573 rkclk_init(priv->cru, priv->grf, 1);
574 if (!priv->armclk_init_hz)
575 priv->armclk_init_hz = rkclk_pll_get_rate(priv->cru,
576 CLK_ARM);
577 #endif
578 return 0;
579 }
580
rk3066_clk_bind(struct udevice * dev)581 static int rk3066_clk_bind(struct udevice *dev)
582 {
583 int ret;
584 struct udevice *sys_child, *sf_child;
585 struct sysreset_reg *priv;
586 struct softreset_reg *sf_priv;
587
588 /* The reset driver does not have a device node, so bind it here */
589 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
590 &sys_child);
591 if (ret) {
592 debug("Warning: No sysreset driver: ret=%d\n", ret);
593 } else {
594 priv = malloc(sizeof(struct sysreset_reg));
595 priv->glb_srst_fst_value = offsetof(struct rk3066_cru,
596 cru_glb_srst_fst_value);
597 priv->glb_srst_snd_value = offsetof(struct rk3066_cru,
598 cru_glb_srst_snd_value);
599 sys_child->priv = priv;
600 }
601
602 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
603 dev_ofnode(dev), &sf_child);
604 if (ret) {
605 debug("Warning: No rockchip reset driver: ret=%d\n", ret);
606 } else {
607 sf_priv = malloc(sizeof(struct softreset_reg));
608 sf_priv->sf_reset_offset = offsetof(struct rk3066_cru,
609 cru_softrst_con[0]);
610 sf_priv->sf_reset_num = 9;
611 sf_child->priv = sf_priv;
612 }
613
614 return 0;
615 }
616
617 static const struct udevice_id rk3066_clk_ids[] = {
618 { .compatible = "rockchip,rk3066a-cru" },
619 { }
620 };
621
622 U_BOOT_DRIVER(rockchip_rk3066a_cru) = {
623 .name = "rockchip_rk3066a_cru",
624 .id = UCLASS_CLK,
625 .of_match = rk3066_clk_ids,
626 .priv_auto_alloc_size = sizeof(struct rk3066_clk_priv),
627 .platdata_auto_alloc_size = sizeof(struct rk3066_clk_plat),
628 .ops = &rk3066_clk_ops,
629 .bind = rk3066_clk_bind,
630 .ofdata_to_platdata = rk3066_clk_ofdata_to_platdata,
631 .probe = rk3066_clk_probe,
632 };
633
634 #ifndef CONFIG_SPL_BUILD
635 /**
636 * soc_clk_dump() - Print clock frequencies
637 * Returns zero on success
638 *
639 * Implementation for the clk dump command.
640 */
soc_clk_dump(void)641 int soc_clk_dump(void)
642 {
643 struct udevice *cru_dev;
644 struct rk3066_clk_priv *priv;
645 const struct rk3066_clk_info *clk_dump;
646 struct clk clk;
647 unsigned long clk_count = ARRAY_SIZE(clks_dump);
648 unsigned long rate;
649 int i, ret;
650
651 ret = uclass_get_device_by_driver(UCLASS_CLK,
652 DM_GET_DRIVER(rockchip_rk3066a_cru),
653 &cru_dev);
654 if (ret) {
655 printf("%s failed to get cru device\n", __func__);
656 return ret;
657 }
658
659 priv = dev_get_priv(cru_dev);
660 printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
661 priv->sync_kernel ? "sync kernel" : "uboot",
662 priv->armclk_enter_hz / 1000,
663 priv->armclk_init_hz / 1000,
664 priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
665 priv->set_armclk_rate ? " KHz" : "N/A");
666 for (i = 0; i < clk_count; i++) {
667 clk_dump = &clks_dump[i];
668 if (clk_dump->name) {
669 clk.id = clk_dump->id;
670 if (clk_dump->is_cru)
671 ret = clk_request(cru_dev, &clk);
672 if (ret < 0)
673 return ret;
674
675 rate = clk_get_rate(&clk);
676 clk_free(&clk);
677 if (i == 0) {
678 if (rate < 0)
679 printf(" %s %s\n", clk_dump->name,
680 "unknown");
681 else
682 printf(" %s %lu KHz\n", clk_dump->name,
683 rate / 1000);
684 } else {
685 if (rate < 0)
686 printf(" %s %s\n", clk_dump->name,
687 "unknown");
688 else
689 printf(" %s %lu KHz\n", clk_dump->name,
690 rate / 1000);
691 }
692 }
693 }
694
695 return 0;
696 }
697 #endif
698
699