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