2 * (C) Copyright 2016 Rockchip Electronics Co., Ltd
3 * Author: Andy Yan <andy.yan@rock-chips.com>
4 * SPDX-License-Identifier: GPL-2.0
9 #include <clk-uclass.h>
14 #include <asm/arch/clock.h>
15 #include <asm/arch/cru_rv1108.h>
16 #include <asm/arch/hardware.h>
18 #include <dt-bindings/clock/rv1108-cru.h>
20 DECLARE_GLOBAL_DATA_PTR
;
23 VCO_MAX_HZ
= 2400U * 1000000,
24 VCO_MIN_HZ
= 600 * 1000000,
25 OUTPUT_MAX_HZ
= 2400U * 1000000,
26 OUTPUT_MIN_HZ
= 24 * 1000000,
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__));
40 /* use integer mode */
41 static inline int rv1108_pll_id(enum rk_clk_id clk_id
)
54 printf("invalid pll id:%d\n", clk_id
);
62 static uint32_t rkclk_pll_get_rate(struct rv1108_cru
*cru
,
63 enum rk_clk_id clk_id
)
65 uint32_t refdiv
, fbdiv
, postdiv1
, postdiv2
;
66 uint32_t con0
, con1
, con3
;
67 int pll_id
= rv1108_pll_id(clk_id
);
68 struct rv1108_pll
*pll
= &cru
->pll
[pll_id
];
71 con3
= readl(&pll
->con3
);
73 if (con3
& WORK_MODE_MASK
) {
74 con0
= readl(&pll
->con0
);
75 con1
= readl(&pll
->con1
);
76 fbdiv
= (con0
>> FBDIV_SHIFT
) & FBDIV_MASK
;
77 postdiv1
= (con1
& POSTDIV1_MASK
) >> POSTDIV1_SHIFT
;
78 postdiv2
= (con1
& POSTDIV2_MASK
) >> POSTDIV2_SHIFT
;
79 refdiv
= (con1
& REFDIV_MASK
) >> REFDIV_SHIFT
;
80 freq
= (24 * fbdiv
/ (refdiv
* postdiv1
* postdiv2
)) * 1000000;
88 static int rv1108_mac_set_clk(struct rv1108_cru
*cru
, ulong rate
)
90 uint32_t con
= readl(&cru
->clksel_con
[24]);
94 if ((con
>> MAC_PLL_SEL_SHIFT
) & MAC_PLL_SEL_GPLL
)
95 pll_rate
= rkclk_pll_get_rate(cru
, CLK_GENERAL
);
97 pll_rate
= rkclk_pll_get_rate(cru
, CLK_ARM
);
99 /*default set 50MHZ for gmac*/
103 div
= DIV_ROUND_UP(pll_rate
, rate
) - 1;
105 rk_clrsetreg(&cru
->clksel_con
[24], MAC_CLK_DIV_MASK
,
106 div
<< MAC_CLK_DIV_SHIFT
);
108 debug("Unsupported div for gmac:%d\n", div
);
110 return DIV_TO_RATE(pll_rate
, div
);
113 static int rv1108_sfc_set_clk(struct rv1108_cru
*cru
, uint rate
)
115 u32 con
= readl(&cru
->clksel_con
[27]);
119 if ((con
>> SFC_PLL_SEL_SHIFT
) && SFC_PLL_SEL_GPLL
)
120 pll_rate
= rkclk_pll_get_rate(cru
, CLK_GENERAL
);
122 pll_rate
= rkclk_pll_get_rate(cru
, CLK_DDR
);
124 div
= DIV_ROUND_UP(pll_rate
, rate
) - 1;
126 rk_clrsetreg(&cru
->clksel_con
[27], SFC_CLK_DIV_MASK
,
127 div
<< SFC_CLK_DIV_SHIFT
);
129 debug("Unsupported sfc clk rate:%d\n", rate
);
131 return DIV_TO_RATE(pll_rate
, div
);
134 static ulong
rv1108_saradc_get_clk(struct rv1108_cru
*cru
)
138 val
= readl(&cru
->clksel_con
[22]);
139 div
= bitfield_extract(val
, CLK_SARADC_DIV_CON_SHIFT
,
140 CLK_SARADC_DIV_CON_WIDTH
);
142 return DIV_TO_RATE(OSC_HZ
, div
);
145 static ulong
rv1108_saradc_set_clk(struct rv1108_cru
*cru
, uint hz
)
149 src_clk_div
= DIV_ROUND_UP(OSC_HZ
, hz
) - 1;
150 assert(src_clk_div
< 128);
152 rk_clrsetreg(&cru
->clksel_con
[22],
153 CLK_SARADC_DIV_CON_MASK
,
154 src_clk_div
<< CLK_SARADC_DIV_CON_SHIFT
);
156 return rv1108_saradc_get_clk(cru
);
159 static ulong
rv1108_clk_get_rate(struct clk
*clk
)
161 struct rv1108_clk_priv
*priv
= dev_get_priv(clk
->dev
);
165 return rkclk_pll_get_rate(priv
->cru
, clk
->id
);
167 return rv1108_saradc_get_clk(priv
->cru
);
173 static ulong
rv1108_clk_set_rate(struct clk
*clk
, ulong rate
)
175 struct rv1108_clk_priv
*priv
= dev_get_priv(clk
->dev
);
180 new_rate
= rv1108_mac_set_clk(priv
->cru
, rate
);
183 new_rate
= rv1108_sfc_set_clk(priv
->cru
, rate
);
186 new_rate
= rv1108_saradc_set_clk(priv
->cru
, rate
);
195 static const struct clk_ops rv1108_clk_ops
= {
196 .get_rate
= rv1108_clk_get_rate
,
197 .set_rate
= rv1108_clk_set_rate
,
200 static void rkclk_init(struct rv1108_cru
*cru
)
202 unsigned int apll
= rkclk_pll_get_rate(cru
, CLK_ARM
);
203 unsigned int dpll
= rkclk_pll_get_rate(cru
, CLK_DDR
);
204 unsigned int gpll
= rkclk_pll_get_rate(cru
, CLK_GENERAL
);
206 rk_clrsetreg(&cru
->clksel_con
[0], CORE_CLK_DIV_MASK
,
207 0 << MAC_CLK_DIV_SHIFT
);
209 printf("APLL: %d DPLL:%d GPLL:%d\n", apll
, dpll
, gpll
);
212 static int rv1108_clk_probe(struct udevice
*dev
)
214 struct rv1108_clk_priv
*priv
= dev_get_priv(dev
);
216 priv
->cru
= (struct rv1108_cru
*)devfdt_get_addr(dev
);
218 rkclk_init(priv
->cru
);
223 static int rv1108_clk_bind(struct udevice
*dev
)
227 /* The reset driver does not have a device node, so bind it here */
228 ret
= device_bind_driver(gd
->dm_root
, "rv1108_sysreset", "reset", &dev
);
230 pr_err("No Rv1108 reset driver: ret=%d\n", ret
);
235 static const struct udevice_id rv1108_clk_ids
[] = {
236 { .compatible
= "rockchip,rv1108-cru" },
240 U_BOOT_DRIVER(clk_rv1108
) = {
241 .name
= "clk_rv1108",
243 .of_match
= rv1108_clk_ids
,
244 .priv_auto_alloc_size
= sizeof(struct rv1108_clk_priv
),
245 .ops
= &rv1108_clk_ops
,
246 .bind
= rv1108_clk_bind
,
247 .probe
= rv1108_clk_probe
,