xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rv1103b.c (revision 76f3cd6af247bad26c0dcc187a8f150d909cc52c)
1*76f3cd6aSElaine Zhang // SPDX-License-Identifier: GPL-2.0
2*76f3cd6aSElaine Zhang /*
3*76f3cd6aSElaine Zhang  * Copyright (c) 2024 Rockchip Electronics Co., Ltd
4*76f3cd6aSElaine Zhang  * Author: Elaine Zhang <zhangqing@rock-chips.com>
5*76f3cd6aSElaine Zhang  */
6*76f3cd6aSElaine Zhang 
7*76f3cd6aSElaine Zhang #include <common.h>
8*76f3cd6aSElaine Zhang #include <bitfield.h>
9*76f3cd6aSElaine Zhang #include <clk-uclass.h>
10*76f3cd6aSElaine Zhang #include <dm.h>
11*76f3cd6aSElaine Zhang #include <errno.h>
12*76f3cd6aSElaine Zhang #include <syscon.h>
13*76f3cd6aSElaine Zhang #include <asm/arch/clock.h>
14*76f3cd6aSElaine Zhang #include <asm/arch/cru_rv1103b.h>
15*76f3cd6aSElaine Zhang #include <asm/arch/grf_rv1103b.h>
16*76f3cd6aSElaine Zhang #include <asm/arch/hardware.h>
17*76f3cd6aSElaine Zhang #include <asm/io.h>
18*76f3cd6aSElaine Zhang #include <dm/lists.h>
19*76f3cd6aSElaine Zhang #include <dt-bindings/clock/rockchip,rv1103b-cru.h>
20*76f3cd6aSElaine Zhang 
21*76f3cd6aSElaine Zhang DECLARE_GLOBAL_DATA_PTR;
22*76f3cd6aSElaine Zhang 
23*76f3cd6aSElaine Zhang #define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
24*76f3cd6aSElaine Zhang 
25*76f3cd6aSElaine Zhang #ifdef CONFIG_SPL_BUILD
26*76f3cd6aSElaine Zhang #ifndef BITS_WITH_WMASK
27*76f3cd6aSElaine Zhang #define BITS_WITH_WMASK(bits, msk, shift) \
28*76f3cd6aSElaine Zhang 	((bits) << (shift)) | ((msk) << ((shift) + 16))
29*76f3cd6aSElaine Zhang #endif
30*76f3cd6aSElaine Zhang #endif
31*76f3cd6aSElaine Zhang 
32*76f3cd6aSElaine Zhang static struct rockchip_pll_rate_table rv1103b_pll_rates[] = {
33*76f3cd6aSElaine Zhang 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
34*76f3cd6aSElaine Zhang 	RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
35*76f3cd6aSElaine Zhang 	RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
36*76f3cd6aSElaine Zhang 	{ /* sentinel */ },
37*76f3cd6aSElaine Zhang };
38*76f3cd6aSElaine Zhang 
39*76f3cd6aSElaine Zhang static struct rockchip_pll_clock rv1103b_pll_clks[] = {
40*76f3cd6aSElaine Zhang 	[GPLL] = PLL(pll_rk3328, PLL_GPLL, RV1103B_PLL_CON(24),
41*76f3cd6aSElaine Zhang 		     RV1103B_MODE_CON, 0, 10, 0, rv1103b_pll_rates),
42*76f3cd6aSElaine Zhang };
43*76f3cd6aSElaine Zhang 
44*76f3cd6aSElaine Zhang #ifndef CONFIG_SPL_BUILD
45*76f3cd6aSElaine Zhang #define RV1103B_CLK_DUMP(_id, _name, _iscru)	\
46*76f3cd6aSElaine Zhang {						\
47*76f3cd6aSElaine Zhang 	.id = _id,				\
48*76f3cd6aSElaine Zhang 	.name = _name,				\
49*76f3cd6aSElaine Zhang 	.is_cru = _iscru,			\
50*76f3cd6aSElaine Zhang }
51*76f3cd6aSElaine Zhang 
52*76f3cd6aSElaine Zhang static const struct rv1103b_clk_info clks_dump[] = {
53*76f3cd6aSElaine Zhang 	RV1103B_CLK_DUMP(PLL_GPLL, "gpll", true),
54*76f3cd6aSElaine Zhang 	RV1103B_CLK_DUMP(ACLK_PERI_SRC, "aclk_peri_src", true),
55*76f3cd6aSElaine Zhang 	RV1103B_CLK_DUMP(LSCLK_PERI_SRC, "lsclk_peri_src", true),
56*76f3cd6aSElaine Zhang 	RV1103B_CLK_DUMP(PCLK_PERI_ROOT, "pclk_peri_root", true),
57*76f3cd6aSElaine Zhang 	RV1103B_CLK_DUMP(PCLK_TOP_ROOT, "pclk_top_root", true),
58*76f3cd6aSElaine Zhang 	RV1103B_CLK_DUMP(LSCLK_PMU_ROOT, "lsclk_pmu_root", true),
59*76f3cd6aSElaine Zhang };
60*76f3cd6aSElaine Zhang #endif
61*76f3cd6aSElaine Zhang 
rv1103b_peri_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)62*76f3cd6aSElaine Zhang static ulong rv1103b_peri_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
63*76f3cd6aSElaine Zhang {
64*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
65*76f3cd6aSElaine Zhang 	u32 con, sel, div, rate, prate;
66*76f3cd6aSElaine Zhang 
67*76f3cd6aSElaine Zhang 	switch (clk_id) {
68*76f3cd6aSElaine Zhang 	case ACLK_PERI_SRC:
69*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[31]);
70*76f3cd6aSElaine Zhang 		sel = (con & ACLK_PERI_SEL_MASK) >> ACLK_PERI_SEL_SHIFT;
71*76f3cd6aSElaine Zhang 		if (sel == ACLK_PERI_SEL_600M)
72*76f3cd6aSElaine Zhang 			rate = 600 * MHz;
73*76f3cd6aSElaine Zhang 		else if (sel == ACLK_PERI_SEL_480M)
74*76f3cd6aSElaine Zhang 			rate = 480 * MHz;
75*76f3cd6aSElaine Zhang 		else
76*76f3cd6aSElaine Zhang 			rate = 400 * MHz;
77*76f3cd6aSElaine Zhang 		break;
78*76f3cd6aSElaine Zhang 	case LSCLK_PERI_SRC:
79*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[31]);
80*76f3cd6aSElaine Zhang 		sel = (con & LSCLK_PERI_SEL_MASK) >> LSCLK_PERI_SEL_SHIFT;
81*76f3cd6aSElaine Zhang 		if (sel == LSCLK_PERI_SEL_300M)
82*76f3cd6aSElaine Zhang 			rate = 300 * MHz;
83*76f3cd6aSElaine Zhang 		else
84*76f3cd6aSElaine Zhang 			rate = 200 * MHz;
85*76f3cd6aSElaine Zhang 		break;
86*76f3cd6aSElaine Zhang 	case PCLK_PERI_ROOT:
87*76f3cd6aSElaine Zhang 		con = readl(&cru->peri_clksel_con[0]);
88*76f3cd6aSElaine Zhang 		div = (con & PCLK_PERI_DIV_MASK) >> PCLK_PERI_DIV_SHIFT;
89*76f3cd6aSElaine Zhang 		rate = DIV_TO_RATE(rv1103b_peri_get_clk(priv, LSCLK_PERI_SRC),
90*76f3cd6aSElaine Zhang 				   div);
91*76f3cd6aSElaine Zhang 		break;
92*76f3cd6aSElaine Zhang 	case PCLK_TOP_ROOT:
93*76f3cd6aSElaine Zhang 		rate = DIV_TO_RATE(priv->gpll_hz, 11);
94*76f3cd6aSElaine Zhang 		break;
95*76f3cd6aSElaine Zhang 	case LSCLK_PMU_ROOT:
96*76f3cd6aSElaine Zhang 	case PCLK_PMU:
97*76f3cd6aSElaine Zhang 		con = readl(&cru->pmu_clksel_con[2]);
98*76f3cd6aSElaine Zhang 		sel = (con & LSCLK_PMU_SEL_MASK) >> LSCLK_PMU_SEL_SHIFT;
99*76f3cd6aSElaine Zhang 		div = (con & LSCLK_PMU_DIV_MASK) >> LSCLK_PMU_DIV_SHIFT;
100*76f3cd6aSElaine Zhang 		if (sel == LSCLK_PMU_SEL_24M)
101*76f3cd6aSElaine Zhang 			prate = OSC_HZ;
102*76f3cd6aSElaine Zhang 		else
103*76f3cd6aSElaine Zhang 			prate = RC_OSC_HZ;
104*76f3cd6aSElaine Zhang 		rate = DIV_TO_RATE(prate, div);
105*76f3cd6aSElaine Zhang 		break;
106*76f3cd6aSElaine Zhang 	default:
107*76f3cd6aSElaine Zhang 		return -ENOENT;
108*76f3cd6aSElaine Zhang 	}
109*76f3cd6aSElaine Zhang 
110*76f3cd6aSElaine Zhang 	return rate;
111*76f3cd6aSElaine Zhang }
112*76f3cd6aSElaine Zhang 
rv1103b_peri_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)113*76f3cd6aSElaine Zhang static ulong rv1103b_peri_set_clk(struct rv1103b_clk_priv *priv,
114*76f3cd6aSElaine Zhang 				  ulong clk_id, ulong rate)
115*76f3cd6aSElaine Zhang {
116*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
117*76f3cd6aSElaine Zhang 	int src_clk, div;
118*76f3cd6aSElaine Zhang 
119*76f3cd6aSElaine Zhang 	switch (clk_id) {
120*76f3cd6aSElaine Zhang 	case ACLK_PERI_SRC:
121*76f3cd6aSElaine Zhang 		if (rate >= 594 * MHz)
122*76f3cd6aSElaine Zhang 			src_clk = ACLK_PERI_SEL_600M;
123*76f3cd6aSElaine Zhang 		else if (rate >= 480 * MHz)
124*76f3cd6aSElaine Zhang 			src_clk = ACLK_PERI_SEL_480M;
125*76f3cd6aSElaine Zhang 		else
126*76f3cd6aSElaine Zhang 			src_clk = ACLK_PERI_SEL_400M;
127*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[31],
128*76f3cd6aSElaine Zhang 			     ACLK_PERI_SEL_MASK,
129*76f3cd6aSElaine Zhang 			     src_clk << ACLK_PERI_SEL_SHIFT);
130*76f3cd6aSElaine Zhang 		break;
131*76f3cd6aSElaine Zhang 	case LSCLK_PERI_SRC:
132*76f3cd6aSElaine Zhang 		if (rate >= 297 * MHz)
133*76f3cd6aSElaine Zhang 			src_clk = LSCLK_PERI_SEL_300M;
134*76f3cd6aSElaine Zhang 		else
135*76f3cd6aSElaine Zhang 			src_clk = LSCLK_PERI_SEL_200M;
136*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[31],
137*76f3cd6aSElaine Zhang 			     LSCLK_PERI_SEL_MASK,
138*76f3cd6aSElaine Zhang 			     src_clk << LSCLK_PERI_SEL_SHIFT);
139*76f3cd6aSElaine Zhang 		break;
140*76f3cd6aSElaine Zhang 	case PCLK_PERI_ROOT:
141*76f3cd6aSElaine Zhang 		div = DIV_ROUND_UP(rv1103b_peri_get_clk(priv, LSCLK_PERI_SRC),
142*76f3cd6aSElaine Zhang 				   rate);
143*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->peri_clksel_con[0],
144*76f3cd6aSElaine Zhang 			     PCLK_PERI_DIV_MASK,
145*76f3cd6aSElaine Zhang 			     (div - 1) << PCLK_PERI_DIV_SHIFT);
146*76f3cd6aSElaine Zhang 		break;
147*76f3cd6aSElaine Zhang 	case PCLK_TOP_ROOT:
148*76f3cd6aSElaine Zhang 		break;
149*76f3cd6aSElaine Zhang 	case LSCLK_PMU_ROOT:
150*76f3cd6aSElaine Zhang 	case PCLK_PMU:
151*76f3cd6aSElaine Zhang 		if (!(OSC_HZ % rate)) {
152*76f3cd6aSElaine Zhang 			src_clk = LSCLK_PMU_SEL_24M;
153*76f3cd6aSElaine Zhang 			div = DIV_ROUND_UP(OSC_HZ, rate);
154*76f3cd6aSElaine Zhang 		} else {
155*76f3cd6aSElaine Zhang 			src_clk = LSCLK_PMU_SEL_RC_OSC;
156*76f3cd6aSElaine Zhang 			div = DIV_ROUND_UP(RC_OSC_HZ, rate);
157*76f3cd6aSElaine Zhang 		}
158*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->pmu_clksel_con[2],
159*76f3cd6aSElaine Zhang 			     LSCLK_PMU_SEL_MASK | LSCLK_PMU_DIV_MASK,
160*76f3cd6aSElaine Zhang 			     (src_clk << LSCLK_PMU_SEL_SHIFT) |
161*76f3cd6aSElaine Zhang 			     ((div - 1) << LSCLK_PMU_DIV_SHIFT));
162*76f3cd6aSElaine Zhang 		break;
163*76f3cd6aSElaine Zhang 	default:
164*76f3cd6aSElaine Zhang 		printf("do not support this permid freq\n");
165*76f3cd6aSElaine Zhang 		return -EINVAL;
166*76f3cd6aSElaine Zhang 	}
167*76f3cd6aSElaine Zhang 
168*76f3cd6aSElaine Zhang 	return rv1103b_peri_get_clk(priv, clk_id);
169*76f3cd6aSElaine Zhang }
170*76f3cd6aSElaine Zhang 
rv1103b_i2c_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)171*76f3cd6aSElaine Zhang static ulong rv1103b_i2c_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
172*76f3cd6aSElaine Zhang {
173*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
174*76f3cd6aSElaine Zhang 	u32 sel, con;
175*76f3cd6aSElaine Zhang 	ulong rate;
176*76f3cd6aSElaine Zhang 
177*76f3cd6aSElaine Zhang 	switch (clk_id) {
178*76f3cd6aSElaine Zhang 	case CLK_I2C1:
179*76f3cd6aSElaine Zhang 	case CLK_I2C2:
180*76f3cd6aSElaine Zhang 	case CLK_I2C3:
181*76f3cd6aSElaine Zhang 	case CLK_I2C4:
182*76f3cd6aSElaine Zhang 	case CLK_I2C_PERI:
183*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[34]);
184*76f3cd6aSElaine Zhang 		sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT;
185*76f3cd6aSElaine Zhang 		break;
186*76f3cd6aSElaine Zhang 	case CLK_I2C0:
187*76f3cd6aSElaine Zhang 	case CLK_I2C_PMU:
188*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[34]);
189*76f3cd6aSElaine Zhang 		sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT;
190*76f3cd6aSElaine Zhang 		break;
191*76f3cd6aSElaine Zhang 	default:
192*76f3cd6aSElaine Zhang 		return -ENOENT;
193*76f3cd6aSElaine Zhang 	}
194*76f3cd6aSElaine Zhang 
195*76f3cd6aSElaine Zhang 	if (sel == CLK_I2C_SEL_100M)
196*76f3cd6aSElaine Zhang 		rate = 100 * MHz;
197*76f3cd6aSElaine Zhang 	else
198*76f3cd6aSElaine Zhang 		rate = OSC_HZ;
199*76f3cd6aSElaine Zhang 
200*76f3cd6aSElaine Zhang 	return rate;
201*76f3cd6aSElaine Zhang }
202*76f3cd6aSElaine Zhang 
rv1103b_crypto_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)203*76f3cd6aSElaine Zhang static ulong rv1103b_crypto_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
204*76f3cd6aSElaine Zhang {
205*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
206*76f3cd6aSElaine Zhang 	u32 sel, con, rate;
207*76f3cd6aSElaine Zhang 
208*76f3cd6aSElaine Zhang 	switch (clk_id) {
209*76f3cd6aSElaine Zhang 	case ACLK_CRYPTO:
210*76f3cd6aSElaine Zhang 	case HCLK_CRYPTO:
211*76f3cd6aSElaine Zhang 	case HCLK_RK_RNG_NS:
212*76f3cd6aSElaine Zhang 	case HCLK_RK_RNG_S:
213*76f3cd6aSElaine Zhang 		return rv1103b_peri_get_clk(priv, LSCLK_PERI_SRC);
214*76f3cd6aSElaine Zhang 	case CLK_CORE_CRYPTO:
215*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[35]);
216*76f3cd6aSElaine Zhang 		sel = (con & CLK_CORE_CRYPTO_SEL_MASK) >>
217*76f3cd6aSElaine Zhang 		      CLK_CORE_CRYPTO_SEL_SHIFT;
218*76f3cd6aSElaine Zhang 		break;
219*76f3cd6aSElaine Zhang 	case CLK_PKA_CRYPTO:
220*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[35]);
221*76f3cd6aSElaine Zhang 		sel = (con & CLK_PKA_CRYPTO_SEL_MASK) >>
222*76f3cd6aSElaine Zhang 		      CLK_PKA_CRYPTO_SEL_SHIFT;
223*76f3cd6aSElaine Zhang 		break;
224*76f3cd6aSElaine Zhang 	default:
225*76f3cd6aSElaine Zhang 		return -ENOENT;
226*76f3cd6aSElaine Zhang 	}
227*76f3cd6aSElaine Zhang 	if (sel == CLK_CORE_CRYPTO_SEL_300M)
228*76f3cd6aSElaine Zhang 		rate = 300 * MHz;
229*76f3cd6aSElaine Zhang 	else if (sel == CLK_CORE_CRYPTO_SEL_200M)
230*76f3cd6aSElaine Zhang 		rate = 200 * MHz;
231*76f3cd6aSElaine Zhang 	else
232*76f3cd6aSElaine Zhang 		rate = 100 * MHz;
233*76f3cd6aSElaine Zhang 
234*76f3cd6aSElaine Zhang 	return rate;
235*76f3cd6aSElaine Zhang 
236*76f3cd6aSElaine Zhang }
237*76f3cd6aSElaine Zhang 
rv1103b_crypto_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)238*76f3cd6aSElaine Zhang static ulong rv1103b_crypto_set_clk(struct rv1103b_clk_priv *priv,
239*76f3cd6aSElaine Zhang 				    ulong clk_id, ulong rate)
240*76f3cd6aSElaine Zhang {
241*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
242*76f3cd6aSElaine Zhang 	u32 sel;
243*76f3cd6aSElaine Zhang 
244*76f3cd6aSElaine Zhang 	if (rate >= 297 * MHz)
245*76f3cd6aSElaine Zhang 		sel = CLK_CORE_CRYPTO_SEL_300M;
246*76f3cd6aSElaine Zhang 	else if (rate >= 198 * MHz)
247*76f3cd6aSElaine Zhang 		sel = CLK_CORE_CRYPTO_SEL_200M;
248*76f3cd6aSElaine Zhang 	else
249*76f3cd6aSElaine Zhang 		sel = CLK_CORE_CRYPTO_SEL_100M;
250*76f3cd6aSElaine Zhang 
251*76f3cd6aSElaine Zhang 	switch (clk_id) {
252*76f3cd6aSElaine Zhang 	case ACLK_CRYPTO:
253*76f3cd6aSElaine Zhang 	case HCLK_CRYPTO:
254*76f3cd6aSElaine Zhang 	case HCLK_RK_RNG_NS:
255*76f3cd6aSElaine Zhang 	case HCLK_RK_RNG_S:
256*76f3cd6aSElaine Zhang 		rv1103b_peri_set_clk(priv, LSCLK_PERI_SRC, rate);
257*76f3cd6aSElaine Zhang 	case CLK_CORE_CRYPTO:
258*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[35],
259*76f3cd6aSElaine Zhang 			     CLK_CORE_CRYPTO_SEL_MASK,
260*76f3cd6aSElaine Zhang 			     (sel << CLK_CORE_CRYPTO_SEL_SHIFT));
261*76f3cd6aSElaine Zhang 		break;
262*76f3cd6aSElaine Zhang 	case CLK_PKA_CRYPTO:
263*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[35],
264*76f3cd6aSElaine Zhang 			     CLK_PKA_CRYPTO_SEL_MASK,
265*76f3cd6aSElaine Zhang 			     (sel << CLK_PKA_CRYPTO_SEL_SHIFT));
266*76f3cd6aSElaine Zhang 		break;
267*76f3cd6aSElaine Zhang 	default:
268*76f3cd6aSElaine Zhang 		return -ENOENT;
269*76f3cd6aSElaine Zhang 	}
270*76f3cd6aSElaine Zhang 	return rv1103b_crypto_get_clk(priv, clk_id);
271*76f3cd6aSElaine Zhang }
272*76f3cd6aSElaine Zhang 
rv1103b_mmc_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)273*76f3cd6aSElaine Zhang static ulong rv1103b_mmc_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
274*76f3cd6aSElaine Zhang {
275*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
276*76f3cd6aSElaine Zhang 	u32 div, sel, con, prate;
277*76f3cd6aSElaine Zhang 
278*76f3cd6aSElaine Zhang 	switch (clk_id) {
279*76f3cd6aSElaine Zhang 	case CCLK_SDMMC1:
280*76f3cd6aSElaine Zhang 	case HCLK_SDMMC1:
281*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[36]);
282*76f3cd6aSElaine Zhang 		sel = (con & CLK_SDMMC_SEL_MASK) >>
283*76f3cd6aSElaine Zhang 		      CLK_SDMMC_SEL_SHIFT;
284*76f3cd6aSElaine Zhang 		div = (con & CLK_SDMMC_DIV_MASK) >>
285*76f3cd6aSElaine Zhang 		      CLK_SDMMC_DIV_SHIFT;
286*76f3cd6aSElaine Zhang 		if (sel == CLK_MMC_SEL_GPLL)
287*76f3cd6aSElaine Zhang 			prate = priv->gpll_hz;
288*76f3cd6aSElaine Zhang 		else
289*76f3cd6aSElaine Zhang 			prate = OSC_HZ;
290*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(prate, div);
291*76f3cd6aSElaine Zhang 	case CCLK_SDMMC0:
292*76f3cd6aSElaine Zhang 	case HCLK_SDMMC0:
293*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[32]);
294*76f3cd6aSElaine Zhang 		sel = (con & CLK_SDMMC_SEL_MASK) >>
295*76f3cd6aSElaine Zhang 		      CLK_SDMMC_SEL_SHIFT;
296*76f3cd6aSElaine Zhang 		div = (con & CLK_SDMMC_DIV_MASK) >>
297*76f3cd6aSElaine Zhang 		      CLK_SDMMC_DIV_SHIFT;
298*76f3cd6aSElaine Zhang 		if (sel == CLK_MMC_SEL_GPLL)
299*76f3cd6aSElaine Zhang 			prate = priv->gpll_hz;
300*76f3cd6aSElaine Zhang 		else
301*76f3cd6aSElaine Zhang 			prate = OSC_HZ;
302*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(prate, div);
303*76f3cd6aSElaine Zhang 	case CCLK_EMMC:
304*76f3cd6aSElaine Zhang 	case HCLK_EMMC:
305*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[31]);
306*76f3cd6aSElaine Zhang 		sel = (con & CLK_EMMC_SEL_MASK) >>
307*76f3cd6aSElaine Zhang 		      CLK_EMMC_SEL_SHIFT;
308*76f3cd6aSElaine Zhang 		div = (con & CLK_EMMC_DIV_MASK) >>
309*76f3cd6aSElaine Zhang 		      CLK_EMMC_DIV_SHIFT;
310*76f3cd6aSElaine Zhang 		if (sel == CLK_MMC_SEL_GPLL)
311*76f3cd6aSElaine Zhang 			prate = priv->gpll_hz;
312*76f3cd6aSElaine Zhang 		else
313*76f3cd6aSElaine Zhang 			prate = OSC_HZ;
314*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(prate, div);
315*76f3cd6aSElaine Zhang 	case SCLK_SFC_2X:
316*76f3cd6aSElaine Zhang 	case HCLK_SFC:
317*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[33]);
318*76f3cd6aSElaine Zhang 		sel = (con & CLK_SFC_SEL_MASK) >>
319*76f3cd6aSElaine Zhang 		      CLK_SFC_SEL_SHIFT;
320*76f3cd6aSElaine Zhang 		div = (con & CLK_SFC_DIV_MASK) >>
321*76f3cd6aSElaine Zhang 		      CLK_SFC_DIV_SHIFT;
322*76f3cd6aSElaine Zhang 		if (sel == CLK_MMC_SEL_GPLL)
323*76f3cd6aSElaine Zhang 			prate = priv->gpll_hz;
324*76f3cd6aSElaine Zhang 		else
325*76f3cd6aSElaine Zhang 			prate = OSC_HZ;
326*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(prate, div);
327*76f3cd6aSElaine Zhang 	default:
328*76f3cd6aSElaine Zhang 		return -ENOENT;
329*76f3cd6aSElaine Zhang 	}
330*76f3cd6aSElaine Zhang }
331*76f3cd6aSElaine Zhang 
rv1103b_mmc_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)332*76f3cd6aSElaine Zhang static ulong rv1103b_mmc_set_clk(struct rv1103b_clk_priv *priv,
333*76f3cd6aSElaine Zhang 				 ulong clk_id, ulong rate)
334*76f3cd6aSElaine Zhang {
335*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
336*76f3cd6aSElaine Zhang 	u32 sel, src_clk_div;
337*76f3cd6aSElaine Zhang 	ulong prate = 0;
338*76f3cd6aSElaine Zhang 
339*76f3cd6aSElaine Zhang 	if ((OSC_HZ % rate) == 0) {
340*76f3cd6aSElaine Zhang 		sel = CLK_MMC_SEL_OSC;
341*76f3cd6aSElaine Zhang 		prate = OSC_HZ;
342*76f3cd6aSElaine Zhang 	} else {
343*76f3cd6aSElaine Zhang 		sel = CLK_MMC_SEL_GPLL;
344*76f3cd6aSElaine Zhang 		prate = priv->gpll_hz;
345*76f3cd6aSElaine Zhang 	}
346*76f3cd6aSElaine Zhang 	src_clk_div = DIV_ROUND_UP(prate, rate);
347*76f3cd6aSElaine Zhang 
348*76f3cd6aSElaine Zhang 	switch (clk_id) {
349*76f3cd6aSElaine Zhang 	case CCLK_SDMMC1:
350*76f3cd6aSElaine Zhang 	case HCLK_SDMMC1:
351*76f3cd6aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(prate, rate);
352*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[36],
353*76f3cd6aSElaine Zhang 			     CLK_SDMMC_SEL_MASK |
354*76f3cd6aSElaine Zhang 			     CLK_SDMMC_DIV_MASK,
355*76f3cd6aSElaine Zhang 			     (sel << CLK_SDMMC_SEL_SHIFT) |
356*76f3cd6aSElaine Zhang 			     ((src_clk_div - 1) <<
357*76f3cd6aSElaine Zhang 			      CLK_SDMMC_DIV_SHIFT));
358*76f3cd6aSElaine Zhang 		break;
359*76f3cd6aSElaine Zhang 	case CCLK_SDMMC0:
360*76f3cd6aSElaine Zhang 	case HCLK_SDMMC0:
361*76f3cd6aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(prate, rate);
362*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[32],
363*76f3cd6aSElaine Zhang 			     CLK_SDMMC_SEL_MASK |
364*76f3cd6aSElaine Zhang 			     CLK_SDMMC_DIV_MASK,
365*76f3cd6aSElaine Zhang 			     (sel << CLK_SDMMC_SEL_SHIFT) |
366*76f3cd6aSElaine Zhang 			     ((src_clk_div - 1) <<
367*76f3cd6aSElaine Zhang 			      CLK_SDMMC_DIV_SHIFT));
368*76f3cd6aSElaine Zhang 		break;
369*76f3cd6aSElaine Zhang 	case CCLK_EMMC:
370*76f3cd6aSElaine Zhang 	case HCLK_EMMC:
371*76f3cd6aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(prate, rate);
372*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[31],
373*76f3cd6aSElaine Zhang 			     CLK_EMMC_SEL_MASK |
374*76f3cd6aSElaine Zhang 			     CLK_EMMC_DIV_MASK,
375*76f3cd6aSElaine Zhang 			     (sel << CLK_EMMC_SEL_SHIFT) |
376*76f3cd6aSElaine Zhang 			     ((src_clk_div - 1) <<
377*76f3cd6aSElaine Zhang 			      CLK_EMMC_DIV_SHIFT));
378*76f3cd6aSElaine Zhang 		break;
379*76f3cd6aSElaine Zhang 	case SCLK_SFC_2X:
380*76f3cd6aSElaine Zhang 	case HCLK_SFC:
381*76f3cd6aSElaine Zhang 		src_clk_div = DIV_ROUND_UP(prate, rate);
382*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[33],
383*76f3cd6aSElaine Zhang 			     CLK_SFC_SEL_MASK |
384*76f3cd6aSElaine Zhang 			     CLK_SFC_DIV_MASK,
385*76f3cd6aSElaine Zhang 			     (sel << CLK_SFC_SEL_SHIFT) |
386*76f3cd6aSElaine Zhang 			     ((src_clk_div - 1) <<
387*76f3cd6aSElaine Zhang 			      CLK_SFC_DIV_SHIFT));
388*76f3cd6aSElaine Zhang 		break;
389*76f3cd6aSElaine Zhang 	default:
390*76f3cd6aSElaine Zhang 		return -ENOENT;
391*76f3cd6aSElaine Zhang 	}
392*76f3cd6aSElaine Zhang 	return rv1103b_mmc_get_clk(priv, clk_id);
393*76f3cd6aSElaine Zhang }
394*76f3cd6aSElaine Zhang 
rv1103b_i2c_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)395*76f3cd6aSElaine Zhang static ulong rv1103b_i2c_set_clk(struct rv1103b_clk_priv *priv, ulong clk_id,
396*76f3cd6aSElaine Zhang 				 ulong rate)
397*76f3cd6aSElaine Zhang {
398*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
399*76f3cd6aSElaine Zhang 	int src_clk;
400*76f3cd6aSElaine Zhang 
401*76f3cd6aSElaine Zhang 	if (rate == OSC_HZ)
402*76f3cd6aSElaine Zhang 		src_clk = CLK_I2C_SEL_24M;
403*76f3cd6aSElaine Zhang 	else
404*76f3cd6aSElaine Zhang 		src_clk = CLK_I2C_SEL_100M;
405*76f3cd6aSElaine Zhang 
406*76f3cd6aSElaine Zhang 	switch (clk_id) {
407*76f3cd6aSElaine Zhang 	case CLK_I2C1:
408*76f3cd6aSElaine Zhang 	case CLK_I2C2:
409*76f3cd6aSElaine Zhang 	case CLK_I2C3:
410*76f3cd6aSElaine Zhang 	case CLK_I2C4:
411*76f3cd6aSElaine Zhang 	case CLK_I2C_PERI:
412*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[34], CLK_I2C1_SEL_MASK,
413*76f3cd6aSElaine Zhang 			     src_clk << CLK_I2C1_SEL_SHIFT);
414*76f3cd6aSElaine Zhang 		break;
415*76f3cd6aSElaine Zhang 	case CLK_I2C0:
416*76f3cd6aSElaine Zhang 	case CLK_I2C_PMU:
417*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[34], CLK_I2C0_SEL_MASK,
418*76f3cd6aSElaine Zhang 			     src_clk << CLK_I2C0_SEL_SHIFT);
419*76f3cd6aSElaine Zhang 		break;
420*76f3cd6aSElaine Zhang 	default:
421*76f3cd6aSElaine Zhang 		return -ENOENT;
422*76f3cd6aSElaine Zhang 	}
423*76f3cd6aSElaine Zhang 	return rv1103b_i2c_get_clk(priv, clk_id);
424*76f3cd6aSElaine Zhang }
425*76f3cd6aSElaine Zhang 
rv1103b_spi_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)426*76f3cd6aSElaine Zhang static ulong rv1103b_spi_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
427*76f3cd6aSElaine Zhang {
428*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
429*76f3cd6aSElaine Zhang 	u32 sel, con, rate;
430*76f3cd6aSElaine Zhang 
431*76f3cd6aSElaine Zhang 	switch (clk_id) {
432*76f3cd6aSElaine Zhang 	case CLK_SPI0:
433*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[34]);
434*76f3cd6aSElaine Zhang 		sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
435*76f3cd6aSElaine Zhang 		break;
436*76f3cd6aSElaine Zhang 	default:
437*76f3cd6aSElaine Zhang 		return -ENOENT;
438*76f3cd6aSElaine Zhang 	}
439*76f3cd6aSElaine Zhang 	if (sel == CLK_SPI0_SEL_200M)
440*76f3cd6aSElaine Zhang 		rate = 200 * MHz;
441*76f3cd6aSElaine Zhang 	else if (sel == CLK_SPI0_SEL_100M)
442*76f3cd6aSElaine Zhang 		rate = 100 * MHz;
443*76f3cd6aSElaine Zhang 	else if (sel == CLK_SPI0_SEL_50M)
444*76f3cd6aSElaine Zhang 		rate = 50 * MHz;
445*76f3cd6aSElaine Zhang 	else
446*76f3cd6aSElaine Zhang 		rate = OSC_HZ;
447*76f3cd6aSElaine Zhang 
448*76f3cd6aSElaine Zhang 	return rate;
449*76f3cd6aSElaine Zhang }
450*76f3cd6aSElaine Zhang 
rv1103b_spi_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)451*76f3cd6aSElaine Zhang static ulong rv1103b_spi_set_clk(struct rv1103b_clk_priv *priv,
452*76f3cd6aSElaine Zhang 				 ulong clk_id, ulong rate)
453*76f3cd6aSElaine Zhang {
454*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
455*76f3cd6aSElaine Zhang 	int src_clk;
456*76f3cd6aSElaine Zhang 
457*76f3cd6aSElaine Zhang 	if (rate >= 198 * MHz)
458*76f3cd6aSElaine Zhang 		src_clk = CLK_SPI0_SEL_200M;
459*76f3cd6aSElaine Zhang 	else if (rate >= 99 * MHz)
460*76f3cd6aSElaine Zhang 		src_clk = CLK_SPI0_SEL_100M;
461*76f3cd6aSElaine Zhang 	else if (rate >= 48 * MHz)
462*76f3cd6aSElaine Zhang 		src_clk = CLK_SPI0_SEL_50M;
463*76f3cd6aSElaine Zhang 	else
464*76f3cd6aSElaine Zhang 		src_clk = CLK_SPI0_SEL_24M;
465*76f3cd6aSElaine Zhang 
466*76f3cd6aSElaine Zhang 	switch (clk_id) {
467*76f3cd6aSElaine Zhang 	case CLK_SPI0:
468*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[34], CLK_SPI0_SEL_MASK,
469*76f3cd6aSElaine Zhang 			     src_clk << CLK_SPI0_SEL_SHIFT);
470*76f3cd6aSElaine Zhang 		break;
471*76f3cd6aSElaine Zhang 	default:
472*76f3cd6aSElaine Zhang 		return -ENOENT;
473*76f3cd6aSElaine Zhang 	}
474*76f3cd6aSElaine Zhang 
475*76f3cd6aSElaine Zhang 	return rv1103b_spi_get_clk(priv, clk_id);
476*76f3cd6aSElaine Zhang }
477*76f3cd6aSElaine Zhang 
rv1103b_pwm_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)478*76f3cd6aSElaine Zhang static ulong rv1103b_pwm_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
479*76f3cd6aSElaine Zhang {
480*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
481*76f3cd6aSElaine Zhang 	u32 sel, con;
482*76f3cd6aSElaine Zhang 
483*76f3cd6aSElaine Zhang 	switch (clk_id) {
484*76f3cd6aSElaine Zhang 	case CLK_PWM0:
485*76f3cd6aSElaine Zhang 	case CLK_PWM0_SRC:
486*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[34]);
487*76f3cd6aSElaine Zhang 		sel = (con & CLK_PWM0_SEL_MASK) >> CLK_PWM0_SEL_SHIFT;
488*76f3cd6aSElaine Zhang 		break;
489*76f3cd6aSElaine Zhang 	case CLK_PWM1:
490*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[34]);
491*76f3cd6aSElaine Zhang 		sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
492*76f3cd6aSElaine Zhang 		break;
493*76f3cd6aSElaine Zhang 	case CLK_PWM2:
494*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[34]);
495*76f3cd6aSElaine Zhang 		sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT;
496*76f3cd6aSElaine Zhang 		break;
497*76f3cd6aSElaine Zhang 	default:
498*76f3cd6aSElaine Zhang 		return -ENOENT;
499*76f3cd6aSElaine Zhang 	}
500*76f3cd6aSElaine Zhang 
501*76f3cd6aSElaine Zhang 	switch (sel) {
502*76f3cd6aSElaine Zhang 	case CLK_PWM_SEL_100M:
503*76f3cd6aSElaine Zhang 		return 100 * MHz;
504*76f3cd6aSElaine Zhang 	case CLK_PWM_SEL_24M:
505*76f3cd6aSElaine Zhang 		return OSC_HZ;
506*76f3cd6aSElaine Zhang 	default:
507*76f3cd6aSElaine Zhang 		return -ENOENT;
508*76f3cd6aSElaine Zhang 	}
509*76f3cd6aSElaine Zhang }
510*76f3cd6aSElaine Zhang 
rv1103b_pwm_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)511*76f3cd6aSElaine Zhang static ulong rv1103b_pwm_set_clk(struct rv1103b_clk_priv *priv,
512*76f3cd6aSElaine Zhang 				 ulong clk_id, ulong rate)
513*76f3cd6aSElaine Zhang {
514*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
515*76f3cd6aSElaine Zhang 	int src_clk;
516*76f3cd6aSElaine Zhang 
517*76f3cd6aSElaine Zhang 	if (rate >= 99 * MHz)
518*76f3cd6aSElaine Zhang 		src_clk = CLK_PWM_SEL_100M;
519*76f3cd6aSElaine Zhang 	else
520*76f3cd6aSElaine Zhang 		src_clk = CLK_PWM_SEL_24M;
521*76f3cd6aSElaine Zhang 
522*76f3cd6aSElaine Zhang 	switch (clk_id) {
523*76f3cd6aSElaine Zhang 	case CLK_PWM0:
524*76f3cd6aSElaine Zhang 	case CLK_PWM0_SRC:
525*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[34],
526*76f3cd6aSElaine Zhang 			     CLK_PWM0_SEL_MASK,
527*76f3cd6aSElaine Zhang 			     src_clk << CLK_PWM0_SEL_SHIFT);
528*76f3cd6aSElaine Zhang 		break;
529*76f3cd6aSElaine Zhang 	case CLK_PWM1:
530*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[34],
531*76f3cd6aSElaine Zhang 			     CLK_PWM1_SEL_MASK,
532*76f3cd6aSElaine Zhang 			     src_clk << CLK_PWM1_SEL_SHIFT);
533*76f3cd6aSElaine Zhang 		break;
534*76f3cd6aSElaine Zhang 	case CLK_PWM2:
535*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[34],
536*76f3cd6aSElaine Zhang 			     CLK_PWM2_SEL_MASK,
537*76f3cd6aSElaine Zhang 			     src_clk << CLK_PWM2_SEL_SHIFT);
538*76f3cd6aSElaine Zhang 		break;
539*76f3cd6aSElaine Zhang 	default:
540*76f3cd6aSElaine Zhang 		return -ENOENT;
541*76f3cd6aSElaine Zhang 	}
542*76f3cd6aSElaine Zhang 
543*76f3cd6aSElaine Zhang 	return rv1103b_pwm_get_clk(priv, clk_id);
544*76f3cd6aSElaine Zhang }
545*76f3cd6aSElaine Zhang 
rv1103b_adc_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)546*76f3cd6aSElaine Zhang static ulong rv1103b_adc_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
547*76f3cd6aSElaine Zhang {
548*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
549*76f3cd6aSElaine Zhang 	u32 div, con;
550*76f3cd6aSElaine Zhang 
551*76f3cd6aSElaine Zhang 	switch (clk_id) {
552*76f3cd6aSElaine Zhang 	case CLK_SARADC:
553*76f3cd6aSElaine Zhang 		con = readl(&cru->peri_clksel_con[1]);
554*76f3cd6aSElaine Zhang 		div = (con & CLK_SARADC_DIV_MASK) >>
555*76f3cd6aSElaine Zhang 		      CLK_SARADC_DIV_SHIFT;
556*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(OSC_HZ, div);
557*76f3cd6aSElaine Zhang 	case CLK_TSADC_TSEN:
558*76f3cd6aSElaine Zhang 		con = readl(&cru->peri_clksel_con[0]);
559*76f3cd6aSElaine Zhang 		div = (con & CLK_TSADC_TSEN_DIV_MASK) >>
560*76f3cd6aSElaine Zhang 		      CLK_TSADC_TSEN_DIV_SHIFT;
561*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(OSC_HZ, div);
562*76f3cd6aSElaine Zhang 	case CLK_TSADC:
563*76f3cd6aSElaine Zhang 		con = readl(&cru->peri_clksel_con[0]);
564*76f3cd6aSElaine Zhang 		div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT;
565*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(OSC_HZ, div);
566*76f3cd6aSElaine Zhang 	default:
567*76f3cd6aSElaine Zhang 		return -ENOENT;
568*76f3cd6aSElaine Zhang 	}
569*76f3cd6aSElaine Zhang }
570*76f3cd6aSElaine Zhang 
rv1103b_adc_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)571*76f3cd6aSElaine Zhang static ulong rv1103b_adc_set_clk(struct rv1103b_clk_priv *priv,
572*76f3cd6aSElaine Zhang 				 ulong clk_id, ulong rate)
573*76f3cd6aSElaine Zhang {
574*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
575*76f3cd6aSElaine Zhang 	int src_clk_div;
576*76f3cd6aSElaine Zhang 
577*76f3cd6aSElaine Zhang 	src_clk_div = DIV_ROUND_UP(OSC_HZ, rate);
578*76f3cd6aSElaine Zhang 
579*76f3cd6aSElaine Zhang 	switch (clk_id) {
580*76f3cd6aSElaine Zhang 	case CLK_SARADC:
581*76f3cd6aSElaine Zhang 		assert(src_clk_div - 1 <= 7);
582*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->peri_clksel_con[1],
583*76f3cd6aSElaine Zhang 			     CLK_SARADC_DIV_MASK,
584*76f3cd6aSElaine Zhang 			     (src_clk_div - 1) <<
585*76f3cd6aSElaine Zhang 			     CLK_SARADC_DIV_SHIFT);
586*76f3cd6aSElaine Zhang 		break;
587*76f3cd6aSElaine Zhang 	case CLK_TSADC_TSEN:
588*76f3cd6aSElaine Zhang 		assert(src_clk_div - 1 <= 32);
589*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->peri_clksel_con[0],
590*76f3cd6aSElaine Zhang 			     CLK_TSADC_TSEN_DIV_MASK,
591*76f3cd6aSElaine Zhang 			     (src_clk_div - 1) <<
592*76f3cd6aSElaine Zhang 			     CLK_TSADC_TSEN_DIV_SHIFT);
593*76f3cd6aSElaine Zhang 		break;
594*76f3cd6aSElaine Zhang 	case CLK_TSADC:
595*76f3cd6aSElaine Zhang 		assert(src_clk_div - 1 <= 32);
596*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->peri_clksel_con[0],
597*76f3cd6aSElaine Zhang 			     CLK_TSADC_DIV_MASK,
598*76f3cd6aSElaine Zhang 			     (src_clk_div - 1) <<
599*76f3cd6aSElaine Zhang 			     CLK_TSADC_DIV_SHIFT);
600*76f3cd6aSElaine Zhang 		break;
601*76f3cd6aSElaine Zhang 	default:
602*76f3cd6aSElaine Zhang 		return -ENOENT;
603*76f3cd6aSElaine Zhang 	}
604*76f3cd6aSElaine Zhang 	return rv1103b_adc_get_clk(priv, clk_id);
605*76f3cd6aSElaine Zhang }
606*76f3cd6aSElaine Zhang 
607*76f3cd6aSElaine Zhang /*
608*76f3cd6aSElaine Zhang  *
609*76f3cd6aSElaine Zhang  * rational_best_approximation(31415, 10000,
610*76f3cd6aSElaine Zhang  *		(1 << 8) - 1, (1 << 5) - 1, &n, &d);
611*76f3cd6aSElaine Zhang  *
612*76f3cd6aSElaine Zhang  * you may look at given_numerator as a fixed point number,
613*76f3cd6aSElaine Zhang  * with the fractional part size described in given_denominator.
614*76f3cd6aSElaine Zhang  *
615*76f3cd6aSElaine Zhang  * for theoretical background, see:
616*76f3cd6aSElaine Zhang  * http://en.wikipedia.org/wiki/Continued_fraction
617*76f3cd6aSElaine Zhang  */
rational_best_approximation(unsigned long given_numerator,unsigned long given_denominator,unsigned long max_numerator,unsigned long max_denominator,unsigned long * best_numerator,unsigned long * best_denominator)618*76f3cd6aSElaine Zhang static void rational_best_approximation(unsigned long given_numerator,
619*76f3cd6aSElaine Zhang 					unsigned long given_denominator,
620*76f3cd6aSElaine Zhang 					unsigned long max_numerator,
621*76f3cd6aSElaine Zhang 					unsigned long max_denominator,
622*76f3cd6aSElaine Zhang 					unsigned long *best_numerator,
623*76f3cd6aSElaine Zhang 					unsigned long *best_denominator)
624*76f3cd6aSElaine Zhang {
625*76f3cd6aSElaine Zhang 	unsigned long n, d, n0, d0, n1, d1;
626*76f3cd6aSElaine Zhang 
627*76f3cd6aSElaine Zhang 	n = given_numerator;
628*76f3cd6aSElaine Zhang 	d = given_denominator;
629*76f3cd6aSElaine Zhang 	n0 = 0;
630*76f3cd6aSElaine Zhang 	d1 = 0;
631*76f3cd6aSElaine Zhang 	n1 = 1;
632*76f3cd6aSElaine Zhang 	d0 = 1;
633*76f3cd6aSElaine Zhang 	for (;;) {
634*76f3cd6aSElaine Zhang 		unsigned long t, a;
635*76f3cd6aSElaine Zhang 
636*76f3cd6aSElaine Zhang 		if (n1 > max_numerator || d1 > max_denominator) {
637*76f3cd6aSElaine Zhang 			n1 = n0;
638*76f3cd6aSElaine Zhang 			d1 = d0;
639*76f3cd6aSElaine Zhang 			break;
640*76f3cd6aSElaine Zhang 		}
641*76f3cd6aSElaine Zhang 		if (d == 0)
642*76f3cd6aSElaine Zhang 			break;
643*76f3cd6aSElaine Zhang 		t = d;
644*76f3cd6aSElaine Zhang 		a = n / d;
645*76f3cd6aSElaine Zhang 		d = n % d;
646*76f3cd6aSElaine Zhang 		n = t;
647*76f3cd6aSElaine Zhang 		t = n0 + a * n1;
648*76f3cd6aSElaine Zhang 		n0 = n1;
649*76f3cd6aSElaine Zhang 		n1 = t;
650*76f3cd6aSElaine Zhang 		t = d0 + a * d1;
651*76f3cd6aSElaine Zhang 		d0 = d1;
652*76f3cd6aSElaine Zhang 		d1 = t;
653*76f3cd6aSElaine Zhang 	}
654*76f3cd6aSElaine Zhang 	*best_numerator = n1;
655*76f3cd6aSElaine Zhang 	*best_denominator = d1;
656*76f3cd6aSElaine Zhang }
657*76f3cd6aSElaine Zhang 
rv1103b_uart_get_rate(struct rv1103b_clk_priv * priv,ulong clk_id)658*76f3cd6aSElaine Zhang static ulong rv1103b_uart_get_rate(struct rv1103b_clk_priv *priv, ulong clk_id)
659*76f3cd6aSElaine Zhang {
660*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
661*76f3cd6aSElaine Zhang 	u32 reg, con, fracdiv, div, src, p_rate;
662*76f3cd6aSElaine Zhang 	unsigned long m, n;
663*76f3cd6aSElaine Zhang 
664*76f3cd6aSElaine Zhang 	switch (clk_id) {
665*76f3cd6aSElaine Zhang 	case SCLK_UART0:
666*76f3cd6aSElaine Zhang 		reg = 10;
667*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[32]);
668*76f3cd6aSElaine Zhang 		src = (con & CLK_UART0_SEL_MASK) >> CLK_UART0_SEL_SHIFT;
669*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[5]);
670*76f3cd6aSElaine Zhang 		div = (con & CLK_UART0_SRC_DIV_MASK) >> CLK_UART0_SRC_DIV_SHIFT;
671*76f3cd6aSElaine Zhang 		break;
672*76f3cd6aSElaine Zhang 	case SCLK_UART1:
673*76f3cd6aSElaine Zhang 		reg = 11;
674*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[32]);
675*76f3cd6aSElaine Zhang 		src = (con & CLK_UART1_SEL_MASK) >> CLK_UART1_SEL_SHIFT;
676*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[5]);
677*76f3cd6aSElaine Zhang 		div = (con & CLK_UART1_SRC_DIV_MASK) >> CLK_UART1_SRC_DIV_SHIFT;
678*76f3cd6aSElaine Zhang 		break;
679*76f3cd6aSElaine Zhang 	case SCLK_UART2:
680*76f3cd6aSElaine Zhang 		reg = 12;
681*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[32]);
682*76f3cd6aSElaine Zhang 		src = (con & CLK_UART2_SEL_MASK) >> CLK_UART2_SEL_SHIFT;
683*76f3cd6aSElaine Zhang 		con = readl(&cru->clksel_con[5]);
684*76f3cd6aSElaine Zhang 		div = (con & CLK_UART2_SRC_DIV_MASK) >> CLK_UART2_SRC_DIV_SHIFT;
685*76f3cd6aSElaine Zhang 		break;
686*76f3cd6aSElaine Zhang 	default:
687*76f3cd6aSElaine Zhang 		return -ENOENT;
688*76f3cd6aSElaine Zhang 	}
689*76f3cd6aSElaine Zhang 
690*76f3cd6aSElaine Zhang 	p_rate = priv->gpll_hz;
691*76f3cd6aSElaine Zhang 	if (src == CLK_UART_SEL_SRC) {
692*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(p_rate, div);
693*76f3cd6aSElaine Zhang 	} else if (src == CLK_UART_SEL_FRAC) {
694*76f3cd6aSElaine Zhang 		fracdiv = readl(&cru->clksel_con[reg]);
695*76f3cd6aSElaine Zhang 		n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK;
696*76f3cd6aSElaine Zhang 		n >>= CLK_UART_FRAC_NUMERATOR_SHIFT;
697*76f3cd6aSElaine Zhang 		m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK;
698*76f3cd6aSElaine Zhang 		m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT;
699*76f3cd6aSElaine Zhang 		return DIV_TO_RATE(p_rate, div) * n / m;
700*76f3cd6aSElaine Zhang 	} else {
701*76f3cd6aSElaine Zhang 		return OSC_HZ;
702*76f3cd6aSElaine Zhang 	}
703*76f3cd6aSElaine Zhang }
704*76f3cd6aSElaine Zhang 
rv1103b_uart_set_rate(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)705*76f3cd6aSElaine Zhang static ulong rv1103b_uart_set_rate(struct rv1103b_clk_priv *priv,
706*76f3cd6aSElaine Zhang 				   ulong clk_id, ulong rate)
707*76f3cd6aSElaine Zhang {
708*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
709*76f3cd6aSElaine Zhang 	u32 reg, uart_src, div;
710*76f3cd6aSElaine Zhang 	unsigned long m = 0, n = 0, val;
711*76f3cd6aSElaine Zhang 
712*76f3cd6aSElaine Zhang 	if (priv->gpll_hz % rate == 0) {
713*76f3cd6aSElaine Zhang 		uart_src = CLK_UART_SEL_SRC;
714*76f3cd6aSElaine Zhang 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
715*76f3cd6aSElaine Zhang 	} else if (rate == OSC_HZ) {
716*76f3cd6aSElaine Zhang 		uart_src = CLK_UART_SEL_OSC;
717*76f3cd6aSElaine Zhang 		div = 2;
718*76f3cd6aSElaine Zhang 	} else {
719*76f3cd6aSElaine Zhang 		uart_src = CLK_UART_SEL_FRAC;
720*76f3cd6aSElaine Zhang 		div = 2;
721*76f3cd6aSElaine Zhang 		rational_best_approximation(rate, priv->gpll_hz / div,
722*76f3cd6aSElaine Zhang 					    GENMASK(16 - 1, 0),
723*76f3cd6aSElaine Zhang 					    GENMASK(16 - 1, 0),
724*76f3cd6aSElaine Zhang 					    &m, &n);
725*76f3cd6aSElaine Zhang 	}
726*76f3cd6aSElaine Zhang 
727*76f3cd6aSElaine Zhang 	switch (clk_id) {
728*76f3cd6aSElaine Zhang 	case SCLK_UART0:
729*76f3cd6aSElaine Zhang 		reg = 10;
730*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[5],
731*76f3cd6aSElaine Zhang 			     CLK_UART0_SRC_DIV_MASK,
732*76f3cd6aSElaine Zhang 			     div << CLK_UART0_SRC_DIV_SHIFT);
733*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[32],
734*76f3cd6aSElaine Zhang 			     CLK_UART0_SEL_MASK,
735*76f3cd6aSElaine Zhang 			     uart_src << CLK_UART0_SEL_SHIFT);
736*76f3cd6aSElaine Zhang 		break;
737*76f3cd6aSElaine Zhang 	case SCLK_UART1:
738*76f3cd6aSElaine Zhang 		reg = 11;
739*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[5],
740*76f3cd6aSElaine Zhang 			     CLK_UART1_SRC_DIV_MASK,
741*76f3cd6aSElaine Zhang 			     div << CLK_UART1_SRC_DIV_SHIFT);
742*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[32],
743*76f3cd6aSElaine Zhang 			     CLK_UART1_SEL_MASK,
744*76f3cd6aSElaine Zhang 			     uart_src << CLK_UART1_SEL_SHIFT);
745*76f3cd6aSElaine Zhang 		break;
746*76f3cd6aSElaine Zhang 	case SCLK_UART2:
747*76f3cd6aSElaine Zhang 		reg = 12;
748*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[5],
749*76f3cd6aSElaine Zhang 			     CLK_UART2_SRC_DIV_MASK,
750*76f3cd6aSElaine Zhang 			     div << CLK_UART2_SRC_DIV_SHIFT);
751*76f3cd6aSElaine Zhang 		rk_clrsetreg(&cru->clksel_con[32],
752*76f3cd6aSElaine Zhang 			     CLK_UART2_SEL_MASK,
753*76f3cd6aSElaine Zhang 			     uart_src << CLK_UART2_SEL_SHIFT);
754*76f3cd6aSElaine Zhang 		break;
755*76f3cd6aSElaine Zhang 	default:
756*76f3cd6aSElaine Zhang 		return -ENOENT;
757*76f3cd6aSElaine Zhang 	}
758*76f3cd6aSElaine Zhang 	if (m && n) {
759*76f3cd6aSElaine Zhang 		val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n;
760*76f3cd6aSElaine Zhang 		writel(val, &cru->clksel_con[reg]);
761*76f3cd6aSElaine Zhang 	}
762*76f3cd6aSElaine Zhang 
763*76f3cd6aSElaine Zhang 	return rv1103b_uart_get_rate(priv, clk_id);
764*76f3cd6aSElaine Zhang }
765*76f3cd6aSElaine Zhang 
rv1103b_decom_get_clk(struct rv1103b_clk_priv * priv)766*76f3cd6aSElaine Zhang static ulong rv1103b_decom_get_clk(struct rv1103b_clk_priv *priv)
767*76f3cd6aSElaine Zhang {
768*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
769*76f3cd6aSElaine Zhang 	u32 sel, con, prate;
770*76f3cd6aSElaine Zhang 
771*76f3cd6aSElaine Zhang 	con = readl(&cru->clksel_con[35]);
772*76f3cd6aSElaine Zhang 	sel = (con & DCLK_DECOM_SEL_MASK) >>
773*76f3cd6aSElaine Zhang 	      DCLK_DECOM_SEL_SHIFT;
774*76f3cd6aSElaine Zhang 	if (sel == DCLK_DECOM_SEL_480M)
775*76f3cd6aSElaine Zhang 		prate = 480 * MHz;
776*76f3cd6aSElaine Zhang 	else if (sel == DCLK_DECOM_SEL_400M)
777*76f3cd6aSElaine Zhang 		prate = 400 * MHz;
778*76f3cd6aSElaine Zhang 	else
779*76f3cd6aSElaine Zhang 		prate = 300 * MHz;
780*76f3cd6aSElaine Zhang 	return prate;
781*76f3cd6aSElaine Zhang }
782*76f3cd6aSElaine Zhang 
rv1103b_decom_set_clk(struct rv1103b_clk_priv * priv,ulong rate)783*76f3cd6aSElaine Zhang static ulong rv1103b_decom_set_clk(struct rv1103b_clk_priv *priv, ulong rate)
784*76f3cd6aSElaine Zhang {
785*76f3cd6aSElaine Zhang 	struct rv1103b_cru *cru = priv->cru;
786*76f3cd6aSElaine Zhang 	u32 sel;
787*76f3cd6aSElaine Zhang 
788*76f3cd6aSElaine Zhang 	if (rate >= 480 * MHz)
789*76f3cd6aSElaine Zhang 		sel = DCLK_DECOM_SEL_480M;
790*76f3cd6aSElaine Zhang 	else if (rate >= 396 * MHz)
791*76f3cd6aSElaine Zhang 		sel = DCLK_DECOM_SEL_400M;
792*76f3cd6aSElaine Zhang 	else
793*76f3cd6aSElaine Zhang 		sel = DCLK_DECOM_SEL_300M;
794*76f3cd6aSElaine Zhang 	rk_clrsetreg(&cru->clksel_con[35], DCLK_DECOM_SEL_MASK,
795*76f3cd6aSElaine Zhang 		     (sel << DCLK_DECOM_SEL_SHIFT));
796*76f3cd6aSElaine Zhang 
797*76f3cd6aSElaine Zhang 	return rv1103b_decom_get_clk(priv);
798*76f3cd6aSElaine Zhang }
799*76f3cd6aSElaine Zhang 
rv1103b_clk_get_rate(struct clk * clk)800*76f3cd6aSElaine Zhang static ulong rv1103b_clk_get_rate(struct clk *clk)
801*76f3cd6aSElaine Zhang {
802*76f3cd6aSElaine Zhang 	struct rv1103b_clk_priv *priv = dev_get_priv(clk->dev);
803*76f3cd6aSElaine Zhang 	ulong rate = 0;
804*76f3cd6aSElaine Zhang 
805*76f3cd6aSElaine Zhang 	if (!priv->gpll_hz) {
806*76f3cd6aSElaine Zhang 		printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
807*76f3cd6aSElaine Zhang 		return -ENOENT;
808*76f3cd6aSElaine Zhang 	}
809*76f3cd6aSElaine Zhang 
810*76f3cd6aSElaine Zhang 	switch (clk->id) {
811*76f3cd6aSElaine Zhang 	case PLL_GPLL:
812*76f3cd6aSElaine Zhang 		rate = rockchip_pll_get_rate(&rv1103b_pll_clks[GPLL], priv->cru,
813*76f3cd6aSElaine Zhang 					     GPLL);
814*76f3cd6aSElaine Zhang 		break;
815*76f3cd6aSElaine Zhang 	case ACLK_PERI_SRC:
816*76f3cd6aSElaine Zhang 	case LSCLK_PERI_SRC:
817*76f3cd6aSElaine Zhang 	case PCLK_PERI_ROOT:
818*76f3cd6aSElaine Zhang 	case PCLK_TOP_ROOT:
819*76f3cd6aSElaine Zhang 	case LSCLK_PMU_ROOT:
820*76f3cd6aSElaine Zhang 	case PCLK_PMU:
821*76f3cd6aSElaine Zhang 		rate = rv1103b_peri_get_clk(priv, clk->id);
822*76f3cd6aSElaine Zhang 		break;
823*76f3cd6aSElaine Zhang 	case ACLK_CRYPTO:
824*76f3cd6aSElaine Zhang 	case HCLK_CRYPTO:
825*76f3cd6aSElaine Zhang 	case HCLK_RK_RNG_NS:
826*76f3cd6aSElaine Zhang 	case HCLK_RK_RNG_S:
827*76f3cd6aSElaine Zhang 	case CLK_CORE_CRYPTO:
828*76f3cd6aSElaine Zhang 	case CLK_PKA_CRYPTO:
829*76f3cd6aSElaine Zhang 		rate = rv1103b_crypto_get_clk(priv, clk->id);
830*76f3cd6aSElaine Zhang 		break;
831*76f3cd6aSElaine Zhang 	case CCLK_SDMMC1:
832*76f3cd6aSElaine Zhang 	case HCLK_SDMMC1:
833*76f3cd6aSElaine Zhang 	case CCLK_SDMMC0:
834*76f3cd6aSElaine Zhang 	case HCLK_SDMMC0:
835*76f3cd6aSElaine Zhang 	case CCLK_EMMC:
836*76f3cd6aSElaine Zhang 	case HCLK_EMMC:
837*76f3cd6aSElaine Zhang 	case SCLK_SFC_2X:
838*76f3cd6aSElaine Zhang 	case HCLK_SFC:
839*76f3cd6aSElaine Zhang 		rate = rv1103b_mmc_get_clk(priv, clk->id);
840*76f3cd6aSElaine Zhang 		break;
841*76f3cd6aSElaine Zhang 	case CLK_I2C1:
842*76f3cd6aSElaine Zhang 	case CLK_I2C2:
843*76f3cd6aSElaine Zhang 	case CLK_I2C3:
844*76f3cd6aSElaine Zhang 	case CLK_I2C4:
845*76f3cd6aSElaine Zhang 	case CLK_I2C_PERI:
846*76f3cd6aSElaine Zhang 	case CLK_I2C0:
847*76f3cd6aSElaine Zhang 	case CLK_I2C_PMU:
848*76f3cd6aSElaine Zhang 		rate = rv1103b_i2c_get_clk(priv, clk->id);
849*76f3cd6aSElaine Zhang 		break;
850*76f3cd6aSElaine Zhang 	case CLK_SPI0:
851*76f3cd6aSElaine Zhang 		rate = rv1103b_spi_get_clk(priv, clk->id);
852*76f3cd6aSElaine Zhang 		break;
853*76f3cd6aSElaine Zhang 	case CLK_PWM0:
854*76f3cd6aSElaine Zhang 	case CLK_PWM0_SRC:
855*76f3cd6aSElaine Zhang 	case CLK_PWM1:
856*76f3cd6aSElaine Zhang 	case CLK_PWM2:
857*76f3cd6aSElaine Zhang 		rate = rv1103b_pwm_get_clk(priv, clk->id);
858*76f3cd6aSElaine Zhang 		break;
859*76f3cd6aSElaine Zhang 	case CLK_SARADC:
860*76f3cd6aSElaine Zhang 	case CLK_TSADC_TSEN:
861*76f3cd6aSElaine Zhang 	case CLK_TSADC:
862*76f3cd6aSElaine Zhang 		rate = rv1103b_adc_get_clk(priv, clk->id);
863*76f3cd6aSElaine Zhang 		break;
864*76f3cd6aSElaine Zhang 	case SCLK_UART0:
865*76f3cd6aSElaine Zhang 	case SCLK_UART1:
866*76f3cd6aSElaine Zhang 	case SCLK_UART2:
867*76f3cd6aSElaine Zhang 		rate = rv1103b_uart_get_rate(priv, clk->id);
868*76f3cd6aSElaine Zhang 		break;
869*76f3cd6aSElaine Zhang 	case DCLK_DECOM_SRC:
870*76f3cd6aSElaine Zhang 	case DCLK_DECOM:
871*76f3cd6aSElaine Zhang 		rate = rv1103b_decom_get_clk(priv);
872*76f3cd6aSElaine Zhang 		break;
873*76f3cd6aSElaine Zhang 	case TCLK_WDT_LPMCU:
874*76f3cd6aSElaine Zhang 	case TCLK_WDT_HPMCU:
875*76f3cd6aSElaine Zhang 	case TCLK_WDT_NS:
876*76f3cd6aSElaine Zhang 	case TCLK_WDT_S:
877*76f3cd6aSElaine Zhang 		rate = OSC_HZ;
878*76f3cd6aSElaine Zhang 		break;
879*76f3cd6aSElaine Zhang 	default:
880*76f3cd6aSElaine Zhang 		return -ENOENT;
881*76f3cd6aSElaine Zhang 	}
882*76f3cd6aSElaine Zhang 
883*76f3cd6aSElaine Zhang 	return rate;
884*76f3cd6aSElaine Zhang };
885*76f3cd6aSElaine Zhang 
rv1103b_clk_set_rate(struct clk * clk,ulong rate)886*76f3cd6aSElaine Zhang static ulong rv1103b_clk_set_rate(struct clk *clk, ulong rate)
887*76f3cd6aSElaine Zhang {
888*76f3cd6aSElaine Zhang 	struct rv1103b_clk_priv *priv = dev_get_priv(clk->dev);
889*76f3cd6aSElaine Zhang 	ulong ret = 0;
890*76f3cd6aSElaine Zhang 
891*76f3cd6aSElaine Zhang 	if (!priv->gpll_hz) {
892*76f3cd6aSElaine Zhang 		printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
893*76f3cd6aSElaine Zhang 		return -ENOENT;
894*76f3cd6aSElaine Zhang 	}
895*76f3cd6aSElaine Zhang 
896*76f3cd6aSElaine Zhang 	switch (clk->id) {
897*76f3cd6aSElaine Zhang 	case PLL_GPLL:
898*76f3cd6aSElaine Zhang 		ret = rockchip_pll_set_rate(&rv1103b_pll_clks[GPLL], priv->cru,
899*76f3cd6aSElaine Zhang 					    GPLL, rate);
900*76f3cd6aSElaine Zhang 		break;
901*76f3cd6aSElaine Zhang 	case ACLK_PERI_SRC:
902*76f3cd6aSElaine Zhang 	case LSCLK_PERI_SRC:
903*76f3cd6aSElaine Zhang 	case PCLK_PERI_ROOT:
904*76f3cd6aSElaine Zhang 	case PCLK_TOP_ROOT:
905*76f3cd6aSElaine Zhang 	case LSCLK_PMU_ROOT:
906*76f3cd6aSElaine Zhang 	case PCLK_PMU:
907*76f3cd6aSElaine Zhang 		ret = rv1103b_peri_set_clk(priv, clk->id, rate);
908*76f3cd6aSElaine Zhang 		break;
909*76f3cd6aSElaine Zhang 	case ACLK_CRYPTO:
910*76f3cd6aSElaine Zhang 	case HCLK_CRYPTO:
911*76f3cd6aSElaine Zhang 	case HCLK_RK_RNG_NS:
912*76f3cd6aSElaine Zhang 	case HCLK_RK_RNG_S:
913*76f3cd6aSElaine Zhang 	case CLK_CORE_CRYPTO:
914*76f3cd6aSElaine Zhang 	case CLK_PKA_CRYPTO:
915*76f3cd6aSElaine Zhang 		ret = rv1103b_crypto_set_clk(priv, clk->id, rate);
916*76f3cd6aSElaine Zhang 		break;
917*76f3cd6aSElaine Zhang 	case CCLK_SDMMC1:
918*76f3cd6aSElaine Zhang 	case HCLK_SDMMC1:
919*76f3cd6aSElaine Zhang 	case CCLK_SDMMC0:
920*76f3cd6aSElaine Zhang 	case HCLK_SDMMC0:
921*76f3cd6aSElaine Zhang 	case CCLK_EMMC:
922*76f3cd6aSElaine Zhang 	case HCLK_EMMC:
923*76f3cd6aSElaine Zhang 	case SCLK_SFC_2X:
924*76f3cd6aSElaine Zhang 	case HCLK_SFC:
925*76f3cd6aSElaine Zhang 		ret = rv1103b_mmc_set_clk(priv, clk->id, rate);
926*76f3cd6aSElaine Zhang 		break;
927*76f3cd6aSElaine Zhang 	case CLK_I2C1:
928*76f3cd6aSElaine Zhang 	case CLK_I2C2:
929*76f3cd6aSElaine Zhang 	case CLK_I2C3:
930*76f3cd6aSElaine Zhang 	case CLK_I2C4:
931*76f3cd6aSElaine Zhang 	case CLK_I2C_PERI:
932*76f3cd6aSElaine Zhang 	case CLK_I2C0:
933*76f3cd6aSElaine Zhang 	case CLK_I2C_PMU:
934*76f3cd6aSElaine Zhang 		ret = rv1103b_i2c_set_clk(priv, clk->id, rate);
935*76f3cd6aSElaine Zhang 		break;
936*76f3cd6aSElaine Zhang 	case CLK_SPI0:
937*76f3cd6aSElaine Zhang 		ret = rv1103b_spi_set_clk(priv, clk->id, rate);
938*76f3cd6aSElaine Zhang 		break;
939*76f3cd6aSElaine Zhang 	case CLK_PWM0:
940*76f3cd6aSElaine Zhang 	case CLK_PWM0_SRC:
941*76f3cd6aSElaine Zhang 	case CLK_PWM1:
942*76f3cd6aSElaine Zhang 	case CLK_PWM2:
943*76f3cd6aSElaine Zhang 		ret = rv1103b_pwm_set_clk(priv, clk->id, rate);
944*76f3cd6aSElaine Zhang 		break;
945*76f3cd6aSElaine Zhang 	case CLK_SARADC:
946*76f3cd6aSElaine Zhang 	case CLK_TSADC_TSEN:
947*76f3cd6aSElaine Zhang 	case CLK_TSADC:
948*76f3cd6aSElaine Zhang 		ret = rv1103b_adc_set_clk(priv, clk->id, rate);
949*76f3cd6aSElaine Zhang 		break;
950*76f3cd6aSElaine Zhang 	case SCLK_UART0:
951*76f3cd6aSElaine Zhang 	case SCLK_UART1:
952*76f3cd6aSElaine Zhang 	case SCLK_UART2:
953*76f3cd6aSElaine Zhang 		ret = rv1103b_uart_set_rate(priv, clk->id, rate);
954*76f3cd6aSElaine Zhang 		break;
955*76f3cd6aSElaine Zhang 	case DCLK_DECOM_SRC:
956*76f3cd6aSElaine Zhang 	case DCLK_DECOM:
957*76f3cd6aSElaine Zhang 		rate = rv1103b_decom_set_clk(priv, rate);
958*76f3cd6aSElaine Zhang 		break;
959*76f3cd6aSElaine Zhang 	default:
960*76f3cd6aSElaine Zhang 		return -ENOENT;
961*76f3cd6aSElaine Zhang 	}
962*76f3cd6aSElaine Zhang 
963*76f3cd6aSElaine Zhang 	return ret;
964*76f3cd6aSElaine Zhang };
965*76f3cd6aSElaine Zhang 
rv1103b_clk_set_parent(struct clk * clk,struct clk * parent)966*76f3cd6aSElaine Zhang static int rv1103b_clk_set_parent(struct clk *clk, struct clk *parent)
967*76f3cd6aSElaine Zhang {
968*76f3cd6aSElaine Zhang 	switch (clk->id) {
969*76f3cd6aSElaine Zhang 	default:
970*76f3cd6aSElaine Zhang 		return -ENOENT;
971*76f3cd6aSElaine Zhang 	}
972*76f3cd6aSElaine Zhang 
973*76f3cd6aSElaine Zhang 	return 0;
974*76f3cd6aSElaine Zhang }
975*76f3cd6aSElaine Zhang 
976*76f3cd6aSElaine Zhang static struct clk_ops rv1103b_clk_ops = {
977*76f3cd6aSElaine Zhang 	.get_rate = rv1103b_clk_get_rate,
978*76f3cd6aSElaine Zhang 	.set_rate = rv1103b_clk_set_rate,
979*76f3cd6aSElaine Zhang #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
980*76f3cd6aSElaine Zhang 	.set_parent = rv1103b_clk_set_parent,
981*76f3cd6aSElaine Zhang #endif
982*76f3cd6aSElaine Zhang };
983*76f3cd6aSElaine Zhang 
rv1103b_clk_init(struct rv1103b_clk_priv * priv)984*76f3cd6aSElaine Zhang static void rv1103b_clk_init(struct rv1103b_clk_priv *priv)
985*76f3cd6aSElaine Zhang {
986*76f3cd6aSElaine Zhang 	int ret;
987*76f3cd6aSElaine Zhang 	u32 div;
988*76f3cd6aSElaine Zhang 
989*76f3cd6aSElaine Zhang 	priv->sync_kernel = false;
990*76f3cd6aSElaine Zhang 	priv->gpll_hz = rockchip_pll_get_rate(&rv1103b_pll_clks[GPLL],
991*76f3cd6aSElaine Zhang 					      priv->cru, GPLL);
992*76f3cd6aSElaine Zhang 	if (priv->gpll_hz != GPLL_HZ) {
993*76f3cd6aSElaine Zhang 		ret = rockchip_pll_set_rate(&rv1103b_pll_clks[GPLL], priv->cru,
994*76f3cd6aSElaine Zhang 					    GPLL, GPLL_HZ);
995*76f3cd6aSElaine Zhang 		if (!ret)
996*76f3cd6aSElaine Zhang 			priv->gpll_hz = GPLL_HZ;
997*76f3cd6aSElaine Zhang 	}
998*76f3cd6aSElaine Zhang     	if (!priv->armclk_enter_hz) {
999*76f3cd6aSElaine Zhang 		div = (readl(&priv->cru->clksel_con[37]) &
1000*76f3cd6aSElaine Zhang 		       CLK_CORE_GPLL_DIV_MASK) >>
1001*76f3cd6aSElaine Zhang 		      CLK_CORE_GPLL_DIV_SHIFT;
1002*76f3cd6aSElaine Zhang 		priv->armclk_enter_hz = DIV_TO_RATE(priv->gpll_hz, div);
1003*76f3cd6aSElaine Zhang 		priv->armclk_init_hz = priv->armclk_enter_hz;
1004*76f3cd6aSElaine Zhang 	}
1005*76f3cd6aSElaine Zhang }
1006*76f3cd6aSElaine Zhang 
rv1103b_clk_probe(struct udevice * dev)1007*76f3cd6aSElaine Zhang static int rv1103b_clk_probe(struct udevice *dev)
1008*76f3cd6aSElaine Zhang {
1009*76f3cd6aSElaine Zhang 	struct rv1103b_clk_priv *priv = dev_get_priv(dev);
1010*76f3cd6aSElaine Zhang 	int ret;
1011*76f3cd6aSElaine Zhang 
1012*76f3cd6aSElaine Zhang #ifdef CONFIG_SPL_BUILD
1013*76f3cd6aSElaine Zhang         /* fix lsclk_prei div */
1014*76f3cd6aSElaine Zhang    	writel(BITS_WITH_WMASK(1, 0x1U, 9),
1015*76f3cd6aSElaine Zhang 	       RV1103B_CRU_BASE + RV1103B_CLKSEL_CON(31));
1016*76f3cd6aSElaine Zhang         /* fix cpu div */
1017*76f3cd6aSElaine Zhang     	writel(BITS_WITH_WMASK(1, 0x7U, 13),
1018*76f3cd6aSElaine Zhang 	       RV1103B_CRU_BASE + RV1103B_CLKSEL_CON(37));
1019*76f3cd6aSElaine Zhang 	/* fix gpll postdiv1 */
1020*76f3cd6aSElaine Zhang 	writel(BITS_WITH_WMASK(1, 0x7U, 12),
1021*76f3cd6aSElaine Zhang 	       RV1103B_CRU_BASE + RV1103B_PLL_CON(24));
1022*76f3cd6aSElaine Zhang #endif
1023*76f3cd6aSElaine Zhang 
1024*76f3cd6aSElaine Zhang 	rv1103b_clk_init(priv);
1025*76f3cd6aSElaine Zhang 
1026*76f3cd6aSElaine Zhang 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1027*76f3cd6aSElaine Zhang 	ret = clk_set_defaults(dev);
1028*76f3cd6aSElaine Zhang 	if (ret)
1029*76f3cd6aSElaine Zhang 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
1030*76f3cd6aSElaine Zhang 	else
1031*76f3cd6aSElaine Zhang 		priv->sync_kernel = true;
1032*76f3cd6aSElaine Zhang 	return 0;
1033*76f3cd6aSElaine Zhang }
1034*76f3cd6aSElaine Zhang 
rv1103b_clk_ofdata_to_platdata(struct udevice * dev)1035*76f3cd6aSElaine Zhang static int rv1103b_clk_ofdata_to_platdata(struct udevice *dev)
1036*76f3cd6aSElaine Zhang {
1037*76f3cd6aSElaine Zhang 	struct rv1103b_clk_priv *priv = dev_get_priv(dev);
1038*76f3cd6aSElaine Zhang 
1039*76f3cd6aSElaine Zhang 	priv->cru = dev_read_addr_ptr(dev);
1040*76f3cd6aSElaine Zhang 
1041*76f3cd6aSElaine Zhang 	return 0;
1042*76f3cd6aSElaine Zhang }
1043*76f3cd6aSElaine Zhang 
rv1103b_clk_bind(struct udevice * dev)1044*76f3cd6aSElaine Zhang static int rv1103b_clk_bind(struct udevice *dev)
1045*76f3cd6aSElaine Zhang {
1046*76f3cd6aSElaine Zhang 	int ret;
1047*76f3cd6aSElaine Zhang 	struct udevice *sys_child, *sf_child;
1048*76f3cd6aSElaine Zhang 	struct sysreset_reg *priv;
1049*76f3cd6aSElaine Zhang 	struct softreset_reg *sf_priv;
1050*76f3cd6aSElaine Zhang 
1051*76f3cd6aSElaine Zhang 	/* The reset driver does not have a device node, so bind it here */
1052*76f3cd6aSElaine Zhang 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1053*76f3cd6aSElaine Zhang 				 &sys_child);
1054*76f3cd6aSElaine Zhang 	if (ret) {
1055*76f3cd6aSElaine Zhang 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1056*76f3cd6aSElaine Zhang 	} else {
1057*76f3cd6aSElaine Zhang 		priv = malloc(sizeof(struct sysreset_reg));
1058*76f3cd6aSElaine Zhang 		priv->glb_srst_fst_value = offsetof(struct rv1103b_cru,
1059*76f3cd6aSElaine Zhang 						    glb_srst_fst);
1060*76f3cd6aSElaine Zhang 		priv->glb_srst_snd_value = offsetof(struct rv1103b_cru,
1061*76f3cd6aSElaine Zhang 						    glb_srst_snd);
1062*76f3cd6aSElaine Zhang 		sys_child->priv = priv;
1063*76f3cd6aSElaine Zhang 	}
1064*76f3cd6aSElaine Zhang 
1065*76f3cd6aSElaine Zhang 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1066*76f3cd6aSElaine Zhang 					 dev_ofnode(dev), &sf_child);
1067*76f3cd6aSElaine Zhang 	if (ret) {
1068*76f3cd6aSElaine Zhang 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1069*76f3cd6aSElaine Zhang 	} else {
1070*76f3cd6aSElaine Zhang 		sf_priv = malloc(sizeof(struct softreset_reg));
1071*76f3cd6aSElaine Zhang 		sf_priv->sf_reset_offset = offsetof(struct rv1103b_cru,
1072*76f3cd6aSElaine Zhang 						    peri_softrst_con[0]);
1073*76f3cd6aSElaine Zhang 		sf_priv->sf_reset_num = CLK_NR_SRST;
1074*76f3cd6aSElaine Zhang 		sf_child->priv = sf_priv;
1075*76f3cd6aSElaine Zhang 	}
1076*76f3cd6aSElaine Zhang 
1077*76f3cd6aSElaine Zhang 	return 0;
1078*76f3cd6aSElaine Zhang }
1079*76f3cd6aSElaine Zhang 
1080*76f3cd6aSElaine Zhang static const struct udevice_id rv1103b_clk_ids[] = {
1081*76f3cd6aSElaine Zhang 	{ .compatible = "rockchip,rv1103b-cru" },
1082*76f3cd6aSElaine Zhang 	{ }
1083*76f3cd6aSElaine Zhang };
1084*76f3cd6aSElaine Zhang 
1085*76f3cd6aSElaine Zhang U_BOOT_DRIVER(rockchip_rv1103b_cru) = {
1086*76f3cd6aSElaine Zhang 	.name		= "rockchip_rv1103b_cru",
1087*76f3cd6aSElaine Zhang 	.id		= UCLASS_CLK,
1088*76f3cd6aSElaine Zhang 	.of_match	= rv1103b_clk_ids,
1089*76f3cd6aSElaine Zhang 	.priv_auto_alloc_size = sizeof(struct rv1103b_clk_priv),
1090*76f3cd6aSElaine Zhang 	.ofdata_to_platdata = rv1103b_clk_ofdata_to_platdata,
1091*76f3cd6aSElaine Zhang 	.ops		= &rv1103b_clk_ops,
1092*76f3cd6aSElaine Zhang 	.bind		= rv1103b_clk_bind,
1093*76f3cd6aSElaine Zhang 	.probe		= rv1103b_clk_probe,
1094*76f3cd6aSElaine Zhang };
1095*76f3cd6aSElaine Zhang 
1096*76f3cd6aSElaine Zhang #ifndef CONFIG_SPL_BUILD
1097*76f3cd6aSElaine Zhang /**
1098*76f3cd6aSElaine Zhang  * soc_clk_dump() - Print clock frequencies
1099*76f3cd6aSElaine Zhang  * Returns zero on success
1100*76f3cd6aSElaine Zhang  *
1101*76f3cd6aSElaine Zhang  * Implementation for the clk dump command.
1102*76f3cd6aSElaine Zhang  */
soc_clk_dump(void)1103*76f3cd6aSElaine Zhang int soc_clk_dump(void)
1104*76f3cd6aSElaine Zhang {
1105*76f3cd6aSElaine Zhang 	struct udevice *cru_dev;
1106*76f3cd6aSElaine Zhang 	struct rv1103b_clk_priv *priv;
1107*76f3cd6aSElaine Zhang 	const struct rv1103b_clk_info *clk_dump;
1108*76f3cd6aSElaine Zhang 	struct clk clk;
1109*76f3cd6aSElaine Zhang 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1110*76f3cd6aSElaine Zhang 	unsigned long rate;
1111*76f3cd6aSElaine Zhang 	int i, ret;
1112*76f3cd6aSElaine Zhang 
1113*76f3cd6aSElaine Zhang 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1114*76f3cd6aSElaine Zhang 					  DM_GET_DRIVER(rockchip_rv1103b_cru),
1115*76f3cd6aSElaine Zhang 					  &cru_dev);
1116*76f3cd6aSElaine Zhang 	if (ret) {
1117*76f3cd6aSElaine Zhang 		printf("%s failed to get cru device\n", __func__);
1118*76f3cd6aSElaine Zhang 		return ret;
1119*76f3cd6aSElaine Zhang 	}
1120*76f3cd6aSElaine Zhang 
1121*76f3cd6aSElaine Zhang 	priv = dev_get_priv(cru_dev);
1122*76f3cd6aSElaine Zhang 	ret = (readl(&priv->cru->core_clksel_con[0]) &
1123*76f3cd6aSElaine Zhang 	       CLK_CORE_SRC_SEL_MASK) >>
1124*76f3cd6aSElaine Zhang 	      CLK_CORE_SRC_SEL_SHIFT;
1125*76f3cd6aSElaine Zhang 	if (ret == CLK_CORE_SRC_SEL_PVTPLL)
1126*76f3cd6aSElaine Zhang 		printf("CLK: (arm clk use pvtpll, rate = 1200M)\n");
1127*76f3cd6aSElaine Zhang 	else
1128*76f3cd6aSElaine Zhang 		printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1129*76f3cd6aSElaine Zhang 		       priv->sync_kernel ? "sync kernel" : "uboot",
1130*76f3cd6aSElaine Zhang 		       priv->armclk_enter_hz / 1000,
1131*76f3cd6aSElaine Zhang 		       priv->armclk_init_hz / 1000,
1132*76f3cd6aSElaine Zhang 		       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1133*76f3cd6aSElaine Zhang 		       priv->set_armclk_rate ? " KHz" : "N/A");
1134*76f3cd6aSElaine Zhang 	for (i = 0; i < clk_count; i++) {
1135*76f3cd6aSElaine Zhang 		clk_dump = &clks_dump[i];
1136*76f3cd6aSElaine Zhang 		if (clk_dump->name) {
1137*76f3cd6aSElaine Zhang 			clk.id = clk_dump->id;
1138*76f3cd6aSElaine Zhang 			if (clk_dump->is_cru)
1139*76f3cd6aSElaine Zhang 				ret = clk_request(cru_dev, &clk);
1140*76f3cd6aSElaine Zhang 			if (ret < 0)
1141*76f3cd6aSElaine Zhang 				return ret;
1142*76f3cd6aSElaine Zhang 
1143*76f3cd6aSElaine Zhang 			rate = clk_get_rate(&clk);
1144*76f3cd6aSElaine Zhang 			clk_free(&clk);
1145*76f3cd6aSElaine Zhang 			if (i == 0) {
1146*76f3cd6aSElaine Zhang 				if (rate < 0)
1147*76f3cd6aSElaine Zhang 					printf("  %s %s\n", clk_dump->name,
1148*76f3cd6aSElaine Zhang 					       "unknown");
1149*76f3cd6aSElaine Zhang 				else
1150*76f3cd6aSElaine Zhang 					printf("  %s %lu KHz\n", clk_dump->name,
1151*76f3cd6aSElaine Zhang 					       rate / 1000);
1152*76f3cd6aSElaine Zhang 			} else {
1153*76f3cd6aSElaine Zhang 				if (rate < 0)
1154*76f3cd6aSElaine Zhang 					printf("  %s %s\n", clk_dump->name,
1155*76f3cd6aSElaine Zhang 					       "unknown");
1156*76f3cd6aSElaine Zhang 				else
1157*76f3cd6aSElaine Zhang 					printf("  %s %lu KHz\n", clk_dump->name,
1158*76f3cd6aSElaine Zhang 					       rate / 1000);
1159*76f3cd6aSElaine Zhang 			}
1160*76f3cd6aSElaine Zhang 		}
1161*76f3cd6aSElaine Zhang 	}
1162*76f3cd6aSElaine Zhang 
1163*76f3cd6aSElaine Zhang 	return 0;
1164*76f3cd6aSElaine Zhang }
1165*76f3cd6aSElaine Zhang #endif
1166