2 * (C) Copyright 2015 Google, Inc
3 * (C) Copyright 2016 Heiko Stuebner <heiko@sntech.de>
5 * SPDX-License-Identifier: GPL-2.0
9 #include <clk-uclass.h>
11 #include <dt-structs.h>
16 #include <asm/arch/clock.h>
17 #include <asm/arch/cru_rk3188.h>
18 #include <asm/arch/grf_rk3188.h>
19 #include <asm/arch/hardware.h>
20 #include <dt-bindings/clock/rk3188-cru.h>
21 #include <dm/device-internal.h>
23 #include <dm/uclass-internal.h>
24 #include <linux/log2.h>
26 DECLARE_GLOBAL_DATA_PTR
;
28 enum rk3188_clk_type
{
33 struct rk3188_clk_plat
{
34 #if CONFIG_IS_ENABLED(OF_PLATDATA)
35 struct dtd_rockchip_rk3188_cru dtd
;
46 VCO_MAX_HZ
= 2200U * 1000000,
47 VCO_MIN_HZ
= 440 * 1000000,
48 OUTPUT_MAX_HZ
= 2200U * 1000000,
49 OUTPUT_MIN_HZ
= 30 * 1000000,
50 FREF_MAX_HZ
= 2200U * 1000000,
51 FREF_MIN_HZ
= 30 * 1000,
62 PLL_BWADJ_MASK
= 0x0fff,
68 SOCSTS_DPLL_LOCK
= 1 << 5,
69 SOCSTS_APLL_LOCK
= 1 << 6,
70 SOCSTS_CPLL_LOCK
= 1 << 7,
71 SOCSTS_GPLL_LOCK
= 1 << 8,
74 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
76 #define PLL_DIVISORS(hz, _nr, _no) {\
77 .nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\
78 _Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
79 (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\
80 "divisors on line " __stringify(__LINE__));
82 /* Keep divisors as low as possible to reduce jitter and power usage */
83 #ifdef CONFIG_SPL_BUILD
84 static const struct pll_div gpll_init_cfg
= PLL_DIVISORS(GPLL_HZ
, 2, 2);
85 static const struct pll_div cpll_init_cfg
= PLL_DIVISORS(CPLL_HZ
, 1, 2);
88 static int rkclk_set_pll(struct rk3188_cru
*cru
, enum rk_clk_id clk_id
,
89 const struct pll_div
*div
, bool has_bwadj
)
91 int pll_id
= rk_pll_id(clk_id
);
92 struct rk3188_pll
*pll
= &cru
->pll
[pll_id
];
93 /* All PLLs have same VCO and output frequency range restrictions. */
94 uint vco_hz
= OSC_HZ
/ 1000 * div
->nf
/ div
->nr
* 1000;
95 uint output_hz
= vco_hz
/ div
->no
;
97 debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
98 (uint
)pll
, div
->nf
, div
->nr
, div
->no
, vco_hz
, output_hz
);
99 assert(vco_hz
>= VCO_MIN_HZ
&& vco_hz
<= VCO_MAX_HZ
&&
100 output_hz
>= OUTPUT_MIN_HZ
&& output_hz
<= OUTPUT_MAX_HZ
&&
101 (div
->no
== 1 || !(div
->no
% 2)));
104 rk_setreg(&pll
->con3
, 1 << PLL_RESET_SHIFT
);
106 rk_clrsetreg(&pll
->con0
,
107 CLKR_MASK
<< CLKR_SHIFT
| PLL_OD_MASK
,
108 ((div
->nr
- 1) << CLKR_SHIFT
) | (div
->no
- 1));
109 rk_clrsetreg(&pll
->con1
, CLKF_MASK
, div
->nf
- 1);
112 rk_clrsetreg(&pll
->con2
, PLL_BWADJ_MASK
, (div
->nf
>> 1) - 1);
116 /* return from reset */
117 rk_clrreg(&pll
->con3
, 1 << PLL_RESET_SHIFT
);
122 static int rkclk_configure_ddr(struct rk3188_cru
*cru
, struct rk3188_grf
*grf
,
123 unsigned int hz
, bool has_bwadj
)
125 static const struct pll_div dpll_cfg
[] = {
126 {.nf
= 25, .nr
= 2, .no
= 1},
127 {.nf
= 400, .nr
= 9, .no
= 2},
128 {.nf
= 500, .nr
= 9, .no
= 2},
129 {.nf
= 100, .nr
= 3, .no
= 1},
137 case 533000000: /* actually 533.3P MHz */
140 case 666000000: /* actually 666.6P MHz */
147 debug("Unsupported SDRAM frequency");
151 /* pll enter slow-mode */
152 rk_clrsetreg(&cru
->cru_mode_con
, DPLL_MODE_MASK
<< DPLL_MODE_SHIFT
,
153 DPLL_MODE_SLOW
<< DPLL_MODE_SHIFT
);
155 rkclk_set_pll(cru
, CLK_DDR
, &dpll_cfg
[cfg
], has_bwadj
);
157 /* wait for pll lock */
158 while (!(readl(&grf
->soc_status0
) & SOCSTS_DPLL_LOCK
))
161 /* PLL enter normal-mode */
162 rk_clrsetreg(&cru
->cru_mode_con
, DPLL_MODE_MASK
<< DPLL_MODE_SHIFT
,
163 DPLL_MODE_NORMAL
<< DPLL_MODE_SHIFT
);
168 static int rkclk_configure_cpu(struct rk3188_cru
*cru
, struct rk3188_grf
*grf
,
169 unsigned int hz
, bool has_bwadj
)
171 static const struct pll_div apll_cfg
[] = {
172 {.nf
= 50, .nr
= 1, .no
= 2},
173 {.nf
= 67, .nr
= 1, .no
= 1},
175 int div_core_peri
, div_aclk_core
, cfg
;
178 * We support two possible frequencies, the safe 600MHz
179 * which will work with default pmic settings and will
180 * be set in SPL to get away from the 24MHz default and
181 * the maximum of 1.6Ghz, which boards can set if they
182 * were able to get pmic support for it.
196 debug("Unsupported ARMCLK frequency");
200 /* pll enter slow-mode */
201 rk_clrsetreg(&cru
->cru_mode_con
, APLL_MODE_MASK
<< APLL_MODE_SHIFT
,
202 APLL_MODE_SLOW
<< APLL_MODE_SHIFT
);
204 rkclk_set_pll(cru
, CLK_ARM
, &apll_cfg
[cfg
], has_bwadj
);
206 /* waiting for pll lock */
207 while (!(readl(&grf
->soc_status0
) & SOCSTS_APLL_LOCK
))
210 /* Set divider for peripherals attached to the cpu core. */
211 rk_clrsetreg(&cru
->cru_clksel_con
[0],
212 CORE_PERI_DIV_MASK
<< CORE_PERI_DIV_SHIFT
,
213 div_core_peri
<< CORE_PERI_DIV_SHIFT
);
215 /* set up dependent divisor for aclk_core */
216 rk_clrsetreg(&cru
->cru_clksel_con
[1],
217 CORE_ACLK_DIV_MASK
<< CORE_ACLK_DIV_SHIFT
,
218 div_aclk_core
<< CORE_ACLK_DIV_SHIFT
);
220 /* PLL enter normal-mode */
221 rk_clrsetreg(&cru
->cru_mode_con
, APLL_MODE_MASK
<< APLL_MODE_SHIFT
,
222 APLL_MODE_NORMAL
<< APLL_MODE_SHIFT
);
227 /* Get pll rate by id */
228 static uint32_t rkclk_pll_get_rate(struct rk3188_cru
*cru
,
229 enum rk_clk_id clk_id
)
233 int pll_id
= rk_pll_id(clk_id
);
234 struct rk3188_pll
*pll
= &cru
->pll
[pll_id
];
235 static u8 clk_shift
[CLK_COUNT
] = {
236 0xff, APLL_MODE_SHIFT
, DPLL_MODE_SHIFT
, CPLL_MODE_SHIFT
,
241 con
= readl(&cru
->cru_mode_con
);
242 shift
= clk_shift
[clk_id
];
243 switch ((con
>> shift
) & APLL_MODE_MASK
) {
246 case APLL_MODE_NORMAL
:
248 con
= readl(&pll
->con0
);
249 no
= ((con
>> CLKOD_SHIFT
) & CLKOD_MASK
) + 1;
250 nr
= ((con
>> CLKR_SHIFT
) & CLKR_MASK
) + 1;
251 con
= readl(&pll
->con1
);
252 nf
= ((con
>> CLKF_SHIFT
) & CLKF_MASK
) + 1;
254 return (24 * nf
/ (nr
* no
)) * 1000000;
261 static ulong
rockchip_mmc_get_clk(struct rk3188_cru
*cru
, uint gclk_rate
,
270 con
= readl(&cru
->cru_clksel_con
[12]);
271 div
= (con
>> EMMC_DIV_SHIFT
) & EMMC_DIV_MASK
;
275 con
= readl(&cru
->cru_clksel_con
[11]);
276 div
= (con
>> MMC0_DIV_SHIFT
) & MMC0_DIV_MASK
;
280 con
= readl(&cru
->cru_clksel_con
[12]);
281 div
= (con
>> SDIO_DIV_SHIFT
) & SDIO_DIV_MASK
;
287 return DIV_TO_RATE(gclk_rate
, div
) / 2;
290 static ulong
rockchip_mmc_set_clk(struct rk3188_cru
*cru
, uint gclk_rate
,
291 int periph
, uint freq
)
295 debug("%s: gclk_rate=%u\n", __func__
, gclk_rate
);
296 /* mmc clock defaulg div 2 internal, need provide double in cru */
297 src_clk_div
= DIV_ROUND_UP(gclk_rate
/ 2, freq
) - 1;
298 assert(src_clk_div
<= 0x3f);
303 rk_clrsetreg(&cru
->cru_clksel_con
[12],
304 EMMC_DIV_MASK
<< EMMC_DIV_SHIFT
,
305 src_clk_div
<< EMMC_DIV_SHIFT
);
309 rk_clrsetreg(&cru
->cru_clksel_con
[11],
310 MMC0_DIV_MASK
<< MMC0_DIV_SHIFT
,
311 src_clk_div
<< MMC0_DIV_SHIFT
);
315 rk_clrsetreg(&cru
->cru_clksel_con
[12],
316 SDIO_DIV_MASK
<< SDIO_DIV_SHIFT
,
317 src_clk_div
<< SDIO_DIV_SHIFT
);
323 return rockchip_mmc_get_clk(cru
, gclk_rate
, periph
);
326 static ulong
rockchip_spi_get_clk(struct rk3188_cru
*cru
, uint gclk_rate
,
334 con
= readl(&cru
->cru_clksel_con
[25]);
335 div
= (con
>> SPI0_DIV_SHIFT
) & SPI0_DIV_MASK
;
338 con
= readl(&cru
->cru_clksel_con
[25]);
339 div
= (con
>> SPI1_DIV_SHIFT
) & SPI1_DIV_MASK
;
345 return DIV_TO_RATE(gclk_rate
, div
);
348 static ulong
rockchip_spi_set_clk(struct rk3188_cru
*cru
, uint gclk_rate
,
349 int periph
, uint freq
)
351 int src_clk_div
= DIV_ROUND_UP(gclk_rate
, freq
) - 1;
353 assert(src_clk_div
< 128);
356 assert(src_clk_div
<= SPI0_DIV_MASK
);
357 rk_clrsetreg(&cru
->cru_clksel_con
[25],
358 SPI0_DIV_MASK
<< SPI0_DIV_SHIFT
,
359 src_clk_div
<< SPI0_DIV_SHIFT
);
362 assert(src_clk_div
<= SPI1_DIV_MASK
);
363 rk_clrsetreg(&cru
->cru_clksel_con
[25],
364 SPI1_DIV_MASK
<< SPI1_DIV_SHIFT
,
365 src_clk_div
<< SPI1_DIV_SHIFT
);
371 return rockchip_spi_get_clk(cru
, gclk_rate
, periph
);
374 #ifdef CONFIG_SPL_BUILD
375 static void rkclk_init(struct rk3188_cru
*cru
, struct rk3188_grf
*grf
,
378 u32 aclk_div
, hclk_div
, pclk_div
, h2p_div
;
380 /* pll enter slow-mode */
381 rk_clrsetreg(&cru
->cru_mode_con
,
382 GPLL_MODE_MASK
<< GPLL_MODE_SHIFT
|
383 CPLL_MODE_MASK
<< CPLL_MODE_SHIFT
,
384 GPLL_MODE_SLOW
<< GPLL_MODE_SHIFT
|
385 CPLL_MODE_SLOW
<< CPLL_MODE_SHIFT
);
388 rkclk_set_pll(cru
, CLK_GENERAL
, &gpll_init_cfg
, has_bwadj
);
389 rkclk_set_pll(cru
, CLK_CODEC
, &cpll_init_cfg
, has_bwadj
);
391 /* waiting for pll lock */
392 while ((readl(&grf
->soc_status0
) &
393 (SOCSTS_CPLL_LOCK
| SOCSTS_GPLL_LOCK
)) !=
394 (SOCSTS_CPLL_LOCK
| SOCSTS_GPLL_LOCK
))
398 * cpu clock pll source selection and
399 * reparent aclk_cpu_pre from apll to gpll
400 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
402 aclk_div
= DIV_ROUND_UP(GPLL_HZ
, CPU_ACLK_HZ
) - 1;
403 assert((aclk_div
+ 1) * CPU_ACLK_HZ
== GPLL_HZ
&& aclk_div
<= 0x1f);
405 rk_clrsetreg(&cru
->cru_clksel_con
[0],
406 CPU_ACLK_PLL_MASK
<< CPU_ACLK_PLL_SHIFT
|
407 A9_CPU_DIV_MASK
<< A9_CPU_DIV_SHIFT
,
408 CPU_ACLK_PLL_SELECT_GPLL
<< CPU_ACLK_PLL_SHIFT
|
409 aclk_div
<< A9_CPU_DIV_SHIFT
);
411 hclk_div
= ilog2(CPU_ACLK_HZ
/ CPU_HCLK_HZ
);
412 assert((1 << hclk_div
) * CPU_HCLK_HZ
== CPU_ACLK_HZ
&& hclk_div
< 0x3);
413 pclk_div
= ilog2(CPU_ACLK_HZ
/ CPU_PCLK_HZ
);
414 assert((1 << pclk_div
) * CPU_PCLK_HZ
== CPU_ACLK_HZ
&& pclk_div
< 0x4);
415 h2p_div
= ilog2(CPU_HCLK_HZ
/ CPU_H2P_HZ
);
416 assert((1 << h2p_div
) * CPU_H2P_HZ
== CPU_HCLK_HZ
&& pclk_div
< 0x3);
418 rk_clrsetreg(&cru
->cru_clksel_con
[1],
419 AHB2APB_DIV_MASK
<< AHB2APB_DIV_SHIFT
|
420 CPU_PCLK_DIV_MASK
<< CPU_PCLK_DIV_SHIFT
|
421 CPU_HCLK_DIV_MASK
<< CPU_HCLK_DIV_SHIFT
,
422 h2p_div
<< AHB2APB_DIV_SHIFT
|
423 pclk_div
<< CPU_PCLK_DIV_SHIFT
|
424 hclk_div
<< CPU_HCLK_DIV_SHIFT
);
427 * peri clock pll source selection and
428 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
430 aclk_div
= GPLL_HZ
/ PERI_ACLK_HZ
- 1;
431 assert((aclk_div
+ 1) * PERI_ACLK_HZ
== GPLL_HZ
&& aclk_div
< 0x1f);
433 hclk_div
= ilog2(PERI_ACLK_HZ
/ PERI_HCLK_HZ
);
434 assert((1 << hclk_div
) * PERI_HCLK_HZ
==
435 PERI_ACLK_HZ
&& (hclk_div
< 0x4));
437 pclk_div
= ilog2(PERI_ACLK_HZ
/ PERI_PCLK_HZ
);
438 assert((1 << pclk_div
) * PERI_PCLK_HZ
==
439 PERI_ACLK_HZ
&& (pclk_div
< 0x4));
441 rk_clrsetreg(&cru
->cru_clksel_con
[10],
442 PERI_PCLK_DIV_MASK
<< PERI_PCLK_DIV_SHIFT
|
443 PERI_HCLK_DIV_MASK
<< PERI_HCLK_DIV_SHIFT
|
444 PERI_ACLK_DIV_MASK
<< PERI_ACLK_DIV_SHIFT
,
445 PERI_SEL_GPLL
<< PERI_SEL_PLL_SHIFT
|
446 pclk_div
<< PERI_PCLK_DIV_SHIFT
|
447 hclk_div
<< PERI_HCLK_DIV_SHIFT
|
448 aclk_div
<< PERI_ACLK_DIV_SHIFT
);
450 /* PLL enter normal-mode */
451 rk_clrsetreg(&cru
->cru_mode_con
,
452 GPLL_MODE_MASK
<< GPLL_MODE_SHIFT
|
453 CPLL_MODE_MASK
<< CPLL_MODE_SHIFT
,
454 GPLL_MODE_NORMAL
<< GPLL_MODE_SHIFT
|
455 CPLL_MODE_NORMAL
<< CPLL_MODE_SHIFT
);
457 rockchip_mmc_set_clk(cru
, PERI_HCLK_HZ
, HCLK_SDMMC
, 16000000);
461 static ulong
rk3188_clk_get_rate(struct clk
*clk
)
463 struct rk3188_clk_priv
*priv
= dev_get_priv(clk
->dev
);
464 ulong new_rate
, gclk_rate
;
466 gclk_rate
= rkclk_pll_get_rate(priv
->cru
, CLK_GENERAL
);
469 new_rate
= rkclk_pll_get_rate(priv
->cru
, clk
->id
);
477 new_rate
= rockchip_mmc_get_clk(priv
->cru
, PERI_HCLK_HZ
,
482 new_rate
= rockchip_spi_get_clk(priv
->cru
, PERI_PCLK_HZ
,
498 static ulong
rk3188_clk_set_rate(struct clk
*clk
, ulong rate
)
500 struct rk3188_clk_priv
*priv
= dev_get_priv(clk
->dev
);
501 struct rk3188_cru
*cru
= priv
->cru
;
506 new_rate
= rkclk_configure_cpu(priv
->cru
, priv
->grf
, rate
,
510 new_rate
= rkclk_configure_ddr(priv
->cru
, priv
->grf
, rate
,
519 new_rate
= rockchip_mmc_set_clk(cru
, PERI_HCLK_HZ
,
524 new_rate
= rockchip_spi_set_clk(cru
, PERI_PCLK_HZ
,
534 static struct clk_ops rk3188_clk_ops
= {
535 .get_rate
= rk3188_clk_get_rate
,
536 .set_rate
= rk3188_clk_set_rate
,
539 static int rk3188_clk_ofdata_to_platdata(struct udevice
*dev
)
541 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
542 struct rk3188_clk_priv
*priv
= dev_get_priv(dev
);
544 priv
->cru
= (struct rk3188_cru
*)devfdt_get_addr(dev
);
550 static int rk3188_clk_probe(struct udevice
*dev
)
552 struct rk3188_clk_priv
*priv
= dev_get_priv(dev
);
553 enum rk3188_clk_type type
= dev_get_driver_data(dev
);
555 priv
->grf
= syscon_get_first_range(ROCKCHIP_SYSCON_GRF
);
556 if (IS_ERR(priv
->grf
))
557 return PTR_ERR(priv
->grf
);
558 priv
->has_bwadj
= (type
== RK3188A_CRU
) ? 1 : 0;
560 #ifdef CONFIG_SPL_BUILD
561 #if CONFIG_IS_ENABLED(OF_PLATDATA)
562 struct rk3188_clk_plat
*plat
= dev_get_platdata(dev
);
564 priv
->cru
= map_sysmem(plat
->dtd
.reg
[0], plat
->dtd
.reg
[1]);
567 rkclk_init(priv
->cru
, priv
->grf
, priv
->has_bwadj
);
573 static int rk3188_clk_bind(struct udevice
*dev
)
576 struct udevice
*sys_child
;
577 struct sysreset_reg
*priv
;
579 /* The reset driver does not have a device node, so bind it here */
580 ret
= device_bind_driver(dev
, "rockchip_sysreset", "sysreset",
583 debug("Warning: No sysreset driver: ret=%d\n", ret
);
585 priv
= malloc(sizeof(struct sysreset_reg
));
586 priv
->glb_srst_fst_value
= offsetof(struct rk3188_cru
,
587 cru_glb_srst_fst_value
);
588 priv
->glb_srst_snd_value
= offsetof(struct rk3188_cru
,
589 cru_glb_srst_snd_value
);
590 sys_child
->priv
= priv
;
596 static const struct udevice_id rk3188_clk_ids
[] = {
597 { .compatible
= "rockchip,rk3188-cru", .data
= RK3188_CRU
},
598 { .compatible
= "rockchip,rk3188a-cru", .data
= RK3188A_CRU
},
602 U_BOOT_DRIVER(rockchip_rk3188_cru
) = {
603 .name
= "rockchip_rk3188_cru",
605 .of_match
= rk3188_clk_ids
,
606 .priv_auto_alloc_size
= sizeof(struct rk3188_clk_priv
),
607 .platdata_auto_alloc_size
= sizeof(struct rk3188_clk_plat
),
608 .ops
= &rk3188_clk_ops
,
609 .bind
= rk3188_clk_bind
,
610 .ofdata_to_platdata
= rk3188_clk_ofdata_to_platdata
,
611 .probe
= rk3188_clk_probe
,