1 // SPDX-License-Identifier: GPL-2.0
3 * (C) Copyright 2017 Rockchip Electronics Co., Ltd
7 #include <clk-uclass.h>
13 #include <asm/arch-rockchip/clock.h>
14 #include <asm/arch-rockchip/cru_rk3328.h>
15 #include <asm/arch-rockchip/hardware.h>
16 #include <asm/arch-rockchip/grf_rk3328.h>
17 #include <dm/device-internal.h>
19 #include <dt-bindings/clock/rk3328-cru.h>
20 #include <linux/bitops.h>
21 #include <linux/delay.h>
31 #define RATE_TO_DIV(input_rate, output_rate) \
32 ((input_rate) / (output_rate) - 1);
33 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
35 #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
37 .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
38 .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};
40 static const struct pll_div gpll_init_cfg
= PLL_DIVISORS(GPLL_HZ
, 1, 4, 1);
41 static const struct pll_div cpll_init_cfg
= PLL_DIVISORS(CPLL_HZ
, 2, 2, 1);
43 static const struct pll_div apll_816_cfg
= PLL_DIVISORS(816 * MHz
, 1, 2, 1);
44 static const struct pll_div apll_600_cfg
= PLL_DIVISORS(600 * MHz
, 1, 3, 1);
46 static const struct pll_div
*apll_cfgs
[] = {
47 [APLL_816_MHZ
] = &apll_816_cfg
,
48 [APLL_600_MHZ
] = &apll_600_cfg
,
53 PLL_POSTDIV1_SHIFT
= 12,
54 PLL_POSTDIV1_MASK
= 0x7 << PLL_POSTDIV1_SHIFT
,
56 PLL_FBDIV_MASK
= 0xfff,
60 PLL_DSMPD_MASK
= 1 << PLL_DSMPD_SHIFT
,
62 PLL_LOCK_STATUS_SHIFT
= 10,
63 PLL_LOCK_STATUS_MASK
= 1 << PLL_LOCK_STATUS_SHIFT
,
64 PLL_POSTDIV2_SHIFT
= 6,
65 PLL_POSTDIV2_MASK
= 0x7 << PLL_POSTDIV2_SHIFT
,
67 PLL_REFDIV_MASK
= 0x3f,
70 PLL_FRACDIV_SHIFT
= 0,
71 PLL_FRACDIV_MASK
= 0xffffff,
83 CLK_CORE_PLL_SEL_APLL
= 0,
84 CLK_CORE_PLL_SEL_GPLL
,
85 CLK_CORE_PLL_SEL_DPLL
,
86 CLK_CORE_PLL_SEL_NPLL
,
87 CLK_CORE_PLL_SEL_SHIFT
= 6,
88 CLK_CORE_PLL_SEL_MASK
= 3 << CLK_CORE_PLL_SEL_SHIFT
,
89 CLK_CORE_DIV_SHIFT
= 0,
90 CLK_CORE_DIV_MASK
= 0x1f,
93 ACLKM_CORE_DIV_SHIFT
= 4,
94 ACLKM_CORE_DIV_MASK
= 0x7 << ACLKM_CORE_DIV_SHIFT
,
95 PCLK_DBG_DIV_SHIFT
= 0,
96 PCLK_DBG_DIV_MASK
= 0xF << PCLK_DBG_DIV_SHIFT
,
99 GMAC2IO_PLL_SEL_SHIFT
= 7,
100 GMAC2IO_PLL_SEL_MASK
= 1 << GMAC2IO_PLL_SEL_SHIFT
,
101 GMAC2IO_PLL_SEL_CPLL
= 0,
102 GMAC2IO_PLL_SEL_GPLL
= 1,
103 GMAC2IO_CLK_DIV_MASK
= 0x1f,
104 GMAC2IO_CLK_DIV_SHIFT
= 0,
107 ACLK_PERIHP_PLL_SEL_CPLL
= 0,
108 ACLK_PERIHP_PLL_SEL_GPLL
,
109 ACLK_PERIHP_PLL_SEL_HDMIPHY
,
110 ACLK_PERIHP_PLL_SEL_SHIFT
= 6,
111 ACLK_PERIHP_PLL_SEL_MASK
= 3 << ACLK_PERIHP_PLL_SEL_SHIFT
,
112 ACLK_PERIHP_DIV_CON_SHIFT
= 0,
113 ACLK_PERIHP_DIV_CON_MASK
= 0x1f,
116 PCLK_PERIHP_DIV_CON_SHIFT
= 4,
117 PCLK_PERIHP_DIV_CON_MASK
= 0x7 << PCLK_PERIHP_DIV_CON_SHIFT
,
118 HCLK_PERIHP_DIV_CON_SHIFT
= 0,
119 HCLK_PERIHP_DIV_CON_MASK
= 3 << HCLK_PERIHP_DIV_CON_SHIFT
,
122 CLK_TSADC_DIV_CON_SHIFT
= 0,
123 CLK_TSADC_DIV_CON_MASK
= 0x3ff,
126 CLK_SARADC_DIV_CON_SHIFT
= 0,
127 CLK_SARADC_DIV_CON_MASK
= GENMASK(9, 0),
128 CLK_SARADC_DIV_CON_WIDTH
= 10,
131 CLK_PWM_PLL_SEL_CPLL
= 0,
132 CLK_PWM_PLL_SEL_GPLL
,
133 CLK_PWM_PLL_SEL_SHIFT
= 15,
134 CLK_PWM_PLL_SEL_MASK
= 1 << CLK_PWM_PLL_SEL_SHIFT
,
135 CLK_PWM_DIV_CON_SHIFT
= 8,
136 CLK_PWM_DIV_CON_MASK
= 0x7f << CLK_PWM_DIV_CON_SHIFT
,
138 CLK_SPI_PLL_SEL_CPLL
= 0,
139 CLK_SPI_PLL_SEL_GPLL
,
140 CLK_SPI_PLL_SEL_SHIFT
= 7,
141 CLK_SPI_PLL_SEL_MASK
= 1 << CLK_SPI_PLL_SEL_SHIFT
,
142 CLK_SPI_DIV_CON_SHIFT
= 0,
143 CLK_SPI_DIV_CON_MASK
= 0x7f << CLK_SPI_DIV_CON_SHIFT
,
146 CLK_SDMMC_PLL_SEL_CPLL
= 0,
147 CLK_SDMMC_PLL_SEL_GPLL
,
148 CLK_SDMMC_PLL_SEL_24M
,
149 CLK_SDMMC_PLL_SEL_USBPHY
,
150 CLK_SDMMC_PLL_SHIFT
= 8,
151 CLK_SDMMC_PLL_MASK
= 0x3 << CLK_SDMMC_PLL_SHIFT
,
152 CLK_SDMMC_DIV_CON_SHIFT
= 0,
153 CLK_SDMMC_DIV_CON_MASK
= 0xff << CLK_SDMMC_DIV_CON_SHIFT
,
156 CLK_EMMC_PLL_SEL_CPLL
= 0,
157 CLK_EMMC_PLL_SEL_GPLL
,
158 CLK_EMMC_PLL_SEL_24M
,
159 CLK_EMMC_PLL_SEL_USBPHY
,
160 CLK_EMMC_PLL_SHIFT
= 8,
161 CLK_EMMC_PLL_MASK
= 0x3 << CLK_EMMC_PLL_SHIFT
,
162 CLK_EMMC_DIV_CON_SHIFT
= 0,
163 CLK_EMMC_DIV_CON_MASK
= 0xff << CLK_EMMC_DIV_CON_SHIFT
,
166 CLK_I2C_PLL_SEL_CPLL
= 0,
167 CLK_I2C_PLL_SEL_GPLL
,
168 CLK_I2C_DIV_CON_MASK
= 0x7f,
169 CLK_I2C_PLL_SEL_MASK
= 1,
170 CLK_I2C1_PLL_SEL_SHIFT
= 15,
171 CLK_I2C1_DIV_CON_SHIFT
= 8,
172 CLK_I2C0_PLL_SEL_SHIFT
= 7,
173 CLK_I2C0_DIV_CON_SHIFT
= 0,
176 CLK_I2C3_PLL_SEL_SHIFT
= 15,
177 CLK_I2C3_DIV_CON_SHIFT
= 8,
178 CLK_I2C2_PLL_SEL_SHIFT
= 7,
179 CLK_I2C2_DIV_CON_SHIFT
= 0,
182 CLK_HDMIPHY_DIV_CON_SHIFT
= 3,
183 CLK_HDMIPHY_DIV_CON_MASK
= 0x7 << CLK_HDMIPHY_DIV_CON_SHIFT
,
186 #define VCO_MAX_KHZ (3200 * (MHz / KHz))
187 #define VCO_MIN_KHZ (800 * (MHz / KHz))
188 #define OUTPUT_MAX_KHZ (3200 * (MHz / KHz))
189 #define OUTPUT_MIN_KHZ (16 * (MHz / KHz))
192 * the div restructions of pll in integer mode, these are defined in
193 * * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0
195 #define PLL_DIV_MIN 16
196 #define PLL_DIV_MAX 3200
199 * How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
200 * Formulas also embedded within the Fractional PLL Verilog model:
201 * If DSMPD = 1 (DSM is disabled, "integer mode")
202 * FOUTVCO = FREF / REFDIV * FBDIV
203 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
205 * FOUTVCO = Fractional PLL non-divided output frequency
206 * FOUTPOSTDIV = Fractional PLL divided output frequency
207 * (output of second post divider)
208 * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
209 * REFDIV = Fractional PLL input reference clock divider
210 * FBDIV = Integer value programmed into feedback divide
213 static void rkclk_set_pll(struct rk3328_cru
*cru
, enum rk_clk_id clk_id
,
214 const struct pll_div
*div
)
217 u32 mode_shift
, mode_mask
;
223 pll_con
= cru
->apll_con
;
224 mode_shift
= APLL_MODE_SHIFT
;
227 pll_con
= cru
->dpll_con
;
228 mode_shift
= DPLL_MODE_SHIFT
;
231 pll_con
= cru
->cpll_con
;
232 mode_shift
= CPLL_MODE_SHIFT
;
235 pll_con
= cru
->gpll_con
;
236 mode_shift
= GPLL_MODE_SHIFT
;
239 pll_con
= cru
->npll_con
;
240 mode_shift
= NPLL_MODE_SHIFT
;
245 mode_mask
= 1 << mode_shift
;
247 /* All 8 PLLs have same VCO and output frequency range restrictions. */
248 u32 vco_khz
= OSC_HZ
/ 1000 * div
->fbdiv
/ div
->refdiv
;
249 u32 output_khz
= vco_khz
/ div
->postdiv1
/ div
->postdiv2
;
251 debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, \
252 postdiv2=%d, vco=%u khz, output=%u khz\n",
253 pll_con
, div
->fbdiv
, div
->refdiv
, div
->postdiv1
,
254 div
->postdiv2
, vco_khz
, output_khz
);
255 assert(vco_khz
>= VCO_MIN_KHZ
&& vco_khz
<= VCO_MAX_KHZ
&&
256 output_khz
>= OUTPUT_MIN_KHZ
&& output_khz
<= OUTPUT_MAX_KHZ
&&
257 div
->fbdiv
>= PLL_DIV_MIN
&& div
->fbdiv
<= PLL_DIV_MAX
);
260 * When power on or changing PLL setting,
261 * we must force PLL into slow mode to ensure output stable clock.
263 rk_clrsetreg(&cru
->mode_con
, mode_mask
, PLL_MODE_SLOW
<< mode_shift
);
265 /* use integer mode */
266 rk_clrsetreg(&pll_con
[1], PLL_DSMPD_MASK
,
267 PLL_INTEGER_MODE
<< PLL_DSMPD_SHIFT
);
269 rk_clrsetreg(&pll_con
[0],
270 PLL_FBDIV_MASK
| PLL_POSTDIV1_MASK
,
271 (div
->fbdiv
<< PLL_FBDIV_SHIFT
) |
272 (div
->postdiv1
<< PLL_POSTDIV1_SHIFT
));
273 rk_clrsetreg(&pll_con
[1],
274 PLL_POSTDIV2_MASK
| PLL_REFDIV_MASK
,
275 (div
->postdiv2
<< PLL_POSTDIV2_SHIFT
) |
276 (div
->refdiv
<< PLL_REFDIV_SHIFT
));
278 /* waiting for pll lock */
279 while (!(readl(&pll_con
[1]) & (1 << PLL_LOCK_STATUS_SHIFT
)))
282 /* pll enter normal mode */
283 rk_clrsetreg(&cru
->mode_con
, mode_mask
, PLL_MODE_NORM
<< mode_shift
);
286 static void rkclk_init(struct rk3328_cru
*cru
)
292 rk3328_configure_cpu(cru
, APLL_600_MHZ
);
294 /* configure gpll cpll */
295 rkclk_set_pll(cru
, CLK_GENERAL
, &gpll_init_cfg
);
296 rkclk_set_pll(cru
, CLK_CODEC
, &cpll_init_cfg
);
298 /* configure perihp aclk, hclk, pclk */
299 aclk_div
= GPLL_HZ
/ PERIHP_ACLK_HZ
- 1;
300 hclk_div
= PERIHP_ACLK_HZ
/ PERIHP_HCLK_HZ
- 1;
301 pclk_div
= PERIHP_ACLK_HZ
/ PERIHP_PCLK_HZ
- 1;
303 rk_clrsetreg(&cru
->clksel_con
[28],
304 ACLK_PERIHP_PLL_SEL_MASK
| ACLK_PERIHP_DIV_CON_MASK
,
305 ACLK_PERIHP_PLL_SEL_GPLL
<< ACLK_PERIHP_PLL_SEL_SHIFT
|
306 aclk_div
<< ACLK_PERIHP_DIV_CON_SHIFT
);
307 rk_clrsetreg(&cru
->clksel_con
[29],
308 PCLK_PERIHP_DIV_CON_MASK
| HCLK_PERIHP_DIV_CON_MASK
,
309 pclk_div
<< PCLK_PERIHP_DIV_CON_SHIFT
|
310 hclk_div
<< HCLK_PERIHP_DIV_CON_SHIFT
);
313 void rk3328_configure_cpu(struct rk3328_cru
*cru
,
314 enum apll_frequencies apll_freq
)
320 rkclk_set_pll(cru
, CLK_ARM
, apll_cfgs
[apll_freq
]);
322 clk_core_div
= APLL_HZ
/ CLK_CORE_HZ
- 1;
323 aclkm_div
= APLL_HZ
/ ACLKM_CORE_HZ
/ (clk_core_div
+ 1) - 1;
324 pclk_dbg_div
= APLL_HZ
/ PCLK_DBG_HZ
/ (clk_core_div
+ 1) - 1;
326 rk_clrsetreg(&cru
->clksel_con
[0],
327 CLK_CORE_PLL_SEL_MASK
| CLK_CORE_DIV_MASK
,
328 CLK_CORE_PLL_SEL_APLL
<< CLK_CORE_PLL_SEL_SHIFT
|
329 clk_core_div
<< CLK_CORE_DIV_SHIFT
);
331 rk_clrsetreg(&cru
->clksel_con
[1],
332 PCLK_DBG_DIV_MASK
| ACLKM_CORE_DIV_MASK
,
333 pclk_dbg_div
<< PCLK_DBG_DIV_SHIFT
|
334 aclkm_div
<< ACLKM_CORE_DIV_SHIFT
);
338 static ulong
rk3328_i2c_get_clk(struct rk3328_cru
*cru
, ulong clk_id
)
344 con
= readl(&cru
->clksel_con
[34]);
345 div
= con
>> CLK_I2C0_DIV_CON_SHIFT
& CLK_I2C_DIV_CON_MASK
;
348 con
= readl(&cru
->clksel_con
[34]);
349 div
= con
>> CLK_I2C1_DIV_CON_SHIFT
& CLK_I2C_DIV_CON_MASK
;
352 con
= readl(&cru
->clksel_con
[35]);
353 div
= con
>> CLK_I2C2_DIV_CON_SHIFT
& CLK_I2C_DIV_CON_MASK
;
356 con
= readl(&cru
->clksel_con
[35]);
357 div
= con
>> CLK_I2C3_DIV_CON_SHIFT
& CLK_I2C_DIV_CON_MASK
;
360 printf("do not support this i2c bus\n");
364 return DIV_TO_RATE(GPLL_HZ
, div
);
367 static ulong
rk3328_i2c_set_clk(struct rk3328_cru
*cru
, ulong clk_id
, uint hz
)
371 src_clk_div
= GPLL_HZ
/ hz
;
372 assert(src_clk_div
- 1 < 127);
376 rk_clrsetreg(&cru
->clksel_con
[34],
377 CLK_I2C_DIV_CON_MASK
<< CLK_I2C0_DIV_CON_SHIFT
|
378 CLK_I2C_PLL_SEL_MASK
<< CLK_I2C0_PLL_SEL_SHIFT
,
379 (src_clk_div
- 1) << CLK_I2C0_DIV_CON_SHIFT
|
380 CLK_I2C_PLL_SEL_GPLL
<< CLK_I2C0_PLL_SEL_SHIFT
);
383 rk_clrsetreg(&cru
->clksel_con
[34],
384 CLK_I2C_DIV_CON_MASK
<< CLK_I2C1_DIV_CON_SHIFT
|
385 CLK_I2C_PLL_SEL_MASK
<< CLK_I2C1_PLL_SEL_SHIFT
,
386 (src_clk_div
- 1) << CLK_I2C1_DIV_CON_SHIFT
|
387 CLK_I2C_PLL_SEL_GPLL
<< CLK_I2C1_PLL_SEL_SHIFT
);
390 rk_clrsetreg(&cru
->clksel_con
[35],
391 CLK_I2C_DIV_CON_MASK
<< CLK_I2C2_DIV_CON_SHIFT
|
392 CLK_I2C_PLL_SEL_MASK
<< CLK_I2C2_PLL_SEL_SHIFT
,
393 (src_clk_div
- 1) << CLK_I2C2_DIV_CON_SHIFT
|
394 CLK_I2C_PLL_SEL_GPLL
<< CLK_I2C2_PLL_SEL_SHIFT
);
397 rk_clrsetreg(&cru
->clksel_con
[35],
398 CLK_I2C_DIV_CON_MASK
<< CLK_I2C3_DIV_CON_SHIFT
|
399 CLK_I2C_PLL_SEL_MASK
<< CLK_I2C3_PLL_SEL_SHIFT
,
400 (src_clk_div
- 1) << CLK_I2C3_DIV_CON_SHIFT
|
401 CLK_I2C_PLL_SEL_GPLL
<< CLK_I2C3_PLL_SEL_SHIFT
);
404 printf("do not support this i2c bus\n");
408 return DIV_TO_RATE(GPLL_HZ
, src_clk_div
);
411 static ulong
rk3328_gmac2io_set_clk(struct rk3328_cru
*cru
, ulong rate
)
413 struct rk3328_grf_regs
*grf
;
416 grf
= syscon_get_first_range(ROCKCHIP_SYSCON_GRF
);
419 * The RGMII CLK can be derived either from an external "clkin"
420 * or can be generated from internally by a divider from SCLK_MAC.
422 if (readl(&grf
->mac_con
[1]) & BIT(10) &&
423 readl(&grf
->soc_con
[4]) & BIT(14)) {
424 /* An external clock will always generate the right rate... */
427 u32 con
= readl(&cru
->clksel_con
[27]);
431 if ((con
>> GMAC2IO_PLL_SEL_SHIFT
) & GMAC2IO_PLL_SEL_GPLL
)
436 div
= DIV_ROUND_UP(pll_rate
, rate
) - 1;
438 rk_clrsetreg(&cru
->clksel_con
[27], GMAC2IO_CLK_DIV_MASK
,
439 div
<< GMAC2IO_CLK_DIV_SHIFT
);
441 debug("Unsupported div for gmac:%d\n", div
);
443 return DIV_TO_RATE(pll_rate
, div
);
449 static ulong
rk3328_mmc_get_clk(struct rk3328_cru
*cru
, uint clk_id
)
451 u32 div
, con
, con_id
;
465 con
= readl(&cru
->clksel_con
[con_id
]);
466 div
= (con
& CLK_EMMC_DIV_CON_MASK
) >> CLK_EMMC_DIV_CON_SHIFT
;
468 if ((con
& CLK_EMMC_PLL_MASK
) >> CLK_EMMC_PLL_SHIFT
469 == CLK_EMMC_PLL_SEL_24M
)
470 return DIV_TO_RATE(OSC_HZ
, div
) / 2;
472 return DIV_TO_RATE(GPLL_HZ
, div
) / 2;
475 static ulong
rk3328_mmc_set_clk(struct rk3328_cru
*cru
,
476 ulong clk_id
, ulong set_rate
)
493 /* Select clk_sdmmc/emmc source from GPLL by default */
494 /* mmc clock defaulg div 2 internal, need provide double in cru */
495 src_clk_div
= DIV_ROUND_UP(GPLL_HZ
/ 2, set_rate
);
497 if (src_clk_div
> 127) {
498 /* use 24MHz source for 400KHz clock */
499 src_clk_div
= DIV_ROUND_UP(OSC_HZ
/ 2, set_rate
);
500 rk_clrsetreg(&cru
->clksel_con
[con_id
],
501 CLK_EMMC_PLL_MASK
| CLK_EMMC_DIV_CON_MASK
,
502 CLK_EMMC_PLL_SEL_24M
<< CLK_EMMC_PLL_SHIFT
|
503 (src_clk_div
- 1) << CLK_EMMC_DIV_CON_SHIFT
);
505 rk_clrsetreg(&cru
->clksel_con
[con_id
],
506 CLK_EMMC_PLL_MASK
| CLK_EMMC_DIV_CON_MASK
,
507 CLK_EMMC_PLL_SEL_GPLL
<< CLK_EMMC_PLL_SHIFT
|
508 (src_clk_div
- 1) << CLK_EMMC_DIV_CON_SHIFT
);
511 return rk3328_mmc_get_clk(cru
, clk_id
);
514 static ulong
rk3328_pwm_get_clk(struct rk3328_cru
*cru
)
518 con
= readl(&cru
->clksel_con
[24]);
519 div
= (con
& CLK_PWM_DIV_CON_MASK
) >> CLK_PWM_DIV_CON_SHIFT
;
521 return DIV_TO_RATE(GPLL_HZ
, div
);
524 static ulong
rk3328_pwm_set_clk(struct rk3328_cru
*cru
, uint hz
)
526 u32 div
= GPLL_HZ
/ hz
;
528 rk_clrsetreg(&cru
->clksel_con
[24],
529 CLK_PWM_PLL_SEL_MASK
| CLK_PWM_DIV_CON_MASK
,
530 CLK_PWM_PLL_SEL_GPLL
<< CLK_PWM_PLL_SEL_SHIFT
|
531 (div
- 1) << CLK_PWM_DIV_CON_SHIFT
);
533 return DIV_TO_RATE(GPLL_HZ
, div
);
536 static ulong
rk3328_saradc_get_clk(struct rk3328_cru
*cru
)
540 val
= readl(&cru
->clksel_con
[23]);
541 div
= bitfield_extract(val
, CLK_SARADC_DIV_CON_SHIFT
,
542 CLK_SARADC_DIV_CON_WIDTH
);
544 return DIV_TO_RATE(OSC_HZ
, div
);
547 static ulong
rk3328_saradc_set_clk(struct rk3328_cru
*cru
, uint hz
)
551 src_clk_div
= DIV_ROUND_UP(OSC_HZ
, hz
) - 1;
552 assert(src_clk_div
< 128);
554 rk_clrsetreg(&cru
->clksel_con
[23],
555 CLK_SARADC_DIV_CON_MASK
,
556 src_clk_div
<< CLK_SARADC_DIV_CON_SHIFT
);
558 return rk3328_saradc_get_clk(cru
);
561 static ulong
rk3328_spi_get_clk(struct rk3328_cru
*cru
)
565 val
= readl(&cru
->clksel_con
[24]);
566 div
= (val
& CLK_SPI_DIV_CON_MASK
) >> CLK_SPI_DIV_CON_SHIFT
;
568 return DIV_TO_RATE(OSC_HZ
, div
);
571 static ulong
rk3328_spi_set_clk(struct rk3328_cru
*cru
, uint hz
)
575 src_clk_div
= GPLL_HZ
/ hz
;
576 assert(src_clk_div
< 128);
578 rk_clrsetreg(&cru
->clksel_con
[24],
579 CLK_PWM_PLL_SEL_MASK
| CLK_PWM_DIV_CON_MASK
,
580 CLK_PWM_PLL_SEL_GPLL
<< CLK_PWM_PLL_SEL_SHIFT
|
581 (src_clk_div
- 1) << CLK_PWM_DIV_CON_SHIFT
);
583 return rk3328_spi_get_clk(cru
);
586 #ifndef CONFIG_SPL_BUILD
587 static ulong
rk3328_vop_get_clk(struct rk3328_clk_priv
*priv
, ulong clk_id
)
589 struct rk3328_cru
*cru
= priv
->cru
;
590 u32 div
, con
, parent
;
594 con
= readl(&cru
->clksel_con
[39]);
595 div
= (con
& ACLK_VOP_DIV_CON_MASK
) >> ACLK_VOP_DIV_CON_SHIFT
;
599 con
= readl(&cru
->clksel_con
[37]);
600 div
= (con
& ACLK_VIO_DIV_CON_MASK
) >> ACLK_VIO_DIV_CON_SHIFT
;
604 con
= readl(&cru
->clksel_con
[40]);
605 div
= (con
& DCLK_LCDC_DIV_CON_MASK
) >> DCLK_LCDC_DIV_CON_SHIFT
;
609 printf("%s: Unsupported vop get clk#%ld\n", __func__
, clk_id
);
613 return DIV_TO_RATE(parent
, div
);
616 static ulong
rk3328_vop_set_clk(struct rk3328_clk_priv
*priv
,
617 ulong clk_id
, uint hz
)
619 struct rk3328_cru
*cru
= priv
->cru
;
623 src_clk_div
= DIV_ROUND_UP(GPLL_HZ
, hz
);
624 assert(src_clk_div
- 1 < 31);
628 rk_clrsetreg(&cru
->clksel_con
[39],
629 ACLK_VOP_PLL_SEL_MASK
| ACLK_VOP_DIV_CON_MASK
,
630 ACLK_VOP_PLL_SEL_CPLL
<< ACLK_VOP_PLL_SEL_SHIFT
|
631 (src_clk_div
- 1) << ACLK_VOP_DIV_CON_SHIFT
);
634 rk_clrsetreg(&cru
->clksel_con
[37],
635 ACLK_VIO_PLL_SEL_MASK
| ACLK_VIO_DIV_CON_MASK
,
636 ACLK_VIO_PLL_SEL_CPLL
<< ACLK_VIO_PLL_SEL_SHIFT
|
637 (src_clk_div
- 1) << ACLK_VIO_DIV_CON_SHIFT
);
640 con
= readl(&cru
->clksel_con
[40]);
641 con
= (con
& DCLK_LCDC_SEL_MASK
) >> DCLK_LCDC_SEL_SHIFT
;
643 parent
= readl(&cru
->clksel_con
[40]);
644 parent
= (parent
& DCLK_LCDC_PLL_SEL_MASK
) >>
645 DCLK_LCDC_PLL_SEL_SHIFT
;
647 src_clk_div
= DIV_ROUND_UP(GPLL_HZ
, hz
);
649 src_clk_div
= DIV_ROUND_UP(GPLL_HZ
, hz
);
651 rk_clrsetreg(&cru
->clksel_con
[40],
652 DCLK_LCDC_DIV_CON_MASK
,
654 DCLK_LCDC_DIV_CON_SHIFT
);
658 printf("%s: Unable to set vop clk#%ld\n", __func__
, clk_id
);
662 return rk3328_vop_get_clk(priv
, clk_id
);
666 static ulong
rk3328_hdmiphy_get_clk(struct rk3328_cru
*cru
)
670 con
= readl(&cru
->clksel_con
[40]);
671 div
= (con
& CLK_HDMIPHY_DIV_CON_MASK
) >> CLK_HDMIPHY_DIV_CON_SHIFT
;
673 return DIV_TO_RATE(GPLL_HZ
, div
);
676 static ulong
rk3328_clk_get_rate(struct clk
*clk
)
678 struct rk3328_clk_priv
*priv
= dev_get_priv(clk
->dev
);
688 rate
= rk3328_mmc_get_clk(priv
->cru
, clk
->id
);
694 rate
= rk3328_i2c_get_clk(priv
->cru
, clk
->id
);
697 rate
= rk3328_pwm_get_clk(priv
->cru
);
700 rate
= rk3328_saradc_get_clk(priv
->cru
);
703 rate
= rk3328_spi_get_clk(priv
->cru
);
706 rate
= rk3328_hdmiphy_get_clk(priv
->cru
);
708 case SCLK_USB3OTG_REF
:
718 static ulong
rk3328_clk_set_rate(struct clk
*clk
, ulong rate
)
720 struct rk3328_clk_priv
*priv
= dev_get_priv(clk
->dev
);
730 ret
= rk3328_mmc_set_clk(priv
->cru
, clk
->id
, rate
);
736 ret
= rk3328_i2c_set_clk(priv
->cru
, clk
->id
, rate
);
739 ret
= rk3328_gmac2io_set_clk(priv
->cru
, rate
);
742 ret
= rk3328_pwm_set_clk(priv
->cru
, rate
);
745 ret
= rk3328_saradc_set_clk(priv
->cru
, rate
);
748 ret
= rk3328_spi_set_clk(priv
->cru
, rate
);
750 #ifndef CONFIG_SPL_BUILD
754 rate
= rk3328_vop_set_clk(priv
, clk
->id
, rate
);
774 case ACLK_RKVDEC_PRE
:
777 case SCLK_VDEC_CABAC
:
785 case SCLK_USB3OTG_REF
:
786 case SCLK_USB3OTG_SUSPEND
:
796 static int rk3328_gmac2io_set_parent(struct clk
*clk
, struct clk
*parent
)
798 struct rk3328_grf_regs
*grf
;
799 const char *clock_output_name
;
802 grf
= syscon_get_first_range(ROCKCHIP_SYSCON_GRF
);
805 * If the requested parent is in the same clock-controller and the id
806 * is SCLK_MAC2IO_SRC ("clk_mac2io_src"), switch to the internal clock.
808 if ((parent
->dev
== clk
->dev
) && (parent
->id
== SCLK_MAC2IO_SRC
)) {
809 debug("%s: switching RGMII to SCLK_MAC2IO_SRC\n", __func__
);
810 rk_clrreg(&grf
->mac_con
[1], BIT(10));
815 * Otherwise, we need to check the clock-output-names of the
816 * requested parent to see if the requested id is "gmac_clkin".
818 ret
= dev_read_string_index(parent
->dev
, "clock-output-names",
819 parent
->id
, &clock_output_name
);
823 /* If this is "gmac_clkin", switch to the external clock input */
824 if (!strcmp(clock_output_name
, "gmac_clkin")) {
825 debug("%s: switching RGMII to CLKIN\n", __func__
);
826 rk_setreg(&grf
->mac_con
[1], BIT(10));
833 static int rk3328_gmac2io_ext_set_parent(struct clk
*clk
, struct clk
*parent
)
835 struct rk3328_grf_regs
*grf
;
836 const char *clock_output_name
;
839 grf
= syscon_get_first_range(ROCKCHIP_SYSCON_GRF
);
842 * If the requested parent is in the same clock-controller and the id
843 * is SCLK_MAC2IO ("clk_mac2io"), switch to the internal clock.
845 if ((parent
->dev
== clk
->dev
) && (parent
->id
== SCLK_MAC2IO
)) {
846 debug("%s: switching RGMII to SCLK_MAC2IO\n", __func__
);
847 rk_clrreg(&grf
->soc_con
[4], BIT(14));
852 * Otherwise, we need to check the clock-output-names of the
853 * requested parent to see if the requested id is "gmac_clkin".
855 ret
= dev_read_string_index(parent
->dev
, "clock-output-names",
856 parent
->id
, &clock_output_name
);
860 /* If this is "gmac_clkin", switch to the external clock input */
861 if (!strcmp(clock_output_name
, "gmac_clkin")) {
862 debug("%s: switching RGMII to CLKIN\n", __func__
);
863 rk_setreg(&grf
->soc_con
[4], BIT(14));
870 static int rk3328_clk_set_parent(struct clk
*clk
, struct clk
*parent
)
874 return rk3328_gmac2io_set_parent(clk
, parent
);
875 case SCLK_MAC2IO_EXT
:
876 return rk3328_gmac2io_ext_set_parent(clk
, parent
);
887 debug("%s: unsupported clk %ld\n", __func__
, clk
->id
);
891 static struct clk_ops rk3328_clk_ops
= {
892 .get_rate
= rk3328_clk_get_rate
,
893 .set_rate
= rk3328_clk_set_rate
,
894 .set_parent
= rk3328_clk_set_parent
,
897 static int rk3328_clk_probe(struct udevice
*dev
)
899 struct rk3328_clk_priv
*priv
= dev_get_priv(dev
);
901 rkclk_init(priv
->cru
);
906 static int rk3328_clk_of_to_plat(struct udevice
*dev
)
908 struct rk3328_clk_priv
*priv
= dev_get_priv(dev
);
910 priv
->cru
= dev_read_addr_ptr(dev
);
915 static int rk3328_clk_bind(struct udevice
*dev
)
918 struct udevice
*sys_child
;
919 struct sysreset_reg
*priv
;
921 /* The reset driver does not have a device node, so bind it here */
922 ret
= device_bind_driver(dev
, "rockchip_sysreset", "sysreset",
925 debug("Warning: No sysreset driver: ret=%d\n", ret
);
927 priv
= malloc(sizeof(struct sysreset_reg
));
928 priv
->glb_srst_fst_value
= offsetof(struct rk3328_cru
,
930 priv
->glb_srst_snd_value
= offsetof(struct rk3328_cru
,
932 dev_set_priv(sys_child
, priv
);
935 #if CONFIG_IS_ENABLED(RESET_ROCKCHIP)
936 ret
= offsetof(struct rk3328_cru
, softrst_con
[0]);
937 ret
= rockchip_reset_bind(dev
, ret
, 12);
939 debug("Warning: software reset driver bind failed\n");
945 static const struct udevice_id rk3328_clk_ids
[] = {
946 { .compatible
= "rockchip,rk3328-cru" },
950 U_BOOT_DRIVER(rockchip_rk3328_cru
) = {
951 .name
= "rockchip_rk3328_cru",
953 .of_match
= rk3328_clk_ids
,
954 .priv_auto
= sizeof(struct rk3328_clk_priv
),
955 .of_to_plat
= rk3328_clk_of_to_plat
,
956 .ops
= &rk3328_clk_ops
,
957 .bind
= rk3328_clk_bind
,
958 .probe
= rk3328_clk_probe
,