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