1 // SPDX-License-Identifier: GPL-2.0
3 * (C) Copyright 2015 Google, Inc
7 #include <clk-uclass.h>
12 #include <asm/arch-rockchip/clock.h>
13 #include <asm/arch-rockchip/cru_rk3036.h>
14 #include <asm/arch-rockchip/hardware.h>
16 #include <dt-bindings/clock/rk3036-cru.h>
17 #include <linux/log2.h>
20 VCO_MAX_HZ
= 2400U * 1000000,
21 VCO_MIN_HZ
= 600 * 1000000,
22 OUTPUT_MAX_HZ
= 2400U * 1000000,
23 OUTPUT_MIN_HZ
= 24 * 1000000,
26 #define RATE_TO_DIV(input_rate, output_rate) \
27 ((input_rate) / (output_rate) - 1);
29 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
31 #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
33 .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
34 .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
35 _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
36 OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
37 #hz "Hz cannot be hit with PLL "\
38 "divisors on line " __stringify(__LINE__));
41 static const struct pll_div apll_init_cfg
= PLL_DIVISORS(APLL_HZ
, 1, 3, 1);
42 static const struct pll_div gpll_init_cfg
= PLL_DIVISORS(GPLL_HZ
, 2, 2, 1);
44 static int rkclk_set_pll(struct rk3036_cru
*cru
, enum rk_clk_id clk_id
,
45 const struct pll_div
*div
)
47 int pll_id
= rk_pll_id(clk_id
);
48 struct rk3036_pll
*pll
= &cru
->pll
[pll_id
];
50 /* All PLLs have same VCO and output frequency range restrictions. */
51 uint vco_hz
= OSC_HZ
/ 1000 * div
->fbdiv
/ div
->refdiv
* 1000;
52 uint output_hz
= vco_hz
/ div
->postdiv1
/ div
->postdiv2
;
54 debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, postdiv2=%d,\
55 vco=%u Hz, output=%u Hz\n",
56 pll
, div
->fbdiv
, div
->refdiv
, div
->postdiv1
,
57 div
->postdiv2
, vco_hz
, output_hz
);
58 assert(vco_hz
>= VCO_MIN_HZ
&& vco_hz
<= VCO_MAX_HZ
&&
59 output_hz
>= OUTPUT_MIN_HZ
&& output_hz
<= OUTPUT_MAX_HZ
);
61 /* use integer mode */
62 rk_setreg(&pll
->con1
, 1 << PLL_DSMPD_SHIFT
);
64 rk_clrsetreg(&pll
->con0
,
65 PLL_POSTDIV1_MASK
| PLL_FBDIV_MASK
,
66 (div
->postdiv1
<< PLL_POSTDIV1_SHIFT
) | div
->fbdiv
);
67 rk_clrsetreg(&pll
->con1
, PLL_POSTDIV2_MASK
| PLL_REFDIV_MASK
,
68 (div
->postdiv2
<< PLL_POSTDIV2_SHIFT
|
69 div
->refdiv
<< PLL_REFDIV_SHIFT
));
71 /* waiting for pll lock */
72 while (readl(&pll
->con1
) & (1 << PLL_LOCK_STATUS_SHIFT
))
78 static void rkclk_init(struct rk3036_cru
*cru
)
84 /* pll enter slow-mode */
85 rk_clrsetreg(&cru
->cru_mode_con
,
86 GPLL_MODE_MASK
| APLL_MODE_MASK
,
87 GPLL_MODE_SLOW
<< GPLL_MODE_SHIFT
|
88 APLL_MODE_SLOW
<< APLL_MODE_SHIFT
);
91 rkclk_set_pll(cru
, CLK_ARM
, &apll_init_cfg
);
92 rkclk_set_pll(cru
, CLK_GENERAL
, &gpll_init_cfg
);
95 * select apll as cpu/core clock pll source and
96 * set up dependent divisors for PERI and ACLK clocks.
97 * core hz : apll = 1:1
99 aclk_div
= APLL_HZ
/ CORE_ACLK_HZ
- 1;
100 assert((aclk_div
+ 1) * CORE_ACLK_HZ
== APLL_HZ
&& aclk_div
< 0x7);
102 pclk_div
= APLL_HZ
/ CORE_PERI_HZ
- 1;
103 assert((pclk_div
+ 1) * CORE_PERI_HZ
== APLL_HZ
&& pclk_div
< 0xf);
105 rk_clrsetreg(&cru
->cru_clksel_con
[0],
106 CORE_CLK_PLL_SEL_MASK
| CORE_DIV_CON_MASK
,
107 CORE_CLK_PLL_SEL_APLL
<< CORE_CLK_PLL_SEL_SHIFT
|
108 0 << CORE_DIV_CON_SHIFT
);
110 rk_clrsetreg(&cru
->cru_clksel_con
[1],
111 CORE_ACLK_DIV_MASK
| CORE_PERI_DIV_MASK
,
112 aclk_div
<< CORE_ACLK_DIV_SHIFT
|
113 pclk_div
<< CORE_PERI_DIV_SHIFT
);
116 * select apll as pd_bus bus clock source and
117 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
119 aclk_div
= GPLL_HZ
/ BUS_ACLK_HZ
- 1;
120 assert((aclk_div
+ 1) * BUS_ACLK_HZ
== GPLL_HZ
&& aclk_div
<= 0x1f);
122 pclk_div
= GPLL_HZ
/ BUS_PCLK_HZ
- 1;
123 assert((pclk_div
+ 1) * BUS_PCLK_HZ
== GPLL_HZ
&& pclk_div
<= 0x7);
125 hclk_div
= GPLL_HZ
/ BUS_HCLK_HZ
- 1;
126 assert((hclk_div
+ 1) * BUS_HCLK_HZ
== GPLL_HZ
&& hclk_div
<= 0x3);
128 rk_clrsetreg(&cru
->cru_clksel_con
[0],
129 BUS_ACLK_PLL_SEL_MASK
| BUS_ACLK_DIV_MASK
,
130 BUS_ACLK_PLL_SEL_GPLL
<< BUS_ACLK_PLL_SEL_SHIFT
|
131 aclk_div
<< BUS_ACLK_DIV_SHIFT
);
133 rk_clrsetreg(&cru
->cru_clksel_con
[1],
134 BUS_PCLK_DIV_MASK
| BUS_HCLK_DIV_MASK
,
135 pclk_div
<< BUS_PCLK_DIV_SHIFT
|
136 hclk_div
<< BUS_HCLK_DIV_SHIFT
);
139 * select gpll as pd_peri bus clock source and
140 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
142 aclk_div
= GPLL_HZ
/ PERI_ACLK_HZ
- 1;
143 assert((aclk_div
+ 1) * PERI_ACLK_HZ
== GPLL_HZ
&& aclk_div
< 0x1f);
145 hclk_div
= ilog2(PERI_ACLK_HZ
/ PERI_HCLK_HZ
);
146 assert((1 << hclk_div
) * PERI_HCLK_HZ
==
147 PERI_ACLK_HZ
&& (hclk_div
< 0x4));
149 pclk_div
= ilog2(PERI_ACLK_HZ
/ PERI_PCLK_HZ
);
150 assert((1 << pclk_div
) * PERI_PCLK_HZ
==
151 PERI_ACLK_HZ
&& pclk_div
< 0x8);
153 rk_clrsetreg(&cru
->cru_clksel_con
[10],
154 PERI_PLL_SEL_MASK
| PERI_PCLK_DIV_MASK
|
155 PERI_HCLK_DIV_MASK
| PERI_ACLK_DIV_MASK
,
156 PERI_PLL_GPLL
<< PERI_PLL_SEL_SHIFT
|
157 pclk_div
<< PERI_PCLK_DIV_SHIFT
|
158 hclk_div
<< PERI_HCLK_DIV_SHIFT
|
159 aclk_div
<< PERI_ACLK_DIV_SHIFT
);
161 /* PLL enter normal-mode */
162 rk_clrsetreg(&cru
->cru_mode_con
,
163 GPLL_MODE_MASK
| APLL_MODE_MASK
,
164 GPLL_MODE_NORM
<< GPLL_MODE_SHIFT
|
165 APLL_MODE_NORM
<< APLL_MODE_SHIFT
);
168 /* Get pll rate by id */
169 static uint32_t rkclk_pll_get_rate(struct rk3036_cru
*cru
,
170 enum rk_clk_id clk_id
)
172 uint32_t refdiv
, fbdiv
, postdiv1
, postdiv2
;
174 int pll_id
= rk_pll_id(clk_id
);
175 struct rk3036_pll
*pll
= &cru
->pll
[pll_id
];
176 static u8 clk_shift
[CLK_COUNT
] = {
177 0xff, APLL_MODE_SHIFT
, DPLL_MODE_SHIFT
, 0xff,
178 GPLL_MODE_SHIFT
, 0xff
180 static u32 clk_mask
[CLK_COUNT
] = {
181 0xffffffff, APLL_MODE_MASK
, DPLL_MODE_MASK
, 0xffffffff,
182 GPLL_MODE_MASK
, 0xffffffff
187 con
= readl(&cru
->cru_mode_con
);
188 shift
= clk_shift
[clk_id
];
189 mask
= clk_mask
[clk_id
];
191 switch ((con
& mask
) >> shift
) {
197 con
= readl(&pll
->con0
);
198 postdiv1
= (con
& PLL_POSTDIV1_MASK
) >> PLL_POSTDIV1_SHIFT
;
199 fbdiv
= (con
& PLL_FBDIV_MASK
) >> PLL_FBDIV_SHIFT
;
200 con
= readl(&pll
->con1
);
201 postdiv2
= (con
& PLL_POSTDIV2_MASK
) >> PLL_POSTDIV2_SHIFT
;
202 refdiv
= (con
& PLL_REFDIV_MASK
) >> PLL_REFDIV_SHIFT
;
203 return (24 * fbdiv
/ (refdiv
* postdiv1
* postdiv2
)) * 1000000;
210 static ulong
rockchip_mmc_get_clk(struct rk3036_cru
*cru
, uint clk_general_rate
,
220 con
= readl(&cru
->cru_clksel_con
[12]);
221 mux
= (con
& EMMC_PLL_MASK
) >> EMMC_PLL_SHIFT
;
222 div
= (con
& EMMC_DIV_MASK
) >> EMMC_DIV_SHIFT
;
226 con
= readl(&cru
->cru_clksel_con
[12]);
227 mux
= (con
& MMC0_PLL_MASK
) >> MMC0_PLL_SHIFT
;
228 div
= (con
& MMC0_DIV_MASK
) >> MMC0_DIV_SHIFT
;
234 src_rate
= mux
== EMMC_SEL_24M
? OSC_HZ
: clk_general_rate
;
235 return DIV_TO_RATE(src_rate
, div
) / 2;
238 static ulong
rockchip_mmc_set_clk(struct rk3036_cru
*cru
, uint clk_general_rate
,
239 int periph
, uint freq
)
244 debug("%s: clk_general_rate=%u\n", __func__
, clk_general_rate
);
246 /* mmc clock auto divide 2 in internal */
247 src_clk_div
= DIV_ROUND_UP(clk_general_rate
/ 2, freq
);
249 if (src_clk_div
> 128) {
250 src_clk_div
= DIV_ROUND_UP(OSC_HZ
/ 2, freq
);
251 assert(src_clk_div
- 1 < 128);
260 rk_clrsetreg(&cru
->cru_clksel_con
[12],
261 EMMC_PLL_MASK
| EMMC_DIV_MASK
,
262 mux
<< EMMC_PLL_SHIFT
|
263 (src_clk_div
- 1) << EMMC_DIV_SHIFT
);
267 rk_clrsetreg(&cru
->cru_clksel_con
[11],
268 MMC0_PLL_MASK
| MMC0_DIV_MASK
,
269 mux
<< MMC0_PLL_SHIFT
|
270 (src_clk_div
- 1) << MMC0_DIV_SHIFT
);
276 return rockchip_mmc_get_clk(cru
, clk_general_rate
, periph
);
279 static ulong
rk3036_clk_get_rate(struct clk
*clk
)
281 struct rk3036_clk_priv
*priv
= dev_get_priv(clk
->dev
);
285 return rkclk_pll_get_rate(priv
->cru
, clk
->id
);
291 static ulong
rk3036_clk_set_rate(struct clk
*clk
, ulong rate
)
293 struct rk3036_clk_priv
*priv
= dev_get_priv(clk
->dev
);
294 ulong new_rate
, gclk_rate
;
296 gclk_rate
= rkclk_pll_get_rate(priv
->cru
, CLK_GENERAL
);
302 new_rate
= rockchip_mmc_set_clk(priv
->cru
, gclk_rate
,
312 static struct clk_ops rk3036_clk_ops
= {
313 .get_rate
= rk3036_clk_get_rate
,
314 .set_rate
= rk3036_clk_set_rate
,
317 static int rk3036_clk_ofdata_to_platdata(struct udevice
*dev
)
319 struct rk3036_clk_priv
*priv
= dev_get_priv(dev
);
321 priv
->cru
= dev_read_addr_ptr(dev
);
326 static int rk3036_clk_probe(struct udevice
*dev
)
328 struct rk3036_clk_priv
*priv
= dev_get_priv(dev
);
330 rkclk_init(priv
->cru
);
335 static int rk3036_clk_bind(struct udevice
*dev
)
338 struct udevice
*sys_child
;
339 struct sysreset_reg
*priv
;
341 /* The reset driver does not have a device node, so bind it here */
342 ret
= device_bind_driver(dev
, "rockchip_sysreset", "sysreset",
345 debug("Warning: No sysreset driver: ret=%d\n", ret
);
347 priv
= malloc(sizeof(struct sysreset_reg
));
348 priv
->glb_srst_fst_value
= offsetof(struct rk3036_cru
,
349 cru_glb_srst_fst_value
);
350 priv
->glb_srst_snd_value
= offsetof(struct rk3036_cru
,
351 cru_glb_srst_snd_value
);
352 sys_child
->priv
= priv
;
355 #if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
356 ret
= offsetof(struct rk3036_cru
, cru_softrst_con
[0]);
357 ret
= rockchip_reset_bind(dev
, ret
, 9);
359 debug("Warning: software reset driver bind faile\n");
365 static const struct udevice_id rk3036_clk_ids
[] = {
366 { .compatible
= "rockchip,rk3036-cru" },
370 U_BOOT_DRIVER(rockchip_rk3036_cru
) = {
371 .name
= "clk_rk3036",
373 .of_match
= rk3036_clk_ids
,
374 .priv_auto_alloc_size
= sizeof(struct rk3036_clk_priv
),
375 .ofdata_to_platdata
= rk3036_clk_ofdata_to_platdata
,
376 .ops
= &rk3036_clk_ops
,
377 .bind
= rk3036_clk_bind
,
378 .probe
= rk3036_clk_probe
,