blob: 5d467447a175ff69c2d2aee0bab3479092065ea9 [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
Jon Lin8f20e732021-08-05 16:27:53 +0800584static ulong px30_sfc_get_clk(struct px30_clk_priv *priv, uint clk_id)
585{
586 struct px30_cru *cru = priv->cru;
587 u32 div, con;
588
589 con = readl(&cru->clksel_con[22]);
590 div = (con & SFC_DIV_CON_MASK) >> SFC_DIV_CON_SHIFT;
591
592 return DIV_TO_RATE(priv->gpll_hz, div);
593}
594
595static ulong px30_sfc_set_clk(struct px30_clk_priv *priv,
596 ulong clk_id, ulong set_rate)
597{
598 struct px30_cru *cru = priv->cru;
599 int src_clk_div;
600
601 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, set_rate);
602 rk_clrsetreg(&cru->clksel_con[22],
603 SFC_PLL_SEL_MASK | SFC_DIV_CON_MASK,
604 0 << SFC_PLL_SEL_SHIFT |
605 (src_clk_div - 1) << SFC_DIV_CON_SHIFT);
606
607 return px30_sfc_get_clk(priv, clk_id);
608}
609
Kever Yangba1033d2019-07-11 10:42:16 +0200610static ulong px30_pwm_get_clk(struct px30_clk_priv *priv, ulong clk_id)
611{
612 struct px30_cru *cru = priv->cru;
613 u32 div, con;
614
615 switch (clk_id) {
616 case SCLK_PWM0:
617 con = readl(&cru->clksel_con[52]);
618 div = con >> CLK_PWM0_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
619 break;
620 case SCLK_PWM1:
621 con = readl(&cru->clksel_con[52]);
622 div = con >> CLK_PWM1_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
623 break;
624 default:
625 printf("do not support this pwm bus\n");
626 return -EINVAL;
627 }
628
629 return DIV_TO_RATE(priv->gpll_hz, div);
630}
631
632static ulong px30_pwm_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
633{
634 struct px30_cru *cru = priv->cru;
635 int src_clk_div;
636
637 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
638 assert(src_clk_div - 1 <= 127);
639
640 switch (clk_id) {
641 case SCLK_PWM0:
642 rk_clrsetreg(&cru->clksel_con[52],
643 CLK_PWM_DIV_CON_MASK << CLK_PWM0_DIV_CON_SHIFT |
644 CLK_PWM_PLL_SEL_MASK << CLK_PWM0_PLL_SEL_SHIFT,
645 (src_clk_div - 1) << CLK_PWM0_DIV_CON_SHIFT |
646 CLK_PWM_PLL_SEL_GPLL << CLK_PWM0_PLL_SEL_SHIFT);
647 break;
648 case SCLK_PWM1:
649 rk_clrsetreg(&cru->clksel_con[52],
650 CLK_PWM_DIV_CON_MASK << CLK_PWM1_DIV_CON_SHIFT |
651 CLK_PWM_PLL_SEL_MASK << CLK_PWM1_PLL_SEL_SHIFT,
652 (src_clk_div - 1) << CLK_PWM1_DIV_CON_SHIFT |
653 CLK_PWM_PLL_SEL_GPLL << CLK_PWM1_PLL_SEL_SHIFT);
654 break;
655 default:
656 printf("do not support this pwm bus\n");
657 return -EINVAL;
658 }
659
660 return px30_pwm_get_clk(priv, clk_id);
661}
662
663static ulong px30_saradc_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[55]);
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_saradc_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[55],
683 CLK_SARADC_DIV_CON_MASK,
684 (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
685
686 return px30_saradc_get_clk(priv);
687}
688
689static ulong px30_tsadc_get_clk(struct px30_clk_priv *priv)
690{
691 struct px30_cru *cru = priv->cru;
692 u32 div, con;
693
694 con = readl(&cru->clksel_con[54]);
695 div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
696
697 return DIV_TO_RATE(OSC_HZ, div);
698}
699
700static ulong px30_tsadc_set_clk(struct px30_clk_priv *priv, uint hz)
701{
702 struct px30_cru *cru = priv->cru;
703 int src_clk_div;
704
705 src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
706 assert(src_clk_div - 1 <= 2047);
707
708 rk_clrsetreg(&cru->clksel_con[54],
709 CLK_SARADC_DIV_CON_MASK,
710 (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
711
712 return px30_tsadc_get_clk(priv);
713}
714
715static ulong px30_spi_get_clk(struct px30_clk_priv *priv, ulong clk_id)
716{
717 struct px30_cru *cru = priv->cru;
718 u32 div, con;
719
720 switch (clk_id) {
721 case SCLK_SPI0:
722 con = readl(&cru->clksel_con[53]);
723 div = con >> CLK_SPI0_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
724 break;
725 case SCLK_SPI1:
726 con = readl(&cru->clksel_con[53]);
727 div = con >> CLK_SPI1_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
728 break;
729 default:
730 printf("do not support this pwm bus\n");
731 return -EINVAL;
732 }
733
734 return DIV_TO_RATE(priv->gpll_hz, div);
735}
736
737static ulong px30_spi_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
738{
739 struct px30_cru *cru = priv->cru;
740 int src_clk_div;
741
742 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
743 assert(src_clk_div - 1 <= 127);
744
745 switch (clk_id) {
746 case SCLK_SPI0:
747 rk_clrsetreg(&cru->clksel_con[53],
748 CLK_SPI_DIV_CON_MASK << CLK_SPI0_DIV_CON_SHIFT |
749 CLK_SPI_PLL_SEL_MASK << CLK_SPI0_PLL_SEL_SHIFT,
750 (src_clk_div - 1) << CLK_SPI0_DIV_CON_SHIFT |
751 CLK_SPI_PLL_SEL_GPLL << CLK_SPI0_PLL_SEL_SHIFT);
752 break;
753 case SCLK_SPI1:
754 rk_clrsetreg(&cru->clksel_con[53],
755 CLK_SPI_DIV_CON_MASK << CLK_SPI1_DIV_CON_SHIFT |
756 CLK_SPI_PLL_SEL_MASK << CLK_SPI1_PLL_SEL_SHIFT,
757 (src_clk_div - 1) << CLK_SPI1_DIV_CON_SHIFT |
758 CLK_SPI_PLL_SEL_GPLL << CLK_SPI1_PLL_SEL_SHIFT);
759 break;
760 default:
761 printf("do not support this pwm bus\n");
762 return -EINVAL;
763 }
764
765 return px30_spi_get_clk(priv, clk_id);
766}
767
768static ulong px30_vop_get_clk(struct px30_clk_priv *priv, ulong clk_id)
769{
770 struct px30_cru *cru = priv->cru;
771 u32 div, con, parent;
772
773 switch (clk_id) {
774 case ACLK_VOPB:
775 case ACLK_VOPL:
776 con = readl(&cru->clksel_con[3]);
777 div = con & ACLK_VO_DIV_MASK;
778 parent = priv->gpll_hz;
779 break;
780 case DCLK_VOPB:
781 con = readl(&cru->clksel_con[5]);
782 div = con & DCLK_VOPB_DIV_MASK;
783 parent = rkclk_pll_get_rate(&cru->pll[CPLL], &cru->mode, CPLL);
784 break;
785 case DCLK_VOPL:
786 con = readl(&cru->clksel_con[8]);
787 div = con & DCLK_VOPL_DIV_MASK;
788 parent = rkclk_pll_get_rate(&cru->pll[NPLL], &cru->mode, NPLL);
789 break;
790 default:
791 return -ENOENT;
792 }
793
794 return DIV_TO_RATE(parent, div);
795}
796
797static ulong px30_vop_set_clk(struct px30_clk_priv *priv, ulong clk_id, uint hz)
798{
799 struct px30_cru *cru = priv->cru;
800 ulong npll_hz;
801 int src_clk_div;
802
803 switch (clk_id) {
804 case ACLK_VOPB:
805 case ACLK_VOPL:
806 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
807 assert(src_clk_div - 1 <= 31);
808 rk_clrsetreg(&cru->clksel_con[3],
809 ACLK_VO_PLL_MASK | ACLK_VO_DIV_MASK,
810 ACLK_VO_SEL_GPLL << ACLK_VO_PLL_SHIFT |
811 (src_clk_div - 1) << ACLK_VO_DIV_SHIFT);
812 break;
813 case DCLK_VOPB:
814 if (hz < PX30_VOP_PLL_LIMIT) {
815 src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT, hz);
816 if (src_clk_div % 2)
817 src_clk_div = src_clk_div - 1;
818 } else {
819 src_clk_div = 1;
820 }
821 assert(src_clk_div - 1 <= 255);
822 rkclk_set_pll(&cru->pll[CPLL], &cru->mode,
823 CPLL, hz * src_clk_div);
824 rk_clrsetreg(&cru->clksel_con[5],
825 DCLK_VOPB_SEL_MASK | DCLK_VOPB_PLL_SEL_MASK |
826 DCLK_VOPB_DIV_MASK,
827 DCLK_VOPB_SEL_DIVOUT << DCLK_VOPB_SEL_SHIFT |
828 DCLK_VOPB_PLL_SEL_CPLL << DCLK_VOPB_PLL_SEL_SHIFT |
829 (src_clk_div - 1) << DCLK_VOPB_DIV_SHIFT);
830 break;
831 case DCLK_VOPL:
832 npll_hz = px30_clk_get_pll_rate(priv, NPLL);
833 if (npll_hz >= PX30_VOP_PLL_LIMIT && npll_hz >= hz &&
834 npll_hz % hz == 0) {
835 src_clk_div = npll_hz / hz;
836 assert(src_clk_div - 1 <= 255);
837 } else {
838 if (hz < PX30_VOP_PLL_LIMIT) {
839 src_clk_div = DIV_ROUND_UP(PX30_VOP_PLL_LIMIT,
840 hz);
841 if (src_clk_div % 2)
842 src_clk_div = src_clk_div - 1;
843 } else {
844 src_clk_div = 1;
845 }
846 assert(src_clk_div - 1 <= 255);
847 rkclk_set_pll(&cru->pll[NPLL], &cru->mode, NPLL,
848 hz * src_clk_div);
849 }
850 rk_clrsetreg(&cru->clksel_con[8],
851 DCLK_VOPL_SEL_MASK | DCLK_VOPL_PLL_SEL_MASK |
852 DCLK_VOPL_DIV_MASK,
853 DCLK_VOPL_SEL_DIVOUT << DCLK_VOPL_SEL_SHIFT |
854 DCLK_VOPL_PLL_SEL_NPLL << DCLK_VOPL_PLL_SEL_SHIFT |
855 (src_clk_div - 1) << DCLK_VOPL_DIV_SHIFT);
856 break;
857 default:
858 printf("do not support this vop freq\n");
859 return -EINVAL;
860 }
861
862 return px30_vop_get_clk(priv, clk_id);
863}
864
865static ulong px30_bus_get_clk(struct px30_clk_priv *priv, ulong clk_id)
866{
867 struct px30_cru *cru = priv->cru;
868 u32 div, con, parent;
869
870 switch (clk_id) {
871 case ACLK_BUS_PRE:
872 con = readl(&cru->clksel_con[23]);
873 div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
874 parent = priv->gpll_hz;
875 break;
876 case HCLK_BUS_PRE:
877 con = readl(&cru->clksel_con[24]);
878 div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
879 parent = priv->gpll_hz;
880 break;
881 case PCLK_BUS_PRE:
882 case PCLK_WDT_NS:
883 parent = px30_bus_get_clk(priv, ACLK_BUS_PRE);
884 con = readl(&cru->clksel_con[24]);
885 div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
886 break;
887 default:
888 return -ENOENT;
889 }
890
891 return DIV_TO_RATE(parent, div);
892}
893
894static ulong px30_bus_set_clk(struct px30_clk_priv *priv, ulong clk_id,
895 ulong hz)
896{
897 struct px30_cru *cru = priv->cru;
898 int src_clk_div;
899
900 /*
901 * select gpll as pd_bus bus clock source and
902 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
903 */
904 switch (clk_id) {
905 case ACLK_BUS_PRE:
906 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
907 assert(src_clk_div - 1 <= 31);
908 rk_clrsetreg(&cru->clksel_con[23],
909 BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
910 BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
911 (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
912 break;
913 case HCLK_BUS_PRE:
914 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
915 assert(src_clk_div - 1 <= 31);
916 rk_clrsetreg(&cru->clksel_con[24],
917 BUS_PLL_SEL_MASK | BUS_HCLK_DIV_MASK,
918 BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
919 (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
920 break;
921 case PCLK_BUS_PRE:
922 src_clk_div =
923 DIV_ROUND_UP(px30_bus_get_clk(priv, ACLK_BUS_PRE), hz);
924 assert(src_clk_div - 1 <= 3);
925 rk_clrsetreg(&cru->clksel_con[24],
926 BUS_PCLK_DIV_MASK,
927 (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
928 break;
929 default:
930 printf("do not support this bus freq\n");
931 return -EINVAL;
932 }
933
934 return px30_bus_get_clk(priv, clk_id);
935}
936
937static ulong px30_peri_get_clk(struct px30_clk_priv *priv, ulong clk_id)
938{
939 struct px30_cru *cru = priv->cru;
940 u32 div, con, parent;
941
942 switch (clk_id) {
943 case ACLK_PERI_PRE:
944 con = readl(&cru->clksel_con[14]);
945 div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
946 parent = priv->gpll_hz;
947 break;
948 case HCLK_PERI_PRE:
949 con = readl(&cru->clksel_con[14]);
950 div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
951 parent = priv->gpll_hz;
952 break;
953 default:
954 return -ENOENT;
955 }
956
957 return DIV_TO_RATE(parent, div);
958}
959
960static ulong px30_peri_set_clk(struct px30_clk_priv *priv, ulong clk_id,
961 ulong hz)
962{
963 struct px30_cru *cru = priv->cru;
964 int src_clk_div;
965
966 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
967 assert(src_clk_div - 1 <= 31);
968
969 /*
970 * select gpll as pd_peri bus clock source and
971 * set up dependent divisors for HCLK and ACLK clocks.
972 */
973 switch (clk_id) {
974 case ACLK_PERI_PRE:
975 rk_clrsetreg(&cru->clksel_con[14],
976 PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
977 PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
978 (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
979 break;
980 case HCLK_PERI_PRE:
981 rk_clrsetreg(&cru->clksel_con[14],
982 PERI_PLL_SEL_MASK | PERI_HCLK_DIV_MASK,
983 PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
984 (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
985 break;
986 default:
987 printf("do not support this peri freq\n");
988 return -EINVAL;
989 }
990
991 return px30_peri_get_clk(priv, clk_id);
992}
993
994#ifndef CONFIG_SPL_BUILD
995static ulong px30_crypto_get_clk(struct px30_clk_priv *priv, ulong clk_id)
996{
997 struct px30_cru *cru = priv->cru;
998 u32 div, con, parent;
999
1000 switch (clk_id) {
1001 case SCLK_CRYPTO:
1002 con = readl(&cru->clksel_con[25]);
1003 div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
1004 parent = priv->gpll_hz;
1005 break;
1006 case SCLK_CRYPTO_APK:
1007 con = readl(&cru->clksel_con[25]);
1008 div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
1009 parent = priv->gpll_hz;
1010 break;
1011 default:
1012 return -ENOENT;
1013 }
1014
1015 return DIV_TO_RATE(parent, div);
1016}
1017
1018static ulong px30_crypto_set_clk(struct px30_clk_priv *priv, ulong clk_id,
1019 ulong hz)
1020{
1021 struct px30_cru *cru = priv->cru;
1022 int src_clk_div;
1023
1024 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
1025 assert(src_clk_div - 1 <= 31);
1026
1027 /*
1028 * select gpll as crypto clock source and
1029 * set up dependent divisors for crypto clocks.
1030 */
1031 switch (clk_id) {
1032 case SCLK_CRYPTO:
1033 rk_clrsetreg(&cru->clksel_con[25],
1034 CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
1035 CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
1036 (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
1037 break;
1038 case SCLK_CRYPTO_APK:
1039 rk_clrsetreg(&cru->clksel_con[25],
1040 CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
1041 CRYPTO_PLL_SEL_GPLL << CRYPTO_APK_SEL_SHIFT |
1042 (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
1043 break;
1044 default:
1045 printf("do not support this peri freq\n");
1046 return -EINVAL;
1047 }
1048
1049 return px30_crypto_get_clk(priv, clk_id);
1050}
1051
1052static ulong px30_i2s1_mclk_get_clk(struct px30_clk_priv *priv, ulong clk_id)
1053{
1054 struct px30_cru *cru = priv->cru;
1055 u32 con;
1056
1057 con = readl(&cru->clksel_con[30]);
1058
1059 if (!(con & CLK_I2S1_OUT_SEL_MASK))
1060 return -ENOENT;
1061
1062 return 12000000;
1063}
1064
1065static ulong px30_i2s1_mclk_set_clk(struct px30_clk_priv *priv, ulong clk_id,
1066 ulong hz)
1067{
1068 struct px30_cru *cru = priv->cru;
1069
1070 if (hz != 12000000) {
1071 printf("do not support this i2s1_mclk freq\n");
1072 return -EINVAL;
1073 }
1074
1075 rk_clrsetreg(&cru->clksel_con[30], CLK_I2S1_OUT_SEL_MASK,
1076 CLK_I2S1_OUT_SEL_OSC);
1077 rk_clrsetreg(&cru->clkgate_con[10], CLK_I2S1_OUT_MCLK_PAD_MASK,
1078 CLK_I2S1_OUT_MCLK_PAD_ENABLE);
1079
1080 return px30_i2s1_mclk_get_clk(priv, clk_id);
1081}
1082
1083static ulong px30_mac_set_clk(struct px30_clk_priv *priv, uint hz)
1084{
1085 struct px30_cru *cru = priv->cru;
1086 u32 con = readl(&cru->clksel_con[22]);
1087 ulong pll_rate;
1088 u8 div;
1089
1090 if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_CPLL)
1091 pll_rate = px30_clk_get_pll_rate(priv, CPLL);
1092 else if ((con >> GMAC_PLL_SEL_SHIFT) & GMAC_PLL_SEL_NPLL)
1093 pll_rate = px30_clk_get_pll_rate(priv, NPLL);
1094 else
1095 pll_rate = priv->gpll_hz;
1096
1097 /*default set 50MHZ for gmac*/
1098 if (!hz)
1099 hz = 50000000;
1100
1101 div = DIV_ROUND_UP(pll_rate, hz) - 1;
1102 assert(div < 32);
1103 rk_clrsetreg(&cru->clksel_con[22], CLK_GMAC_DIV_MASK,
1104 div << CLK_GMAC_DIV_SHIFT);
1105
1106 return DIV_TO_RATE(pll_rate, div);
1107}
1108
1109static int px30_mac_set_speed_clk(struct px30_clk_priv *priv, uint hz)
1110{
1111 struct px30_cru *cru = priv->cru;
1112
1113 if (hz != 2500000 && hz != 25000000) {
1114 debug("Unsupported mac speed:%d\n", hz);
1115 return -EINVAL;
1116 }
1117
1118 rk_clrsetreg(&cru->clksel_con[23], RMII_CLK_SEL_MASK,
1119 ((hz == 2500000) ? 0 : 1) << RMII_CLK_SEL_SHIFT);
1120
1121 return 0;
1122}
1123
1124#endif
1125
1126static ulong px30_clk_get_pll_rate(struct px30_clk_priv *priv,
1127 enum px30_pll_id pll_id)
1128{
1129 struct px30_cru *cru = priv->cru;
1130
1131 return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id);
1132}
1133
1134static ulong px30_clk_set_pll_rate(struct px30_clk_priv *priv,
1135 enum px30_pll_id pll_id, ulong hz)
1136{
1137 struct px30_cru *cru = priv->cru;
1138
1139 if (rkclk_set_pll(&cru->pll[pll_id], &cru->mode, pll_id, hz))
1140 return -EINVAL;
1141 return rkclk_pll_get_rate(&cru->pll[pll_id], &cru->mode, pll_id);
1142}
1143
1144static ulong px30_armclk_set_clk(struct px30_clk_priv *priv, ulong hz)
1145{
1146 struct px30_cru *cru = priv->cru;
1147 const struct cpu_rate_table *rate;
1148 ulong old_rate;
1149
1150 rate = get_cpu_settings(hz);
1151 if (!rate) {
1152 printf("%s unsupport rate\n", __func__);
1153 return -EINVAL;
1154 }
1155
1156 /*
1157 * select apll as cpu/core clock pll source and
1158 * set up dependent divisors for PERI and ACLK clocks.
1159 * core hz : apll = 1:1
1160 */
1161 old_rate = px30_clk_get_pll_rate(priv, APLL);
1162 if (old_rate > hz) {
1163 if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz))
1164 return -EINVAL;
1165 rk_clrsetreg(&cru->clksel_con[0],
1166 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
1167 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
1168 rate->aclk_div << CORE_ACLK_DIV_SHIFT |
1169 rate->pclk_div << CORE_DBG_DIV_SHIFT |
1170 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
1171 0 << CORE_DIV_CON_SHIFT);
1172 } else if (old_rate < hz) {
1173 rk_clrsetreg(&cru->clksel_con[0],
1174 CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
1175 CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
1176 rate->aclk_div << CORE_ACLK_DIV_SHIFT |
1177 rate->pclk_div << CORE_DBG_DIV_SHIFT |
1178 CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
1179 0 << CORE_DIV_CON_SHIFT);
1180 if (rkclk_set_pll(&cru->pll[APLL], &cru->mode, APLL, hz))
1181 return -EINVAL;
1182 }
1183
1184 return px30_clk_get_pll_rate(priv, APLL);
1185}
1186
1187static ulong px30_clk_get_rate(struct clk *clk)
1188{
1189 struct px30_clk_priv *priv = dev_get_priv(clk->dev);
1190 ulong rate = 0;
1191
1192 if (!priv->gpll_hz && clk->id > ARMCLK) {
1193 printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1194 return -ENOENT;
1195 }
1196
1197 debug("%s %ld\n", __func__, clk->id);
1198 switch (clk->id) {
1199 case PLL_APLL:
1200 rate = px30_clk_get_pll_rate(priv, APLL);
1201 break;
1202 case PLL_DPLL:
1203 rate = px30_clk_get_pll_rate(priv, DPLL);
1204 break;
1205 case PLL_CPLL:
1206 rate = px30_clk_get_pll_rate(priv, CPLL);
1207 break;
1208 case PLL_NPLL:
1209 rate = px30_clk_get_pll_rate(priv, NPLL);
1210 break;
1211 case ARMCLK:
1212 rate = px30_clk_get_pll_rate(priv, APLL);
1213 break;
1214 case HCLK_SDMMC:
1215 case HCLK_EMMC:
1216 case SCLK_SDMMC:
1217 case SCLK_EMMC:
1218 case SCLK_EMMC_SAMPLE:
1219 rate = px30_mmc_get_clk(priv, clk->id);
1220 break;
Jon Lin8f20e732021-08-05 16:27:53 +08001221 case SCLK_SFC:
1222 rate = px30_sfc_get_clk(priv, clk->id);
1223 break;
Kever Yangba1033d2019-07-11 10:42:16 +02001224 case SCLK_I2C0:
1225 case SCLK_I2C1:
1226 case SCLK_I2C2:
1227 case SCLK_I2C3:
1228 rate = px30_i2c_get_clk(priv, clk->id);
1229 break;
1230 case SCLK_I2S1:
1231 rate = px30_i2s_get_clk(priv, clk->id);
1232 break;
1233 case SCLK_NANDC:
1234 rate = px30_nandc_get_clk(priv);
1235 break;
1236 case SCLK_PWM0:
1237 case SCLK_PWM1:
1238 rate = px30_pwm_get_clk(priv, clk->id);
1239 break;
1240 case SCLK_SARADC:
1241 rate = px30_saradc_get_clk(priv);
1242 break;
1243 case SCLK_TSADC:
1244 rate = px30_tsadc_get_clk(priv);
1245 break;
1246 case SCLK_SPI0:
1247 case SCLK_SPI1:
1248 rate = px30_spi_get_clk(priv, clk->id);
1249 break;
1250 case ACLK_VOPB:
1251 case ACLK_VOPL:
1252 case DCLK_VOPB:
1253 case DCLK_VOPL:
1254 rate = px30_vop_get_clk(priv, clk->id);
1255 break;
1256 case ACLK_BUS_PRE:
1257 case HCLK_BUS_PRE:
1258 case PCLK_BUS_PRE:
1259 case PCLK_WDT_NS:
1260 rate = px30_bus_get_clk(priv, clk->id);
1261 break;
1262 case ACLK_PERI_PRE:
1263 case HCLK_PERI_PRE:
1264 rate = px30_peri_get_clk(priv, clk->id);
1265 break;
1266#ifndef CONFIG_SPL_BUILD
1267 case SCLK_CRYPTO:
1268 case SCLK_CRYPTO_APK:
1269 rate = px30_crypto_get_clk(priv, clk->id);
1270 break;
1271#endif
1272 default:
1273 return -ENOENT;
1274 }
1275
1276 return rate;
1277}
1278
1279static ulong px30_clk_set_rate(struct clk *clk, ulong rate)
1280{
1281 struct px30_clk_priv *priv = dev_get_priv(clk->dev);
1282 ulong ret = 0;
1283
1284 if (!priv->gpll_hz && clk->id > ARMCLK) {
1285 printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1286 return -ENOENT;
1287 }
1288
1289 debug("%s %ld %ld\n", __func__, clk->id, rate);
1290 switch (clk->id) {
1291 case PLL_NPLL:
1292 ret = px30_clk_set_pll_rate(priv, NPLL, rate);
1293 break;
Chris Morganb9599102021-08-05 11:48:47 -05001294 case PLL_CPLL:
1295 ret = px30_clk_set_pll_rate(priv, CPLL, rate);
1296 break;
Kever Yangba1033d2019-07-11 10:42:16 +02001297 case ARMCLK:
1298 ret = px30_armclk_set_clk(priv, rate);
1299 break;
1300 case HCLK_SDMMC:
1301 case HCLK_EMMC:
1302 case SCLK_SDMMC:
1303 case SCLK_EMMC:
1304 ret = px30_mmc_set_clk(priv, clk->id, rate);
1305 break;
Jon Lin8f20e732021-08-05 16:27:53 +08001306 case SCLK_SFC:
1307 ret = px30_sfc_set_clk(priv, clk->id, rate);
1308 break;
Kever Yangba1033d2019-07-11 10:42:16 +02001309 case SCLK_I2C0:
1310 case SCLK_I2C1:
1311 case SCLK_I2C2:
1312 case SCLK_I2C3:
1313 ret = px30_i2c_set_clk(priv, clk->id, rate);
1314 break;
1315 case SCLK_I2S1:
1316 ret = px30_i2s_set_clk(priv, clk->id, rate);
1317 break;
1318 case SCLK_NANDC:
1319 ret = px30_nandc_set_clk(priv, rate);
1320 break;
1321 case SCLK_PWM0:
1322 case SCLK_PWM1:
1323 ret = px30_pwm_set_clk(priv, clk->id, rate);
1324 break;
1325 case SCLK_SARADC:
1326 ret = px30_saradc_set_clk(priv, rate);
1327 break;
1328 case SCLK_TSADC:
1329 ret = px30_tsadc_set_clk(priv, rate);
1330 break;
1331 case SCLK_SPI0:
1332 case SCLK_SPI1:
1333 ret = px30_spi_set_clk(priv, clk->id, rate);
1334 break;
1335 case ACLK_VOPB:
1336 case ACLK_VOPL:
1337 case DCLK_VOPB:
1338 case DCLK_VOPL:
1339 ret = px30_vop_set_clk(priv, clk->id, rate);
1340 break;
1341 case ACLK_BUS_PRE:
1342 case HCLK_BUS_PRE:
1343 case PCLK_BUS_PRE:
1344 ret = px30_bus_set_clk(priv, clk->id, rate);
1345 break;
1346 case ACLK_PERI_PRE:
1347 case HCLK_PERI_PRE:
1348 ret = px30_peri_set_clk(priv, clk->id, rate);
1349 break;
1350#ifndef CONFIG_SPL_BUILD
1351 case SCLK_CRYPTO:
1352 case SCLK_CRYPTO_APK:
1353 ret = px30_crypto_set_clk(priv, clk->id, rate);
1354 break;
1355 case SCLK_I2S1_OUT:
1356 ret = px30_i2s1_mclk_set_clk(priv, clk->id, rate);
1357 break;
1358 case SCLK_GMAC:
1359 case SCLK_GMAC_SRC:
1360 ret = px30_mac_set_clk(priv, rate);
1361 break;
1362 case SCLK_GMAC_RMII:
1363 ret = px30_mac_set_speed_clk(priv, rate);
1364 break;
1365#endif
1366 default:
1367 return -ENOENT;
1368 }
1369
1370 return ret;
1371}
1372
Simon Glass3580f6d2021-08-07 07:24:03 -06001373#if CONFIG_IS_ENABLED(OF_REAL)
Kever Yangba1033d2019-07-11 10:42:16 +02001374static int px30_gmac_set_parent(struct clk *clk, struct clk *parent)
1375{
1376 struct px30_clk_priv *priv = dev_get_priv(clk->dev);
1377 struct px30_cru *cru = priv->cru;
1378
1379 if (parent->id == SCLK_GMAC_SRC) {
1380 debug("%s: switching GAMC to SCLK_GMAC_SRC\n", __func__);
1381 rk_clrsetreg(&cru->clksel_con[23], RMII_EXTCLK_SEL_MASK,
1382 RMII_EXTCLK_SEL_INT << RMII_EXTCLK_SEL_SHIFT);
1383 } else {
1384 debug("%s: switching GMAC to external clock\n", __func__);
1385 rk_clrsetreg(&cru->clksel_con[23], RMII_EXTCLK_SEL_MASK,
1386 RMII_EXTCLK_SEL_EXT << RMII_EXTCLK_SEL_SHIFT);
1387 }
1388 return 0;
1389}
1390
1391static int px30_clk_set_parent(struct clk *clk, struct clk *parent)
1392{
1393 switch (clk->id) {
1394 case SCLK_GMAC:
1395 return px30_gmac_set_parent(clk, parent);
1396 default:
1397 return -ENOENT;
1398 }
1399}
1400#endif
1401
1402static int px30_clk_enable(struct clk *clk)
1403{
1404 switch (clk->id) {
1405 case HCLK_HOST:
Chris Morgana5798682022-03-25 12:09:22 -05001406 case HCLK_OTG:
1407 case HCLK_SFC:
Kever Yangba1033d2019-07-11 10:42:16 +02001408 case SCLK_GMAC:
1409 case SCLK_GMAC_RX_TX:
1410 case SCLK_MAC_REF:
1411 case SCLK_MAC_REFOUT:
Chris Morgana5798682022-03-25 12:09:22 -05001412 case SCLK_SFC:
Kever Yangba1033d2019-07-11 10:42:16 +02001413 case ACLK_GMAC:
1414 case PCLK_GMAC:
1415 case SCLK_GMAC_RMII:
1416 /* Required to successfully probe the Designware GMAC driver */
1417 return 0;
1418 }
1419
1420 debug("%s: unsupported clk %ld\n", __func__, clk->id);
1421 return -ENOENT;
1422}
1423
1424static struct clk_ops px30_clk_ops = {
1425 .get_rate = px30_clk_get_rate,
1426 .set_rate = px30_clk_set_rate,
Simon Glass3580f6d2021-08-07 07:24:03 -06001427#if CONFIG_IS_ENABLED(OF_REAL)
Kever Yangba1033d2019-07-11 10:42:16 +02001428 .set_parent = px30_clk_set_parent,
1429#endif
1430 .enable = px30_clk_enable,
1431};
1432
1433static void px30_clk_init(struct px30_clk_priv *priv)
1434{
1435 ulong npll_hz;
1436 int ret;
1437
1438 npll_hz = px30_clk_get_pll_rate(priv, NPLL);
1439 if (npll_hz != NPLL_HZ) {
1440 ret = px30_clk_set_pll_rate(priv, NPLL, NPLL_HZ);
1441 if (ret < 0)
1442 printf("%s failed to set npll rate\n", __func__);
1443 }
1444
1445 px30_bus_set_clk(priv, ACLK_BUS_PRE, ACLK_BUS_HZ);
1446 px30_bus_set_clk(priv, HCLK_BUS_PRE, HCLK_BUS_HZ);
1447 px30_bus_set_clk(priv, PCLK_BUS_PRE, PCLK_BUS_HZ);
1448 px30_peri_set_clk(priv, ACLK_PERI_PRE, ACLK_PERI_HZ);
1449 px30_peri_set_clk(priv, HCLK_PERI_PRE, HCLK_PERI_HZ);
1450}
1451
1452static int px30_clk_probe(struct udevice *dev)
1453{
1454 struct px30_clk_priv *priv = dev_get_priv(dev);
1455 struct clk clk_gpll;
1456 int ret;
1457
1458 if (px30_clk_get_pll_rate(priv, APLL) != APLL_HZ)
1459 px30_armclk_set_clk(priv, APLL_HZ);
1460
1461 /* get the GPLL rate from the pmucru */
1462 ret = clk_get_by_name(dev, "gpll", &clk_gpll);
1463 if (ret) {
1464 printf("%s: failed to get gpll clk from pmucru\n", __func__);
1465 return ret;
1466 }
1467
1468 priv->gpll_hz = clk_get_rate(&clk_gpll);
1469
1470 px30_clk_init(priv);
1471
1472 return 0;
1473}
1474
Simon Glassaad29ae2020-12-03 16:55:21 -07001475static int px30_clk_of_to_plat(struct udevice *dev)
Kever Yangba1033d2019-07-11 10:42:16 +02001476{
1477 struct px30_clk_priv *priv = dev_get_priv(dev);
1478
1479 priv->cru = dev_read_addr_ptr(dev);
1480
1481 return 0;
1482}
1483
1484static int px30_clk_bind(struct udevice *dev)
1485{
1486 int ret;
1487 struct udevice *sys_child;
1488 struct sysreset_reg *priv;
1489
1490 /* The reset driver does not have a device node, so bind it here */
1491 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1492 &sys_child);
1493 if (ret) {
1494 debug("Warning: No sysreset driver: ret=%d\n", ret);
1495 } else {
1496 priv = malloc(sizeof(struct sysreset_reg));
1497 priv->glb_srst_fst_value = offsetof(struct px30_cru,
1498 glb_srst_fst);
1499 priv->glb_srst_snd_value = offsetof(struct px30_cru,
1500 glb_srst_snd);
Simon Glass95588622020-12-22 19:30:28 -07001501 dev_set_priv(sys_child, priv);
Kever Yangba1033d2019-07-11 10:42:16 +02001502 }
1503
1504#if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
1505 ret = offsetof(struct px30_cru, softrst_con[0]);
1506 ret = rockchip_reset_bind(dev, ret, 12);
1507 if (ret)
1508 debug("Warning: software reset driver bind faile\n");
1509#endif
1510
1511 return 0;
1512}
1513
1514static const struct udevice_id px30_clk_ids[] = {
1515 { .compatible = "rockchip,px30-cru" },
1516 { }
1517};
1518
1519U_BOOT_DRIVER(rockchip_px30_cru) = {
1520 .name = "rockchip_px30_cru",
1521 .id = UCLASS_CLK,
1522 .of_match = px30_clk_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001523 .priv_auto = sizeof(struct px30_clk_priv),
Simon Glassaad29ae2020-12-03 16:55:21 -07001524 .of_to_plat = px30_clk_of_to_plat,
Kever Yangba1033d2019-07-11 10:42:16 +02001525 .ops = &px30_clk_ops,
1526 .bind = px30_clk_bind,
1527 .probe = px30_clk_probe,
1528};
1529
1530static ulong px30_pclk_pmu_get_pmuclk(struct px30_pmuclk_priv *priv)
1531{
1532 struct px30_pmucru *pmucru = priv->pmucru;
1533 u32 div, con;
1534
1535 con = readl(&pmucru->pmu_clksel_con[0]);
1536 div = (con & CLK_PMU_PCLK_DIV_MASK) >> CLK_PMU_PCLK_DIV_SHIFT;
1537
1538 return DIV_TO_RATE(priv->gpll_hz, div);
1539}
1540
1541static ulong px30_pclk_pmu_set_pmuclk(struct px30_pmuclk_priv *priv, ulong hz)
1542{
1543 struct px30_pmucru *pmucru = priv->pmucru;
1544 int src_clk_div;
1545
1546 src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
1547 assert(src_clk_div - 1 <= 31);
1548
1549 rk_clrsetreg(&pmucru->pmu_clksel_con[0],
1550 CLK_PMU_PCLK_DIV_MASK,
1551 (src_clk_div - 1) << CLK_PMU_PCLK_DIV_SHIFT);
1552
1553 return px30_pclk_pmu_get_pmuclk(priv);
1554}
1555
1556static ulong px30_pmuclk_get_gpll_rate(struct px30_pmuclk_priv *priv)
1557{
1558 struct px30_pmucru *pmucru = priv->pmucru;
1559
1560 return rkclk_pll_get_rate(&pmucru->pll, &pmucru->pmu_mode, GPLL);
1561}
1562
1563static ulong px30_pmuclk_set_gpll_rate(struct px30_pmuclk_priv *priv, ulong hz)
1564{
1565 struct px30_pmucru *pmucru = priv->pmucru;
1566 ulong pclk_pmu_rate;
1567 u32 div;
1568
1569 if (priv->gpll_hz == hz)
1570 return priv->gpll_hz;
1571
1572 div = DIV_ROUND_UP(hz, priv->gpll_hz);
1573
1574 /* save clock rate */
1575 pclk_pmu_rate = px30_pclk_pmu_get_pmuclk(priv);
1576
1577 /* avoid rate too large, reduce rate first */
1578 px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate / div);
1579
1580 /* change gpll rate */
1581 rkclk_set_pll(&pmucru->pll, &pmucru->pmu_mode, GPLL, hz);
1582 priv->gpll_hz = px30_pmuclk_get_gpll_rate(priv);
1583
1584 /* restore clock rate */
1585 px30_pclk_pmu_set_pmuclk(priv, pclk_pmu_rate);
1586
1587 return priv->gpll_hz;
1588}
1589
1590static ulong px30_pmuclk_get_rate(struct clk *clk)
1591{
1592 struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev);
1593 ulong rate = 0;
1594
1595 debug("%s %ld\n", __func__, clk->id);
1596 switch (clk->id) {
1597 case PLL_GPLL:
1598 rate = px30_pmuclk_get_gpll_rate(priv);
1599 break;
1600 case PCLK_PMU_PRE:
1601 rate = px30_pclk_pmu_get_pmuclk(priv);
1602 break;
1603 default:
1604 return -ENOENT;
1605 }
1606
1607 return rate;
1608}
1609
1610static ulong px30_pmuclk_set_rate(struct clk *clk, ulong rate)
1611{
1612 struct px30_pmuclk_priv *priv = dev_get_priv(clk->dev);
1613 ulong ret = 0;
1614
1615 debug("%s %ld %ld\n", __func__, clk->id, rate);
1616 switch (clk->id) {
1617 case PLL_GPLL:
1618 ret = px30_pmuclk_set_gpll_rate(priv, rate);
1619 break;
1620 case PCLK_PMU_PRE:
1621 ret = px30_pclk_pmu_set_pmuclk(priv, rate);
1622 break;
1623 default:
1624 return -ENOENT;
1625 }
1626
1627 return ret;
1628}
1629
1630static struct clk_ops px30_pmuclk_ops = {
1631 .get_rate = px30_pmuclk_get_rate,
1632 .set_rate = px30_pmuclk_set_rate,
1633};
1634
1635static void px30_pmuclk_init(struct px30_pmuclk_priv *priv)
1636{
1637 priv->gpll_hz = px30_pmuclk_get_gpll_rate(priv);
1638 px30_pmuclk_set_gpll_rate(priv, GPLL_HZ);
1639
1640 px30_pclk_pmu_set_pmuclk(priv, PCLK_PMU_HZ);
1641}
1642
1643static int px30_pmuclk_probe(struct udevice *dev)
1644{
1645 struct px30_pmuclk_priv *priv = dev_get_priv(dev);
1646
1647 px30_pmuclk_init(priv);
1648
1649 return 0;
1650}
1651
Simon Glassaad29ae2020-12-03 16:55:21 -07001652static int px30_pmuclk_of_to_plat(struct udevice *dev)
Kever Yangba1033d2019-07-11 10:42:16 +02001653{
1654 struct px30_pmuclk_priv *priv = dev_get_priv(dev);
1655
1656 priv->pmucru = dev_read_addr_ptr(dev);
1657
1658 return 0;
1659}
1660
1661static const struct udevice_id px30_pmuclk_ids[] = {
1662 { .compatible = "rockchip,px30-pmucru" },
1663 { }
1664};
1665
1666U_BOOT_DRIVER(rockchip_px30_pmucru) = {
1667 .name = "rockchip_px30_pmucru",
1668 .id = UCLASS_CLK,
1669 .of_match = px30_pmuclk_ids,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001670 .priv_auto = sizeof(struct px30_pmuclk_priv),
Simon Glassaad29ae2020-12-03 16:55:21 -07001671 .of_to_plat = px30_pmuclk_of_to_plat,
Kever Yangba1033d2019-07-11 10:42:16 +02001672 .ops = &px30_pmuclk_ops,
1673 .probe = px30_pmuclk_probe,
1674};