2 * (C) Copyright 2016 Rockchip Electronics Co., Ltd
3 * Author: Andy Yan <andy.yan@rock-chips.com>
4 * SPDX-License-Identifier: GPL-2.0
8 #include <clk-uclass.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/cru_rv1108.h>
15 #include <asm/arch/hardware.h>
17 #include <dt-bindings/clock/rv1108-cru.h>
19 DECLARE_GLOBAL_DATA_PTR
;
22 VCO_MAX_HZ
= 2400U * 1000000,
23 VCO_MIN_HZ
= 600 * 1000000,
24 OUTPUT_MAX_HZ
= 2400U * 1000000,
25 OUTPUT_MIN_HZ
= 24 * 1000000,
28 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
30 #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
32 .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
33 .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
34 _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
35 OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
36 #hz "Hz cannot be hit with PLL "\
37 "divisors on line " __stringify(__LINE__));
40 static inline int rv1108_pll_id(enum rk_clk_id clk_id
)
53 printf("invalid pll id:%d\n", clk_id
);
61 static uint32_t rkclk_pll_get_rate(struct rv1108_cru
*cru
,
62 enum rk_clk_id clk_id
)
64 uint32_t refdiv
, fbdiv
, postdiv1
, postdiv2
;
65 uint32_t con0
, con1
, con3
;
66 int pll_id
= rv1108_pll_id(clk_id
);
67 struct rv1108_pll
*pll
= &cru
->pll
[pll_id
];
70 con3
= readl(&pll
->con3
);
72 if (con3
& WORK_MODE_MASK
) {
73 con0
= readl(&pll
->con0
);
74 con1
= readl(&pll
->con1
);
75 fbdiv
= (con0
>> FBDIV_SHIFT
) & FBDIV_MASK
;
76 postdiv1
= (con1
& POSTDIV1_MASK
) >> POSTDIV1_SHIFT
;
77 postdiv2
= (con1
& POSTDIV2_MASK
) >> POSTDIV2_SHIFT
;
78 refdiv
= (con1
& REFDIV_MASK
) >> REFDIV_SHIFT
;
79 freq
= (24 * fbdiv
/ (refdiv
* postdiv1
* postdiv2
)) * 1000000;
87 static int rv1108_mac_set_clk(struct rv1108_cru
*cru
, ulong rate
)
89 uint32_t con
= readl(&cru
->clksel_con
[24]);
93 if ((con
>> MAC_PLL_SEL_SHIFT
) & MAC_PLL_SEL_GPLL
)
94 pll_rate
= rkclk_pll_get_rate(cru
, CLK_GENERAL
);
96 pll_rate
= rkclk_pll_get_rate(cru
, CLK_ARM
);
98 /*default set 50MHZ for gmac*/
102 div
= DIV_ROUND_UP(pll_rate
, rate
) - 1;
104 rk_clrsetreg(&cru
->clksel_con
[24], MAC_CLK_DIV_MASK
,
105 div
<< MAC_CLK_DIV_SHIFT
);
107 debug("Unsupported div for gmac:%d\n", div
);
109 return DIV_TO_RATE(pll_rate
, div
);
112 static int rv1108_sfc_set_clk(struct rv1108_cru
*cru
, uint rate
)
114 u32 con
= readl(&cru
->clksel_con
[27]);
118 if ((con
>> SFC_PLL_SEL_SHIFT
) && SFC_PLL_SEL_GPLL
)
119 pll_rate
= rkclk_pll_get_rate(cru
, CLK_GENERAL
);
121 pll_rate
= rkclk_pll_get_rate(cru
, CLK_DDR
);
123 div
= DIV_ROUND_UP(pll_rate
, rate
) - 1;
125 rk_clrsetreg(&cru
->clksel_con
[27], SFC_CLK_DIV_MASK
,
126 div
<< SFC_CLK_DIV_SHIFT
);
128 debug("Unsupported sfc clk rate:%d\n", rate
);
130 return DIV_TO_RATE(pll_rate
, div
);
133 static ulong
rv1108_clk_get_rate(struct clk
*clk
)
135 struct rv1108_clk_priv
*priv
= dev_get_priv(clk
->dev
);
139 return rkclk_pll_get_rate(priv
->cru
, clk
->id
);
145 static ulong
rv1108_clk_set_rate(struct clk
*clk
, ulong rate
)
147 struct rv1108_clk_priv
*priv
= dev_get_priv(clk
->dev
);
152 new_rate
= rv1108_mac_set_clk(priv
->cru
, rate
);
155 new_rate
= rv1108_sfc_set_clk(priv
->cru
, rate
);
164 static const struct clk_ops rv1108_clk_ops
= {
165 .get_rate
= rv1108_clk_get_rate
,
166 .set_rate
= rv1108_clk_set_rate
,
169 static void rkclk_init(struct rv1108_cru
*cru
)
171 unsigned int apll
= rkclk_pll_get_rate(cru
, CLK_ARM
);
172 unsigned int dpll
= rkclk_pll_get_rate(cru
, CLK_DDR
);
173 unsigned int gpll
= rkclk_pll_get_rate(cru
, CLK_GENERAL
);
175 rk_clrsetreg(&cru
->clksel_con
[0], CORE_CLK_DIV_MASK
,
176 0 << MAC_CLK_DIV_SHIFT
);
178 printf("APLL: %d DPLL:%d GPLL:%d\n", apll
, dpll
, gpll
);
181 static int rv1108_clk_probe(struct udevice
*dev
)
183 struct rv1108_clk_priv
*priv
= dev_get_priv(dev
);
185 priv
->cru
= (struct rv1108_cru
*)devfdt_get_addr(dev
);
187 rkclk_init(priv
->cru
);
192 static int rv1108_clk_bind(struct udevice
*dev
)
196 /* The reset driver does not have a device node, so bind it here */
197 ret
= device_bind_driver(gd
->dm_root
, "rv1108_sysreset", "reset", &dev
);
199 error("No Rv1108 reset driver: ret=%d\n", ret
);
204 static const struct udevice_id rv1108_clk_ids
[] = {
205 { .compatible
= "rockchip,rv1108-cru" },
209 U_BOOT_DRIVER(clk_rv1108
) = {
210 .name
= "clk_rv1108",
212 .of_match
= rv1108_clk_ids
,
213 .priv_auto_alloc_size
= sizeof(struct rv1108_clk_priv
),
214 .ops
= &rv1108_clk_ops
,
215 .bind
= rv1108_clk_bind
,
216 .probe
= rv1108_clk_probe
,