1 /*
2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <syscon.h>
12 #include <asm/io.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/cru_rk322x.h>
15 #include <asm/arch/hardware.h>
16 #include <dm/lists.h>
17 #include <dt-bindings/clock/rk3228-cru.h>
18 #include <linux/log2.h>
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
23
24 #ifndef CONFIG_SPL_BUILD
25 #define RK322x_CLK_DUMP(_id, _name, _iscru) \
26 { \
27 .id = _id, \
28 .name = _name, \
29 .is_cru = _iscru, \
30 }
31 #endif
32
33 static struct rockchip_pll_rate_table rk322x_pll_rates[] = {
34 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
35 RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
36 #ifndef CONFIG_SPL_BUILD
37 RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
38 RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
39 #endif
40 RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
41 RK3036_PLL_RATE(800000000, 1, 100, 3, 1, 1, 0),
42 RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
43 #ifndef CONFIG_SPL_BUILD
44 RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
45 RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
46 RK3036_PLL_RATE(400000000, 1, 50, 3, 1, 1, 0),
47 #endif
48 { /* sentinel */ },
49 };
50
51 #define RK322x_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
52 { \
53 .rate = _rate##U, \
54 .aclk_div = _aclk_div, \
55 .pclk_div = _pclk_div, \
56 }
57
58 static struct rockchip_cpu_rate_table rk322x_cpu_rates[] = {
59 RK322x_CPUCLK_RATE(1200000000, 1, 5),
60 RK322x_CPUCLK_RATE(1008000000, 1, 5),
61 RK322x_CPUCLK_RATE(816000000, 1, 3),
62 RK322x_CPUCLK_RATE(600000000, 1, 3),
63 };
64
65 #ifndef CONFIG_SPL_BUILD
66 static const struct rk322x_clk_info clks_dump[] = {
67 RK322x_CLK_DUMP(PLL_APLL, "apll", true),
68 RK322x_CLK_DUMP(PLL_DPLL, "dpll", true),
69 RK322x_CLK_DUMP(PLL_CPLL, "cpll", true),
70 RK322x_CLK_DUMP(PLL_GPLL, "gpll", true),
71 RK322x_CLK_DUMP(ARMCLK, "armclk", true),
72 RK322x_CLK_DUMP(ACLK_CPU, "aclk_bus", true),
73 RK322x_CLK_DUMP(HCLK_CPU, "hclk_bus", true),
74 RK322x_CLK_DUMP(PCLK_CPU, "pclk_bus", true),
75 RK322x_CLK_DUMP(ACLK_PERI, "aclk_peri", true),
76 RK322x_CLK_DUMP(HCLK_PERI, "hclk_peri", true),
77 RK322x_CLK_DUMP(PCLK_PERI, "pclk_peri", true),
78 };
79 #endif
80
81 static struct rockchip_pll_clock rk322x_pll_clks[] = {
82 [APLL] = PLL(pll_rk3036, PLL_APLL, RK2928_PLL_CON(0),
83 RK2928_MODE_CON, 0, 10, 0, rk322x_pll_rates),
84 [DPLL] = PLL(pll_rk3036, PLL_DPLL, RK2928_PLL_CON(3),
85 RK2928_MODE_CON, 4, 10, 0, rk322x_pll_rates),
86 [CPLL] = PLL(pll_rk3036, PLL_CPLL, RK2928_PLL_CON(6),
87 RK2928_MODE_CON, 8, 10, 0, rk322x_pll_rates),
88 [GPLL] = PLL(pll_rk3036, PLL_GPLL, RK2928_PLL_CON(9),
89 RK2928_MODE_CON, 12, 10, 0, rk322x_pll_rates),
90 };
91
rk322x_armclk_set_clk(struct rk322x_clk_priv * priv,ulong hz)92 static ulong rk322x_armclk_set_clk(struct rk322x_clk_priv *priv, ulong hz)
93 {
94 struct rk322x_cru *cru = priv->cru;
95 const struct rockchip_cpu_rate_table *rate;
96 ulong old_rate;
97
98 rate = rockchip_get_cpu_settings(rk322x_cpu_rates, hz);
99 if (!rate) {
100 printf("%s unsupported rate\n", __func__);
101 return -EINVAL;
102 }
103
104 /*
105 * select apll as cpu/core clock pll source and
106 * set up dependent divisors for PERI and ACLK clocks.
107 * core hz : apll = 1:1
108 */
109 old_rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
110 priv->cru, APLL);
111 if (old_rate > hz) {
112 if (rockchip_pll_set_rate(&rk322x_pll_clks[APLL],
113 priv->cru, APLL, hz))
114 return -EINVAL;
115 rk_clrsetreg(&cru->cru_clksel_con[0],
116 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
117 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
118 0 << CORE_DIV_CON_SHIFT);
119 rk_clrsetreg(&cru->cru_clksel_con[1],
120 CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK,
121 rate->aclk_div << CORE_ACLK_DIV_SHIFT |
122 rate->pclk_div << CORE_PERI_DIV_SHIFT);
123 } else if (old_rate < hz) {
124 rk_clrsetreg(&cru->cru_clksel_con[1],
125 CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK,
126 rate->aclk_div << CORE_ACLK_DIV_SHIFT |
127 rate->pclk_div << CORE_PERI_DIV_SHIFT);
128 rk_clrsetreg(&cru->cru_clksel_con[0],
129 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
130 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
131 0 << CORE_DIV_CON_SHIFT);
132 if (rockchip_pll_set_rate(&rk322x_pll_clks[APLL],
133 priv->cru, APLL, hz))
134 return -EINVAL;
135 }
136
137 return rockchip_pll_get_rate(&rk322x_pll_clks[APLL], priv->cru, APLL);
138 }
139
rk322x_mmc_get_clk(struct rk322x_clk_priv * priv,int periph)140 static ulong rk322x_mmc_get_clk(struct rk322x_clk_priv *priv,
141 int periph)
142 {
143 struct rk322x_cru *cru = priv->cru;
144 uint src_rate;
145 uint div, mux;
146 u32 con;
147
148 switch (periph) {
149 case HCLK_EMMC:
150 case SCLK_EMMC:
151 case SCLK_EMMC_SAMPLE:
152 con = readl(&cru->cru_clksel_con[11]);
153 mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT;
154 con = readl(&cru->cru_clksel_con[12]);
155 div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
156 break;
157 case HCLK_SDMMC:
158 case SCLK_SDMMC:
159 case SCLK_SDMMC_SAMPLE:
160 con = readl(&cru->cru_clksel_con[11]);
161 mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT;
162 div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT;
163 break;
164 case SCLK_SDIO:
165 case SCLK_SDIO_SAMPLE:
166 con = readl(&cru->cru_clksel_con[11]);
167 mux = (con & SDIO_PLL_MASK) >> SDIO_PLL_SHIFT;
168 con = readl(&cru->cru_clksel_con[12]);
169 div = (con & SDIO_DIV_MASK) >> SDIO_DIV_SHIFT;
170 break;
171 default:
172 return -EINVAL;
173 }
174
175 src_rate = mux == EMMC_SEL_24M ? OSC_HZ : priv->gpll_hz;
176 return DIV_TO_RATE(src_rate, div) / 2;
177 }
178
179 #ifndef CONFIG_SPL_BUILD
rk322x_mac_set_clk(struct rk322x_clk_priv * priv,uint freq)180 static ulong rk322x_mac_set_clk(struct rk322x_clk_priv *priv, uint freq)
181 {
182 struct rk322x_cru *cru = priv->cru;
183 ulong ret;
184
185 /*
186 * The gmac clock can be derived either from an external clock
187 * or can be generated from internally by a divider from SCLK_MAC.
188 */
189 if (readl(&cru->cru_clksel_con[5]) & BIT(5)) {
190 /* An external clock will always generate the right rate... */
191 ret = freq;
192 } else {
193 u32 con = readl(&cru->cru_clksel_con[5]);
194 ulong pll_rate;
195 u8 div;
196
197 if (con & MAC_PLL_SEL_MASK)
198 pll_rate = priv->gpll_hz;
199 else
200 /* CPLL is not set */
201 return -EPERM;
202
203 div = DIV_ROUND_UP(pll_rate, freq) - 1;
204 if (div <= 0x1f)
205 rk_clrsetreg(&cru->cru_clksel_con[5], CLK_MAC_DIV_MASK,
206 div << CLK_MAC_DIV_SHIFT);
207 else
208 debug("Unsupported div for gmac:%d\n", div);
209
210 return DIV_TO_RATE(pll_rate, div);
211 }
212
213 return ret;
214 }
215 #endif
216
rk322x_mmc_set_clk(struct rk322x_clk_priv * priv,int periph,uint freq)217 static ulong rk322x_mmc_set_clk(struct rk322x_clk_priv *priv,
218 int periph, uint freq)
219 {
220 struct rk322x_cru *cru = priv->cru;
221 int src_clk_div;
222 int mux;
223
224 /* mmc clock defaulg div 2 internal, need provide double in cru */
225 src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, freq);
226
227 if (src_clk_div > 128) {
228 src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq);
229 assert(src_clk_div - 1 < 128);
230 mux = EMMC_SEL_24M;
231 } else {
232 mux = EMMC_SEL_GPLL;
233 }
234
235 switch (periph) {
236 case HCLK_EMMC:
237 case SCLK_EMMC:
238 case SCLK_EMMC_SAMPLE:
239 rk_clrsetreg(&cru->cru_clksel_con[11],
240 EMMC_PLL_MASK,
241 mux << EMMC_PLL_SHIFT);
242 rk_clrsetreg(&cru->cru_clksel_con[12],
243 EMMC_DIV_MASK,
244 (src_clk_div - 1) << EMMC_DIV_SHIFT);
245 break;
246 case HCLK_SDMMC:
247 case SCLK_SDMMC:
248 case SCLK_SDMMC_SAMPLE:
249 rk_clrsetreg(&cru->cru_clksel_con[11],
250 MMC0_PLL_MASK | MMC0_DIV_MASK,
251 mux << MMC0_PLL_SHIFT |
252 (src_clk_div - 1) << MMC0_DIV_SHIFT);
253 break;
254 case SCLK_SDIO:
255 case SCLK_SDIO_SAMPLE:
256 rk_clrsetreg(&cru->cru_clksel_con[11],
257 SDIO_PLL_MASK,
258 mux << SDIO_PLL_SHIFT);
259 rk_clrsetreg(&cru->cru_clksel_con[12],
260 SDIO_DIV_MASK,
261 (src_clk_div - 1) << SDIO_DIV_SHIFT);
262 break;
263 default:
264 return -EINVAL;
265 }
266
267 return rk322x_mmc_get_clk(priv, periph);
268 }
269
rk322x_bus_get_clk(struct rk322x_clk_priv * priv,ulong clk_id)270 static ulong rk322x_bus_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
271 {
272 struct rk322x_cru *cru = priv->cru;
273 u32 div, con, parent;
274
275 switch (clk_id) {
276 case ACLK_CPU:
277 con = readl(&cru->cru_clksel_con[0]);
278 div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
279 parent = priv->gpll_hz;
280 break;
281 case HCLK_CPU:
282 con = readl(&cru->cru_clksel_con[1]);
283 div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
284 parent = rk322x_bus_get_clk(priv, ACLK_CPU);
285 break;
286 case PCLK_CPU:
287 case PCLK_I2C0:
288 case PCLK_I2C1:
289 case PCLK_I2C2:
290 case PCLK_I2C3:
291 case PCLK_PWM:
292 con = readl(&cru->cru_clksel_con[1]);
293 div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
294 parent = rk322x_bus_get_clk(priv, ACLK_CPU);
295 break;
296 default:
297 return -ENOENT;
298 }
299
300 return DIV_TO_RATE(parent, div);
301 }
302
rk322x_bus_set_clk(struct rk322x_clk_priv * priv,ulong clk_id,ulong hz)303 static ulong rk322x_bus_set_clk(struct rk322x_clk_priv *priv,
304 ulong clk_id, ulong hz)
305 {
306 struct rk322x_cru *cru = priv->cru;
307 int src_clk_div;
308
309 /*
310 * select gpll as pd_bus bus clock source and
311 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
312 */
313 switch (clk_id) {
314 case ACLK_CPU:
315 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
316 assert(src_clk_div - 1 < 32);
317 rk_clrsetreg(&cru->cru_clksel_con[0],
318 BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
319 BUS_ACLK_PLL_SEL_GPLL << BUS_ACLK_PLL_SEL_SHIFT |
320 (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
321 break;
322 case HCLK_CPU:
323 src_clk_div = DIV_ROUND_UP(rk322x_bus_get_clk(priv,
324 ACLK_CPU),
325 hz);
326 assert(src_clk_div - 1 < 4);
327 rk_clrsetreg(&cru->cru_clksel_con[1],
328 BUS_HCLK_DIV_MASK,
329 (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
330 break;
331 case PCLK_CPU:
332 src_clk_div = DIV_ROUND_UP(rk322x_bus_get_clk(priv,
333 ACLK_CPU),
334 hz);
335 assert(src_clk_div - 1 < 8);
336 rk_clrsetreg(&cru->cru_clksel_con[1],
337 BUS_PCLK_DIV_MASK,
338 (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
339 break;
340 default:
341 printf("do not support this bus freq\n");
342 return -EINVAL;
343 }
344
345 return rk322x_bus_get_clk(priv, clk_id);
346 }
347
rk322x_peri_get_clk(struct rk322x_clk_priv * priv,ulong clk_id)348 static ulong rk322x_peri_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
349 {
350 struct rk322x_cru *cru = priv->cru;
351 u32 div, con, parent;
352
353 switch (clk_id) {
354 case ACLK_PERI:
355 con = readl(&cru->cru_clksel_con[10]);
356 div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
357 parent = priv->gpll_hz;
358 break;
359 case HCLK_PERI:
360 con = readl(&cru->cru_clksel_con[10]);
361 div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
362 parent = rk322x_peri_get_clk(priv, ACLK_PERI);
363 break;
364 case PCLK_PERI:
365 con = readl(&cru->cru_clksel_con[10]);
366 div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
367 parent = rk322x_peri_get_clk(priv, ACLK_PERI);
368 break;
369 default:
370 return -ENOENT;
371 }
372
373 return DIV_TO_RATE(parent, div);
374 }
375
rk322x_peri_set_clk(struct rk322x_clk_priv * priv,ulong clk_id,ulong hz)376 static ulong rk322x_peri_set_clk(struct rk322x_clk_priv *priv,
377 ulong clk_id, ulong hz)
378 {
379 struct rk322x_cru *cru = priv->cru;
380 int src_clk_div;
381
382 /*
383 * select gpll as pd_bus bus clock source and
384 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
385 */
386 switch (clk_id) {
387 case ACLK_PERI:
388 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
389 assert(src_clk_div - 1 < 32);
390 rk_clrsetreg(&cru->cru_clksel_con[10],
391 PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
392 PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
393 (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
394 break;
395 case HCLK_PERI:
396 src_clk_div = DIV_ROUND_UP(rk322x_peri_get_clk(priv,
397 ACLK_PERI),
398 hz);
399 assert(src_clk_div - 1 < 4);
400 rk_clrsetreg(&cru->cru_clksel_con[10],
401 PERI_HCLK_DIV_MASK,
402 (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
403 break;
404 case PCLK_PERI:
405 src_clk_div = DIV_ROUND_UP(rk322x_peri_get_clk(priv,
406 ACLK_PERI),
407 hz);
408 assert(src_clk_div - 1 < 8);
409 rk_clrsetreg(&cru->cru_clksel_con[10],
410 PERI_PCLK_DIV_MASK,
411 (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
412 break;
413 default:
414 printf("do not support this bus freq\n");
415 return -EINVAL;
416 }
417
418 return rk322x_peri_get_clk(priv, clk_id);
419 }
420
rk322x_spi_get_clk(struct rk322x_clk_priv * priv)421 static ulong rk322x_spi_get_clk(struct rk322x_clk_priv *priv)
422 {
423 struct rk322x_cru *cru = priv->cru;
424 u32 div, con, parent;
425
426 con = readl(&cru->cru_clksel_con[25]);
427 div = (con & SPI_DIV_MASK) >> SPI_DIV_SHIFT;
428 parent = priv->gpll_hz;
429
430 return DIV_TO_RATE(parent, div);
431 }
432
rk322x_spi_set_clk(struct rk322x_clk_priv * priv,ulong hz)433 static ulong rk322x_spi_set_clk(struct rk322x_clk_priv *priv, ulong hz)
434 {
435 struct rk322x_cru *cru = priv->cru;
436 int div;
437
438 div = DIV_ROUND_UP(priv->gpll_hz, hz);
439 assert(div - 1 < 128);
440 rk_clrsetreg(&cru->cru_clksel_con[25],
441 SPI_PLL_SEL_MASK | SPI_DIV_MASK,
442 SPI_PLL_SEL_GPLL << SPI_PLL_SEL_SHIFT |
443 (div - 1) << SPI_DIV_SHIFT);
444 return rk322x_spi_get_clk(priv);
445 }
446
447 #ifndef CONFIG_SPL_BUILD
rk322x_vop_get_clk(struct rk322x_clk_priv * priv,ulong clk_id)448 static ulong rk322x_vop_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
449 {
450 struct rk322x_cru *cru = priv->cru;
451 u32 div, con, sel, parent;
452
453 switch (clk_id) {
454 case ACLK_VOP:
455 con = readl(&cru->cru_clksel_con[33]);
456 div = (con & ACLK_VOP_DIV_CON_MASK) >> ACLK_VOP_DIV_CON_SHIFT;
457 parent = priv->gpll_hz;
458 break;
459 case DCLK_VOP:
460 con = readl(&cru->cru_clksel_con[27]);
461 con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT;
462 if (con) {
463 sel = readl(&cru->cru_clksel_con[27]);
464 sel = (sel & DCLK_LCDC_PLL_SEL_MASK) >>
465 DCLK_LCDC_PLL_SEL_SHIFT;
466 if (sel)
467 parent = priv->cpll_hz;
468 else
469 parent = priv->gpll_hz;
470
471 con = readl(&cru->cru_clksel_con[27]);
472 div = (con & DCLK_LCDC_DIV_CON_MASK) >>
473 DCLK_LCDC_DIV_CON_SHIFT;
474 } else {
475 parent = priv->cpll_hz;
476 div = 1;
477 }
478 break;
479 default:
480 return -ENOENT;
481 }
482
483 return DIV_TO_RATE(parent, div);
484 }
485
rk322x_vop_set_clk(struct rk322x_clk_priv * priv,ulong clk_id,uint hz)486 static ulong rk322x_vop_set_clk(struct rk322x_clk_priv *priv,
487 ulong clk_id, uint hz)
488 {
489 struct rk322x_cru *cru = priv->cru;
490 int src_clk_div;
491 u32 con, parent;
492
493 switch (clk_id) {
494 case ACLK_VOP:
495 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
496 assert(src_clk_div - 1 < 32);
497 rk_clrsetreg(&cru->cru_clksel_con[33],
498 ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
499 ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
500 (src_clk_div - 1) << ACLK_VOP_DIV_CON_SHIFT);
501 break;
502 case DCLK_VOP:
503 con = readl(&cru->cru_clksel_con[27]);
504 con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT;
505 if (con) {
506 parent = readl(&cru->cru_clksel_con[27]);
507 parent = (parent & DCLK_LCDC_PLL_SEL_MASK) >>
508 DCLK_LCDC_PLL_SEL_SHIFT;
509 if (parent)
510 src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz);
511 else
512 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
513
514 assert(src_clk_div - 1 < 256);
515 rk_clrsetreg(&cru->cru_clksel_con[27],
516 DCLK_LCDC_DIV_CON_MASK,
517 (src_clk_div - 1) <<
518 DCLK_LCDC_DIV_CON_SHIFT);
519 }
520 break;
521 default:
522 printf("do not support this vop freq\n");
523 return -EINVAL;
524 }
525
526 return rk322x_vop_get_clk(priv, clk_id);
527 }
528
rk322x_crypto_get_clk(struct rk322x_clk_priv * priv,ulong clk_id)529 static ulong rk322x_crypto_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
530 {
531 struct rk322x_cru *cru = priv->cru;
532 u32 div, con, parent;
533
534 switch (clk_id) {
535 case SCLK_CRYPTO:
536 con = readl(&cru->cru_clksel_con[24]);
537 div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
538 parent = priv->gpll_hz;
539 break;
540 default:
541 return -ENOENT;
542 }
543
544 return DIV_TO_RATE(parent, div);
545 }
546
rk322x_crypto_set_clk(struct rk322x_clk_priv * priv,ulong clk_id,ulong hz)547 static ulong rk322x_crypto_set_clk(struct rk322x_clk_priv *priv, ulong clk_id,
548 ulong hz)
549 {
550 struct rk322x_cru *cru = priv->cru;
551 int src_clk_div;
552
553 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
554 assert(src_clk_div - 1 <= 31);
555
556 /*
557 * select gpll as crypto clock source and
558 * set up dependent divisors for crypto clocks.
559 */
560 switch (clk_id) {
561 case SCLK_CRYPTO:
562 rk_clrsetreg(&cru->cru_clksel_con[24],
563 CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
564 CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
565 (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
566 break;
567 default:
568 printf("do not support this peri freq\n");
569 return -EINVAL;
570 }
571
572 return rk322x_crypto_get_clk(priv, clk_id);
573 }
574 #endif
575
rk322x_clk_get_rate(struct clk * clk)576 static ulong rk322x_clk_get_rate(struct clk *clk)
577 {
578 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
579 ulong rate;
580
581 switch (clk->id) {
582 case PLL_APLL:
583 case PLL_DPLL:
584 case PLL_CPLL:
585 case PLL_GPLL:
586 rate = rockchip_pll_get_rate(&rk322x_pll_clks[clk->id - 1],
587 priv->cru, clk->id - 1);
588 break;
589 case ARMCLK:
590 rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
591 priv->cru, APLL);
592 break;
593 case HCLK_EMMC:
594 case SCLK_EMMC:
595 case SCLK_EMMC_SAMPLE:
596 case HCLK_SDMMC:
597 case SCLK_SDMMC:
598 case SCLK_SDMMC_SAMPLE:
599 case SCLK_SDIO:
600 case SCLK_SDIO_SAMPLE:
601 rate = rk322x_mmc_get_clk(priv, clk->id);
602 break;
603 case SCLK_SPI0:
604 rate = rk322x_spi_get_clk(priv);
605 break;
606 case ACLK_CPU:
607 case HCLK_CPU:
608 case PCLK_CPU:
609 case PCLK_I2C0:
610 case PCLK_I2C1:
611 case PCLK_I2C2:
612 case PCLK_I2C3:
613 case PCLK_PWM:
614 rate = rk322x_bus_get_clk(priv, clk->id);
615 break;
616 case ACLK_PERI:
617 case HCLK_PERI:
618 case PCLK_PERI:
619 rate = rk322x_peri_get_clk(priv, clk->id);
620 break;
621 #ifndef CONFIG_SPL_BUILD
622 case DCLK_VOP:
623 case ACLK_VOP:
624 rate = rk322x_vop_get_clk(priv, clk->id);
625 break;
626 case SCLK_CRYPTO:
627 rate = rk322x_crypto_get_clk(priv, clk->id);
628 break;
629 #endif
630 default:
631 return -ENOENT;
632 }
633
634 return rate;
635 }
636
rk322x_clk_set_rate(struct clk * clk,ulong rate)637 static ulong rk322x_clk_set_rate(struct clk *clk, ulong rate)
638 {
639 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
640 ulong ret = 0;
641
642 switch (clk->id) {
643 case PLL_APLL:
644 case PLL_DPLL:
645 ret = rockchip_pll_set_rate(&rk322x_pll_clks[clk->id - 1],
646 priv->cru, clk->id - 1, rate);
647 break;
648 case PLL_CPLL:
649 ret = rockchip_pll_set_rate(&rk322x_pll_clks[CPLL],
650 priv->cru, CPLL, rate);
651 priv->cpll_hz = rate;
652 break;
653 case PLL_GPLL:
654 ret = rockchip_pll_set_rate(&rk322x_pll_clks[GPLL],
655 priv->cru, GPLL, rate);
656 priv->gpll_hz = rate;
657 break;
658 case ARMCLK:
659 if (priv->armclk_hz)
660 ret = rk322x_armclk_set_clk(priv, rate);
661 priv->armclk_hz = rate;
662 break;
663 case HCLK_EMMC:
664 case SCLK_EMMC:
665 case SCLK_EMMC_SAMPLE:
666 case HCLK_SDMMC:
667 case SCLK_SDMMC:
668 case SCLK_SDMMC_SAMPLE:
669 case SCLK_SDIO:
670 case SCLK_SDIO_SAMPLE:
671 ret = rk322x_mmc_set_clk(priv, clk->id, rate);
672 break;
673 case SCLK_DDRC:
674 ret = rockchip_pll_set_rate(&rk322x_pll_clks[DPLL],
675 priv->cru, DPLL, rate);
676 break;
677 case SCLK_SPI0:
678 rate = rk322x_spi_set_clk(priv, rate);
679 break;
680 case ACLK_CPU:
681 case HCLK_CPU:
682 case PCLK_CPU:
683 ret = rk322x_bus_set_clk(priv, clk->id, rate);
684 break;
685 case ACLK_PERI:
686 case HCLK_PERI:
687 case PCLK_PERI:
688 ret = rk322x_peri_set_clk(priv, clk->id, rate);
689 break;
690 #ifndef CONFIG_SPL_BUILD
691 case SCLK_MAC_SRC:
692 case SCLK_MAC:
693 ret = rk322x_mac_set_clk(priv, rate);
694 break;
695 case DCLK_VOP:
696 case ACLK_VOP:
697 ret = rk322x_vop_set_clk(priv, clk->id, rate);
698 break;
699 case SCLK_CRYPTO:
700 ret = rk322x_crypto_set_clk(priv, clk->id, rate);
701 break;
702 #endif
703 default:
704 return -ENOENT;
705 }
706
707 return ret;
708 }
709
710 #ifndef CONFIG_SPL_BUILD
rk322x_gmac_set_parent(struct clk * clk,struct clk * parent)711 static int rk322x_gmac_set_parent(struct clk *clk, struct clk *parent)
712 {
713 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
714 struct rk322x_cru *cru = priv->cru;
715
716 /*
717 * If the requested parent is in the same clock-controller and the id
718 * is SCLK_MAC_SRC ("sclk_gmac_src"), switch to the internal clock.
719 */
720 if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_SRC)) {
721 debug("%s: switching RGMII to SCLK_MAC_SRC\n", __func__);
722 rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), 0);
723 return 0;
724 }
725
726 /*
727 * If the requested parent is in the same clock-controller and the id
728 * is SCLK_MAC_EXTCLK (sclk_mac_extclk), switch to the external clock.
729 */
730 if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_EXTCLK)) {
731 debug("%s: switching RGMII to SCLK_MAC_EXTCLK\n", __func__);
732 rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), BIT(5));
733 return 0;
734 }
735
736 return -EINVAL;
737 }
738
rk322x_gmac_extclk_set_parent(struct clk * clk,struct clk * parent)739 static int rk322x_gmac_extclk_set_parent(struct clk *clk, struct clk *parent)
740 {
741 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
742 const char *clock_output_name;
743 struct rk322x_cru *cru = priv->cru;
744 int ret;
745
746 ret = dev_read_string_index(parent->dev, "clock-output-names",
747 parent->id, &clock_output_name);
748 if (ret < 0)
749 return -ENODATA;
750
751 if (!strcmp(clock_output_name, "ext_gmac")) {
752 debug("%s: switching gmac extclk to ext_gmac\n", __func__);
753 rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), 0);
754 return 0;
755 } else if (!strcmp(clock_output_name, "phy_50m_out")) {
756 debug("%s: switching gmac extclk to phy_50m_out\n", __func__);
757 rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), BIT(10));
758 return 0;
759 }
760
761 return -EINVAL;
762 }
763
rk322x_lcdc_set_parent(struct clk * clk,struct clk * parent)764 static int rk322x_lcdc_set_parent(struct clk *clk, struct clk *parent)
765 {
766 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
767
768 if (parent->id == HDMIPHY)
769 rk_clrsetreg(&priv->cru->cru_clksel_con[27],
770 DCLK_LCDC_SEL_MASK,
771 DCLK_LCDC_SEL_HDMIPHY << DCLK_LCDC_SEL_SHIFT);
772 else if (parent->id == PLL_CPLL)
773 rk_clrsetreg(&priv->cru->cru_clksel_con[27],
774 DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK,
775 (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) |
776 (DCLK_LCDC_PLL_SEL_CPLL <<
777 DCLK_LCDC_PLL_SEL_SHIFT));
778 else
779 rk_clrsetreg(&priv->cru->cru_clksel_con[27],
780 DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK,
781 (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) |
782 (DCLK_LCDC_PLL_SEL_GPLL <<
783 DCLK_LCDC_PLL_SEL_SHIFT));
784
785 return 0;
786 }
787 #endif
788
rk322x_clk_set_parent(struct clk * clk,struct clk * parent)789 static int rk322x_clk_set_parent(struct clk *clk, struct clk *parent)
790 {
791 switch (clk->id) {
792 #ifndef CONFIG_SPL_BUILD
793 case SCLK_MAC:
794 return rk322x_gmac_set_parent(clk, parent);
795 case SCLK_MAC_EXTCLK:
796 return rk322x_gmac_extclk_set_parent(clk, parent);
797 case DCLK_VOP:
798 return rk322x_lcdc_set_parent(clk, parent);
799 #endif
800 }
801
802 debug("%s: unsupported clk %ld\n", __func__, clk->id);
803 return -ENOENT;
804 }
805
806 #define ROCKCHIP_MMC_DELAY_SEL BIT(10)
807 #define ROCKCHIP_MMC_DEGREE_MASK 0x3
808 #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
809 #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
810
811 #define PSECS_PER_SEC 1000000000000LL
812 /*
813 * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
814 * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
815 */
816 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
817
rk322x_mmc_get_phase(struct clk * clk)818 int rk322x_mmc_get_phase(struct clk *clk)
819 {
820 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
821 struct rk322x_cru *cru = priv->cru;
822 u32 raw_value, delay_num;
823 u16 degrees = 0;
824 ulong rate;
825
826 rate = rk322x_clk_get_rate(clk);
827
828 if (rate < 0)
829 return rate;
830
831 if (clk->id == SCLK_EMMC_SAMPLE)
832 raw_value = readl(&cru->cru_emmc_con[1]);
833 else if (clk->id == SCLK_SDMMC_SAMPLE)
834 raw_value = readl(&cru->cru_sdmmc_con[1]);
835 else
836 raw_value = readl(&cru->cru_sdio_con[1]);
837
838 raw_value >>= 1;
839 degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
840
841 if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
842 /* degrees/delaynum * 10000 */
843 unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
844 36 * (rate / 1000000);
845
846 delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
847 delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
848 degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
849 }
850
851 return degrees % 360;
852 }
853
rk322x_mmc_set_phase(struct clk * clk,u32 degrees)854 int rk322x_mmc_set_phase(struct clk *clk, u32 degrees)
855 {
856 struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
857 struct rk322x_cru *cru = priv->cru;
858 u8 nineties, remainder, delay_num;
859 u32 raw_value, delay;
860 ulong rate;
861
862 rate = rk322x_clk_get_rate(clk);
863
864 if (rate < 0)
865 return rate;
866
867 nineties = degrees / 90;
868 remainder = (degrees % 90);
869
870 /*
871 * Convert to delay; do a little extra work to make sure we
872 * don't overflow 32-bit / 64-bit numbers.
873 */
874 delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
875 delay *= remainder;
876 delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
877 (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
878
879 delay_num = (u8)min_t(u32, delay, 255);
880
881 raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
882 raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
883 raw_value |= nineties;
884
885 raw_value <<= 1;
886 if (clk->id == SCLK_EMMC_SAMPLE)
887 writel(raw_value | 0xffff0000, &cru->cru_emmc_con[1]);
888 else if (clk->id == SCLK_SDMMC_SAMPLE)
889 writel(raw_value | 0xffff0000, &cru->cru_sdmmc_con[1]);
890 else
891 writel(raw_value | 0xffff0000, &cru->cru_sdio_con[1]);
892
893 debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
894 degrees, delay_num, raw_value, rk322x_mmc_get_phase(clk));
895
896 return 0;
897 }
898
rk322x_clk_get_phase(struct clk * clk)899 static int rk322x_clk_get_phase(struct clk *clk)
900 {
901 int ret;
902
903 debug("%s %ld\n", __func__, clk->id);
904 switch (clk->id) {
905 case SCLK_EMMC_SAMPLE:
906 case SCLK_SDMMC_SAMPLE:
907 case SCLK_SDIO_SAMPLE:
908 ret = rk322x_mmc_get_phase(clk);
909 break;
910 default:
911 return -ENOENT;
912 }
913
914 return ret;
915 }
916
rk322x_clk_set_phase(struct clk * clk,int degrees)917 static int rk322x_clk_set_phase(struct clk *clk, int degrees)
918 {
919 int ret;
920
921 debug("%s %ld\n", __func__, clk->id);
922 switch (clk->id) {
923 case SCLK_EMMC_SAMPLE:
924 case SCLK_SDMMC_SAMPLE:
925 case SCLK_SDIO_SAMPLE:
926 ret = rk322x_mmc_set_phase(clk, degrees);
927 break;
928 default:
929 return -ENOENT;
930 }
931
932 return ret;
933 }
934
935 static struct clk_ops rk322x_clk_ops = {
936 .get_rate = rk322x_clk_get_rate,
937 .set_rate = rk322x_clk_set_rate,
938 .set_parent = rk322x_clk_set_parent,
939 .get_phase = rk322x_clk_get_phase,
940 .set_phase = rk322x_clk_set_phase,
941 };
942
rk322x_clk_ofdata_to_platdata(struct udevice * dev)943 static int rk322x_clk_ofdata_to_platdata(struct udevice *dev)
944 {
945 struct rk322x_clk_priv *priv = dev_get_priv(dev);
946
947 priv->cru = dev_read_addr_ptr(dev);
948
949 return 0;
950 }
951
952 #ifndef CONFIG_TPL_BUILD
rkclk_init(struct rk322x_clk_priv * priv)953 static void rkclk_init(struct rk322x_clk_priv *priv)
954 {
955 struct rk322x_cru *cru = priv->cru;
956
957 if (rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
958 priv->cru, APLL) != APLL_HZ)
959 rk322x_armclk_set_clk(priv, APLL_HZ);
960
961 priv->gpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[GPLL],
962 priv->cru, GPLL);
963 priv->cpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[CPLL],
964 priv->cru, CPLL);
965
966 /* before set pll set child div first */
967 rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ / 4);
968 rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ / 4);
969 rk322x_mmc_set_clk(priv, SCLK_EMMC, 50000000);
970 rk322x_mmc_set_clk(priv, SCLK_SDMMC, 50000000);
971 rk322x_mmc_set_clk(priv, SCLK_SDIO, 50000000);
972 rk_clrsetreg(&cru->cru_clksel_con[2], (0x1 << 14) |
973 (0x1f << 8), (1 << 14) | (0xb << 8));
974 rk_clrsetreg(&cru->cru_clksel_con[23], (0x1f << 0) | (0x1f << 8),
975 (0x1f << 0) | (5 << 8));
976 rk_clrsetreg(&cru->cru_clksel_con[33],
977 ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
978 ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
979 3 << ACLK_VOP_DIV_CON_SHIFT);
980 rk_clrsetreg(&cru->cru_clksel_con[22], 0x1f << 0, 5 << 0);
981 rk_clrsetreg(&cru->cru_clksel_con[24], 0x1f << 0, 0xb << 0);
982 rk_clrsetreg(&cru->cru_clksel_con[28], (0x1f << 8) | (0x1f << 0),
983 (5 << 8) | (5 << 0));
984 rk_clrsetreg(&cru->cru_clksel_con[31], (0x1f << 8) | (0x1f << 0),
985 (5 << 8) | (5 << 0));
986 rk_clrsetreg(&cru->cru_clksel_con[32], 0x1f << 0, 5 << 0);
987 rk_clrsetreg(&cru->cru_clksel_con[33], (0x1f << 8) | (0x1f << 0),
988 (5 << 8) | (5 << 0));
989 rk_clrsetreg(&cru->cru_clksel_con[34], (0x1f << 8) | (0x1f << 0),
990 (5 << 8) | (3 << 0));
991
992 rockchip_pll_set_rate(&rk322x_pll_clks[GPLL],
993 priv->cru, GPLL, GPLL_HZ);
994 priv->gpll_hz = GPLL_HZ;
995
996 rockchip_pll_set_rate(&rk322x_pll_clks[CPLL],
997 priv->cru, CPLL, CPLL_HZ);
998 priv->cpll_hz = CPLL_HZ;
999
1000 rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ);
1001 rk322x_bus_set_clk(priv, HCLK_CPU, ACLK_BUS_HZ / 2);
1002 rk322x_bus_set_clk(priv, PCLK_CPU, ACLK_BUS_HZ / 2);
1003 rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ);
1004 rk322x_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2);
1005 rk322x_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2);
1006 /*rk322x_mmc_set_clk(priv, SCLK_EMMC, rate);*/
1007
1008 /* set usbphy and hdmiphy from phy */
1009 rk_clrsetreg(&cru->cru_misc_con, (0x1 << 13) |
1010 (0x1 << 15), (0 << 15) | (0 << 13));
1011 }
1012 #endif
1013
rk322x_clk_probe(struct udevice * dev)1014 static int rk322x_clk_probe(struct udevice *dev)
1015 {
1016 #ifndef CONFIG_TPL_BUILD
1017 struct rk322x_clk_priv *priv = dev_get_priv(dev);
1018 int ret = 0;
1019
1020 priv->sync_kernel = false;
1021 if (!priv->armclk_enter_hz)
1022 priv->armclk_enter_hz =
1023 rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
1024 priv->cru, APLL);
1025 rkclk_init(priv);
1026 if (!priv->armclk_init_hz)
1027 priv->armclk_init_hz =
1028 rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
1029 priv->cru, APLL);
1030 ret = clk_set_defaults(dev);
1031 if (ret)
1032 debug("%s clk_set_defaults failed %d\n", __func__, ret);
1033 else
1034 priv->sync_kernel = true;
1035 #endif
1036 return 0;
1037 }
1038
rk322x_clk_bind(struct udevice * dev)1039 static int rk322x_clk_bind(struct udevice *dev)
1040 {
1041 int ret;
1042 struct udevice *sys_child, *sf_child;
1043 struct sysreset_reg *priv;
1044 struct softreset_reg *sf_priv;
1045
1046 /* The reset driver does not have a device node, so bind it here */
1047 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1048 &sys_child);
1049 if (ret) {
1050 debug("Warning: No sysreset driver: ret=%d\n", ret);
1051 } else {
1052 priv = malloc(sizeof(struct sysreset_reg));
1053 priv->glb_srst_fst_value = offsetof(struct rk322x_cru,
1054 cru_glb_srst_fst_value);
1055 priv->glb_srst_snd_value = offsetof(struct rk322x_cru,
1056 cru_glb_srst_snd_value);
1057 sys_child->priv = priv;
1058 }
1059
1060 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1061 dev_ofnode(dev), &sf_child);
1062 if (ret) {
1063 debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1064 } else {
1065 sf_priv = malloc(sizeof(struct softreset_reg));
1066 sf_priv->sf_reset_offset = offsetof(struct rk322x_cru,
1067 cru_softrst_con[0]);
1068 sf_priv->sf_reset_num = 9;
1069 sf_child->priv = sf_priv;
1070 }
1071
1072 return 0;
1073 }
1074
1075 static const struct udevice_id rk322x_clk_ids[] = {
1076 { .compatible = "rockchip,rk3228-cru" },
1077 { }
1078 };
1079
1080 U_BOOT_DRIVER(rockchip_rk322x_cru) = {
1081 .name = "clk_rk322x",
1082 .id = UCLASS_CLK,
1083 .of_match = rk322x_clk_ids,
1084 .priv_auto_alloc_size = sizeof(struct rk322x_clk_priv),
1085 .ofdata_to_platdata = rk322x_clk_ofdata_to_platdata,
1086 .ops = &rk322x_clk_ops,
1087 .bind = rk322x_clk_bind,
1088 .probe = rk322x_clk_probe,
1089 };
1090
1091 #ifndef CONFIG_SPL_BUILD
1092 /**
1093 * soc_clk_dump() - Print clock frequencies
1094 * Returns zero on success
1095 *
1096 * Implementation for the clk dump command.
1097 */
soc_clk_dump(void)1098 int soc_clk_dump(void)
1099 {
1100 struct udevice *cru_dev;
1101 struct rk322x_clk_priv *priv;
1102 const struct rk322x_clk_info *clk_dump;
1103 struct clk clk;
1104 unsigned long clk_count = ARRAY_SIZE(clks_dump);
1105 unsigned long rate;
1106 int i, ret;
1107
1108 ret = uclass_get_device_by_driver(UCLASS_CLK,
1109 DM_GET_DRIVER(rockchip_rk322x_cru),
1110 &cru_dev);
1111 if (ret) {
1112 printf("%s failed to get cru device\n", __func__);
1113 return ret;
1114 }
1115
1116 priv = dev_get_priv(cru_dev);
1117 printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1118 priv->sync_kernel ? "sync kernel" : "uboot",
1119 priv->armclk_enter_hz / 1000,
1120 priv->armclk_init_hz / 1000,
1121 priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1122 priv->set_armclk_rate ? " KHz" : "N/A");
1123 for (i = 0; i < clk_count; i++) {
1124 clk_dump = &clks_dump[i];
1125 if (clk_dump->name) {
1126 clk.id = clk_dump->id;
1127 if (clk_dump->is_cru)
1128 ret = clk_request(cru_dev, &clk);
1129 if (ret < 0)
1130 return ret;
1131
1132 rate = clk_get_rate(&clk);
1133 clk_free(&clk);
1134 if (i == 0) {
1135 if (rate < 0)
1136 printf(" %s %s\n", clk_dump->name,
1137 "unknown");
1138 else
1139 printf(" %s %lu KHz\n", clk_dump->name,
1140 rate / 1000);
1141 } else {
1142 if (rate < 0)
1143 printf(" %s %s\n", clk_dump->name,
1144 "unknown");
1145 else
1146 printf(" %s %lu KHz\n", clk_dump->name,
1147 rate / 1000);
1148 }
1149 }
1150 }
1151
1152 return 0;
1153 }
1154 #endif
1155
1156