2 * (C) Copyright 2017 Rockchip Electronics Co., Ltd
4 * SPDX-License-Identifier: GPL-2.0
8 #include <clk-uclass.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/cru_rk3128.h>
15 #include <asm/arch/hardware.h>
18 #include <dt-bindings/clock/rk3128-cru.h>
19 #include <linux/log2.h>
21 DECLARE_GLOBAL_DATA_PTR
;
24 VCO_MAX_HZ
= 2400U * 1000000,
25 VCO_MIN_HZ
= 600 * 1000000,
26 OUTPUT_MAX_HZ
= 2400U * 1000000,
27 OUTPUT_MIN_HZ
= 24 * 1000000,
30 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
32 #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
34 .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
35 .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};
38 static const struct pll_div apll_init_cfg
= PLL_DIVISORS(APLL_HZ
, 1, 3, 1);
39 static const struct pll_div gpll_init_cfg
= PLL_DIVISORS(GPLL_HZ
, 2, 2, 1);
41 static int rkclk_set_pll(struct rk3128_cru
*cru
, enum rk_clk_id clk_id
,
42 const struct pll_div
*div
)
44 int pll_id
= rk_pll_id(clk_id
);
45 struct rk3128_pll
*pll
= &cru
->pll
[pll_id
];
47 /* All PLLs have same VCO and output frequency range restrictions. */
48 uint vco_hz
= OSC_HZ
/ 1000 * div
->fbdiv
/ div
->refdiv
* 1000;
49 uint output_hz
= vco_hz
/ div
->postdiv1
/ div
->postdiv2
;
51 debug("PLL at %p:fd=%d,rd=%d,pd1=%d,pd2=%d,vco=%uHz,output=%uHz\n",
52 pll
, div
->fbdiv
, div
->refdiv
, div
->postdiv1
,
53 div
->postdiv2
, vco_hz
, output_hz
);
54 assert(vco_hz
>= VCO_MIN_HZ
&& vco_hz
<= VCO_MAX_HZ
&&
55 output_hz
>= OUTPUT_MIN_HZ
&& output_hz
<= OUTPUT_MAX_HZ
);
57 /* use integer mode */
58 rk_setreg(&pll
->con1
, 1 << PLL_DSMPD_SHIFT
);
60 rk_setreg(&pll
->con1
, 1 << PLL_PD_SHIFT
);
62 rk_clrsetreg(&pll
->con0
,
63 PLL_POSTDIV1_MASK
| PLL_FBDIV_MASK
,
64 (div
->postdiv1
<< PLL_POSTDIV1_SHIFT
) | div
->fbdiv
);
65 rk_clrsetreg(&pll
->con1
, PLL_POSTDIV2_MASK
| PLL_REFDIV_MASK
,
66 (div
->postdiv2
<< PLL_POSTDIV2_SHIFT
|
67 div
->refdiv
<< PLL_REFDIV_SHIFT
));
70 rk_clrreg(&pll
->con1
, 1 << PLL_PD_SHIFT
);
72 /* waiting for pll lock */
73 while (readl(&pll
->con1
) & (1 << PLL_LOCK_STATUS_SHIFT
))
79 static int pll_para_config(u32 freq_hz
, struct pll_div
*div
)
81 u32 ref_khz
= OSC_HZ
/ 1000, refdiv
, fbdiv
= 0;
82 u32 postdiv1
, postdiv2
= 1;
84 u32 diff_khz
, best_diff_khz
;
85 const u32 max_refdiv
= 63, max_fbdiv
= 3200, min_fbdiv
= 16;
86 const u32 max_postdiv1
= 7, max_postdiv2
= 7;
88 u32 freq_khz
= freq_hz
/ 1000;
91 printf("%s: the frequency can't be 0 Hz\n", __func__
);
95 postdiv1
= DIV_ROUND_UP(VCO_MIN_HZ
/ 1000, freq_khz
);
96 if (postdiv1
> max_postdiv1
) {
97 postdiv2
= DIV_ROUND_UP(postdiv1
, max_postdiv1
);
98 postdiv1
= DIV_ROUND_UP(postdiv1
, postdiv2
);
101 vco_khz
= freq_khz
* postdiv1
* postdiv2
;
103 if (vco_khz
< (VCO_MIN_HZ
/ 1000) || vco_khz
> (VCO_MAX_HZ
/ 1000) ||
104 postdiv2
> max_postdiv2
) {
105 printf("%s: Cannot find out a supported VCO for Freq (%uHz)\n",
110 div
->postdiv1
= postdiv1
;
111 div
->postdiv2
= postdiv2
;
113 best_diff_khz
= vco_khz
;
114 for (refdiv
= 1; refdiv
< max_refdiv
&& best_diff_khz
; refdiv
++) {
115 fref_khz
= ref_khz
/ refdiv
;
117 fbdiv
= vco_khz
/ fref_khz
;
118 if ((fbdiv
>= max_fbdiv
) || (fbdiv
<= min_fbdiv
))
120 diff_khz
= vco_khz
- fbdiv
* fref_khz
;
121 if (fbdiv
+ 1 < max_fbdiv
&& diff_khz
> fref_khz
/ 2) {
123 diff_khz
= fref_khz
- diff_khz
;
126 if (diff_khz
>= best_diff_khz
)
129 best_diff_khz
= diff_khz
;
130 div
->refdiv
= refdiv
;
134 if (best_diff_khz
> 4 * (1000)) {
135 printf("%s: Failed to match output frequency %u bestis %u Hz\n",
137 best_diff_khz
* 1000);
143 static void rkclk_init(struct rk3128_cru
*cru
)
149 /* pll enter slow-mode */
150 rk_clrsetreg(&cru
->cru_mode_con
,
151 GPLL_MODE_MASK
| APLL_MODE_MASK
,
152 GPLL_MODE_SLOW
<< GPLL_MODE_SHIFT
|
153 APLL_MODE_SLOW
<< APLL_MODE_SHIFT
);
156 rkclk_set_pll(cru
, CLK_ARM
, &apll_init_cfg
);
157 rkclk_set_pll(cru
, CLK_GENERAL
, &gpll_init_cfg
);
160 * select apll as cpu/core clock pll source and
161 * set up dependent divisors for PERI and ACLK clocks.
162 * core hz : apll = 1:1
164 aclk_div
= APLL_HZ
/ CORE_ACLK_HZ
- 1;
165 assert((aclk_div
+ 1) * CORE_ACLK_HZ
== APLL_HZ
&& aclk_div
< 0x7);
167 pclk_div
= APLL_HZ
/ CORE_PERI_HZ
- 1;
168 assert((pclk_div
+ 1) * CORE_PERI_HZ
== APLL_HZ
&& pclk_div
< 0xf);
170 rk_clrsetreg(&cru
->cru_clksel_con
[0],
171 CORE_CLK_PLL_SEL_MASK
| CORE_DIV_CON_MASK
,
172 CORE_CLK_PLL_SEL_APLL
<< CORE_CLK_PLL_SEL_SHIFT
|
173 0 << CORE_DIV_CON_SHIFT
);
175 rk_clrsetreg(&cru
->cru_clksel_con
[1],
176 CORE_ACLK_DIV_MASK
| CORE_PERI_DIV_MASK
,
177 aclk_div
<< CORE_ACLK_DIV_SHIFT
|
178 pclk_div
<< CORE_PERI_DIV_SHIFT
);
181 * select gpll as pd_bus bus clock source and
182 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
184 aclk_div
= GPLL_HZ
/ BUS_ACLK_HZ
- 1;
185 assert((aclk_div
+ 1) * BUS_ACLK_HZ
== GPLL_HZ
&& aclk_div
<= 0x1f);
187 pclk_div
= BUS_ACLK_HZ
/ BUS_PCLK_HZ
- 1;
188 assert((pclk_div
+ 1) * BUS_PCLK_HZ
== BUS_ACLK_HZ
&& pclk_div
<= 0x7);
190 hclk_div
= BUS_ACLK_HZ
/ BUS_HCLK_HZ
- 1;
191 assert((hclk_div
+ 1) * BUS_HCLK_HZ
== BUS_ACLK_HZ
&& hclk_div
<= 0x3);
193 rk_clrsetreg(&cru
->cru_clksel_con
[0],
194 BUS_ACLK_PLL_SEL_MASK
| BUS_ACLK_DIV_MASK
,
195 BUS_ACLK_PLL_SEL_GPLL
<< BUS_ACLK_PLL_SEL_SHIFT
|
196 aclk_div
<< BUS_ACLK_DIV_SHIFT
);
198 rk_clrsetreg(&cru
->cru_clksel_con
[1],
199 BUS_PCLK_DIV_MASK
| BUS_HCLK_DIV_MASK
,
200 pclk_div
<< BUS_PCLK_DIV_SHIFT
|
201 hclk_div
<< BUS_HCLK_DIV_SHIFT
);
204 * select gpll as pd_peri bus clock source and
205 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
207 aclk_div
= GPLL_HZ
/ PERI_ACLK_HZ
- 1;
208 assert((aclk_div
+ 1) * PERI_ACLK_HZ
== GPLL_HZ
&& aclk_div
< 0x1f);
210 hclk_div
= ilog2(PERI_ACLK_HZ
/ PERI_HCLK_HZ
);
211 assert((1 << hclk_div
) * PERI_HCLK_HZ
==
212 PERI_ACLK_HZ
&& (hclk_div
< 0x4));
214 pclk_div
= ilog2(PERI_ACLK_HZ
/ PERI_PCLK_HZ
);
215 assert((1 << pclk_div
) * PERI_PCLK_HZ
==
216 PERI_ACLK_HZ
&& pclk_div
< 0x8);
218 rk_clrsetreg(&cru
->cru_clksel_con
[10],
219 PERI_PLL_SEL_MASK
| PERI_PCLK_DIV_MASK
|
220 PERI_HCLK_DIV_MASK
| PERI_ACLK_DIV_MASK
,
221 PERI_PLL_GPLL
<< PERI_PLL_SEL_SHIFT
|
222 pclk_div
<< PERI_PCLK_DIV_SHIFT
|
223 hclk_div
<< PERI_HCLK_DIV_SHIFT
|
224 aclk_div
<< PERI_ACLK_DIV_SHIFT
);
226 /* PLL enter normal-mode */
227 rk_clrsetreg(&cru
->cru_mode_con
,
228 GPLL_MODE_MASK
| APLL_MODE_MASK
| CPLL_MODE_MASK
,
229 GPLL_MODE_NORM
<< GPLL_MODE_SHIFT
|
230 APLL_MODE_NORM
<< APLL_MODE_SHIFT
|
231 CPLL_MODE_NORM
<< CPLL_MODE_SHIFT
);
233 /*fix NAND controller working clock max to 150Mhz */
234 rk_clrsetreg(&cru
->cru_clksel_con
[2],
235 NANDC_PLL_SEL_MASK
| NANDC_CLK_DIV_MASK
,
236 NANDC_PLL_SEL_GPLL
<< NANDC_PLL_SEL_SHIFT
|
237 3 << NANDC_CLK_DIV_SHIFT
);
240 /* Get pll rate by id */
241 static u32
rkclk_pll_get_rate(struct rk3128_cru
*cru
,
242 enum rk_clk_id clk_id
)
244 u32 refdiv
, fbdiv
, postdiv1
, postdiv2
;
246 int pll_id
= rk_pll_id(clk_id
);
247 struct rk3128_pll
*pll
= &cru
->pll
[pll_id
];
248 static u8 clk_shift
[CLK_COUNT
] = {
249 0xff, APLL_MODE_SHIFT
, DPLL_MODE_SHIFT
, CPLL_MODE_SHIFT
,
250 GPLL_MODE_SHIFT
, 0xff
252 static u32 clk_mask
[CLK_COUNT
] = {
253 0xff, APLL_MODE_MASK
, DPLL_MODE_MASK
, CPLL_MODE_MASK
,
259 con
= readl(&cru
->cru_mode_con
);
260 shift
= clk_shift
[clk_id
];
261 mask
= clk_mask
[clk_id
];
263 switch ((con
& mask
) >> shift
) {
268 con
= readl(&pll
->con0
);
269 postdiv1
= (con
& PLL_POSTDIV1_MASK
) >> PLL_POSTDIV1_SHIFT
;
270 fbdiv
= (con
& PLL_FBDIV_MASK
) >> PLL_FBDIV_SHIFT
;
271 con
= readl(&pll
->con1
);
272 postdiv2
= (con
& PLL_POSTDIV2_MASK
) >> PLL_POSTDIV2_SHIFT
;
273 refdiv
= (con
& PLL_REFDIV_MASK
) >> PLL_REFDIV_SHIFT
;
274 return (24 * fbdiv
/ (refdiv
* postdiv1
* postdiv2
)) * 1000000;
281 static ulong
rockchip_mmc_get_clk(struct rk3128_cru
*cru
, uint clk_general_rate
,
291 case SCLK_EMMC_SAMPLE
:
292 con
= readl(&cru
->cru_clksel_con
[12]);
293 mux
= (con
& EMMC_PLL_MASK
) >> EMMC_PLL_SHIFT
;
294 div
= (con
& EMMC_DIV_MASK
) >> EMMC_DIV_SHIFT
;
298 con
= readl(&cru
->cru_clksel_con
[11]);
299 mux
= (con
& MMC0_PLL_MASK
) >> MMC0_PLL_SHIFT
;
300 div
= (con
& MMC0_DIV_MASK
) >> MMC0_DIV_SHIFT
;
306 src_rate
= mux
== EMMC_SEL_24M
? OSC_HZ
: clk_general_rate
;
307 return DIV_TO_RATE(src_rate
, div
);
310 static ulong
rockchip_mmc_set_clk(struct rk3128_cru
*cru
, uint clk_general_rate
,
311 int periph
, uint freq
)
316 debug("%s: clk_general_rate=%u\n", __func__
, clk_general_rate
);
318 /* mmc clock defaulg div 2 internal, need provide double in cru */
319 src_clk_div
= DIV_ROUND_UP(clk_general_rate
/ 2, freq
);
321 if (src_clk_div
> 128) {
322 src_clk_div
= DIV_ROUND_UP(OSC_HZ
/ 2, freq
);
330 rk_clrsetreg(&cru
->cru_clksel_con
[12],
331 EMMC_PLL_MASK
| EMMC_DIV_MASK
,
332 mux
<< EMMC_PLL_SHIFT
|
333 (src_clk_div
- 1) << EMMC_DIV_SHIFT
);
337 rk_clrsetreg(&cru
->cru_clksel_con
[11],
338 MMC0_PLL_MASK
| MMC0_DIV_MASK
,
339 mux
<< MMC0_PLL_SHIFT
|
340 (src_clk_div
- 1) << MMC0_DIV_SHIFT
);
346 return rockchip_mmc_get_clk(cru
, clk_general_rate
, periph
);
349 static ulong
rk3128_peri_get_pclk(struct rk3128_cru
*cru
, ulong clk_id
)
359 con
= readl(&cru
->cru_clksel_con
[10]);
360 div
= con
>> 12 & 0x3;
363 printf("do not support this peripheral bus\n");
367 return DIV_TO_RATE(PERI_ACLK_HZ
, div
);
370 static ulong
rk3128_peri_set_pclk(struct rk3128_cru
*cru
, ulong clk_id
, uint hz
)
374 src_clk_div
= PERI_ACLK_HZ
/ hz
;
375 assert(src_clk_div
- 1 < 4);
383 rk_setreg(&cru
->cru_clksel_con
[10],
384 ((src_clk_div
- 1) << 12));
387 printf("do not support this peripheral bus\n");
391 return DIV_TO_RATE(PERI_ACLK_HZ
, src_clk_div
);
394 static ulong
rk3128_saradc_get_clk(struct rk3128_cru
*cru
)
398 val
= readl(&cru
->cru_clksel_con
[24]);
399 div
= bitfield_extract(val
, SARADC_DIV_CON_SHIFT
,
400 SARADC_DIV_CON_WIDTH
);
402 return DIV_TO_RATE(OSC_HZ
, div
);
405 static ulong
rk3128_saradc_set_clk(struct rk3128_cru
*cru
, uint hz
)
409 src_clk_div
= DIV_ROUND_UP(OSC_HZ
, hz
) - 1;
410 assert(src_clk_div
< 128);
412 rk_clrsetreg(&cru
->cru_clksel_con
[24],
414 src_clk_div
<< SARADC_DIV_CON_SHIFT
);
416 return rk3128_saradc_get_clk(cru
);
419 static ulong
rk3128_vop_set_clk(struct rk3128_cru
*cru
, ulong clk_id
, uint hz
)
422 struct pll_div cpll_config
= {0};
424 src_clk_div
= GPLL_HZ
/ hz
;
425 assert(src_clk_div
- 1 < 31);
429 rk_clrsetreg(&cru
->cru_clksel_con
[31],
430 VIO0_PLL_MASK
| VIO0_DIV_MASK
,
431 VIO0_SEL_GPLL
<< VIO0_PLL_SHIFT
|
432 (src_clk_div
- 1) << VIO0_DIV_SHIFT
);
435 rk_clrsetreg(&cru
->cru_clksel_con
[31],
436 VIO1_PLL_MASK
| VIO1_DIV_MASK
,
437 VIO1_SEL_GPLL
<< VIO1_PLL_SHIFT
|
438 (src_clk_div
- 1) << VIO1_DIV_SHIFT
);
441 if (pll_para_config(hz
, &cpll_config
))
443 rkclk_set_pll(cru
, CLK_CODEC
, &cpll_config
);
445 rk_clrsetreg(&cru
->cru_clksel_con
[27],
446 DCLK_VOP_SEL_MASK
| DCLK_VOP_DIV_CON_MASK
,
447 DCLK_VOP_PLL_SEL_CPLL
<< DCLK_VOP_SEL_SHIFT
|
448 (1 - 1) << DCLK_VOP_DIV_CON_SHIFT
);
451 printf("do not support this vop freq\n");
458 static ulong
rk3128_vop_get_rate(struct rk3128_cru
*cru
, ulong clk_id
)
460 u32 div
, con
, parent
;
464 con
= readl(&cru
->cru_clksel_con
[31]);
469 con
= readl(&cru
->cru_clksel_con
[31]);
470 div
= (con
>> 8) & 0x1f;
474 con
= readl(&cru
->cru_clksel_con
[27]);
475 div
= (con
>> 8) & 0xfff;
476 parent
= rkclk_pll_get_rate(cru
, CLK_CODEC
);
481 return DIV_TO_RATE(parent
, div
);
484 static ulong
rk3128_clk_get_rate(struct clk
*clk
)
486 struct rk3128_clk_priv
*priv
= dev_get_priv(clk
->dev
);
490 return rkclk_pll_get_rate(priv
->cru
, clk
->id
);
496 return rk3128_peri_get_pclk(priv
->cru
, clk
->id
);
498 return rk3128_saradc_get_clk(priv
->cru
);
502 return rk3128_vop_get_rate(priv
->cru
, clk
->id
);
508 static ulong
rk3128_clk_set_rate(struct clk
*clk
, ulong rate
)
510 struct rk3128_clk_priv
*priv
= dev_get_priv(clk
->dev
);
511 ulong new_rate
, gclk_rate
;
513 gclk_rate
= rkclk_pll_get_rate(priv
->cru
, CLK_GENERAL
);
520 new_rate
= rk3128_vop_set_clk(priv
->cru
,
524 new_rate
= rockchip_mmc_set_clk(priv
->cru
, gclk_rate
,
532 new_rate
= rk3128_peri_set_pclk(priv
->cru
, clk
->id
, rate
);
535 new_rate
= rk3128_saradc_set_clk(priv
->cru
, rate
);
544 static struct clk_ops rk3128_clk_ops
= {
545 .get_rate
= rk3128_clk_get_rate
,
546 .set_rate
= rk3128_clk_set_rate
,
549 static int rk3128_clk_probe(struct udevice
*dev
)
551 struct rk3128_clk_priv
*priv
= dev_get_priv(dev
);
553 priv
->cru
= (struct rk3128_cru
*)dev_read_addr(dev
);
554 rkclk_init(priv
->cru
);
559 static int rk3128_clk_bind(struct udevice
*dev
)
562 struct udevice
*sys_child
;
563 struct sysreset_reg
*priv
;
565 /* The reset driver does not have a device node, so bind it here */
566 ret
= device_bind_driver(dev
, "rockchip_sysreset", "sysreset",
569 debug("Warning: No sysreset driver: ret=%d\n", ret
);
571 priv
= malloc(sizeof(struct sysreset_reg
));
572 priv
->glb_srst_fst_value
= offsetof(struct rk3128_cru
,
573 cru_glb_srst_fst_value
);
574 priv
->glb_srst_snd_value
= offsetof(struct rk3128_cru
,
575 cru_glb_srst_snd_value
);
576 sys_child
->priv
= priv
;
582 static const struct udevice_id rk3128_clk_ids
[] = {
583 { .compatible
= "rockchip,rk3128-cru" },
584 { .compatible
= "rockchip,rk3126-cru" },
588 U_BOOT_DRIVER(rockchip_rk3128_cru
) = {
589 .name
= "clk_rk3128",
591 .of_match
= rk3128_clk_ids
,
592 .priv_auto_alloc_size
= sizeof(struct rk3128_clk_priv
),
593 .ops
= &rk3128_clk_ops
,
594 .bind
= rk3128_clk_bind
,
595 .probe
= rk3128_clk_probe
,