blob: 36764c128b05443eecefef7fd9ca4d4d06048924 [file] [log] [blame]
Kever Yangd49a5262019-07-11 10:42:16 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * (C) Copyright 2017 Rockchip Electronics Co., Ltd
4 */
5
6#include <common.h>
7#include <bitfield.h>
8#include <clk-uclass.h>
9#include <dm.h>
10#include <errno.h>
11#include <syscon.h>
12#include <asm/arch-rockchip/clock.h>
13#include <asm/arch-rockchip/cru_px30.h>
14#include <asm/arch-rockchip/hardware.h>
15#include <asm/io.h>
16#include <dm/lists.h>
17#include <dt-bindings/clock/px30-cru.h>
18
19DECLARE_GLOBAL_DATA_PTR;
20
21enum {
22 VCO_MAX_HZ = 3200U * 1000000,
23 VCO_MIN_HZ = 800 * 1000000,
24 OUTPUT_MAX_HZ = 3200U * 1000000,
25 OUTPUT_MIN_HZ = 24 * 1000000,
26};
27
28#define PX30_VOP_PLL_LIMIT 600000000
29
30#define PX30_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \
31 _postdiv2, _dsmpd, _frac) \
32{ \
33 .rate = _rate##U, \
34 .fbdiv = _fbdiv, \
35 .postdiv1 = _postdiv1, \
36 .refdiv = _refdiv, \
37 .postdiv2 = _postdiv2, \
38 .dsmpd = _dsmpd, \
39 .frac = _frac, \
40}
41
42#define PX30_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
43{ \
44 .rate = _rate##U, \
45 .aclk_div = _aclk_div, \
46 .pclk_div = _pclk_div, \
47}
48
49#define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
50
51#define PX30_CLK_DUMP(_id, _name, _iscru) \
52{ \
53 .id = _id, \
54 .name = _name, \
55 .is_cru = _iscru, \
56}
57
58static struct pll_rate_table px30_pll_rates[] = {
59 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
60 PX30_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
61 PX30_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
62 PX30_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
63 PX30_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
64 PX30_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
65 PX30_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
66 PX30_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
67};
68
69static struct cpu_rate_table px30_cpu_rates[] = {
70 PX30_CPUCLK_RATE(1200000000, 1, 5),
71 PX30_CPUCLK_RATE(1008000000, 1, 5),
72 PX30_CPUCLK_RATE(816000000, 1, 3),
73 PX30_CPUCLK_RATE(600000000, 1, 3),
74 PX30_CPUCLK_RATE(408000000, 1, 1),
75};
76
77static u8 pll_mode_shift[PLL_COUNT] = {
78 APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT,
79 NPLL_MODE_SHIFT, GPLL_MODE_SHIFT
80};
81
82static u32 pll_mode_mask[PLL_COUNT] = {
83 APLL_MODE_MASK, DPLL_MODE_MASK, CPLL_MODE_MASK,
84 NPLL_MODE_MASK, GPLL_MODE_MASK
85};
86
87static struct pll_rate_table auto_table;
88
89static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv,
90 enum px30_pll_id pll_id);
91
92static struct pll_rate_table *pll_clk_set_by_auto(u32 drate)
93{
94 struct pll_rate_table *rate = &auto_table;
95 u32 ref_khz = OSC_HZ / KHz, refdiv, fbdiv = 0;
96 u32 postdiv1, postdiv2 = 1;
97 u32 fref_khz;
98 u32 diff_khz, best_diff_khz;
99 const u32 max_refdiv = 63, max_fbdiv = 3200, min_fbdiv = 16;
100 const u32 max_postdiv1 = 7, max_postdiv2 = 7;
101 u32 vco_khz;
102 u32 rate_khz = drate / KHz;
103
104 if (!drate) {
105 printf("%s: the frequency can't be 0 Hz\n", __func__);
106 return NULL;
107 }
108
109 postdiv1 = DIV_ROUND_UP(VCO_MIN_HZ / 1000, rate_khz);
110 if (postdiv1 > max_postdiv1) {
111 postdiv2 = DIV_ROUND_UP(postdiv1, max_postdiv1);
112 postdiv1 = DIV_ROUND_UP(postdiv1, postdiv2);
113 }
114
115 vco_khz = rate_khz * postdiv1 * postdiv2;
116
117 if (vco_khz < (VCO_MIN_HZ / KHz) || vco_khz > (VCO_MAX_HZ / KHz) ||
118 postdiv2 > max_postdiv2) {
119 printf("%s: Cannot find out a supported VCO for Freq (%uHz)\n",
120 __func__, rate_khz);
121 return NULL;
122 }
123
124 rate->postdiv1 = postdiv1;
125 rate->postdiv2 = postdiv2;
126
127 best_diff_khz = vco_khz;
128 for (refdiv = 1; refdiv < max_refdiv && best_diff_khz; refdiv++) {
129 fref_khz = ref_khz / refdiv;
130
131 fbdiv = vco_khz / fref_khz;
132 if (fbdiv >= max_fbdiv || fbdiv <= min_fbdiv)
133 continue;
134
135 diff_khz = vco_khz - fbdiv * fref_khz;
136 if (fbdiv + 1 < max_fbdiv && diff_khz > fref_khz / 2) {
137 fbdiv++;
138 diff_khz = fref_khz - diff_khz;
139 }
140
141 if (diff_khz >= best_diff_khz)
142 continue;
143
144 best_diff_khz = diff_khz;
145 rate->refdiv = refdiv;
146 rate->fbdiv = fbdiv;
147 }
148
149 if (best_diff_khz > 4 * (MHz / KHz)) {
150 printf("%s: Failed to match output frequency %u bestis %u Hz\n",
151 __func__, rate_khz,
152 best_diff_khz * KHz);
153 return NULL;
154 }
155
156 return rate;
157}
158
159static const struct pll_rate_table *get_pll_settings(unsigned long rate)
160{
161 unsigned int rate_count = ARRAY_SIZE(px30_pll_rates);
162 int i;
163
164 for (i = 0; i < rate_count; i++) {
165 if (rate == px30_pll_rates[i].rate)
166 return &px30_pll_rates[i];
167 }
168
169 return pll_clk_set_by_auto(rate);
170}
171
172static const struct cpu_rate_table *get_cpu_settings(unsigned long rate)
173{
174 unsigned int rate_count = ARRAY_SIZE(px30_cpu_rates);
175 int i;
176
177 for (i = 0; i < rate_count; i++) {
178 if (rate == px30_cpu_rates[i].rate)
179 return &px30_cpu_rates[i];
180 }
181
182 return NULL;
183}
184
185/*
186 * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
187 * Formulas also embedded within the Fractional PLL Verilog model:
188 * If DSMPD = 1 (DSM is disabled, "integer mode")
189 * FOUTVCO = FREF / REFDIV * FBDIV
190 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
191 * Where:
192 * FOUTVCO = Fractional PLL non-divided output frequency
193 * FOUTPOSTDIV = Fractional PLL divided output frequency
194 * (output of second post divider)
195 * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
196 * REFDIV = Fractional PLL input reference clock divider
197 * FBDIV = Integer value programmed into feedback divide
198 *
199 */
200static int rkclk_set_pll(struct px30_pll *pll, unsigned int *mode,
201 enum px30_pll_id pll_id,
202 unsigned long drate)
203{
204 const struct pll_rate_table *rate;
205 uint vco_hz, output_hz;
206
207 rate = get_pll_settings(drate);
208 if (!rate) {
209 printf("%s unsupport rate\n", __func__);
210 return -EINVAL;
211 }
212
213 /* All PLLs have same VCO and output frequency range restrictions. */
214 vco_hz = OSC_HZ / 1000 * rate->fbdiv / rate->refdiv * 1000;
215 output_hz = vco_hz / rate->postdiv1 / rate->postdiv2;
216
217 debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n",
218 pll, rate->fbdiv, rate->refdiv, rate->postdiv1,
219 rate->postdiv2, vco_hz, output_hz);
220 assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
221 output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ);
222
223 /*
224 * When power on or changing PLL setting,
225 * we must force PLL into slow mode to ensure output stable clock.
226 */
227 rk_clrsetreg(mode, pll_mode_mask[pll_id],
228 PLLMUX_FROM_XIN24M << pll_mode_shift[pll_id]);
229
230 /* use integer mode */
231 rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
232 /* Power down */
233 rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT);
234
235 rk_clrsetreg(&pll->con0,
236 PLL_POSTDIV1_MASK | PLL_FBDIV_MASK,
237 (rate->postdiv1 << PLL_POSTDIV1_SHIFT) | rate->fbdiv);
238 rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK,
239 (rate->postdiv2 << PLL_POSTDIV2_SHIFT |
240 rate->refdiv << PLL_REFDIV_SHIFT));
241
242 /* Power Up */
243 rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT);
244
245 /* waiting for pll lock */
246 while (!(readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT)))
247 udelay(1);
248
249 rk_clrsetreg(mode, pll_mode_mask[pll_id],
250 PLLMUX_FROM_PLL << pll_mode_shift[pll_id]);
251
252 return 0;
253}
254
255static uint32_t rkclk_pll_get_rate(struct px30_pll *pll, unsigned int *mode,
256 enum px30_pll_id pll_id)
257{
258 u32 refdiv, fbdiv, postdiv1, postdiv2;
259 u32 con, shift, mask;
260
261 con = readl(mode);
262 shift = pll_mode_shift[pll_id];
263 mask = pll_mode_mask[pll_id];
264
265 switch ((con & mask) >> shift) {
266 case PLLMUX_FROM_XIN24M:
267 return OSC_HZ;
268 case PLLMUX_FROM_PLL:
269 /* normal mode */
270 con = readl(&pll->con0);
271 postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
272 fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
273 con = readl(&pll->con1);
274 postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
275 refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
276 return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
277 case PLLMUX_FROM_RTC32K:
278 default:
279 return 32768;
280 }
281}
282
283static ulong px30_i2c_get_clk(struct px30_clk_priv *priv, ulong clk_id)
284{
285 struct px30_cru *cru = priv->cru;
286 u32 div, con;
287
288 switch (clk_id) {
289 case SCLK_I2C0:
290 con = readl(&cru->clksel_con[49]);
291 div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
292 break;
293 case SCLK_I2C1:
294 con = readl(&cru->clksel_con[49]);
295 div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
296 break;
297 case SCLK_I2C2:
298 con = readl(&cru->clksel_con[50]);
299 div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
300 break;
301 case SCLK_I2C3:
302 con = readl(&cru->clksel_con[50]);
303 div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
304 break;
305 default:
306 printf("do not support this i2c bus\n");
307 return -EINVAL;
308 }
309
310 return DIV_TO_RATE(priv->gpll_hz, div);
311}
312
313static ulong px30_i2c_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
314{
315 struct px30_cru *cru = priv->cru;
316 int src_clk_div;
317
318 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
319 assert(src_clk_div - 1 <= 127);
320
321 switch (clk_id) {
322 case SCLK_I2C0:
323 rk_clrsetreg(&cru->clksel_con[49],
324 CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT |
325 CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT,
326 (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT |
327 CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT);
328 break;
329 case SCLK_I2C1:
330 rk_clrsetreg(&cru->clksel_con[49],
331 CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT |
332 CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT,
333 (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT |
334 CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT);
335 break;
336 case SCLK_I2C2:
337 rk_clrsetreg(&cru->clksel_con[50],
338 CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT |
339 CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT,
340 (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT |
341 CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT);
342 break;
343 case SCLK_I2C3:
344 rk_clrsetreg(&cru->clksel_con[50],
345 CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT |
346 CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT,
347 (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT |
348 CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT);
349 break;
350 default:
351 printf("do not support this i2c bus\n");
352 return -EINVAL;
353 }
354
355 return px30_i2c_get_clk(priv, clk_id);
356}
357
358/*
359 * calculate best rational approximation for a given fraction
360 * taking into account restricted register size, e.g. to find
361 * appropriate values for a pll with 5 bit denominator and
362 * 8 bit numerator register fields, trying to set up with a
363 * frequency ratio of 3.1415, one would say:
364 *
365 * rational_best_approximation(31415, 10000,
366 * (1 << 8) - 1, (1 << 5) - 1, &n, &d);
367 *
368 * you may look at given_numerator as a fixed point number,
369 * with the fractional part size described in given_denominator.
370 *
371 * for theoretical background, see:
372 * http://en.wikipedia.org/wiki/Continued_fraction
373 */
374static void rational_best_approximation(unsigned long given_numerator,
375 unsigned long given_denominator,
376 unsigned long max_numerator,
377 unsigned long max_denominator,
378 unsigned long *best_numerator,
379 unsigned long *best_denominator)
380{
381 unsigned long n, d, n0, d0, n1, d1;
382
383 n = given_numerator;
384 d = given_denominator;
385 n0 = 0;
386 d1 = 0;
387 n1 = 1;
388 d0 = 1;
389 for (;;) {
390 unsigned long t, a;
391
392 if (n1 > max_numerator || d1 > max_denominator) {
393 n1 = n0;
394 d1 = d0;
395 break;
396 }
397 if (d == 0)
398 break;
399 t = d;
400 a = n / d;
401 d = n % d;
402 n = t;
403 t = n0 + a * n1;
404 n0 = n1;
405 n1 = t;
406 t = d0 + a * d1;
407 d0 = d1;
408 d1 = t;
409 }
410 *best_numerator = n1;
411 *best_denominator = d1;
412}
413
414static ulong px30_i2s_get_clk(struct px30_clk_priv *priv, ulong clk_id)
415{
416 u32 con, fracdiv, gate;
417 u32 clk_src = priv->gpll_hz / 2;
418 unsigned long m, n;
419 struct px30_cru *cru = priv->cru;
420
421 switch (clk_id) {
422 case SCLK_I2S1:
423 con = readl(&cru->clksel_con[30]);
424 fracdiv = readl(&cru->clksel_con[31]);
425 gate = readl(&cru->clkgate_con[10]);
426 m = fracdiv & CLK_I2S1_FRAC_NUMERATOR_MASK;
427 m >>= CLK_I2S1_FRAC_NUMERATOR_SHIFT;
428 n = fracdiv & CLK_I2S1_FRAC_DENOMINATOR_MASK;
429 n >>= CLK_I2S1_FRAC_DENOMINATOR_SHIFT;
430 debug("con30: 0x%x, gate: 0x%x, frac: 0x%x\n",
431 con, gate, fracdiv);
432 break;
433 default:
434 printf("do not support this i2s bus\n");
435 return -EINVAL;
436 }
437
438 return clk_src * n / m;
439}
440
441static ulong px30_i2s_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
442{
443 u32 clk_src;
444 unsigned long m, n, val;
445 struct px30_cru *cru = priv->cru;
446
447 clk_src = priv->gpll_hz / 2;
448 rational_best_approximation(hz, clk_src,
449 GENMASK(16 - 1, 0),
450 GENMASK(16 - 1, 0),
451 &m, &n);
452 switch (clk_id) {
453 case SCLK_I2S1:
454 rk_clrsetreg(&cru->clksel_con[30],
455 CLK_I2S1_PLL_SEL_MASK, CLK_I2S1_PLL_SEL_GPLL);
456 rk_clrsetreg(&cru->clksel_con[30],
457 CLK_I2S1_DIV_CON_MASK, 0x1);
458 rk_clrsetreg(&cru->clksel_con[30],
459 CLK_I2S1_SEL_MASK, CLK_I2S1_SEL_FRAC);
460 val = m << CLK_I2S1_FRAC_NUMERATOR_SHIFT | n;
461 writel(val, &cru->clksel_con[31]);
462 rk_clrsetreg(&cru->clkgate_con[10],
463 CLK_I2S1_OUT_MCLK_PAD_MASK,
464 CLK_I2S1_OUT_MCLK_PAD_ENABLE);
465 break;
466 default:
467 printf("do not support this i2s bus\n");
468 return -EINVAL;
469 }
470
471 return px30_i2s_get_clk(priv, clk_id);
472}
473
474static ulong px30_nandc_get_clk(struct px30_clk_priv *priv)
475{
476 struct px30_cru *cru = priv->cru;
477 u32 div, con;
478
479 con = readl(&cru->clksel_con[15]);
480 div = (con & NANDC_DIV_MASK) >> NANDC_DIV_SHIFT;
481
482 return DIV_TO_RATE(priv->gpll_hz, div);
483}
484
485static ulong px30_nandc_set_clk(struct px30_clk_priv *priv,
486 ulong set_rate)
487{
488 struct px30_cru *cru = priv->cru;
489 int src_clk_div;
490
491 /* Select nandc source from GPLL by default */
492 /* nandc clock defaulg div 2 internal, need provide double in cru */
493 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, set_rate);
494 assert(src_clk_div - 1 <= 31);
495
496 rk_clrsetreg(&cru->clksel_con[15],
497 NANDC_CLK_SEL_MASK | NANDC_PLL_MASK |
498 NANDC_DIV_MASK,
499 NANDC_CLK_SEL_NANDC << NANDC_CLK_SEL_SHIFT |
500 NANDC_SEL_GPLL << NANDC_PLL_SHIFT |
501 (src_clk_div - 1) << NANDC_DIV_SHIFT);
502
503 return px30_nandc_get_clk(priv);
504}
505
506static ulong px30_mmc_get_clk(struct px30_clk_priv *priv, uint clk_id)
507{
508 struct px30_cru *cru = priv->cru;
509 u32 div, con, con_id;
510
511 switch (clk_id) {
512 case HCLK_SDMMC:
513 case SCLK_SDMMC:
514 con_id = 16;
515 break;
516 case HCLK_EMMC:
517 case SCLK_EMMC:
518 case SCLK_EMMC_SAMPLE:
519 con_id = 20;
520 break;
521 default:
522 return -EINVAL;
523 }
524
525 con = readl(&cru->clksel_con[con_id]);
526 div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
527
528 if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
529 == EMMC_SEL_24M)
530 return DIV_TO_RATE(OSC_HZ, div) / 2;
531 else
532 return DIV_TO_RATE(priv->gpll_hz, div) / 2;
533}
534
535static ulong px30_mmc_set_clk(struct px30_clk_priv *priv,
536 ulong clk_id, ulong set_rate)
537{
538 struct px30_cru *cru = priv->cru;
539 int src_clk_div;
540 u32 con_id;
541
542 switch (clk_id) {
543 case HCLK_SDMMC:
544 case SCLK_SDMMC:
545 con_id = 16;
546 break;
547 case HCLK_EMMC:
548 case SCLK_EMMC:
549 con_id = 20;
550 break;
551 default:
552 return -EINVAL;
553 }
554
555 /* Select clk_sdmmc/emmc source from GPLL by default */
556 /* mmc clock defaulg div 2 internal, need provide double in cru */
557 src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, set_rate);
558
559 if (src_clk_div > 127) {
560 /* use 24MHz source for 400KHz clock */
561 src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
562 rk_clrsetreg(&cru->clksel_con[con_id],
563 EMMC_PLL_MASK | EMMC_DIV_MASK,
564 EMMC_SEL_24M << EMMC_PLL_SHIFT |
565 (src_clk_div - 1) << EMMC_DIV_SHIFT);
566 } else {
567 rk_clrsetreg(&cru->clksel_con[con_id],
568 EMMC_PLL_MASK | EMMC_DIV_MASK,
569 EMMC_SEL_GPLL << EMMC_PLL_SHIFT |
570 (src_clk_div - 1) << EMMC_DIV_SHIFT);
571 }
572 rk_clrsetreg(&cru->clksel_con[con_id + 1], EMMC_CLK_SEL_MASK,
573 EMMC_CLK_SEL_EMMC);
574
575 return px30_mmc_get_clk(priv, clk_id);
576}
577
578static ulong px30_pwm_get_clk(struct px30_clk_priv *priv, ulong clk_id)
579{
580 struct px30_cru *cru = priv->cru;
581 u32 div, con;
582
583 switch (clk_id) {
584 case SCLK_PWM0:
585 con = readl(&cru->clksel_con[52]);
586 div = con >> CLK_PWM0_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
587 break;
588 case SCLK_PWM1:
589 con = readl(&cru->clksel_con[52]);
590 div = con >> CLK_PWM1_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
591 break;
592 default:
593 printf("do not support this pwm bus\n");
594 return -EINVAL;
595 }
596
597 return DIV_TO_RATE(priv->gpll_hz, div);
598}
599
600static ulong px30_pwm_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
601{
602 struct px30_cru *cru = priv->cru;
603 int src_clk_div;
604
605 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
606 assert(src_clk_div - 1 <= 127);
607
608 switch (clk_id) {
609 case SCLK_PWM0:
610 rk_clrsetreg(&cru->clksel_con[52],
611 CLK_PWM_DIV_CON_MASK << CLK_PWM0_DIV_CON_SHIFT |
612 CLK_PWM_PLL_SEL_MASK << CLK_PWM0_PLL_SEL_SHIFT,
613 (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT |
614 CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT);
615 break;
616 case SCLK_PWM1:
617 rk_clrsetreg(&cru->clksel_con[52],
618 CLK_PWM_DIV_CON_MASK << CLK_PWM1_DIV_CON_SHIFT |
619 CLK_PWM_PLL_SEL_MASK << CLK_PWM1_PLL_SEL_SHIFT,
620 (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT |
621 CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT);
622 break;
623 default:
624 printf("do not support this pwm bus\n");
625 return -EINVAL;
626 }
627
628 return px30_pwm_get_clk(priv, clk_id);
629}
630
631static ulong px30_saradc_get_clk(struct px30_clk_priv *priv)
632{
633 struct px30_cru *cru = priv->cru;
634 u32 div, con;
635
636 con = readl(&cru->clksel_con[55]);
637 div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
638
639 return DIV_TO_RATE(OSC_HZ, div);
640}
641
642static ulong px30_saradc_set_clk(struct px30_clk_priv *priv, uint hz)
643{
644 struct px30_cru *cru = priv->cru;
645 int src_clk_div;
646
647 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
648 assert(src_clk_div - 1 <= 2047);
649
650 rk_clrsetreg(&cru->clksel_con[55],
651 CLK_SARADC_DIV_CON_MASK,
652 (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
653
654 return px30_saradc_get_clk(priv);
655}
656
657static ulong px30_tsadc_get_clk(struct px30_clk_priv *priv)
658{
659 struct px30_cru *cru = priv->cru;
660 u32 div, con;
661
662 con = readl(&cru->clksel_con[54]);
663 div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
664
665 return DIV_TO_RATE(OSC_HZ, div);
666}
667
668static ulong px30_tsadc_set_clk(struct px30_clk_priv *priv, uint hz)
669{
670 struct px30_cru *cru = priv->cru;
671 int src_clk_div;
672
673 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
674 assert(src_clk_div - 1 <= 2047);
675
676 rk_clrsetreg(&cru->clksel_con[54],
677 CLK_SARADC_DIV_CON_MASK,
678 (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
679
680 return px30_tsadc_get_clk(priv);
681}
682
683static ulong px30_spi_get_clk(struct px30_clk_priv *priv, ulong clk_id)
684{
685 struct px30_cru *cru = priv->cru;
686 u32 div, con;
687
688 switch (clk_id) {
689 case SCLK_SPI0:
690 con = readl(&cru->clksel_con[53]);
691 div = con >> CLK_SPI0_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
692 break;
693 case SCLK_SPI1:
694 con = readl(&cru->clksel_con[53]);
695 div = con >> CLK_SPI1_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
696 break;
697 default:
698 printf("do not support this pwm bus\n");
699 return -EINVAL;
700 }
701
702 return DIV_TO_RATE(priv->gpll_hz, div);
703}
704
705static ulong px30_spi_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
706{
707 struct px30_cru *cru = priv->cru;
708 int src_clk_div;
709
710 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
711 assert(src_clk_div - 1 <= 127);
712
713 switch (clk_id) {
714 case SCLK_SPI0:
715 rk_clrsetreg(&cru->clksel_con[53],
716 CLK_SPI_DIV_CON_MASK << CLK_SPI0_DIV_CON_SHIFT |
717 CLK_SPI_PLL_SEL_MASK << CLK_SPI0_PLL_SEL_SHIFT,
718 (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT |
719 CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT);
720 break;
721 case SCLK_SPI1:
722 rk_clrsetreg(&cru->clksel_con[53],
723 CLK_SPI_DIV_CON_MASK << CLK_SPI1_DIV_CON_SHIFT |
724 CLK_SPI_PLL_SEL_MASK << CLK_SPI1_PLL_SEL_SHIFT,
725 (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT |
726 CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_PLL_SEL_SHIFT);
727 break;
728 default:
729 printf("do not support this pwm bus\n");
730 return -EINVAL;
731 }
732
733 return px30_spi_get_clk(priv, clk_id);
734}
735
736static ulong px30_vop_get_clk(struct px30_clk_priv *priv, ulong clk_id)
737{
738 struct px30_cru *cru = priv->cru;
739 u32 div, con, parent;
740
741 switch (clk_id) {
742 case ACLK_VOPB:
743 case ACLK_VOPL:
744 con = readl(&cru->clksel_con[3]);
745 div = con & ACLK_VO_DIV_MASK;
746 parent = priv->gpll_hz;
747 break;
748 case DCLK_VOPB:
749 con = readl(&cru->clksel_con[5]);
750 div = con & DCLK_VOPB_DIV_MASK;
751 parent = rkclk_pll_get_rate(&cru->pll[CPLL], &cru->mode, CPLL);
752 break;
753 case DCLK_VOPL:
754 con = readl(&cru->clksel_con[8]);
755 div = con & DCLK_VOPL_DIV_MASK;
756 parent = rkclk_pll_get_rate(&cru->pll[NPLL], &cru->mode, NPLL);
757 break;
758 default:
759 return -ENOENT;
760 }
761
762 return DIV_TO_RATE(parent, div);
763}
764
765static ulong px30_vop_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
766{
767 struct px30_cru *cru = priv->cru;
768 ulong npll_hz;
769 int src_clk_div;
770
771 switch (clk_id) {
772 case ACLK_VOPB:
773 case ACLK_VOPL:
774 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
775 assert(src_clk_div - 1 <= 31);
776 rk_clrsetreg(&cru->clksel_con[3],
777 ACLK_VO_PLL_MASK | ACLK_VO_DIV_MASK,
778 ACLK_VO_SEL_GPLL << ACLK_VO_PLL_SHIFT |
779 (src_clk_div - 1) << ACLK_VO_DIV_SHIFT);
780 break;
781 case DCLK_VOPB:
782 if (hz < PX30_VOP_PLL_LIMIT) {
783 src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT, hz);
784 if (src_clk_div % 2)
785 src_clk_div = src_clk_div - 1;
786 } else {
787 src_clk_div = 1;
788 }
789 assert(src_clk_div - 1 <= 255);
790 rkclk_set_pll(&cru->pll[CPLL], &cru->mode,
791 CPLL, hz * src_clk_div);
792 rk_clrsetreg(&cru->clksel_con[5],
793 DCLK_VOPB_SEL_MASK | DCLK_VOPB_PLL_SEL_MASK |
794 DCLK_VOPB_DIV_MASK,
795 DCLK_VOPB_SEL_DIVOUT << DCLK_VOPB_SEL_SHIFT |
796 DCLK_VOPB_PLL_SEL_CPLL << DCLK_VOPB_PLL_SEL_SHIFT |
797 (src_clk_div - 1) << DCLK_VOPB_DIV_SHIFT);
798 break;
799 case DCLK_VOPL:
800 npll_hz = px30_clk_get_pll_rate(priv, NPLL);
801 if (npll_hz >= PX30_VOP_PLL_LIMIT && npll_hz >= hz &&
802 npll_hz % hz == 0) {
803 src_clk_div = npll_hz / hz;
804 assert(src_clk_div - 1 <= 255);
805 } else {
806 if (hz < PX30_VOP_PLL_LIMIT) {
807 src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT,
808 hz);
809 if (src_clk_div % 2)
810 src_clk_div = src_clk_div - 1;
811 } else {
812 src_clk_div = 1;
813 }
814 assert(src_clk_div - 1 <= 255);
815 rkclk_set_pll(&cru->pll[NPLL], &cru->mode, NPLL,
816 hz * src_clk_div);
817 }
818 rk_clrsetreg(&cru->clksel_con[8],
819 DCLK_VOPL_SEL_MASK | DCLK_VOPL_PLL_SEL_MASK |
820 DCLK_VOPL_DIV_MASK,
821 DCLK_VOPL_SEL_DIVOUT << DCLK_VOPL_SEL_SHIFT |
822 DCLK_VOPL_PLL_SEL_NPLL << DCLK_VOPL_PLL_SEL_SHIFT |
823 (src_clk_div - 1) << DCLK_VOPL_DIV_SHIFT);
824 break;
825 default:
826 printf("do not support this vop freq\n");
827 return -EINVAL;
828 }
829
830 return px30_vop_get_clk(priv, clk_id);
831}
832
833static ulong px30_bus_get_clk(struct px30_clk_priv *priv, ulong clk_id)
834{
835 struct px30_cru *cru = priv->cru;
836 u32 div, con, parent;
837
838 switch (clk_id) {
839 case ACLK_BUS_PRE:
840 con = readl(&cru->clksel_con[23]);
841 div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
842 parent = priv->gpll_hz;
843 break;
844 case HCLK_BUS_PRE:
845 con = readl(&cru->clksel_con[24]);
846 div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
847 parent = priv->gpll_hz;
848 break;
849 case PCLK_BUS_PRE:
850 case PCLK_WDT_NS:
851 parent = px30_bus_get_clk(priv, ACLK_BUS_PRE);
852 con = readl(&cru->clksel_con[24]);
853 div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
854 break;
855 default:
856 return -ENOENT;
857 }
858
859 return DIV_TO_RATE(parent, div);
860}
861
862static ulong px30_bus_set_clk(struct px30_clk_priv *priv, ulong clk_id,
863 ulong hz)
864{
865 struct px30_cru *cru = priv->cru;
866 int src_clk_div;
867
868 /*
869 * select gpll as pd_bus bus clock source and
870 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
871 */
872 switch (clk_id) {
873 case ACLK_BUS_PRE:
874 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
875 assert(src_clk_div - 1 <= 31);
876 rk_clrsetreg(&cru->clksel_con[23],
877 BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
878 BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
879 (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
880 break;
881 case HCLK_BUS_PRE:
882 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
883 assert(src_clk_div - 1 <= 31);
884 rk_clrsetreg(&cru->clksel_con[24],
885 BUS_PLL_SEL_MASK | BUS_HCLK_DIV_MASK,
886 BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
887 (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
888 break;
889 case PCLK_BUS_PRE:
890 src_clk_div =
891 DIV_ROUND_UP(px30_bus_get_clk(priv, ACLK_BUS_PRE), hz);
892 assert(src_clk_div - 1 <= 3);
893 rk_clrsetreg(&cru->clksel_con[24],
894 BUS_PCLK_DIV_MASK,
895 (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
896 break;
897 default:
898 printf("do not support this bus freq\n");
899 return -EINVAL;
900 }
901
902 return px30_bus_get_clk(priv, clk_id);
903}
904
905static ulong px30_peri_get_clk(struct px30_clk_priv *priv, ulong clk_id)
906{
907 struct px30_cru *cru = priv->cru;
908 u32 div, con, parent;
909
910 switch (clk_id) {
911 case ACLK_PERI_PRE:
912 con = readl(&cru->clksel_con[14]);
913 div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
914 parent = priv->gpll_hz;
915 break;
916 case HCLK_PERI_PRE:
917 con = readl(&cru->clksel_con[14]);
918 div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
919 parent = priv->gpll_hz;
920 break;
921 default:
922 return -ENOENT;
923 }
924
925 return DIV_TO_RATE(parent, div);
926}
927
928static ulong px30_peri_set_clk(struct px30_clk_priv *priv, ulong clk_id,
929 ulong hz)
930{
931 struct px30_cru *cru = priv->cru;
932 int src_clk_div;
933
934 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
935 assert(src_clk_div - 1 <= 31);
936
937 /*
938 * select gpll as pd_peri bus clock source and
939 * set up dependent divisors for HCLK and ACLK clocks.
940 */
941 switch (clk_id) {
942 case ACLK_PERI_PRE:
943 rk_clrsetreg(&cru->clksel_con[14],
944 PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
945 PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
946 (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
947 break;
948 case HCLK_PERI_PRE:
949 rk_clrsetreg(&cru->clksel_con[14],
950 PERI_PLL_SEL_MASK | PERI_HCLK_DIV_MASK,
951 PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
952 (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
953 break;
954 default:
955 printf("do not support this peri freq\n");
956 return -EINVAL;
957 }
958
959 return px30_peri_get_clk(priv, clk_id);
960}
961
962#ifndef CONFIG_SPL_BUILD
963static ulong px30_crypto_get_clk(struct px30_clk_priv *priv, ulong clk_id)
964{
965 struct px30_cru *cru = priv->cru;
966 u32 div, con, parent;
967
968 switch (clk_id) {
969 case SCLK_CRYPTO:
970 con = readl(&cru->clksel_con[25]);
971 div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
972 parent = priv->gpll_hz;
973 break;
974 case SCLK_CRYPTO_APK:
975 con = readl(&cru->clksel_con[25]);
976 div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
977 parent = priv->gpll_hz;
978 break;
979 default:
980 return -ENOENT;
981 }
982
983 return DIV_TO_RATE(parent, div);
984}
985
986static ulong px30_crypto_set_clk(struct px30_clk_priv *priv, ulong clk_id,
987 ulong hz)
988{
989 struct px30_cru *cru = priv->cru;
990 int src_clk_div;
991
992 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
993 assert(src_clk_div - 1 <= 31);
994
995 /*
996 * select gpll as crypto clock source and
997 * set up dependent divisors for crypto clocks.
998 */
999 switch (clk_id) {
1000 case SCLK_CRYPTO:
1001 rk_clrsetreg(&cru->clksel_con[25],
1002 CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
1003 CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
1004 (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
1005 break;
1006 case SCLK_CRYPTO_APK:
1007 rk_clrsetreg(&cru->clksel_con[25],
1008 CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
1009 CRYPTO_PLL_SEL_GPLL << CRYPTO_APK_SEL_SHIFT |
1010 (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
1011 break;
1012 default:
1013 printf("do not support this peri freq\n");
1014 return -EINVAL;
1015 }
1016
1017 return px30_crypto_get_clk(priv, clk_id);
1018}
1019
1020static ulong px30_i2s1_mclk_get_clk(struct px30_clk_priv *priv, ulong clk_id)
1021{
1022 struct px30_cru *cru = priv->cru;
1023 u32 con;
1024
1025 con = readl(&cru->clksel_con[30]);
1026
1027 if (!(con & CLK_I2S1_OUT_SEL_MASK))
1028 return -ENOENT;
1029
1030 return 12000000;
1031}
1032
1033static ulong px30_i2s1_mclk_set_clk(struct px30_clk_priv *priv, ulong clk_id,
1034 ulong hz)
1035{
1036 struct px30_cru *cru = priv->cru;
1037
1038 if (hz != 12000000) {
1039 printf("do not support this i2s1_mclk freq\n");
1040 return -EINVAL;
1041 }
1042
1043 rk_clrsetreg(&cru->clksel_con[30], CLK_I2S1_OUT_SEL_MASK,
1044 CLK_I2S1_OUT_SEL_OSC);
1045 rk_clrsetreg(&cru->clkgate_con[10], CLK_I2S1_OUT_MCLK_PAD_MASK,
1046 CLK_I2S1_OUT_MCLK_PAD_ENABLE);
1047
1048 return px30_i2s1_mclk_get_clk(priv, clk_id);
1049}
1050
1051static ulong px30_mac_set_clk(struct px30_clk_priv *priv, uint hz)
1052{
1053 struct px30_cru *cru = priv->cru;
1054 u32 con = readl(&cru->clksel_con[22]);
1055 ulong pll_rate;
1056 u8 div;
1057
1058 if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_CPLL)
1059 pll_rate = px30_clk_get_pll_rate(priv, CPLL);
1060 else if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_NPLL)
1061 pll_rate = px30_clk_get_pll_rate(priv, NPLL);
1062 else
1063 pll_rate = priv->gpll_hz;
1064
1065 /*default set 50MHZ for gmac*/
1066 if (!hz)
1067 hz = 50000000;
1068
1069 div = DIV_ROUND_UP(pll_rate, hz) - 1;
1070 assert(div < 32);
1071 rk_clrsetreg(&cru->clksel_con[22], CLK_GMAC_DIV_MASK,
1072 div << CLK_GMAC_DIV_SHIFT);
1073
1074 return DIV_TO_RATE(pll_rate, div);
1075}
1076
1077static int px30_mac_set_speed_clk(struct px30_clk_priv *priv, uint hz)
1078{
1079 struct px30_cru *cru = priv->cru;
1080
1081 if (hz != 2500000 && hz != 25000000) {
1082 debug("Unsupported mac speed:%d\n", hz);
1083 return -EINVAL;
1084 }
1085
1086 rk_clrsetreg(&cru->clksel_con[23], RMII_CLK_SEL_MASK,
1087 ((hz == 2500000) ? 0 : 1) << RMII_CLK_SEL_SHIFT);
1088
1089 return 0;
1090}
1091
1092#endif
1093
1094static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv,
1095 enum px30_pll_id pll_id)
1096{
1097 struct px30_cru *cru = priv->cru;
1098
1099 return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id);
1100}
1101
1102static ulong px30_clk_set_pll_rate(struct px30_clk_priv *priv,
1103 enum px30_pll_id pll_id, ulong hz)
1104{
1105 struct px30_cru *cru = priv->cru;
1106
1107 if (rkclk_set_pll(&cru->pll[pll_id], &cru->mode, pll_id, hz))
1108 return -EINVAL;
1109 return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id);
1110}
1111
1112static ulong px30_armclk_set_clk(struct px30_clk_priv *priv, ulong hz)
1113{
1114 struct px30_cru *cru = priv->cru;
1115 const struct cpu_rate_table *rate;
1116 ulong old_rate;
1117
1118 rate = get_cpu_settings(hz);
1119 if (!rate) {
1120 printf("%s unsupport rate\n", __func__);
1121 return -EINVAL;
1122 }
1123
1124 /*
1125 * select apll as cpu/core clock pll source and
1126 * set up dependent divisors for PERI and ACLK clocks.
1127 * core hz : apll = 1:1
1128 */
1129 old_rate = px30_clk_get_pll_rate(priv, APLL);
1130 if (old_rate > hz) {
1131 if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz))
1132 return -EINVAL;
1133 rk_clrsetreg(&cru->clksel_con[0],
1134 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
1135 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
1136 rate->aclk_div << CORE_ACLK_DIV_SHIFT |
1137 rate->pclk_div << CORE_DBG_DIV_SHIFT |
1138 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
1139 0 << CORE_DIV_CON_SHIFT);
1140 } else if (old_rate < hz) {
1141 rk_clrsetreg(&cru->clksel_con[0],
1142 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
1143 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
1144 rate->aclk_div << CORE_ACLK_DIV_SHIFT |
1145 rate->pclk_div << CORE_DBG_DIV_SHIFT |
1146 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
1147 0 << CORE_DIV_CON_SHIFT);
1148 if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz))
1149 return -EINVAL;
1150 }
1151
1152 return px30_clk_get_pll_rate(priv, APLL);
1153}
1154
1155static ulong px30_clk_get_rate(struct clk *clk)
1156{
1157 struct px30_clk_priv *priv = dev_get_priv(clk->dev);
1158 ulong rate = 0;
1159
1160 if (!priv->gpll_hz && clk->id > ARMCLK) {
1161 printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1162 return -ENOENT;
1163 }
1164
1165 debug("%s %ld\n", __func__, clk->id);
1166 switch (clk->id) {
1167 case PLL_APLL:
1168 rate = px30_clk_get_pll_rate(priv, APLL);
1169 break;
1170 case PLL_DPLL:
1171 rate = px30_clk_get_pll_rate(priv, DPLL);
1172 break;
1173 case PLL_CPLL:
1174 rate = px30_clk_get_pll_rate(priv, CPLL);
1175 break;
1176 case PLL_NPLL:
1177 rate = px30_clk_get_pll_rate(priv, NPLL);
1178 break;
1179 case ARMCLK:
1180 rate = px30_clk_get_pll_rate(priv, APLL);
1181 break;
1182 case HCLK_SDMMC:
1183 case HCLK_EMMC:
1184 case SCLK_SDMMC:
1185 case SCLK_EMMC:
1186 case SCLK_EMMC_SAMPLE:
1187 rate = px30_mmc_get_clk(priv, clk->id);
1188 break;
1189 case SCLK_I2C0:
1190 case SCLK_I2C1:
1191 case SCLK_I2C2:
1192 case SCLK_I2C3:
1193 rate = px30_i2c_get_clk(priv, clk->id);
1194 break;
1195 case SCLK_I2S1:
1196 rate = px30_i2s_get_clk(priv, clk->id);
1197 break;
1198 case SCLK_NANDC:
1199 rate = px30_nandc_get_clk(priv);
1200 break;
1201 case SCLK_PWM0:
1202 case SCLK_PWM1:
1203 rate = px30_pwm_get_clk(priv, clk->id);
1204 break;
1205 case SCLK_SARADC:
1206 rate = px30_saradc_get_clk(priv);
1207 break;
1208 case SCLK_TSADC:
1209 rate = px30_tsadc_get_clk(priv);
1210 break;
1211 case SCLK_SPI0:
1212 case SCLK_SPI1:
1213 rate = px30_spi_get_clk(priv, clk->id);
1214 break;
1215 case ACLK_VOPB:
1216 case ACLK_VOPL:
1217 case DCLK_VOPB:
1218 case DCLK_VOPL:
1219 rate = px30_vop_get_clk(priv, clk->id);
1220 break;
1221 case ACLK_BUS_PRE:
1222 case HCLK_BUS_PRE:
1223 case PCLK_BUS_PRE:
1224 case PCLK_WDT_NS:
1225 rate = px30_bus_get_clk(priv, clk->id);
1226 break;
1227 case ACLK_PERI_PRE:
1228 case HCLK_PERI_PRE:
1229 rate = px30_peri_get_clk(priv, clk->id);
1230 break;
1231#ifndef CONFIG_SPL_BUILD
1232 case SCLK_CRYPTO:
1233 case SCLK_CRYPTO_APK:
1234 rate = px30_crypto_get_clk(priv, clk->id);
1235 break;
1236#endif
1237 default:
1238 return -ENOENT;
1239 }
1240
1241 return rate;
1242}
1243
1244static ulong px30_clk_set_rate(struct clk *clk, ulong rate)
1245{
1246 struct px30_clk_priv *priv = dev_get_priv(clk->dev);
1247 ulong ret = 0;
1248
1249 if (!priv->gpll_hz && clk->id > ARMCLK) {
1250 printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1251 return -ENOENT;
1252 }
1253
1254 debug("%s %ld %ld\n", __func__, clk->id, rate);
1255 switch (clk->id) {
1256 case PLL_NPLL:
1257 ret = px30_clk_set_pll_rate(priv, NPLL, rate);
1258 break;
1259 case ARMCLK:
1260 ret = px30_armclk_set_clk(priv, rate);
1261 break;
1262 case HCLK_SDMMC:
1263 case HCLK_EMMC:
1264 case SCLK_SDMMC:
1265 case SCLK_EMMC:
1266 ret = px30_mmc_set_clk(priv, clk->id, rate);
1267 break;
1268 case SCLK_I2C0:
1269 case SCLK_I2C1:
1270 case SCLK_I2C2:
1271 case SCLK_I2C3:
1272 ret = px30_i2c_set_clk(priv, clk->id, rate);
1273 break;
1274 case SCLK_I2S1:
1275 ret = px30_i2s_set_clk(priv, clk->id, rate);
1276 break;
1277 case SCLK_NANDC:
1278 ret = px30_nandc_set_clk(priv, rate);
1279 break;
1280 case SCLK_PWM0:
1281 case SCLK_PWM1:
1282 ret = px30_pwm_set_clk(priv, clk->id, rate);
1283 break;
1284 case SCLK_SARADC:
1285 ret = px30_saradc_set_clk(priv, rate);
1286 break;
1287 case SCLK_TSADC:
1288 ret = px30_tsadc_set_clk(priv, rate);
1289 break;
1290 case SCLK_SPI0:
1291 case SCLK_SPI1:
1292 ret = px30_spi_set_clk(priv, clk->id, rate);
1293 break;
1294 case ACLK_VOPB:
1295 case ACLK_VOPL:
1296 case DCLK_VOPB:
1297 case DCLK_VOPL:
1298 ret = px30_vop_set_clk(priv, clk->id, rate);
1299 break;
1300 case ACLK_BUS_PRE:
1301 case HCLK_BUS_PRE:
1302 case PCLK_BUS_PRE:
1303 ret = px30_bus_set_clk(priv, clk->id, rate);
1304 break;
1305 case ACLK_PERI_PRE:
1306 case HCLK_PERI_PRE:
1307 ret = px30_peri_set_clk(priv, clk->id, rate);
1308 break;
1309#ifndef CONFIG_SPL_BUILD
1310 case SCLK_CRYPTO:
1311 case SCLK_CRYPTO_APK:
1312 ret = px30_crypto_set_clk(priv, clk->id, rate);
1313 break;
1314 case SCLK_I2S1_OUT:
1315 ret = px30_i2s1_mclk_set_clk(priv, clk->id, rate);
1316 break;
1317 case SCLK_GMAC:
1318 case SCLK_GMAC_SRC:
1319 ret = px30_mac_set_clk(priv, rate);
1320 break;
1321 case SCLK_GMAC_RMII:
1322 ret = px30_mac_set_speed_clk(priv, rate);
1323 break;
1324#endif
1325 default:
1326 return -ENOENT;
1327 }
1328
1329 return ret;
1330}
1331
1332#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1333static int px30_gmac_set_parent(struct clk *clk, struct clk *parent)
1334{
1335 struct px30_clk_priv *priv = dev_get_priv(clk->dev);
1336 struct px30_cru *cru = priv->cru;
1337
1338 if (parent->id == SCLK_GMAC_SRC) {
1339 debug("%s: switching GAMC to SCLK_GMAC_SRC\n", __func__);
1340 rk_clrsetreg(&cru->clksel_con[23], RMII_EXTCLK_SEL_MASK,
1341 RMII_EXTCLK_SEL_INT << RMII_EXTCLK_SEL_SHIFT);
1342 } else {
1343 debug("%s: switching GMAC to external clock\n", __func__);
1344 rk_clrsetreg(&cru->clksel_con[23], RMII_EXTCLK_SEL_MASK,
1345 RMII_EXTCLK_SEL_EXT << RMII_EXTCLK_SEL_SHIFT);
1346 }
1347 return 0;
1348}
1349
1350static int px30_clk_set_parent(struct clk *clk, struct clk *parent)
1351{
1352 switch (clk->id) {
1353 case SCLK_GMAC:
1354 return px30_gmac_set_parent(clk, parent);
1355 default:
1356 return -ENOENT;
1357 }
1358}
1359#endif
1360
1361static int px30_clk_enable(struct clk *clk)
1362{
1363 switch (clk->id) {
1364 case HCLK_HOST:
1365 case SCLK_GMAC:
1366 case SCLK_GMAC_RX_TX:
1367 case SCLK_MAC_REF:
1368 case SCLK_MAC_REFOUT:
1369 case ACLK_GMAC:
1370 case PCLK_GMAC:
1371 case SCLK_GMAC_RMII:
1372 /* Required to successfully probe the Designware GMAC driver */
1373 return 0;
1374 }
1375
1376 debug("%s: unsupported clk %ld\n", __func__, clk->id);
1377 return -ENOENT;
1378}
1379
1380static struct clk_ops px30_clk_ops = {
1381 .get_rate = px30_clk_get_rate,
1382 .set_rate = px30_clk_set_rate,
1383#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1384 .set_parent = px30_clk_set_parent,
1385#endif
1386 .enable = px30_clk_enable,
1387};
1388
1389static void px30_clk_init(struct px30_clk_priv *priv)
1390{
1391 ulong npll_hz;
1392 int ret;
1393
1394 npll_hz = px30_clk_get_pll_rate(priv, NPLL);
1395 if (npll_hz != NPLL_HZ) {
1396 ret = px30_clk_set_pll_rate(priv, NPLL, NPLL_HZ);
1397 if (ret < 0)
1398 printf("%s failed to set npll rate\n", __func__);
1399 }
1400
1401 px30_bus_set_clk(priv, ACLK_BUS_PRE, ACLK_BUS_HZ);
1402 px30_bus_set_clk(priv, HCLK_BUS_PRE, HCLK_BUS_HZ);
1403 px30_bus_set_clk(priv, PCLK_BUS_PRE, PCLK_BUS_HZ);
1404 px30_peri_set_clk(priv, ACLK_PERI_PRE, ACLK_PERI_HZ);
1405 px30_peri_set_clk(priv, HCLK_PERI_PRE, HCLK_PERI_HZ);
1406}
1407
1408static int px30_clk_probe(struct udevice *dev)
1409{
1410 struct px30_clk_priv *priv = dev_get_priv(dev);
1411 struct clk clk_gpll;
1412 int ret;
1413
1414 if (px30_clk_get_pll_rate(priv, APLL) != APLL_HZ)
1415 px30_armclk_set_clk(priv, APLL_HZ);
1416
1417 /* get the GPLL rate from the pmucru */
1418 ret = clk_get_by_name(dev, "gpll", &clk_gpll);
1419 if (ret) {
1420 printf("%s: failed to get gpll clk from pmucru\n", __func__);
1421 return ret;
1422 }
1423
1424 priv->gpll_hz = clk_get_rate(&clk_gpll);
1425
1426 px30_clk_init(priv);
1427
1428 return 0;
1429}
1430
1431static int px30_clk_ofdata_to_platdata(struct udevice *dev)
1432{
1433 struct px30_clk_priv *priv = dev_get_priv(dev);
1434
1435 priv->cru = dev_read_addr_ptr(dev);
1436
1437 return 0;
1438}
1439
1440static int px30_clk_bind(struct udevice *dev)
1441{
1442 int ret;
1443 struct udevice *sys_child;
1444 struct sysreset_reg *priv;
1445
1446 /* The reset driver does not have a device node, so bind it here */
1447 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1448 &sys_child);
1449 if (ret) {
1450 debug("Warning: No sysreset driver: ret=%d\n", ret);
1451 } else {
1452 priv = malloc(sizeof(struct sysreset_reg));
1453 priv->glb_srst_fst_value = offsetof(struct px30_cru,
1454 glb_srst_fst);
1455 priv->glb_srst_snd_value = offsetof(struct px30_cru,
1456 glb_srst_snd);
1457 sys_child->priv = priv;
1458 }
1459
1460#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
1461 ret = offsetof(struct px30_cru, softrst_con[0]);
1462 ret = rockchip_reset_bind(dev, ret, 12);
1463 if (ret)
1464 debug("Warning: software reset driver bind faile\n");
1465#endif
1466
1467 return 0;
1468}
1469
1470static const struct udevice_id px30_clk_ids[] = {
1471 { .compatible = "rockchip,px30-cru" },
1472 { }
1473};
1474
1475U_BOOT_DRIVER(rockchip_px30_cru) = {
1476 .name = "rockchip_px30_cru",
1477 .id = UCLASS_CLK,
1478 .of_match = px30_clk_ids,
1479 .priv_auto_alloc_size = sizeof(struct px30_clk_priv),
1480 .ofdata_to_platdata = px30_clk_ofdata_to_platdata,
1481 .ops = &px30_clk_ops,
1482 .bind = px30_clk_bind,
1483 .probe = px30_clk_probe,
1484};
1485
1486static ulong px30_pclk_pmu_get_pmuclk(struct px30_pmuclk_priv *priv)
1487{
1488 struct px30_pmucru *pmucru = priv->pmucru;
1489 u32 div, con;
1490
1491 con = readl(&pmucru->pmu_clksel_con[0]);
1492 div = (con & CLK_PMU_PCLK_DIV_MASK) >> CLK_PMU_PCLK_DIV_SHIFT;
1493
1494 return DIV_TO_RATE(priv->gpll_hz, div);
1495}
1496
1497static ulong px30_pclk_pmu_set_pmuclk(struct px30_pmuclk_priv *priv, ulong hz)
1498{
1499 struct px30_pmucru *pmucru = priv->pmucru;
1500 int src_clk_div;
1501
1502 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
1503 assert(src_clk_div - 1 <= 31);
1504
1505 rk_clrsetreg(&pmucru->pmu_clksel_con[0],
1506 CLK_PMU_PCLK_DIV_MASK,
1507 (src_clk_div - 1) << CLK_PMU_PCLK_DIV_SHIFT);
1508
1509 return px30_pclk_pmu_get_pmuclk(priv);
1510}
1511
1512static ulong px30_pmuclk_get_gpll_rate(struct px30_pmuclk_priv *priv)
1513{
1514 struct px30_pmucru *pmucru = priv->pmucru;
1515
1516 return rkclk_pll_get_rate(&pmucru->pll, &pmucru->pmu_mode, GPLL);
1517}
1518
1519static ulong px30_pmuclk_set_gpll_rate(struct px30_pmuclk_priv *priv, ulong hz)
1520{
1521 struct px30_pmucru *pmucru = priv->pmucru;
1522 ulong pclk_pmu_rate;
1523 u32 div;
1524
1525 if (priv->gpll_hz == hz)
1526 return priv->gpll_hz;
1527
1528 div = DIV_ROUND_UP(hz, priv->gpll_hz);
1529
1530 /* save clock rate */
1531 pclk_pmu_rate = px30_pclk_pmu_get_pmuclk(priv);
1532
1533 /* avoid rate too large, reduce rate first */
1534 px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate / div);
1535
1536 /* change gpll rate */
1537 rkclk_set_pll(&pmucru->pll, &pmucru->pmu_mode, GPLL, hz);
1538 priv->gpll_hz = px30_pmuclk_get_gpll_rate(priv);
1539
1540 /* restore clock rate */
1541 px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate);
1542
1543 return priv->gpll_hz;
1544}
1545
1546static ulong px30_pmuclk_get_rate(struct clk *clk)
1547{
1548 struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev);
1549 ulong rate = 0;
1550
1551 debug("%s %ld\n", __func__, clk->id);
1552 switch (clk->id) {
1553 case PLL_GPLL:
1554 rate = px30_pmuclk_get_gpll_rate(priv);
1555 break;
1556 case PCLK_PMU_PRE:
1557 rate = px30_pclk_pmu_get_pmuclk(priv);
1558 break;
1559 default:
1560 return -ENOENT;
1561 }
1562
1563 return rate;
1564}
1565
1566static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate)
1567{
1568 struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev);
1569 ulong ret = 0;
1570
1571 debug("%s %ld %ld\n", __func__, clk->id, rate);
1572 switch (clk->id) {
1573 case PLL_GPLL:
1574 ret = px30_pmuclk_set_gpll_rate(priv, rate);
1575 break;
1576 case PCLK_PMU_PRE:
1577 ret = px30_pclk_pmu_set_pmuclk(priv, rate);
1578 break;
1579 default:
1580 return -ENOENT;
1581 }
1582
1583 return ret;
1584}
1585
1586static struct clk_ops px30_pmuclk_ops = {
1587 .get_rate = px30_pmuclk_get_rate,
1588 .set_rate = px30_pmuclk_set_rate,
1589};
1590
1591static void px30_pmuclk_init(struct px30_pmuclk_priv *priv)
1592{
1593 priv->gpll_hz = px30_pmuclk_get_gpll_rate(priv);
1594 px30_pmuclk_set_gpll_rate(priv, GPLL_HZ);
1595
1596 px30_pclk_pmu_set_pmuclk(priv, PCLK_PMU_HZ);
1597}
1598
1599static int px30_pmuclk_probe(struct udevice *dev)
1600{
1601 struct px30_pmuclk_priv *priv = dev_get_priv(dev);
1602
1603 px30_pmuclk_init(priv);
1604
1605 return 0;
1606}
1607
1608static int px30_pmuclk_ofdata_to_platdata(struct udevice *dev)
1609{
1610 struct px30_pmuclk_priv *priv = dev_get_priv(dev);
1611
1612 priv->pmucru = dev_read_addr_ptr(dev);
1613
1614 return 0;
1615}
1616
1617static const struct udevice_id px30_pmuclk_ids[] = {
1618 { .compatible = "rockchip,px30-pmucru" },
1619 { }
1620};
1621
1622U_BOOT_DRIVER(rockchip_px30_pmucru) = {
1623 .name = "rockchip_px30_pmucru",
1624 .id = UCLASS_CLK,
1625 .of_match = px30_pmuclk_ids,
1626 .priv_auto_alloc_size = sizeof(struct px30_pmuclk_priv),
1627 .ofdata_to_platdata = px30_pmuclk_ofdata_to_platdata,
1628 .ops = &px30_pmuclk_ops,
1629 .probe = px30_pmuclk_probe,
1630};