xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rv1126b.c (revision 5683539d5fcfa4770891a0228ab01bfa7628ac7e)
1b991d4b5SXuhui Lin // SPDX-License-Identifier: GPL-2.0
2b991d4b5SXuhui Lin /*
3b991d4b5SXuhui Lin  * Copyright (c) 2025 Rockchip Electronics Co., Ltd
4b991d4b5SXuhui Lin  * Author: Elaine Zhang <zhangqing@rock-chips.com>
5b991d4b5SXuhui Lin  */
6b991d4b5SXuhui Lin 
7b991d4b5SXuhui Lin #include <common.h>
8b991d4b5SXuhui Lin #include <bitfield.h>
9b991d4b5SXuhui Lin #include <clk-uclass.h>
10b991d4b5SXuhui Lin #include <dm.h>
11b991d4b5SXuhui Lin #include <errno.h>
12b991d4b5SXuhui Lin #include <syscon.h>
13b991d4b5SXuhui Lin #include <asm/arch/clock.h>
14b991d4b5SXuhui Lin #include <asm/arch/cru_rv1126b.h>
15b991d4b5SXuhui Lin #include <asm/arch/hardware.h>
16b991d4b5SXuhui Lin #include <asm/io.h>
17b991d4b5SXuhui Lin #include <dm/lists.h>
18b991d4b5SXuhui Lin #include <dt-bindings/clock/rockchip,rv1126b-cru.h>
19b991d4b5SXuhui Lin 
20b991d4b5SXuhui Lin DECLARE_GLOBAL_DATA_PTR;
21b991d4b5SXuhui Lin 
22b991d4b5SXuhui Lin #define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
23b991d4b5SXuhui Lin 
24b991d4b5SXuhui Lin #ifdef CONFIG_SPL_BUILD
25b991d4b5SXuhui Lin #ifndef BITS_WITH_WMASK
26b991d4b5SXuhui Lin #define BITS_WITH_WMASK(bits, msk, shift) \
27b991d4b5SXuhui Lin 	((bits) << (shift)) | ((msk) << ((shift) + 16))
28b991d4b5SXuhui Lin #endif
29b991d4b5SXuhui Lin #endif
30b991d4b5SXuhui Lin 
31b991d4b5SXuhui Lin static struct rockchip_pll_rate_table rv1126b_pll_rates[] = {
32b991d4b5SXuhui Lin 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
33b991d4b5SXuhui Lin 	RK3036_PLL_RATE(1200000000, 1, 100, 2, 1, 1, 0),
34b991d4b5SXuhui Lin 	RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
35b991d4b5SXuhui Lin 	RK3036_PLL_RATE(1179648000, 1, 49, 1, 1, 0, 2550137),
36b991d4b5SXuhui Lin 	RK3036_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0),
37b991d4b5SXuhui Lin 	RK3036_PLL_RATE(993484800, 1, 41, 1, 1, 0, 6630355),
38b991d4b5SXuhui Lin 	RK3036_PLL_RATE(983040000, 1, 40, 1, 1, 0, 16106127),
39b991d4b5SXuhui Lin 	RK3036_PLL_RATE(903168000, 1, 75, 2, 1, 0, 4429185),
40b991d4b5SXuhui Lin 	{ /* sentinel */ },
41b991d4b5SXuhui Lin };
42b991d4b5SXuhui Lin 
43b991d4b5SXuhui Lin static struct rockchip_pll_clock rv1126b_pll_clks[] = {
44b991d4b5SXuhui Lin 	[GPLL] = PLL(pll_rk3328, PLL_GPLL, RV1126B_PLL_CON(8),
45b991d4b5SXuhui Lin 		     RV1126B_MODE_CON, 2, 10, 0, rv1126b_pll_rates),
46b991d4b5SXuhui Lin 	[AUPLL] = PLL(pll_rk3328, PLL_AUPLL, RV1126B_PLL_CON(0),
47b991d4b5SXuhui Lin 		     RV1126B_MODE_CON, 0, 10, 0, rv1126b_pll_rates),
48b991d4b5SXuhui Lin 	[CPLL] = PLL(pll_rk3328, PLL_CPLL, RV1126B_PERIPLL_CON(0),
49b991d4b5SXuhui Lin 		     RV1126B_MODE_CON, 4, 10, 0, rv1126b_pll_rates),
50b991d4b5SXuhui Lin };
51b991d4b5SXuhui Lin 
52b991d4b5SXuhui Lin #ifndef CONFIG_SPL_BUILD
53b991d4b5SXuhui Lin #define RV1126B_CLK_DUMP(_id, _name, _iscru)	\
54b991d4b5SXuhui Lin {						\
55b991d4b5SXuhui Lin 	.id = _id,				\
56b991d4b5SXuhui Lin 	.name = _name,				\
57b991d4b5SXuhui Lin 	.is_cru = _iscru,			\
58b991d4b5SXuhui Lin }
59b991d4b5SXuhui Lin 
60b991d4b5SXuhui Lin static const struct rv1126b_clk_info clks_dump[] = {
61b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(PLL_GPLL, "gpll", true),
62b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(PLL_AUPLL, "aupll", true),
63b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(PLL_CPLL, "cpll", true),
64b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(ACLK_PERI_ROOT, "aclk_peri_root", true),
65b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(PCLK_PERI_ROOT, "pclk_peri_root", true),
66b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(ACLK_TOP_ROOT, "aclk_top_root", true),
67b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(PCLK_TOP_ROOT, "pclk_top_root", true),
68b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(ACLK_BUS_ROOT, "aclk_bus_root", true),
69b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(HCLK_BUS_ROOT, "hclk_bus_root", true),
70b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(PCLK_BUS_ROOT, "pclk_bus_root", true),
71b991d4b5SXuhui Lin 	RV1126B_CLK_DUMP(BUSCLK_PMU_SRC, "busclk_pmu_src", true),
72b991d4b5SXuhui Lin };
73b991d4b5SXuhui Lin #endif
74b991d4b5SXuhui Lin 
rv1126b_peri_get_clk(struct rv1126b_clk_priv * priv,ulong clk_id)75b991d4b5SXuhui Lin static ulong rv1126b_peri_get_clk(struct rv1126b_clk_priv *priv, ulong clk_id)
76b991d4b5SXuhui Lin {
77b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
78b991d4b5SXuhui Lin 	u32 con, sel, rate;
79b991d4b5SXuhui Lin 
80b991d4b5SXuhui Lin 	switch (clk_id) {
81b991d4b5SXuhui Lin 	case ACLK_PERI_ROOT:
82b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[47]);
83b991d4b5SXuhui Lin 		sel = (con & ACLK_PERI_SEL_MASK) >> ACLK_PERI_SEL_SHIFT;
84b991d4b5SXuhui Lin 		if (sel == ACLK_PERI_SEL_200M)
85b991d4b5SXuhui Lin 			rate = 200 * MHz;
86b991d4b5SXuhui Lin 		else
87b991d4b5SXuhui Lin 			rate = OSC_HZ;
88b991d4b5SXuhui Lin 		break;
89b991d4b5SXuhui Lin 	case PCLK_PERI_ROOT:
90b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[47]);
91b991d4b5SXuhui Lin 		sel = (con & PCLK_PERI_SEL_MASK) >> PCLK_PERI_SEL_SHIFT;
92b991d4b5SXuhui Lin 		if (sel == PCLK_PERI_SEL_100M)
93b991d4b5SXuhui Lin 			rate = 100 * MHz;
94b991d4b5SXuhui Lin 		else
95b991d4b5SXuhui Lin 			rate = OSC_HZ;
96b991d4b5SXuhui Lin 		break;
97b991d4b5SXuhui Lin 	case ACLK_TOP_ROOT:
98b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[44]);
99b991d4b5SXuhui Lin 		sel = (con & ACLK_TOP_SEL_MASK) >> ACLK_TOP_SEL_SHIFT;
100b991d4b5SXuhui Lin 		if (sel == ACLK_TOP_SEL_600M)
101b991d4b5SXuhui Lin 			rate = 600 * MHz;
102b991d4b5SXuhui Lin 		else if (sel == ACLK_TOP_SEL_400M)
103b991d4b5SXuhui Lin 			rate = 400 * MHz;
104b991d4b5SXuhui Lin 		else
105b991d4b5SXuhui Lin 			rate = 200 * MHz;
106b991d4b5SXuhui Lin 		break;
107b991d4b5SXuhui Lin 	case PCLK_TOP_ROOT:
108b991d4b5SXuhui Lin 	case PCLK_BUS_ROOT:
109b991d4b5SXuhui Lin 	case BUSCLK_PMU_SRC:
110b991d4b5SXuhui Lin 		rate = 100 * MHz;
111b991d4b5SXuhui Lin 		break;
112b991d4b5SXuhui Lin 	case ACLK_BUS_ROOT:
113b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[44]);
114b991d4b5SXuhui Lin 		sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT;
115b991d4b5SXuhui Lin 		if (sel == ACLK_BUS_SEL_400M)
116b991d4b5SXuhui Lin 			rate = 400 * MHz;
117b991d4b5SXuhui Lin 		else if (sel == ACLK_BUS_SEL_300M)
118b991d4b5SXuhui Lin 			rate = 300 * MHz;
119b991d4b5SXuhui Lin 		else
120b991d4b5SXuhui Lin 			rate = 200 * MHz;
121b991d4b5SXuhui Lin 		break;
122b991d4b5SXuhui Lin 	case HCLK_BUS_ROOT:
123b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[44]);
124b991d4b5SXuhui Lin 		sel = (con & HCLK_BUS_SEL_MASK) >> HCLK_BUS_SEL_SHIFT;
125b991d4b5SXuhui Lin 		if (sel == HCLK_BUS_SEL_200M)
126b991d4b5SXuhui Lin 			rate = 200 * MHz;
127b991d4b5SXuhui Lin 		else
128b991d4b5SXuhui Lin 			rate = 100 * MHz;
129b991d4b5SXuhui Lin 		break;
130b991d4b5SXuhui Lin 	default:
131b991d4b5SXuhui Lin 		return -ENOENT;
132b991d4b5SXuhui Lin 	}
133b991d4b5SXuhui Lin 
134b991d4b5SXuhui Lin 	return rate;
135b991d4b5SXuhui Lin }
136b991d4b5SXuhui Lin 
rv1126b_peri_set_clk(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)137b991d4b5SXuhui Lin static ulong rv1126b_peri_set_clk(struct rv1126b_clk_priv *priv,
138b991d4b5SXuhui Lin 				  ulong clk_id, ulong rate)
139b991d4b5SXuhui Lin {
140b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
141b991d4b5SXuhui Lin 	int src_clk;
142b991d4b5SXuhui Lin 
143b991d4b5SXuhui Lin 	switch (clk_id) {
144b991d4b5SXuhui Lin 	case ACLK_PERI_ROOT:
145b991d4b5SXuhui Lin 		if (rate >= 198 * MHz)
146b991d4b5SXuhui Lin 			src_clk = ACLK_PERI_SEL_200M;
147b991d4b5SXuhui Lin 		else
148b991d4b5SXuhui Lin 			src_clk = ACLK_PERI_SEL_24M;
149b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[47],
150b991d4b5SXuhui Lin 			     ACLK_PERI_SEL_MASK,
151b991d4b5SXuhui Lin 			     src_clk << ACLK_PERI_SEL_SHIFT);
152b991d4b5SXuhui Lin 		break;
153b991d4b5SXuhui Lin 	case PCLK_PERI_ROOT:
154b991d4b5SXuhui Lin 		if (rate >= 99 * MHz)
155b991d4b5SXuhui Lin 			src_clk = PCLK_PERI_SEL_100M;
156b991d4b5SXuhui Lin 		else
157b991d4b5SXuhui Lin 			src_clk = PCLK_PERI_SEL_24M;
158b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[47],
159b991d4b5SXuhui Lin 			     PCLK_PERI_SEL_MASK,
160b991d4b5SXuhui Lin 			     src_clk << PCLK_PERI_SEL_SHIFT);
161b991d4b5SXuhui Lin 		break;
162b991d4b5SXuhui Lin 	case ACLK_TOP_ROOT:
163b991d4b5SXuhui Lin 		if (rate >= 594 * MHz)
164b991d4b5SXuhui Lin 			src_clk = ACLK_TOP_SEL_600M;
165b991d4b5SXuhui Lin 		else if (rate >= 396 * MHz)
166b991d4b5SXuhui Lin 			src_clk = ACLK_TOP_SEL_400M;
167b991d4b5SXuhui Lin 		else
168b991d4b5SXuhui Lin 			src_clk = ACLK_TOP_SEL_200M;
169b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[44],
170b991d4b5SXuhui Lin 			     ACLK_TOP_SEL_MASK,
171b991d4b5SXuhui Lin 			     src_clk << ACLK_TOP_SEL_SHIFT);
172b991d4b5SXuhui Lin 		break;
173b991d4b5SXuhui Lin 	case PCLK_TOP_ROOT:
174b991d4b5SXuhui Lin 	case PCLK_BUS_ROOT:
175b991d4b5SXuhui Lin 	case BUSCLK_PMU_SRC:
176b991d4b5SXuhui Lin 		break;
177b991d4b5SXuhui Lin 	case ACLK_BUS_ROOT:
178b991d4b5SXuhui Lin 		if (rate >= 396 * MHz)
179b991d4b5SXuhui Lin 			src_clk = ACLK_BUS_SEL_400M;
180b991d4b5SXuhui Lin 		else if (rate >= 297 * MHz)
181b991d4b5SXuhui Lin 			src_clk = ACLK_BUS_SEL_300M;
182b991d4b5SXuhui Lin 		else
183b991d4b5SXuhui Lin 			src_clk = ACLK_BUS_SEL_200M;
184b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[44],
185b991d4b5SXuhui Lin 			     ACLK_BUS_SEL_MASK,
186b991d4b5SXuhui Lin 			     src_clk << ACLK_BUS_SEL_SHIFT);
187b991d4b5SXuhui Lin 		break;
188b991d4b5SXuhui Lin 	case HCLK_BUS_ROOT:
189b991d4b5SXuhui Lin 		if (rate >= 198 * MHz)
190b991d4b5SXuhui Lin 			src_clk = HCLK_BUS_SEL_200M;
191b991d4b5SXuhui Lin 		else
192b991d4b5SXuhui Lin 			src_clk = HCLK_BUS_SEL_100M;
193b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[44],
194b991d4b5SXuhui Lin 			     HCLK_BUS_SEL_MASK,
195b991d4b5SXuhui Lin 			     src_clk << HCLK_BUS_SEL_SHIFT);
196b991d4b5SXuhui Lin 		break;
197b991d4b5SXuhui Lin 	default:
198b991d4b5SXuhui Lin 		printf("do not support this permid freq\n");
199b991d4b5SXuhui Lin 		return -EINVAL;
200b991d4b5SXuhui Lin 	}
201b991d4b5SXuhui Lin 
202b991d4b5SXuhui Lin 	return rv1126b_peri_get_clk(priv, clk_id);
203b991d4b5SXuhui Lin }
204b991d4b5SXuhui Lin 
rv1126b_i2c_get_clk(struct rv1126b_clk_priv * priv,ulong clk_id)205b991d4b5SXuhui Lin static ulong rv1126b_i2c_get_clk(struct rv1126b_clk_priv *priv, ulong clk_id)
206b991d4b5SXuhui Lin {
207b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
208b991d4b5SXuhui Lin 	u32 sel, con;
209b991d4b5SXuhui Lin 	ulong rate;
210b991d4b5SXuhui Lin 
211b991d4b5SXuhui Lin 	switch (clk_id) {
212b991d4b5SXuhui Lin 	case CLK_I2C0:
213b991d4b5SXuhui Lin 	case CLK_I2C1:
214b991d4b5SXuhui Lin 	case CLK_I2C3:
215b991d4b5SXuhui Lin 	case CLK_I2C4:
216b991d4b5SXuhui Lin 	case CLK_I2C5:
217b991d4b5SXuhui Lin 	case CLK_I2C_BUS_SRC:
218b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[50]);
219b991d4b5SXuhui Lin 		sel = (con & CLK_I2C_SEL_MASK) >> CLK_I2C_SEL_SHIFT;
220b991d4b5SXuhui Lin 		if (sel == CLK_I2C_SEL_200M)
221b991d4b5SXuhui Lin 			rate = 200 * MHz;
222b991d4b5SXuhui Lin 		else
223b991d4b5SXuhui Lin 			rate = OSC_HZ;
224b991d4b5SXuhui Lin 		break;
225b991d4b5SXuhui Lin 	case CLK_I2C2:
226b991d4b5SXuhui Lin 		con = readl(&cru->pmu_clksel_con[2]);
227b991d4b5SXuhui Lin 		sel = (con & CLK_I2C2_SEL_MASK) >> CLK_I2C2_SEL_SHIFT;
228b991d4b5SXuhui Lin 		if (sel == CLK_I2C2_SEL_100M)
229b991d4b5SXuhui Lin 			rate = 100 * MHz;
230b991d4b5SXuhui Lin 		else if (sel == CLK_I2C2_SEL_RCOSC)
231b991d4b5SXuhui Lin 			rate = RC_OSC_HZ;
232b991d4b5SXuhui Lin 		else
233b991d4b5SXuhui Lin 			rate = OSC_HZ;
234b991d4b5SXuhui Lin 		break;
235b991d4b5SXuhui Lin 	default:
236b991d4b5SXuhui Lin 		return -ENOENT;
237b991d4b5SXuhui Lin 	}
238b991d4b5SXuhui Lin 
239b991d4b5SXuhui Lin 	return rate;
240b991d4b5SXuhui Lin }
241b991d4b5SXuhui Lin 
rv1126b_i2c_set_clk(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)242b991d4b5SXuhui Lin static ulong rv1126b_i2c_set_clk(struct rv1126b_clk_priv *priv, ulong clk_id,
243b991d4b5SXuhui Lin 				 ulong rate)
244b991d4b5SXuhui Lin {
245b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
246b991d4b5SXuhui Lin 	int src_clk;
247b991d4b5SXuhui Lin 
248b991d4b5SXuhui Lin 	switch (clk_id) {
249b991d4b5SXuhui Lin 	case CLK_I2C0:
250b991d4b5SXuhui Lin 	case CLK_I2C1:
251b991d4b5SXuhui Lin 	case CLK_I2C3:
252b991d4b5SXuhui Lin 	case CLK_I2C4:
253b991d4b5SXuhui Lin 	case CLK_I2C5:
254b991d4b5SXuhui Lin 	case CLK_I2C_BUS_SRC:
255b991d4b5SXuhui Lin 		if (rate == OSC_HZ)
256b991d4b5SXuhui Lin 			src_clk = CLK_I2C_SEL_24M;
257b991d4b5SXuhui Lin 		else
258b991d4b5SXuhui Lin 			src_clk = CLK_I2C_SEL_200M;
259b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[50], CLK_I2C_SEL_MASK,
260b991d4b5SXuhui Lin 			     src_clk << CLK_I2C_SEL_SHIFT);
261b991d4b5SXuhui Lin 		break;
262b991d4b5SXuhui Lin 	case CLK_I2C2:
263b991d4b5SXuhui Lin 		if (rate == OSC_HZ)
264b991d4b5SXuhui Lin 			src_clk = CLK_I2C2_SEL_24M;
265b991d4b5SXuhui Lin 		else if (rate == RC_OSC_HZ)
266b991d4b5SXuhui Lin 			src_clk = CLK_I2C2_SEL_RCOSC;
267b991d4b5SXuhui Lin 		else
268b991d4b5SXuhui Lin 			src_clk = CLK_I2C2_SEL_100M;
269b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->pmu_clksel_con[2], CLK_I2C2_SEL_MASK,
270b991d4b5SXuhui Lin 			     src_clk << CLK_I2C2_SEL_SHIFT);
271b991d4b5SXuhui Lin 		break;
272b991d4b5SXuhui Lin 	default:
273b991d4b5SXuhui Lin 		return -ENOENT;
274b991d4b5SXuhui Lin 	}
275b991d4b5SXuhui Lin 	return rv1126b_i2c_get_clk(priv, clk_id);
276b991d4b5SXuhui Lin }
277b991d4b5SXuhui Lin 
rv1126b_crypto_get_clk(struct rv1126b_clk_priv * priv,ulong clk_id)278b991d4b5SXuhui Lin static ulong rv1126b_crypto_get_clk(struct rv1126b_clk_priv *priv, ulong clk_id)
279b991d4b5SXuhui Lin {
280b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
281b991d4b5SXuhui Lin 	u32 sel, con, rate;
282b991d4b5SXuhui Lin 
283b991d4b5SXuhui Lin 	switch (clk_id) {
284b991d4b5SXuhui Lin 	case PCLK_RKCE:
285b991d4b5SXuhui Lin 		return rv1126b_peri_get_clk(priv, PCLK_BUS_ROOT);
286b991d4b5SXuhui Lin 	case HCLK_NS_RKCE:
287b991d4b5SXuhui Lin 		return rv1126b_peri_get_clk(priv, HCLK_BUS_ROOT);
288b991d4b5SXuhui Lin 	case ACLK_RKCE_SRC:
289b991d4b5SXuhui Lin 	case ACLK_NSRKCE:
290b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[50]);
291b991d4b5SXuhui Lin 		sel = (con & ACLK_RKCE_SEL_MASK) >>
292b991d4b5SXuhui Lin 		      ACLK_RKCE_SEL_SHIFT;
293b991d4b5SXuhui Lin 		if (sel == ACLK_RKCE_SEL_200M)
294b991d4b5SXuhui Lin 			rate = 200 * MHz;
295b991d4b5SXuhui Lin 		else
296b991d4b5SXuhui Lin 			rate = OSC_HZ;
297b991d4b5SXuhui Lin 		break;
298b991d4b5SXuhui Lin 	case CLK_PKA_RKCE_SRC:
299b991d4b5SXuhui Lin 	case CLK_PKA_NSRKCE:
300b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[50]);
301b991d4b5SXuhui Lin 		sel = (con & CLK_PKA_RKCE_SEL_MASK) >>
302b991d4b5SXuhui Lin 		      CLK_PKA_RKCE_SEL_SHIFT;
303b991d4b5SXuhui Lin 		if (sel == CLK_PKA_RKCE_SEL_300M)
304b991d4b5SXuhui Lin 			rate = 300 * MHz;
305b991d4b5SXuhui Lin 		else
306b991d4b5SXuhui Lin 			rate = 200 * MHz;
307b991d4b5SXuhui Lin 		break;
308b991d4b5SXuhui Lin 	default:
309b991d4b5SXuhui Lin 		return -ENOENT;
310b991d4b5SXuhui Lin 	}
311b991d4b5SXuhui Lin 	return rate;
312b991d4b5SXuhui Lin }
313b991d4b5SXuhui Lin 
rv1126b_crypto_set_clk(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)314b991d4b5SXuhui Lin static ulong rv1126b_crypto_set_clk(struct rv1126b_clk_priv *priv,
315b991d4b5SXuhui Lin 				    ulong clk_id, ulong rate)
316b991d4b5SXuhui Lin {
317b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
318b991d4b5SXuhui Lin 	u32 sel;
319b991d4b5SXuhui Lin 
320b991d4b5SXuhui Lin 	switch (clk_id) {
321b991d4b5SXuhui Lin 	case PCLK_RKCE:
322b991d4b5SXuhui Lin 		break;
323b991d4b5SXuhui Lin 	case HCLK_NS_RKCE:
324b991d4b5SXuhui Lin 		rv1126b_peri_set_clk(priv, HCLK_BUS_ROOT, rate);
325b991d4b5SXuhui Lin 	case ACLK_RKCE_SRC:
326b991d4b5SXuhui Lin 	case ACLK_NSRKCE:
327b991d4b5SXuhui Lin 		if (rate >= 198 * MHz)
328b991d4b5SXuhui Lin 			sel = ACLK_RKCE_SEL_200M;
329b991d4b5SXuhui Lin 		else
330b991d4b5SXuhui Lin 			sel = ACLK_RKCE_SEL_24M;
331b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[50],
332b991d4b5SXuhui Lin 			     ACLK_RKCE_SEL_MASK,
333b991d4b5SXuhui Lin 			     (sel << ACLK_RKCE_SEL_SHIFT));
334b991d4b5SXuhui Lin 		break;
335b991d4b5SXuhui Lin 	case CLK_PKA_RKCE_SRC:
336b991d4b5SXuhui Lin 	case CLK_PKA_NSRKCE:
337b991d4b5SXuhui Lin 		if (rate >= 297 * MHz)
338b991d4b5SXuhui Lin 			sel = CLK_PKA_RKCE_SEL_300M;
339b991d4b5SXuhui Lin 		else
340b991d4b5SXuhui Lin 			sel = CLK_PKA_RKCE_SEL_200M;
341b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[50],
342b991d4b5SXuhui Lin 			     CLK_PKA_RKCE_SEL_MASK,
343b991d4b5SXuhui Lin 			     (sel << CLK_PKA_RKCE_SEL_SHIFT));
344b991d4b5SXuhui Lin 		break;
345b991d4b5SXuhui Lin 	default:
346b991d4b5SXuhui Lin 		return -ENOENT;
347b991d4b5SXuhui Lin 	}
348b991d4b5SXuhui Lin 	return rv1126b_crypto_get_clk(priv, clk_id);
349b991d4b5SXuhui Lin }
350b991d4b5SXuhui Lin 
rv1126b_mmc_get_clk(struct rv1126b_clk_priv * priv,ulong clk_id)351b991d4b5SXuhui Lin static ulong rv1126b_mmc_get_clk(struct rv1126b_clk_priv *priv, ulong clk_id)
352b991d4b5SXuhui Lin {
353b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
354b991d4b5SXuhui Lin 	u32 div, sel, con, prate;
355b991d4b5SXuhui Lin 
356b991d4b5SXuhui Lin 	switch (clk_id) {
357b991d4b5SXuhui Lin 	case CCLK_SDMMC0:
358b991d4b5SXuhui Lin 	case HCLK_SDMMC0:
359b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[45]);
360b991d4b5SXuhui Lin 		sel = (con & CLK_SDMMC_SEL_MASK) >>
361b991d4b5SXuhui Lin 		      CLK_SDMMC_SEL_SHIFT;
362b991d4b5SXuhui Lin 		div = (con & CLK_SDMMC_DIV_MASK) >>
363b991d4b5SXuhui Lin 		      CLK_SDMMC_DIV_SHIFT;
364b991d4b5SXuhui Lin 		if (sel == CLK_SDMMC_SEL_GPLL)
365b991d4b5SXuhui Lin 			prate = priv->gpll_hz;
366b991d4b5SXuhui Lin 		else if (sel == CLK_SDMMC_SEL_CPLL)
367b991d4b5SXuhui Lin 			prate = priv->cpll_hz;
368b991d4b5SXuhui Lin 		else
369b991d4b5SXuhui Lin 			prate = OSC_HZ;
370b991d4b5SXuhui Lin 		return DIV_TO_RATE(prate, div);
371b991d4b5SXuhui Lin 	case CCLK_SDMMC1:
372b991d4b5SXuhui Lin 	case HCLK_SDMMC1:
373b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[46]);
374b991d4b5SXuhui Lin 		sel = (con & CLK_SDMMC_SEL_MASK) >>
375b991d4b5SXuhui Lin 		      CLK_SDMMC_SEL_SHIFT;
376b991d4b5SXuhui Lin 		div = (con & CLK_SDMMC_DIV_MASK) >>
377b991d4b5SXuhui Lin 		      CLK_SDMMC_DIV_SHIFT;
378b991d4b5SXuhui Lin 		if (sel == CLK_SDMMC_SEL_GPLL)
379b991d4b5SXuhui Lin 			prate = priv->gpll_hz;
380b991d4b5SXuhui Lin 		else if (sel == CLK_SDMMC_SEL_CPLL)
381b991d4b5SXuhui Lin 			prate = priv->cpll_hz;
382b991d4b5SXuhui Lin 		else
383b991d4b5SXuhui Lin 			prate = OSC_HZ;
384b991d4b5SXuhui Lin 		return DIV_TO_RATE(prate, div);
385b991d4b5SXuhui Lin 	case CCLK_EMMC:
386b991d4b5SXuhui Lin 	case HCLK_EMMC:
387b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[47]);
388b991d4b5SXuhui Lin 		sel = (con & CLK_SDMMC_SEL_MASK) >>
389b991d4b5SXuhui Lin 		      CLK_SDMMC_SEL_SHIFT;
390b991d4b5SXuhui Lin 		div = (con & CLK_SDMMC_DIV_MASK) >>
391b991d4b5SXuhui Lin 		      CLK_SDMMC_DIV_SHIFT;
392b991d4b5SXuhui Lin 		if (sel == CLK_SDMMC_SEL_GPLL)
393b991d4b5SXuhui Lin 			prate = priv->gpll_hz;
394b991d4b5SXuhui Lin 		else if (sel == CLK_SDMMC_SEL_CPLL)
395b991d4b5SXuhui Lin 			prate = priv->cpll_hz;
396b991d4b5SXuhui Lin 		else
397b991d4b5SXuhui Lin 			prate = OSC_HZ;
398b991d4b5SXuhui Lin 		return DIV_TO_RATE(prate, div);
399b991d4b5SXuhui Lin 	case SCLK_2X_FSPI0:
400b991d4b5SXuhui Lin 	case HCLK_FSPI0:
401b991d4b5SXuhui Lin 	case HCLK_XIP_FSPI0:
402b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[48]);
403b991d4b5SXuhui Lin 		sel = (con & CLK_SDMMC_SEL_MASK) >>
404b991d4b5SXuhui Lin 		      CLK_SDMMC_SEL_SHIFT;
405b991d4b5SXuhui Lin 		div = (con & CLK_SDMMC_DIV_MASK) >>
406b991d4b5SXuhui Lin 		      CLK_SDMMC_DIV_SHIFT;
407b991d4b5SXuhui Lin 		if (sel == CLK_SDMMC_SEL_GPLL)
408b991d4b5SXuhui Lin 			prate = priv->gpll_hz;
409b991d4b5SXuhui Lin 		else if (sel == CLK_SDMMC_SEL_CPLL)
410b991d4b5SXuhui Lin 			prate = priv->cpll_hz;
411b991d4b5SXuhui Lin 		else
412b991d4b5SXuhui Lin 			prate = OSC_HZ;
413b991d4b5SXuhui Lin 		return DIV_TO_RATE(prate, div);
414b991d4b5SXuhui Lin 	case SCLK_1X_FSPI1:
415b991d4b5SXuhui Lin 	case HCLK_FSPI1:
416b991d4b5SXuhui Lin 	case HCLK_XIP_FSPI1:
417b991d4b5SXuhui Lin 		con = readl(&cru->pmu1_clksel_con[0]);
418b991d4b5SXuhui Lin 		sel = (con & SCLK_1X_FSPI1_SEL_MASK) >>
419b991d4b5SXuhui Lin 		     SCLK_1X_FSPI1_SEL_SHIFT;
420b991d4b5SXuhui Lin 		div = (con & SCLK_1X_FSPI1_DIV_MASK) >>
421b991d4b5SXuhui Lin 		      SCLK_1X_FSPI1_DIV_SHIFT;
422b991d4b5SXuhui Lin 		if (sel == SCLK_1X_FSPI1_SEL_100M)
423b991d4b5SXuhui Lin 			prate = 100 * MHz;
424b991d4b5SXuhui Lin 		else if (sel == SCLK_1X_FSPI1_SEL_RCOSC)
425b991d4b5SXuhui Lin 			prate = RC_OSC_HZ;
426b991d4b5SXuhui Lin 		else
427b991d4b5SXuhui Lin 			prate = OSC_HZ;
428b991d4b5SXuhui Lin 		return DIV_TO_RATE(prate, div);
429b991d4b5SXuhui Lin 	default:
430b991d4b5SXuhui Lin 		return -ENOENT;
431b991d4b5SXuhui Lin 	}
432b991d4b5SXuhui Lin }
433b991d4b5SXuhui Lin 
rv1126b_mmc_set_clk(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)434b991d4b5SXuhui Lin static ulong rv1126b_mmc_set_clk(struct rv1126b_clk_priv *priv,
435b991d4b5SXuhui Lin 				 ulong clk_id, ulong rate)
436b991d4b5SXuhui Lin {
437b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
438b991d4b5SXuhui Lin 	u32 sel, src_clk_div;
439b991d4b5SXuhui Lin 	ulong prate = 0;
440b991d4b5SXuhui Lin 
441b991d4b5SXuhui Lin 	if ((OSC_HZ % rate) == 0) {
442b991d4b5SXuhui Lin 		sel = CLK_SDMMC_SEL_24M;
443b991d4b5SXuhui Lin 		prate = OSC_HZ;
444b991d4b5SXuhui Lin 	} else if ((priv->cpll_hz % rate) == 0) {
445b991d4b5SXuhui Lin 		sel = CLK_SDMMC_SEL_CPLL;
446b991d4b5SXuhui Lin 		prate = priv->cpll_hz;
447b991d4b5SXuhui Lin 	} else {
448b991d4b5SXuhui Lin 		sel = CLK_SDMMC_SEL_GPLL;
449b991d4b5SXuhui Lin 		prate = priv->gpll_hz;
450b991d4b5SXuhui Lin 	}
451b991d4b5SXuhui Lin 	src_clk_div = DIV_ROUND_UP(prate, rate);
452b991d4b5SXuhui Lin 
453b991d4b5SXuhui Lin 	switch (clk_id) {
454b991d4b5SXuhui Lin 	case CCLK_SDMMC0:
455b991d4b5SXuhui Lin 	case HCLK_SDMMC0:
456b991d4b5SXuhui Lin 		src_clk_div = DIV_ROUND_UP(prate, rate);
457b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[45],
458b991d4b5SXuhui Lin 			     CLK_SDMMC_SEL_MASK |
459b991d4b5SXuhui Lin 			     CLK_SDMMC_DIV_MASK,
460b991d4b5SXuhui Lin 			     (sel << CLK_SDMMC_SEL_SHIFT) |
461b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
462b991d4b5SXuhui Lin 			      CLK_SDMMC_DIV_SHIFT));
463b991d4b5SXuhui Lin 		break;
464b991d4b5SXuhui Lin 	case CCLK_SDMMC1:
465b991d4b5SXuhui Lin 	case HCLK_SDMMC1:
466b991d4b5SXuhui Lin 		src_clk_div = DIV_ROUND_UP(prate, rate);
467b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[46],
468b991d4b5SXuhui Lin 			     CLK_SDMMC_SEL_MASK |
469b991d4b5SXuhui Lin 			     CLK_SDMMC_DIV_MASK,
470b991d4b5SXuhui Lin 			     (sel << CLK_SDMMC_SEL_SHIFT) |
471b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
472b991d4b5SXuhui Lin 			      CLK_SDMMC_DIV_SHIFT));
473b991d4b5SXuhui Lin 		break;
474b991d4b5SXuhui Lin 	case CCLK_EMMC:
475b991d4b5SXuhui Lin 	case HCLK_EMMC:
476b991d4b5SXuhui Lin 		src_clk_div = DIV_ROUND_UP(prate, rate);
477b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[47],
478b991d4b5SXuhui Lin 			     CLK_SDMMC_SEL_MASK |
479b991d4b5SXuhui Lin 			     CLK_SDMMC_DIV_MASK,
480b991d4b5SXuhui Lin 			     (sel << CLK_SDMMC_SEL_SHIFT) |
481b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
482b991d4b5SXuhui Lin 			      CLK_SDMMC_DIV_SHIFT));
483b991d4b5SXuhui Lin 		break;
484b991d4b5SXuhui Lin 	case SCLK_2X_FSPI0:
485b991d4b5SXuhui Lin 	case HCLK_FSPI0:
486b991d4b5SXuhui Lin 	case HCLK_XIP_FSPI0:
487b991d4b5SXuhui Lin 		src_clk_div = DIV_ROUND_UP(prate, rate);
488b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[48],
489b991d4b5SXuhui Lin 			     CLK_SDMMC_SEL_MASK |
490b991d4b5SXuhui Lin 			     CLK_SDMMC_DIV_MASK,
491b991d4b5SXuhui Lin 			     (sel << CLK_SDMMC_SEL_SHIFT) |
492b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
493b991d4b5SXuhui Lin 			      CLK_SDMMC_DIV_SHIFT));
494b991d4b5SXuhui Lin 		break;
495b991d4b5SXuhui Lin 	case SCLK_1X_FSPI1:
496b991d4b5SXuhui Lin 	case HCLK_FSPI1:
497b991d4b5SXuhui Lin 	case HCLK_XIP_FSPI1:
498b991d4b5SXuhui Lin 		if ((OSC_HZ % rate) == 0) {
499b991d4b5SXuhui Lin 			sel = SCLK_1X_FSPI1_SEL_24M;
500b991d4b5SXuhui Lin 			prate = OSC_HZ;
501b991d4b5SXuhui Lin 		} else if ((100 * MHz % rate) == 0) {
502b991d4b5SXuhui Lin 			sel = SCLK_1X_FSPI1_SEL_100M;
503b991d4b5SXuhui Lin 			prate = priv->cpll_hz;
504b991d4b5SXuhui Lin 		} else {
505b991d4b5SXuhui Lin 			sel = SCLK_1X_FSPI1_SEL_RCOSC;
506b991d4b5SXuhui Lin 			prate = RC_OSC_HZ;
507b991d4b5SXuhui Lin 		}
508b991d4b5SXuhui Lin 		src_clk_div = DIV_ROUND_UP(prate, rate);
509b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->pmu1_clksel_con[0],
510b991d4b5SXuhui Lin 			     SCLK_1X_FSPI1_SEL_MASK |
511b991d4b5SXuhui Lin 			     SCLK_1X_FSPI1_DIV_MASK,
512b991d4b5SXuhui Lin 			     (sel << SCLK_1X_FSPI1_SEL_SHIFT) |
513b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
514b991d4b5SXuhui Lin 			      SCLK_1X_FSPI1_DIV_SHIFT));
515b991d4b5SXuhui Lin 		break;
516b991d4b5SXuhui Lin 	default:
517b991d4b5SXuhui Lin 		return -ENOENT;
518b991d4b5SXuhui Lin 	}
519b991d4b5SXuhui Lin 	return rv1126b_mmc_get_clk(priv, clk_id);
520b991d4b5SXuhui Lin }
521b991d4b5SXuhui Lin 
rv1126b_spi_get_clk(struct rv1126b_clk_priv * priv,ulong clk_id)522b991d4b5SXuhui Lin static ulong rv1126b_spi_get_clk(struct rv1126b_clk_priv *priv, ulong clk_id)
523b991d4b5SXuhui Lin {
524b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
525b991d4b5SXuhui Lin 	u32 sel, con, rate;
526b991d4b5SXuhui Lin 
527b991d4b5SXuhui Lin 	switch (clk_id) {
528b991d4b5SXuhui Lin 	case CLK_SPI0:
529b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[50]);
530b991d4b5SXuhui Lin 		sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
531b991d4b5SXuhui Lin 		break;
532b991d4b5SXuhui Lin 	case CLK_SPI1:
533b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[50]);
534b991d4b5SXuhui Lin 		sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT;
535b991d4b5SXuhui Lin 		break;
536b991d4b5SXuhui Lin 	default:
537b991d4b5SXuhui Lin 		return -ENOENT;
538b991d4b5SXuhui Lin 	}
539b991d4b5SXuhui Lin 	if (sel == CLK_SPI0_SEL_200M)
540b991d4b5SXuhui Lin 		rate = 200 * MHz;
541b991d4b5SXuhui Lin 	else if (sel == CLK_SPI0_SEL_100M)
542b991d4b5SXuhui Lin 		rate = 100 * MHz;
543b991d4b5SXuhui Lin 	else if (sel == CLK_SPI0_SEL_50M)
544b991d4b5SXuhui Lin 		rate = 50 * MHz;
545b991d4b5SXuhui Lin 	else
546b991d4b5SXuhui Lin 		rate = OSC_HZ;
547b991d4b5SXuhui Lin 
548b991d4b5SXuhui Lin 	return rate;
549b991d4b5SXuhui Lin }
550b991d4b5SXuhui Lin 
rv1126b_spi_set_clk(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)551b991d4b5SXuhui Lin static ulong rv1126b_spi_set_clk(struct rv1126b_clk_priv *priv,
552b991d4b5SXuhui Lin 				 ulong clk_id, ulong rate)
553b991d4b5SXuhui Lin {
554b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
555b991d4b5SXuhui Lin 	int src_clk;
556b991d4b5SXuhui Lin 
557b991d4b5SXuhui Lin 	if (rate >= 198 * MHz)
558b991d4b5SXuhui Lin 		src_clk = CLK_SPI0_SEL_200M;
559b991d4b5SXuhui Lin 	else if (rate >= 99 * MHz)
560b991d4b5SXuhui Lin 		src_clk = CLK_SPI0_SEL_100M;
561b991d4b5SXuhui Lin 	else if (rate >= 48 * MHz)
562b991d4b5SXuhui Lin 		src_clk = CLK_SPI0_SEL_50M;
563b991d4b5SXuhui Lin 	else
564b991d4b5SXuhui Lin 		src_clk = CLK_SPI0_SEL_24M;
565b991d4b5SXuhui Lin 
566b991d4b5SXuhui Lin 	switch (clk_id) {
567b991d4b5SXuhui Lin 	case CLK_SPI0:
568b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[50], CLK_SPI0_SEL_MASK,
569b991d4b5SXuhui Lin 			     src_clk << CLK_SPI0_SEL_SHIFT);
570b991d4b5SXuhui Lin 		break;
571b991d4b5SXuhui Lin 	case CLK_SPI1:
572b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[50], CLK_SPI1_SEL_MASK,
573b991d4b5SXuhui Lin 			     src_clk << CLK_SPI1_SEL_SHIFT);
574b991d4b5SXuhui Lin 		break;
575b991d4b5SXuhui Lin 	default:
576b991d4b5SXuhui Lin 		return -ENOENT;
577b991d4b5SXuhui Lin 	}
578b991d4b5SXuhui Lin 
579b991d4b5SXuhui Lin 	return rv1126b_spi_get_clk(priv, clk_id);
580b991d4b5SXuhui Lin }
581b991d4b5SXuhui Lin 
rv1126b_pwm_get_clk(struct rv1126b_clk_priv * priv,ulong clk_id)582b991d4b5SXuhui Lin static ulong rv1126b_pwm_get_clk(struct rv1126b_clk_priv *priv, ulong clk_id)
583b991d4b5SXuhui Lin {
584b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
585b991d4b5SXuhui Lin 	u32 sel, div, con;
586b991d4b5SXuhui Lin 
587b991d4b5SXuhui Lin 	switch (clk_id) {
588b991d4b5SXuhui Lin 	case CLK_PWM0:
589b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[50]);
590b991d4b5SXuhui Lin 		sel = (con & CLK_PWM0_SEL_MASK) >> CLK_PWM0_SEL_SHIFT;
591b991d4b5SXuhui Lin 		break;
592b991d4b5SXuhui Lin 	case CLK_PWM2:
593b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[50]);
594b991d4b5SXuhui Lin 		sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT;
595b991d4b5SXuhui Lin 		break;
596b991d4b5SXuhui Lin 	case CLK_PWM3:
597b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[50]);
598b991d4b5SXuhui Lin 		sel = (con & CLK_PWM3_SEL_MASK) >> CLK_PWM3_SEL_SHIFT;
599b991d4b5SXuhui Lin 		break;
600b991d4b5SXuhui Lin 	case CLK_PWM1:
601b991d4b5SXuhui Lin 		con = readl(&cru->pmu_clksel_con[2]);
602b991d4b5SXuhui Lin 		sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
603b991d4b5SXuhui Lin 		div = (con & CLK_PWM1_DIV_MASK) >>
604b991d4b5SXuhui Lin 		      CLK_PWM1_DIV_SHIFT;
605b991d4b5SXuhui Lin 		if (sel == CLK_PWM1_SEL_100M)
606b991d4b5SXuhui Lin 			return DIV_TO_RATE(100 * MHz, div);
607b991d4b5SXuhui Lin 		else if (sel == CLK_PWM1_SEL_RCOSC)
608b991d4b5SXuhui Lin 			return DIV_TO_RATE(RC_OSC_HZ, div);
609b991d4b5SXuhui Lin 		else
610b991d4b5SXuhui Lin 			return DIV_TO_RATE(OSC_HZ, div);
611b991d4b5SXuhui Lin 	default:
612b991d4b5SXuhui Lin 		return -ENOENT;
613b991d4b5SXuhui Lin 	}
614b991d4b5SXuhui Lin 
615b991d4b5SXuhui Lin 	switch (sel) {
616b991d4b5SXuhui Lin 	case CLK_PWM_SEL_100M:
617b991d4b5SXuhui Lin 		return 100 * MHz;
618b991d4b5SXuhui Lin 	case CLK_PWM_SEL_24M:
619b991d4b5SXuhui Lin 		return OSC_HZ;
620b991d4b5SXuhui Lin 	default:
621b991d4b5SXuhui Lin 		return -ENOENT;
622b991d4b5SXuhui Lin 	}
623b991d4b5SXuhui Lin }
624b991d4b5SXuhui Lin 
rv1126b_pwm_set_clk(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)625b991d4b5SXuhui Lin static ulong rv1126b_pwm_set_clk(struct rv1126b_clk_priv *priv,
626b991d4b5SXuhui Lin 				 ulong clk_id, ulong rate)
627b991d4b5SXuhui Lin {
628b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
629b991d4b5SXuhui Lin 	int src_clk, src_clk_div, prate;
630b991d4b5SXuhui Lin 
631b991d4b5SXuhui Lin 	if (rate >= 99 * MHz)
632b991d4b5SXuhui Lin 		src_clk = CLK_PWM_SEL_100M;
633b991d4b5SXuhui Lin 	else
634b991d4b5SXuhui Lin 		src_clk = CLK_PWM_SEL_24M;
635b991d4b5SXuhui Lin 
636b991d4b5SXuhui Lin 	switch (clk_id) {
637b991d4b5SXuhui Lin 	case CLK_PWM0:
638b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[50],
639b991d4b5SXuhui Lin 			     CLK_PWM0_SEL_MASK,
640b991d4b5SXuhui Lin 			     src_clk << CLK_PWM0_SEL_SHIFT);
641b991d4b5SXuhui Lin 		break;
642b991d4b5SXuhui Lin 	case CLK_PWM2:
643b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[50],
644b991d4b5SXuhui Lin 			     CLK_PWM2_SEL_MASK,
645b991d4b5SXuhui Lin 			     src_clk << CLK_PWM2_SEL_SHIFT);
646b991d4b5SXuhui Lin 		break;
647b991d4b5SXuhui Lin 	case CLK_PWM3:
648b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[50],
649b991d4b5SXuhui Lin 			     CLK_PWM3_SEL_MASK,
650b991d4b5SXuhui Lin 			     src_clk << CLK_PWM3_SEL_SHIFT);
651b991d4b5SXuhui Lin 		break;
652b991d4b5SXuhui Lin 	case CLK_PWM1:
653b991d4b5SXuhui Lin 		if ((OSC_HZ % rate) == 0) {
654b991d4b5SXuhui Lin 			src_clk = CLK_PWM1_SEL_24M;
655b991d4b5SXuhui Lin 			prate = OSC_HZ;
656b991d4b5SXuhui Lin 		} else if ((100 * MHz % rate) == 0) {
657b991d4b5SXuhui Lin 			src_clk = CLK_PWM1_SEL_100M;
658b991d4b5SXuhui Lin 			prate = priv->cpll_hz;
659b991d4b5SXuhui Lin 		} else {
660b991d4b5SXuhui Lin 			src_clk = CLK_PWM1_SEL_RCOSC;
661b991d4b5SXuhui Lin 			prate = RC_OSC_HZ;
662b991d4b5SXuhui Lin 		}
663b991d4b5SXuhui Lin 		src_clk_div = DIV_ROUND_UP(prate, rate);
664b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->pmu1_clksel_con[2],
665b991d4b5SXuhui Lin 			     CLK_PWM1_SEL_MASK |
666b991d4b5SXuhui Lin 			     CLK_PWM1_DIV_MASK,
667b991d4b5SXuhui Lin 			     (src_clk << CLK_PWM1_SEL_SHIFT) |
668b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
669b991d4b5SXuhui Lin 			      CLK_PWM1_DIV_SHIFT));
670b991d4b5SXuhui Lin 		break;
671b991d4b5SXuhui Lin 
672b991d4b5SXuhui Lin 	default:
673b991d4b5SXuhui Lin 		return -ENOENT;
674b991d4b5SXuhui Lin 	}
675b991d4b5SXuhui Lin 
676b991d4b5SXuhui Lin 	return rv1126b_pwm_get_clk(priv, clk_id);
677b991d4b5SXuhui Lin }
678b991d4b5SXuhui Lin 
rv1126b_adc_get_clk(struct rv1126b_clk_priv * priv,ulong clk_id)679b991d4b5SXuhui Lin static ulong rv1126b_adc_get_clk(struct rv1126b_clk_priv *priv, ulong clk_id)
680b991d4b5SXuhui Lin {
681b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
682b991d4b5SXuhui Lin 	u32 sel, div, con;
683b991d4b5SXuhui Lin 
684b991d4b5SXuhui Lin 	switch (clk_id) {
685b991d4b5SXuhui Lin 	case CLK_SARADC0:
686b991d4b5SXuhui Lin 	case CLK_SARADC0_SRC:
687b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[63]);
688b991d4b5SXuhui Lin 		sel = (con & CLK_SARADC0_SEL_MASK) >> CLK_SARADC0_SEL_SHIFT;
689b991d4b5SXuhui Lin 		div = (con & CLK_SARADC0_DIV_MASK) >>
690b991d4b5SXuhui Lin 		      CLK_SARADC0_DIV_SHIFT;
691b991d4b5SXuhui Lin 		break;
692b991d4b5SXuhui Lin 	case CLK_SARADC1:
693b991d4b5SXuhui Lin 	case CLK_SARADC1_SRC:
694b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[63]);
695b991d4b5SXuhui Lin 		sel = (con & CLK_SARADC1_SEL_MASK) >> CLK_SARADC1_SEL_SHIFT;
696b991d4b5SXuhui Lin 		div = (con & CLK_SARADC1_DIV_MASK) >>
697b991d4b5SXuhui Lin 		      CLK_SARADC1_DIV_SHIFT;
698b991d4b5SXuhui Lin 		break;
699b991d4b5SXuhui Lin 	case CLK_SARADC2:
700b991d4b5SXuhui Lin 	case CLK_SARADC2_SRC:
701b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[63]);
702b991d4b5SXuhui Lin 		sel = (con & CLK_SARADC2_SEL_MASK) >> CLK_SARADC2_SEL_SHIFT;
703b991d4b5SXuhui Lin 		div = (con & CLK_SARADC2_DIV_MASK) >>
704b991d4b5SXuhui Lin 		      CLK_SARADC2_DIV_SHIFT;
705b991d4b5SXuhui Lin 		break;
706b991d4b5SXuhui Lin 	case CLK_TSADC:
707b991d4b5SXuhui Lin 	case CLK_TSADC_PHYCTRL:
708b991d4b5SXuhui Lin 		return OSC_HZ;
709b991d4b5SXuhui Lin 	default:
710b991d4b5SXuhui Lin 		return -ENOENT;
711b991d4b5SXuhui Lin 	}
712b991d4b5SXuhui Lin 
713b991d4b5SXuhui Lin 	if (sel == CLK_SARADC_SEL_200M)
714b991d4b5SXuhui Lin 		return DIV_TO_RATE(200 * MHz, div);
715b991d4b5SXuhui Lin 	else
716b991d4b5SXuhui Lin 		return DIV_TO_RATE(OSC_HZ, div);
717b991d4b5SXuhui Lin }
718b991d4b5SXuhui Lin 
rv1126b_adc_set_clk(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)719b991d4b5SXuhui Lin static ulong rv1126b_adc_set_clk(struct rv1126b_clk_priv *priv,
720b991d4b5SXuhui Lin 				 ulong clk_id, ulong rate)
721b991d4b5SXuhui Lin {
722b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
723b991d4b5SXuhui Lin 	int src_clk_sel, src_clk_div, prate;
724b991d4b5SXuhui Lin 
725b991d4b5SXuhui Lin 	if ((OSC_HZ % rate) == 0) {
726b991d4b5SXuhui Lin 		src_clk_sel = CLK_SARADC_SEL_24M;
727b991d4b5SXuhui Lin 		prate = OSC_HZ;
728b991d4b5SXuhui Lin 	} else {
729b991d4b5SXuhui Lin 		src_clk_sel = CLK_SARADC_SEL_200M;
730b991d4b5SXuhui Lin 		prate = 200 * MHz;
731b991d4b5SXuhui Lin 	}
732b991d4b5SXuhui Lin 	src_clk_div = DIV_ROUND_UP(prate, rate);
733b991d4b5SXuhui Lin 
734b991d4b5SXuhui Lin 	switch (clk_id) {
735b991d4b5SXuhui Lin 	case CLK_SARADC0:
736b991d4b5SXuhui Lin 	case CLK_SARADC0_SRC:
737b991d4b5SXuhui Lin 		assert(src_clk_div - 1 <= 7);
738b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[63],
739b991d4b5SXuhui Lin 			     CLK_SARADC0_SEL_MASK |
740b991d4b5SXuhui Lin 			     CLK_SARADC0_DIV_MASK,
741b991d4b5SXuhui Lin 			     (src_clk_sel << CLK_SARADC0_SEL_SHIFT) |
742b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
743b991d4b5SXuhui Lin 			      CLK_SARADC0_DIV_SHIFT));
744b991d4b5SXuhui Lin 		break;
745b991d4b5SXuhui Lin 	case CLK_SARADC1:
746b991d4b5SXuhui Lin 	case CLK_SARADC1_SRC:
747b991d4b5SXuhui Lin 		assert(src_clk_div - 1 <= 7);
748b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[63],
749b991d4b5SXuhui Lin 			     CLK_SARADC1_SEL_MASK |
750b991d4b5SXuhui Lin 			     CLK_SARADC1_DIV_MASK,
751b991d4b5SXuhui Lin 			     (src_clk_sel << CLK_SARADC1_SEL_SHIFT) |
752b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
753b991d4b5SXuhui Lin 			      CLK_SARADC1_DIV_SHIFT));
754b991d4b5SXuhui Lin 		break;
755b991d4b5SXuhui Lin 	case CLK_SARADC2:
756b991d4b5SXuhui Lin 	case CLK_SARADC2_SRC:
757b991d4b5SXuhui Lin 		assert(src_clk_div - 1 <= 7);
758b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[63],
759b991d4b5SXuhui Lin 			     CLK_SARADC2_SEL_MASK |
760b991d4b5SXuhui Lin 			     CLK_SARADC2_DIV_MASK,
761b991d4b5SXuhui Lin 			     (src_clk_sel << CLK_SARADC2_SEL_SHIFT) |
762b991d4b5SXuhui Lin 			     ((src_clk_div - 1) <<
763b991d4b5SXuhui Lin 			      CLK_SARADC2_DIV_SHIFT));
764b991d4b5SXuhui Lin 		break;
765b991d4b5SXuhui Lin 	case CLK_TSADC:
766b991d4b5SXuhui Lin 	case CLK_TSADC_PHYCTRL:
767b991d4b5SXuhui Lin 		break;
768b991d4b5SXuhui Lin 	default:
769b991d4b5SXuhui Lin 		return -ENOENT;
770b991d4b5SXuhui Lin 	}
771b991d4b5SXuhui Lin 	return rv1126b_adc_get_clk(priv, clk_id);
772b991d4b5SXuhui Lin }
773b991d4b5SXuhui Lin 
774b991d4b5SXuhui Lin /*
775b991d4b5SXuhui Lin  *
776b991d4b5SXuhui Lin  * rational_best_approximation(31415, 10000,
777b991d4b5SXuhui Lin  *		(1 << 8) - 1, (1 << 5) - 1, &n, &d);
778b991d4b5SXuhui Lin  *
779b991d4b5SXuhui Lin  * you may look at given_numerator as a fixed point number,
780b991d4b5SXuhui Lin  * with the fractional part size described in given_denominator.
781b991d4b5SXuhui Lin  *
782b991d4b5SXuhui Lin  * for theoretical background, see:
783b991d4b5SXuhui Lin  * http://en.wikipedia.org/wiki/Continued_fraction
784b991d4b5SXuhui Lin  */
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)785b991d4b5SXuhui Lin static void rational_best_approximation(unsigned long given_numerator,
786b991d4b5SXuhui Lin 					unsigned long given_denominator,
787b991d4b5SXuhui Lin 					unsigned long max_numerator,
788b991d4b5SXuhui Lin 					unsigned long max_denominator,
789b991d4b5SXuhui Lin 					unsigned long *best_numerator,
790b991d4b5SXuhui Lin 					unsigned long *best_denominator)
791b991d4b5SXuhui Lin {
792b991d4b5SXuhui Lin 	unsigned long n, d, n0, d0, n1, d1;
793b991d4b5SXuhui Lin 
794b991d4b5SXuhui Lin 	n = given_numerator;
795b991d4b5SXuhui Lin 	d = given_denominator;
796b991d4b5SXuhui Lin 	n0 = 0;
797b991d4b5SXuhui Lin 	d1 = 0;
798b991d4b5SXuhui Lin 	n1 = 1;
799b991d4b5SXuhui Lin 	d0 = 1;
800b991d4b5SXuhui Lin 	for (;;) {
801b991d4b5SXuhui Lin 		unsigned long t, a;
802b991d4b5SXuhui Lin 
803b991d4b5SXuhui Lin 		if (n1 > max_numerator || d1 > max_denominator) {
804b991d4b5SXuhui Lin 			n1 = n0;
805b991d4b5SXuhui Lin 			d1 = d0;
806b991d4b5SXuhui Lin 			break;
807b991d4b5SXuhui Lin 		}
808b991d4b5SXuhui Lin 		if (d == 0)
809b991d4b5SXuhui Lin 			break;
810b991d4b5SXuhui Lin 		t = d;
811b991d4b5SXuhui Lin 		a = n / d;
812b991d4b5SXuhui Lin 		d = n % d;
813b991d4b5SXuhui Lin 		n = t;
814b991d4b5SXuhui Lin 		t = n0 + a * n1;
815b991d4b5SXuhui Lin 		n0 = n1;
816b991d4b5SXuhui Lin 		n1 = t;
817b991d4b5SXuhui Lin 		t = d0 + a * d1;
818b991d4b5SXuhui Lin 		d0 = d1;
819b991d4b5SXuhui Lin 		d1 = t;
820b991d4b5SXuhui Lin 	}
821b991d4b5SXuhui Lin 	*best_numerator = n1;
822b991d4b5SXuhui Lin 	*best_denominator = d1;
823b991d4b5SXuhui Lin }
824b991d4b5SXuhui Lin 
rv1126b_frac_get_rate(struct rv1126b_clk_priv * priv,ulong clk_id)825b991d4b5SXuhui Lin static ulong rv1126b_frac_get_rate(struct rv1126b_clk_priv *priv, ulong clk_id)
826b991d4b5SXuhui Lin {
827b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
828b991d4b5SXuhui Lin 	u32 reg, reg_h, src, con, p_rate;
829b991d4b5SXuhui Lin 	unsigned long m, n, m_l, n_l, m_h, n_h;
830b991d4b5SXuhui Lin 
831b991d4b5SXuhui Lin 	switch (clk_id) {
832b991d4b5SXuhui Lin 	case CLK_CM_FRAC0:
833b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[10]);
834b991d4b5SXuhui Lin 		src = (con & CLK_CM_FRAC0_SRC_SEL_MASK) >>
835b991d4b5SXuhui Lin 		      CLK_CM_FRAC0_SRC_SEL_SHIFT;
836b991d4b5SXuhui Lin 		reg = readl(&cru->clksel_con[25]);
837b991d4b5SXuhui Lin 		reg_h = readl(&cru->clk_cm_frac0_div_h);
838b991d4b5SXuhui Lin 		break;
839b991d4b5SXuhui Lin 	case CLK_CM_FRAC1:
840b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[10]);
841b991d4b5SXuhui Lin 		src = (con & CLK_CM_FRAC1_SRC_SEL_MASK) >>
842b991d4b5SXuhui Lin 		      CLK_CM_FRAC1_SRC_SEL_SHIFT;
843b991d4b5SXuhui Lin 		reg = readl(&cru->clksel_con[26]);
844b991d4b5SXuhui Lin 		reg_h = readl(&cru->clk_cm_frac1_div_h);
845b991d4b5SXuhui Lin 		break;
846b991d4b5SXuhui Lin 	case CLK_CM_FRAC2:
847b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[10]);
848b991d4b5SXuhui Lin 		src = (con & CLK_CM_FRAC2_SRC_SEL_MASK) >>
849b991d4b5SXuhui Lin 		      CLK_CM_FRAC2_SRC_SEL_SHIFT;
850b991d4b5SXuhui Lin 		reg = readl(&cru->clksel_con[27]);
851b991d4b5SXuhui Lin 		reg_h = readl(&cru->clk_cm_frac2_div_h);
852b991d4b5SXuhui Lin 		break;
853b991d4b5SXuhui Lin 	case CLK_UART_FRAC0:
854b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[10]);
855b991d4b5SXuhui Lin 		src = (con & CLK_UART_FRAC0_SRC_SEL_MASK) >>
856b991d4b5SXuhui Lin 		      CLK_UART_FRAC0_SRC_SEL_SHIFT;
857b991d4b5SXuhui Lin 		reg = readl(&cru->clksel_con[28]);
858b991d4b5SXuhui Lin 		reg_h = readl(&cru->clk_uart_frac0_div_h);
859b991d4b5SXuhui Lin 		break;
860b991d4b5SXuhui Lin 	case CLK_UART_FRAC1:
861b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[10]);
862b991d4b5SXuhui Lin 		src = (con & CLK_UART_FRAC1_SRC_SEL_MASK) >>
863b991d4b5SXuhui Lin 		      CLK_UART_FRAC1_SRC_SEL_SHIFT;
864b991d4b5SXuhui Lin 		reg = readl(&cru->clksel_con[29]);
865b991d4b5SXuhui Lin 		reg_h = readl(&cru->clk_uart_frac1_div_h);
866b991d4b5SXuhui Lin 		break;
867b991d4b5SXuhui Lin 	case CLK_AUDIO_FRAC0:
868b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[10]);
869b991d4b5SXuhui Lin 		src = (con & CLK_AUDIO_FRAC0_SRC_SEL_MASK) >>
870b991d4b5SXuhui Lin 		      CLK_AUDIO_FRAC0_SRC_SEL_SHIFT;
871b991d4b5SXuhui Lin 		reg = readl(&cru->clksel_con[30]);
872b991d4b5SXuhui Lin 		reg_h = readl(&cru->clk_audio_frac0_div_h);
873b991d4b5SXuhui Lin 		break;
874b991d4b5SXuhui Lin 	case CLK_AUDIO_FRAC1:
875b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[10]);
876b991d4b5SXuhui Lin 		src = (con & CLK_AUDIO_FRAC1_SRC_SEL_MASK) >>
877b991d4b5SXuhui Lin 		      CLK_AUDIO_FRAC1_SRC_SEL_SHIFT;
878b991d4b5SXuhui Lin 		reg = readl(&cru->clksel_con[31]);
879b991d4b5SXuhui Lin 		reg_h = readl(&cru->clk_audio_frac1_div_h);
880b991d4b5SXuhui Lin 		break;
881b991d4b5SXuhui Lin 
882b991d4b5SXuhui Lin 	default:
883b991d4b5SXuhui Lin 		return -ENOENT;
884b991d4b5SXuhui Lin 	}
885b991d4b5SXuhui Lin 
886b991d4b5SXuhui Lin 	switch (src) {
887b991d4b5SXuhui Lin 	case CLK_FRAC_SRC_SEL_24M:
888b991d4b5SXuhui Lin 		p_rate = OSC_HZ;
889b991d4b5SXuhui Lin 		break;
890b991d4b5SXuhui Lin 	case CLK_FRAC_SRC_SEL_GPLL:
891b991d4b5SXuhui Lin 		p_rate = priv->gpll_hz;
892b991d4b5SXuhui Lin 		break;
893b991d4b5SXuhui Lin 	case CLK_FRAC_SRC_SEL_AUPLL:
894b991d4b5SXuhui Lin 		p_rate = priv->aupll_hz;
895b991d4b5SXuhui Lin 		break;
896b991d4b5SXuhui Lin 	case CLK_FRAC_SRC_SEL_CPLL:
897b991d4b5SXuhui Lin 		p_rate = priv->cpll_hz;
898b991d4b5SXuhui Lin 		break;
899b991d4b5SXuhui Lin 	default:
900b991d4b5SXuhui Lin 		return -ENOENT;
901b991d4b5SXuhui Lin 	}
902b991d4b5SXuhui Lin 
903b991d4b5SXuhui Lin 	n_l = reg & CLK_FRAC_NUMERATOR_MASK;
904b991d4b5SXuhui Lin 	n_l >>= CLK_FRAC_NUMERATOR_SHIFT;
905b991d4b5SXuhui Lin 	m_l = reg & CLK_FRAC_DENOMINATOR_MASK;
906b991d4b5SXuhui Lin 	m_l >>= CLK_FRAC_DENOMINATOR_SHIFT;
907b991d4b5SXuhui Lin 	n_h = reg_h & CLK_FRAC_H_NUMERATOR_MASK;
908b991d4b5SXuhui Lin 	n_h >>= CLK_FRAC_H_NUMERATOR_SHIFT;
909b991d4b5SXuhui Lin 	m_h = reg_h & CLK_FRAC_H_DENOMINATOR_MASK;
910b991d4b5SXuhui Lin 	m_h >>= CLK_FRAC_H_DENOMINATOR_SHIFT;
911b991d4b5SXuhui Lin 	n = n_l | (n_h << 16);
912b991d4b5SXuhui Lin 	m = m_l | (m_h << 16);
913b991d4b5SXuhui Lin 	return p_rate * n / m;
914b991d4b5SXuhui Lin }
915b991d4b5SXuhui Lin 
rv1126b_frac_set_rate(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)916b991d4b5SXuhui Lin static ulong rv1126b_frac_set_rate(struct rv1126b_clk_priv *priv,
917b991d4b5SXuhui Lin 				   ulong clk_id, ulong rate)
918b991d4b5SXuhui Lin {
919b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
920b991d4b5SXuhui Lin 	u32 src, p_rate, val;
921b991d4b5SXuhui Lin 	unsigned long m, n, m_l, n_l, m_h, n_h;
922b991d4b5SXuhui Lin 
923b991d4b5SXuhui Lin 	if ((OSC_HZ % rate) == 0) {
924b991d4b5SXuhui Lin 		src = CLK_FRAC_SRC_SEL_24M;
925b991d4b5SXuhui Lin 		p_rate = OSC_HZ;
926b991d4b5SXuhui Lin 	} else if ((priv->aupll_hz % rate) == 0) {
927b991d4b5SXuhui Lin 		src = CLK_FRAC_SRC_SEL_AUPLL;
928b991d4b5SXuhui Lin 		p_rate = priv->aupll_hz;
929b991d4b5SXuhui Lin 	} else if ((priv->cpll_hz % rate) == 0) {
930b991d4b5SXuhui Lin 		src = CLK_FRAC_SRC_SEL_CPLL;
931b991d4b5SXuhui Lin 		p_rate = priv->cpll_hz;
932b991d4b5SXuhui Lin 	} else {
933b991d4b5SXuhui Lin 		src = CLK_FRAC_SRC_SEL_GPLL;
934b991d4b5SXuhui Lin 		p_rate = priv->gpll_hz;
935b991d4b5SXuhui Lin 	}
936b991d4b5SXuhui Lin 
937b991d4b5SXuhui Lin 	rational_best_approximation(rate, p_rate,
938b991d4b5SXuhui Lin 				    GENMASK(24 - 1, 0),
939b991d4b5SXuhui Lin 				    GENMASK(24 - 1, 0),
940b991d4b5SXuhui Lin 				    &m, &n);
941b991d4b5SXuhui Lin 
942b991d4b5SXuhui Lin 	if (m < 4 && m != 0) {
943b991d4b5SXuhui Lin 		if (n % 2 == 0)
944b991d4b5SXuhui Lin 			val = 1;
945b991d4b5SXuhui Lin 		else
946b991d4b5SXuhui Lin 			val = DIV_ROUND_UP(4, m);
947b991d4b5SXuhui Lin 
948b991d4b5SXuhui Lin 		n *= val;
949b991d4b5SXuhui Lin 		m *= val;
950b991d4b5SXuhui Lin 		if (n > 0xffffff)
951b991d4b5SXuhui Lin 			n = 0xffffff;
952b991d4b5SXuhui Lin 	}
953b991d4b5SXuhui Lin 
954b991d4b5SXuhui Lin 	n_l = n & 0xffff;
955b991d4b5SXuhui Lin 	m_l = m & 0xffff;
956b991d4b5SXuhui Lin 	n_h = (n & 0xff0000) >> 16;
957b991d4b5SXuhui Lin 	m_h = (m & 0xff0000) >> 16;
958b991d4b5SXuhui Lin 
959b991d4b5SXuhui Lin 	switch (clk_id) {
960b991d4b5SXuhui Lin 	case CLK_CM_FRAC0:
961b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[10],
962b991d4b5SXuhui Lin 			     CLK_CM_FRAC0_SRC_SEL_MASK,
963b991d4b5SXuhui Lin 			     (src << CLK_CM_FRAC0_SRC_SEL_SHIFT));
964b991d4b5SXuhui Lin 		val = m_h << CLK_FRAC_H_NUMERATOR_SHIFT | n_h;
965b991d4b5SXuhui Lin 		writel(val, &cru->clk_cm_frac0_div_h);
966b991d4b5SXuhui Lin 		val = m_l << CLK_FRAC_NUMERATOR_SHIFT | n_l;
967b991d4b5SXuhui Lin 		writel(val, &cru->clksel_con[25]);
968b991d4b5SXuhui Lin 		break;
969b991d4b5SXuhui Lin 	case CLK_CM_FRAC1:
970b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[10],
971b991d4b5SXuhui Lin 			     CLK_CM_FRAC1_SRC_SEL_MASK,
972b991d4b5SXuhui Lin 			     (src << CLK_CM_FRAC1_SRC_SEL_SHIFT));
973b991d4b5SXuhui Lin 		val = m_h << CLK_FRAC_H_NUMERATOR_SHIFT | n_h;
974b991d4b5SXuhui Lin 		writel(val, &cru->clk_cm_frac1_div_h);
975b991d4b5SXuhui Lin 		val = m_l << CLK_FRAC_NUMERATOR_SHIFT | n_l;
976b991d4b5SXuhui Lin 		writel(val, &cru->clksel_con[26]);
977b991d4b5SXuhui Lin 		break;
978b991d4b5SXuhui Lin 	case CLK_CM_FRAC2:
979b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[10],
980b991d4b5SXuhui Lin 			     CLK_CM_FRAC2_SRC_SEL_MASK,
981b991d4b5SXuhui Lin 			     (src << CLK_CM_FRAC2_SRC_SEL_SHIFT));
982b991d4b5SXuhui Lin 		val = m_h << CLK_FRAC_H_NUMERATOR_SHIFT | n_h;
983b991d4b5SXuhui Lin 		writel(val, &cru->clk_cm_frac2_div_h);
984b991d4b5SXuhui Lin 		val = m_l << CLK_FRAC_NUMERATOR_SHIFT | n_l;
985b991d4b5SXuhui Lin 		writel(val, &cru->clksel_con[27]);
986b991d4b5SXuhui Lin 		break;
987b991d4b5SXuhui Lin 	case CLK_UART_FRAC0:
988b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[10],
989b991d4b5SXuhui Lin 			     CLK_UART_FRAC0_SRC_SEL_MASK,
990b991d4b5SXuhui Lin 			     (src << CLK_UART_FRAC0_SRC_SEL_SHIFT));
991b991d4b5SXuhui Lin 		val = m_h << CLK_FRAC_H_NUMERATOR_SHIFT | n_h;
992b991d4b5SXuhui Lin 		writel(val, &cru->clk_uart_frac0_div_h);
993b991d4b5SXuhui Lin 		val = m_l << CLK_FRAC_NUMERATOR_SHIFT | n_l;
994b991d4b5SXuhui Lin 		writel(val, &cru->clksel_con[28]);
995b991d4b5SXuhui Lin 		break;
996b991d4b5SXuhui Lin 	case CLK_UART_FRAC1:
997b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[10],
998b991d4b5SXuhui Lin 			     CLK_UART_FRAC1_SRC_SEL_MASK,
999b991d4b5SXuhui Lin 			     (src << CLK_UART_FRAC1_SRC_SEL_SHIFT));
1000b991d4b5SXuhui Lin 		val = m_h << CLK_FRAC_H_NUMERATOR_SHIFT | n_h;
1001b991d4b5SXuhui Lin 		writel(val, &cru->clk_uart_frac1_div_h);
1002b991d4b5SXuhui Lin 		val = m_l << CLK_FRAC_NUMERATOR_SHIFT | n_l;
1003b991d4b5SXuhui Lin 		writel(val, &cru->clksel_con[29]);
1004b991d4b5SXuhui Lin 		break;
1005b991d4b5SXuhui Lin 	case CLK_AUDIO_FRAC0:
1006b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[10],
1007b991d4b5SXuhui Lin 			     CLK_AUDIO_FRAC0_SRC_SEL_MASK,
1008b991d4b5SXuhui Lin 			     (src << CLK_AUDIO_FRAC0_SRC_SEL_SHIFT));
1009b991d4b5SXuhui Lin 		val = m_h << CLK_FRAC_H_NUMERATOR_SHIFT | n_h;
1010b991d4b5SXuhui Lin 		writel(val, &cru->clk_audio_frac0_div_h);
1011b991d4b5SXuhui Lin 		val = m_l << CLK_FRAC_NUMERATOR_SHIFT | n_l;
1012b991d4b5SXuhui Lin 		writel(val, &cru->clksel_con[30]);
1013b991d4b5SXuhui Lin 		break;
1014b991d4b5SXuhui Lin 	case CLK_AUDIO_FRAC1:
1015b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[10],
1016b991d4b5SXuhui Lin 			     CLK_AUDIO_FRAC0_SRC_SEL_MASK,
1017b991d4b5SXuhui Lin 			     (src << CLK_AUDIO_FRAC0_SRC_SEL_SHIFT));
1018b991d4b5SXuhui Lin 		val = m_h << CLK_FRAC_H_NUMERATOR_SHIFT | n_h;
1019b991d4b5SXuhui Lin 		writel(val, &cru->clk_audio_frac1_div_h);
1020b991d4b5SXuhui Lin 		val = m_l << CLK_FRAC_NUMERATOR_SHIFT | n_l;
1021b991d4b5SXuhui Lin 		writel(val, &cru->clksel_con[31]);
1022b991d4b5SXuhui Lin 		break;
1023b991d4b5SXuhui Lin 
1024b991d4b5SXuhui Lin 	default:
1025b991d4b5SXuhui Lin 		return -ENOENT;
1026b991d4b5SXuhui Lin 	}
1027b991d4b5SXuhui Lin 
1028b991d4b5SXuhui Lin 	return rv1126b_frac_get_rate(priv, clk_id);
1029b991d4b5SXuhui Lin }
1030b991d4b5SXuhui Lin 
rv1126b_uart_get_rate(struct rv1126b_clk_priv * priv,ulong clk_id)1031b991d4b5SXuhui Lin static ulong rv1126b_uart_get_rate(struct rv1126b_clk_priv *priv, ulong clk_id)
1032b991d4b5SXuhui Lin {
1033b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
1034b991d4b5SXuhui Lin 	u32 con, div, src, p_rate;
1035b991d4b5SXuhui Lin 
1036b991d4b5SXuhui Lin 	switch (clk_id) {
1037b991d4b5SXuhui Lin 	case SCLK_UART0:
1038b991d4b5SXuhui Lin 		con = readl(&cru->pmu_clksel_con[3]);
1039b991d4b5SXuhui Lin 		src = (con & SCLK_UART0_SEL_MASK) >> SCLK_UART0_SEL_SHIFT;
1040b991d4b5SXuhui Lin 		if (src == SCLK_UART0_SEL_UART0_SRC)
1041b991d4b5SXuhui Lin 			return rv1126b_uart_get_rate(priv, SCLK_UART0_SRC);
1042b991d4b5SXuhui Lin 		else if (src == SCLK_UART0_SEL_UART0_SRC)
1043b991d4b5SXuhui Lin 			return RC_OSC_HZ;
1044b991d4b5SXuhui Lin 		else
1045b991d4b5SXuhui Lin 			return OSC_HZ;
1046b991d4b5SXuhui Lin 	case SCLK_UART0_SRC:
1047b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[12]);
1048b991d4b5SXuhui Lin 		src = (con & SCLK_UART0_SRC_SEL_MASK) >>
1049b991d4b5SXuhui Lin 		      SCLK_UART0_SRC_SEL_SHIFT;
1050b991d4b5SXuhui Lin 		div = (con & SCLK_UART0_SRC_DIV_MASK) >>
1051b991d4b5SXuhui Lin 		      SCLK_UART0_SRC_DIV_SHIFT;
1052b991d4b5SXuhui Lin 		break;
1053b991d4b5SXuhui Lin 	case SCLK_UART1:
1054b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[12]);
1055b991d4b5SXuhui Lin 		src = (con & SCLK_UART1_SEL_MASK) >> SCLK_UART1_SEL_SHIFT;
1056b991d4b5SXuhui Lin 		div = (con & SCLK_UART1_DIV_MASK) >> SCLK_UART1_DIV_SHIFT;
1057b991d4b5SXuhui Lin 		break;
1058b991d4b5SXuhui Lin 	case SCLK_UART2:
1059b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[13]);
1060b991d4b5SXuhui Lin 		src = (con & SCLK_UART2_SEL_MASK) >> SCLK_UART2_SEL_SHIFT;
1061b991d4b5SXuhui Lin 		div = (con & SCLK_UART2_DIV_MASK) >> SCLK_UART2_DIV_SHIFT;
1062b991d4b5SXuhui Lin 		break;
1063b991d4b5SXuhui Lin 	case SCLK_UART3:
1064b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[13]);
1065b991d4b5SXuhui Lin 		src = (con & SCLK_UART3_SEL_MASK) >> SCLK_UART3_SEL_SHIFT;
1066b991d4b5SXuhui Lin 		div = (con & SCLK_UART3_DIV_MASK) >> SCLK_UART3_DIV_SHIFT;
1067b991d4b5SXuhui Lin 		break;
1068b991d4b5SXuhui Lin 	case SCLK_UART4:
1069b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[14]);
1070b991d4b5SXuhui Lin 		src = (con & SCLK_UART4_SEL_MASK) >> SCLK_UART4_SEL_SHIFT;
1071b991d4b5SXuhui Lin 		div = (con & SCLK_UART4_DIV_MASK) >> SCLK_UART4_DIV_SHIFT;
1072b991d4b5SXuhui Lin 		break;
1073b991d4b5SXuhui Lin 	case SCLK_UART5:
1074b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[14]);
1075b991d4b5SXuhui Lin 		src = (con & SCLK_UART5_SEL_MASK) >> SCLK_UART5_SEL_SHIFT;
1076b991d4b5SXuhui Lin 		div = (con & SCLK_UART5_DIV_MASK) >> SCLK_UART5_DIV_SHIFT;
1077b991d4b5SXuhui Lin 		break;
1078b991d4b5SXuhui Lin 	case SCLK_UART6:
1079b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[15]);
1080b991d4b5SXuhui Lin 		src = (con & SCLK_UART6_SEL_MASK) >> SCLK_UART6_SEL_SHIFT;
1081b991d4b5SXuhui Lin 		div = (con & SCLK_UART6_DIV_MASK) >> SCLK_UART6_DIV_SHIFT;
1082b991d4b5SXuhui Lin 		break;
1083b991d4b5SXuhui Lin 	case SCLK_UART7:
1084b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[15]);
1085b991d4b5SXuhui Lin 		src = (con & SCLK_UART7_SEL_MASK) >> SCLK_UART7_SEL_SHIFT;
1086b991d4b5SXuhui Lin 		div = (con & SCLK_UART7_DIV_MASK) >> SCLK_UART7_DIV_SHIFT;
1087b991d4b5SXuhui Lin 		break;
1088b991d4b5SXuhui Lin 
1089b991d4b5SXuhui Lin 	default:
1090b991d4b5SXuhui Lin 		return -ENOENT;
1091b991d4b5SXuhui Lin 	}
1092b991d4b5SXuhui Lin 
1093b991d4b5SXuhui Lin 	switch (src) {
1094b991d4b5SXuhui Lin 	case SCLK_UART_SEL_OSC:
1095b991d4b5SXuhui Lin 		p_rate = OSC_HZ;
1096b991d4b5SXuhui Lin 		break;
1097b991d4b5SXuhui Lin 	case SCLK_UART_SEL_CM_FRAC0:
1098b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_CM_FRAC0);
1099b991d4b5SXuhui Lin 		break;
1100b991d4b5SXuhui Lin 	case SCLK_UART_SEL_CM_FRAC1:
1101b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_CM_FRAC1);
1102b991d4b5SXuhui Lin 		break;
1103b991d4b5SXuhui Lin 	case SCLK_UART_SEL_CM_FRAC2:
1104b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_CM_FRAC2);
1105b991d4b5SXuhui Lin 		break;
1106b991d4b5SXuhui Lin 	case SCLK_UART_SEL_UART_FRAC0:
1107b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_UART_FRAC0);
1108b991d4b5SXuhui Lin 		break;
1109b991d4b5SXuhui Lin 	case SCLK_UART_SEL_UART_FRAC1:
1110b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_UART_FRAC1);
1111b991d4b5SXuhui Lin 		break;
1112b991d4b5SXuhui Lin 	default:
1113b991d4b5SXuhui Lin 		return -ENOENT;
1114b991d4b5SXuhui Lin 	}
1115b991d4b5SXuhui Lin 
1116b991d4b5SXuhui Lin 	return DIV_TO_RATE(p_rate, div);
1117b991d4b5SXuhui Lin }
1118b991d4b5SXuhui Lin 
rv1126b_uart_set_rate(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)1119b991d4b5SXuhui Lin static ulong rv1126b_uart_set_rate(struct rv1126b_clk_priv *priv,
1120b991d4b5SXuhui Lin 				   ulong clk_id, ulong rate)
1121b991d4b5SXuhui Lin {
1122b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
1123b991d4b5SXuhui Lin 	u32 uart_src, div, p_rate;
1124b991d4b5SXuhui Lin 
1125b991d4b5SXuhui Lin 	if (rv1126b_frac_get_rate(priv, CLK_CM_FRAC0) % rate == 0) {
1126b991d4b5SXuhui Lin 		uart_src = SCLK_UART_SEL_CM_FRAC0;
1127b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_CM_FRAC0);
1128b991d4b5SXuhui Lin 	} else if (rv1126b_frac_get_rate(priv, CLK_CM_FRAC1) % rate == 0) {
1129b991d4b5SXuhui Lin 		uart_src = SCLK_UART_SEL_CM_FRAC1;
1130b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_CM_FRAC1);
1131b991d4b5SXuhui Lin 	} else if (rv1126b_frac_get_rate(priv, CLK_CM_FRAC2) % rate == 0) {
1132b991d4b5SXuhui Lin 		uart_src = SCLK_UART_SEL_CM_FRAC2;
1133b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_CM_FRAC2);
1134b991d4b5SXuhui Lin 	} else if (rv1126b_frac_get_rate(priv, CLK_UART_FRAC0) % rate == 0) {
1135b991d4b5SXuhui Lin 		uart_src = SCLK_UART_SEL_UART_FRAC0;
1136b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_UART_FRAC0);
1137b991d4b5SXuhui Lin 	} else if (rv1126b_frac_get_rate(priv, CLK_UART_FRAC1) % rate == 0) {
1138b991d4b5SXuhui Lin 		uart_src = SCLK_UART_SEL_UART_FRAC1;
1139b991d4b5SXuhui Lin 		p_rate = rv1126b_frac_get_rate(priv, CLK_UART_FRAC1);
1140b991d4b5SXuhui Lin 	} else {
1141b991d4b5SXuhui Lin 		uart_src = SCLK_UART_SEL_OSC;
1142b991d4b5SXuhui Lin 		p_rate = OSC_HZ;
1143b991d4b5SXuhui Lin 	}
1144b991d4b5SXuhui Lin 
1145b991d4b5SXuhui Lin 	div = DIV_ROUND_UP(p_rate, rate);
1146b991d4b5SXuhui Lin 
1147b991d4b5SXuhui Lin 	switch (clk_id) {
1148b991d4b5SXuhui Lin 	case SCLK_UART0:
1149b991d4b5SXuhui Lin 		if (rate == OSC_HZ)
1150b991d4b5SXuhui Lin 			uart_src = SCLK_UART0_SEL_OSC;
1151b991d4b5SXuhui Lin 		else if (rate == RC_OSC_HZ)
1152b991d4b5SXuhui Lin 			uart_src = SCLK_UART0_SEL_RCOSC;
1153b991d4b5SXuhui Lin 		else
1154b991d4b5SXuhui Lin 			uart_src = SCLK_UART0_SEL_UART0_SRC;
1155b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->pmu_clksel_con[3],
1156b991d4b5SXuhui Lin 			     SCLK_UART0_SEL_MASK,
1157b991d4b5SXuhui Lin 			     uart_src << SCLK_UART0_SEL_SHIFT);
1158b991d4b5SXuhui Lin 		if (uart_src == SCLK_UART0_SEL_UART0_SRC)
1159b991d4b5SXuhui Lin 			rv1126b_uart_set_rate(priv, SCLK_UART0_SRC, rate);
1160b991d4b5SXuhui Lin 		break;
1161b991d4b5SXuhui Lin 	case SCLK_UART0_SRC:
1162b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[12],
1163b991d4b5SXuhui Lin 			     SCLK_UART0_SRC_SEL_MASK |
1164b991d4b5SXuhui Lin 			     SCLK_UART0_SRC_DIV_MASK,
1165b991d4b5SXuhui Lin 			     (uart_src << SCLK_UART0_SRC_SEL_SHIFT) |
1166b991d4b5SXuhui Lin 			     ((div - 1) <<
1167b991d4b5SXuhui Lin 			      SCLK_UART0_SRC_DIV_SHIFT));
1168b991d4b5SXuhui Lin 		break;
1169b991d4b5SXuhui Lin 	case SCLK_UART1:
1170b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[12],
1171b991d4b5SXuhui Lin 			     SCLK_UART1_SEL_MASK |
1172b991d4b5SXuhui Lin 			     SCLK_UART1_DIV_MASK,
1173b991d4b5SXuhui Lin 			     (uart_src << SCLK_UART1_SEL_SHIFT) |
1174b991d4b5SXuhui Lin 			     ((div - 1) <<
1175b991d4b5SXuhui Lin 			      SCLK_UART1_DIV_SHIFT));
1176b991d4b5SXuhui Lin 		break;
1177b991d4b5SXuhui Lin 	case SCLK_UART2:
1178b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[13],
1179b991d4b5SXuhui Lin 			     SCLK_UART2_SEL_MASK |
1180b991d4b5SXuhui Lin 			     SCLK_UART2_DIV_MASK,
1181b991d4b5SXuhui Lin 			     (uart_src << SCLK_UART2_SEL_SHIFT) |
1182b991d4b5SXuhui Lin 			     ((div - 1) <<
1183b991d4b5SXuhui Lin 			      SCLK_UART2_DIV_SHIFT));
1184b991d4b5SXuhui Lin 		break;
1185b991d4b5SXuhui Lin 	case SCLK_UART3:
1186b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[13],
1187b991d4b5SXuhui Lin 			     SCLK_UART3_SEL_MASK |
1188b991d4b5SXuhui Lin 			     SCLK_UART3_DIV_MASK,
1189b991d4b5SXuhui Lin 			     (uart_src << SCLK_UART3_SEL_SHIFT) |
1190b991d4b5SXuhui Lin 			     ((div - 1) <<
1191b991d4b5SXuhui Lin 			      SCLK_UART3_DIV_SHIFT));
1192b991d4b5SXuhui Lin 		break;
1193b991d4b5SXuhui Lin 	case SCLK_UART4:
1194b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[14],
1195b991d4b5SXuhui Lin 			     SCLK_UART4_SEL_MASK |
1196b991d4b5SXuhui Lin 			     SCLK_UART4_DIV_MASK,
1197b991d4b5SXuhui Lin 			     (uart_src << SCLK_UART4_SEL_SHIFT) |
1198b991d4b5SXuhui Lin 			     ((div - 1) <<
1199b991d4b5SXuhui Lin 			      SCLK_UART4_DIV_SHIFT));
1200b991d4b5SXuhui Lin 		break;
1201b991d4b5SXuhui Lin 	case SCLK_UART5:
1202b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[14],
1203b991d4b5SXuhui Lin 			     SCLK_UART5_SEL_MASK |
1204b991d4b5SXuhui Lin 			     SCLK_UART5_DIV_MASK,
1205b991d4b5SXuhui Lin 			     (uart_src << SCLK_UART5_SEL_SHIFT) |
1206b991d4b5SXuhui Lin 			     ((div - 1) <<
1207b991d4b5SXuhui Lin 			      SCLK_UART5_DIV_SHIFT));
1208b991d4b5SXuhui Lin 		break;
1209b991d4b5SXuhui Lin 	case SCLK_UART6:
1210b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[15],
1211b991d4b5SXuhui Lin 			     SCLK_UART6_SEL_MASK |
1212b991d4b5SXuhui Lin 			     SCLK_UART6_DIV_MASK,
1213b991d4b5SXuhui Lin 			     (uart_src << SCLK_UART6_SEL_SHIFT) |
1214b991d4b5SXuhui Lin 			     ((div - 1) <<
1215b991d4b5SXuhui Lin 			      SCLK_UART6_DIV_SHIFT));
1216b991d4b5SXuhui Lin 		break;
1217b991d4b5SXuhui Lin 	case SCLK_UART7:
1218b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[15],
1219b991d4b5SXuhui Lin 			     SCLK_UART7_SEL_MASK |
1220b991d4b5SXuhui Lin 			     SCLK_UART7_DIV_MASK,
1221b991d4b5SXuhui Lin 			     (uart_src << SCLK_UART7_SEL_SHIFT) |
1222b991d4b5SXuhui Lin 			     ((div - 1) <<
1223b991d4b5SXuhui Lin 			      SCLK_UART7_DIV_SHIFT));
1224b991d4b5SXuhui Lin 		break;
1225b991d4b5SXuhui Lin 	default:
1226b991d4b5SXuhui Lin 		return -ENOENT;
1227b991d4b5SXuhui Lin 	}
1228b991d4b5SXuhui Lin 
1229b991d4b5SXuhui Lin 	return rv1126b_uart_get_rate(priv, clk_id);
1230b991d4b5SXuhui Lin }
1231b991d4b5SXuhui Lin 
rv1126b_wdt_get_rate(struct rv1126b_clk_priv * priv,ulong clk_id)1232b991d4b5SXuhui Lin static ulong rv1126b_wdt_get_rate(struct rv1126b_clk_priv *priv, ulong clk_id)
1233b991d4b5SXuhui Lin {
1234b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
1235b991d4b5SXuhui Lin 	u32 sel, con;
1236b991d4b5SXuhui Lin 
1237b991d4b5SXuhui Lin 	switch (clk_id) {
1238b991d4b5SXuhui Lin 	case TCLK_WDT_NS_SRC:
1239b991d4b5SXuhui Lin 	case TCLK_WDT_NS:
1240b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[46]);
1241b991d4b5SXuhui Lin 		sel = (con & TCLK_WDT_NS_SEL_MASK) >>
1242b991d4b5SXuhui Lin 		      TCLK_WDT_NS_SEL_SHIFT;
1243b991d4b5SXuhui Lin 		break;
1244b991d4b5SXuhui Lin 	case TCLK_WDT_S:
1245b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[46]);
1246b991d4b5SXuhui Lin 		sel = (con & TCLK_WDT_S_SEL_MASK) >>
1247b991d4b5SXuhui Lin 		      TCLK_WDT_S_SEL_SHIFT;
1248b991d4b5SXuhui Lin 		break;
1249b991d4b5SXuhui Lin 	case TCLK_WDT_HPMCU:
1250b991d4b5SXuhui Lin 		con = readl(&cru->clksel_con[46]);
1251b991d4b5SXuhui Lin 		sel = (con & TCLK_WDT_HPMCU_SEL_MASK) >>
1252b991d4b5SXuhui Lin 		      TCLK_WDT_HPMCU_SEL_SHIFT;
1253b991d4b5SXuhui Lin 		break;
1254b991d4b5SXuhui Lin 	case TCLK_WDT_LPMCU:
1255b991d4b5SXuhui Lin 		con = readl(&cru->pmu_clksel_con[3]);
1256b991d4b5SXuhui Lin 		sel = (con & TCLK_WDT_LPMCU_SEL_MASK) >>
1257b991d4b5SXuhui Lin 		      TCLK_WDT_LPMCU_SEL_SHIFT;
1258b991d4b5SXuhui Lin 		if (sel == TCLK_WDT_LPMCU_SEL_100M)
1259b991d4b5SXuhui Lin 			return 100 * MHz;
1260b991d4b5SXuhui Lin 		else if (sel == TCLK_WDT_LPMCU_SEL_RCOSC)
1261b991d4b5SXuhui Lin 			return RC_OSC_HZ;
1262b991d4b5SXuhui Lin 		else if (sel == TCLK_WDT_LPMCU_SEL_OSC)
1263b991d4b5SXuhui Lin 			return OSC_HZ;
1264b991d4b5SXuhui Lin 		else
1265b991d4b5SXuhui Lin 			return 32768;
1266b991d4b5SXuhui Lin 	default:
1267b991d4b5SXuhui Lin 		return -ENOENT;
1268b991d4b5SXuhui Lin 	}
1269b991d4b5SXuhui Lin 
1270b991d4b5SXuhui Lin 	if (sel == TCLK_WDT_SEL_100M)
1271b991d4b5SXuhui Lin 		return 100 * MHz;
1272b991d4b5SXuhui Lin 	else
1273b991d4b5SXuhui Lin 		return OSC_HZ;
1274b991d4b5SXuhui Lin }
1275b991d4b5SXuhui Lin 
rv1126b_wdt_set_rate(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)1276b991d4b5SXuhui Lin static ulong rv1126b_wdt_set_rate(struct rv1126b_clk_priv *priv,
1277b991d4b5SXuhui Lin 				  ulong clk_id, ulong rate)
1278b991d4b5SXuhui Lin {
1279b991d4b5SXuhui Lin 	struct rv1126b_cru *cru = priv->cru;
1280b991d4b5SXuhui Lin 	int src_clk_sel;
1281b991d4b5SXuhui Lin 
1282b991d4b5SXuhui Lin 	if (rate == OSC_HZ)
1283b991d4b5SXuhui Lin 		src_clk_sel = TCLK_WDT_SEL_OSC;
1284b991d4b5SXuhui Lin 	else
1285b991d4b5SXuhui Lin 		src_clk_sel = TCLK_WDT_SEL_100M;
1286b991d4b5SXuhui Lin 
1287b991d4b5SXuhui Lin 	switch (clk_id) {
1288b991d4b5SXuhui Lin 	case TCLK_WDT_NS_SRC:
1289b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[46],
1290b991d4b5SXuhui Lin 			     TCLK_WDT_NS_SEL_MASK,
1291b991d4b5SXuhui Lin 			     (src_clk_sel << TCLK_WDT_NS_SEL_SHIFT));
1292b991d4b5SXuhui Lin 		break;
1293b991d4b5SXuhui Lin 	case TCLK_WDT_S:
1294b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[46],
1295b991d4b5SXuhui Lin 			     TCLK_WDT_NS_SEL_MASK,
1296b991d4b5SXuhui Lin 			     (src_clk_sel << TCLK_WDT_NS_SEL_SHIFT));
1297b991d4b5SXuhui Lin 		break;
1298b991d4b5SXuhui Lin 	case TCLK_WDT_HPMCU:
1299b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->clksel_con[46],
1300b991d4b5SXuhui Lin 			     TCLK_WDT_HPMCU_SEL_MASK,
1301b991d4b5SXuhui Lin 			     (src_clk_sel << TCLK_WDT_HPMCU_SEL_SHIFT));
1302b991d4b5SXuhui Lin 		break;
1303b991d4b5SXuhui Lin 	case TCLK_WDT_LPMCU:
1304b991d4b5SXuhui Lin 		if (rate == OSC_HZ)
1305b991d4b5SXuhui Lin 			src_clk_sel = TCLK_WDT_LPMCU_SEL_OSC;
1306b991d4b5SXuhui Lin 		else if (rate == RC_OSC_HZ)
1307b991d4b5SXuhui Lin 			src_clk_sel = TCLK_WDT_LPMCU_SEL_RCOSC;
1308b991d4b5SXuhui Lin 		else if (rate == 1000000)
1309b991d4b5SXuhui Lin 			src_clk_sel = TCLK_WDT_LPMCU_SEL_100M;
1310b991d4b5SXuhui Lin 		else
1311b991d4b5SXuhui Lin 			src_clk_sel = TCLK_WDT_LPMCU_SEL_32K;
1312b991d4b5SXuhui Lin 		rk_clrsetreg(&cru->pmu_clksel_con[3],
1313b991d4b5SXuhui Lin 			     TCLK_WDT_LPMCU_SEL_MASK,
1314b991d4b5SXuhui Lin 			     (src_clk_sel << TCLK_WDT_LPMCU_SEL_SHIFT));
1315b991d4b5SXuhui Lin 		break;
1316b991d4b5SXuhui Lin 	default:
1317b991d4b5SXuhui Lin 		return -ENOENT;
1318b991d4b5SXuhui Lin 	}
1319b991d4b5SXuhui Lin 	return rv1126b_wdt_get_rate(priv, clk_id);
1320b991d4b5SXuhui Lin }
1321b991d4b5SXuhui Lin 
rv1126b_vop_get_rate(struct rv1126b_clk_priv * priv,ulong clk_id)1322d744c1e3SElaine Zhang static ulong rv1126b_vop_get_rate(struct rv1126b_clk_priv *priv, ulong clk_id)
1323d744c1e3SElaine Zhang {
1324d744c1e3SElaine Zhang 	struct rv1126b_cru *cru = priv->cru;
1325d744c1e3SElaine Zhang 	u32 sel, div, con, p_rate;
1326d744c1e3SElaine Zhang 
1327d744c1e3SElaine Zhang 	switch (clk_id) {
1328d744c1e3SElaine Zhang 	case DCLK_VOP:
1329d744c1e3SElaine Zhang 		con = readl(&cru->clksel_con[43]);
1330d744c1e3SElaine Zhang 		sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
1331d744c1e3SElaine Zhang 		div = (con & DCLK_VOP_DIV_MASK) >> DCLK_VOP_DIV_SHIFT;
1332d744c1e3SElaine Zhang 		break;
1333d744c1e3SElaine Zhang 	default:
1334d744c1e3SElaine Zhang 		return -ENOENT;
1335d744c1e3SElaine Zhang 	}
1336d744c1e3SElaine Zhang 	if (sel == DCLK_VOP_SEL_CPLL)
1337d744c1e3SElaine Zhang 		p_rate = priv->cpll_hz;
1338d744c1e3SElaine Zhang 	else
1339d744c1e3SElaine Zhang 		p_rate = priv->gpll_hz;
1340d744c1e3SElaine Zhang 
1341d744c1e3SElaine Zhang 	return DIV_TO_RATE(p_rate, div);
1342d744c1e3SElaine Zhang }
1343d744c1e3SElaine Zhang 
rv1126b_vop_set_rate(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)1344d744c1e3SElaine Zhang static ulong rv1126b_vop_set_rate(struct rv1126b_clk_priv *priv,
1345d744c1e3SElaine Zhang 				 ulong clk_id, ulong rate)
1346d744c1e3SElaine Zhang {
1347d744c1e3SElaine Zhang 	struct rv1126b_cru *cru = priv->cru;
1348d744c1e3SElaine Zhang 	int src_clk, div, p_rate;
1349d744c1e3SElaine Zhang 
1350d744c1e3SElaine Zhang 	if (!(priv->cpll_hz % rate)) {
1351d744c1e3SElaine Zhang 		src_clk = DCLK_VOP_SEL_CPLL;
1352d744c1e3SElaine Zhang 		p_rate = priv->cpll_hz;
1353d744c1e3SElaine Zhang 	} else {
1354d744c1e3SElaine Zhang 		src_clk = DCLK_VOP_SEL_GPLL;
1355d744c1e3SElaine Zhang 		p_rate = priv->gpll_hz;
1356d744c1e3SElaine Zhang 	}
1357d744c1e3SElaine Zhang 
1358d744c1e3SElaine Zhang 	div = DIV_ROUND_UP(p_rate, rate);
1359d744c1e3SElaine Zhang 	switch (clk_id) {
1360d744c1e3SElaine Zhang 	case DCLK_VOP:
1361d744c1e3SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[43], DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK,
1362d744c1e3SElaine Zhang 			     (src_clk << DCLK_VOP_SEL_SHIFT) |
1363d744c1e3SElaine Zhang 			     ((div - 1) << DCLK_VOP_DIV_SHIFT) );
1364d744c1e3SElaine Zhang 		break;
1365d744c1e3SElaine Zhang 	default:
1366d744c1e3SElaine Zhang 		return -ENOENT;
1367d744c1e3SElaine Zhang 	}
1368d744c1e3SElaine Zhang 
1369d744c1e3SElaine Zhang 	return rv1126b_vop_get_rate(priv, clk_id);
1370d744c1e3SElaine Zhang }
1371d744c1e3SElaine Zhang 
rv1126b_mac_get_rate(struct rv1126b_clk_priv * priv,ulong clk_id)137256591f59SElaine Zhang static ulong rv1126b_mac_get_rate(struct rv1126b_clk_priv *priv, ulong clk_id)
137356591f59SElaine Zhang {
137456591f59SElaine Zhang 	struct rv1126b_cru *cru = priv->cru;
137556591f59SElaine Zhang 	u32 sel, div, con, p_rate;
137656591f59SElaine Zhang 
137756591f59SElaine Zhang 	switch (clk_id) {
137856591f59SElaine Zhang 	case CLK_GMAC_PTP_REF_SRC:
137956591f59SElaine Zhang 	case CLK_GMAC_PTP_REF:
138056591f59SElaine Zhang 		con = readl(&cru->clksel_con[45]);
138156591f59SElaine Zhang 		sel = (con & CLK_GMAC_PTP_REF_SRC_SEL_MASK) >>
138256591f59SElaine Zhang 		      CLK_GMAC_PTP_REF_SRC_SEL_SHIFT;
138356591f59SElaine Zhang 		div = (con & CLK_GMAC_PTP_REF_SRC_DIV_MASK) >>
138456591f59SElaine Zhang 		      CLK_GMAC_PTP_REF_SRC_DIV_SHIFT;
138556591f59SElaine Zhang 		if (sel == CLK_GMAC_PTP_REF_SRC_SEL_CPLL)
138656591f59SElaine Zhang 			p_rate = priv->cpll_hz;
138756591f59SElaine Zhang 		else
138856591f59SElaine Zhang 			p_rate = OSC_HZ;
138956591f59SElaine Zhang 		break;
139056591f59SElaine Zhang 	case CLK_MAC_OUT2IO:
139156591f59SElaine Zhang 		con = readl(&cru->clksel_con[69]);
139256591f59SElaine Zhang 		sel = (con & CLK_MAC_OUT2IO_SEL_MASK) >>
139356591f59SElaine Zhang 		      CLK_MAC_OUT2IO_SEL_SHIFT;
139456591f59SElaine Zhang 		div = (con & CLK_MAC_OUT2IO_DIV_MASK) >>
139556591f59SElaine Zhang 		      CLK_MAC_OUT2IO_DIV_SHIFT;
139656591f59SElaine Zhang 		if (sel == CLK_MAC_OUT2IO_SEL_CPLL)
139756591f59SElaine Zhang 			p_rate = priv->cpll_hz;
139856591f59SElaine Zhang 		else if (sel == CLK_MAC_OUT2IO_SEL_GPLL)
139956591f59SElaine Zhang 			p_rate = priv->gpll_hz;
140056591f59SElaine Zhang 		else
140156591f59SElaine Zhang 			p_rate = OSC_HZ;
140256591f59SElaine Zhang 		break;
140356591f59SElaine Zhang 	case CLK_GMAC_125M:
140456591f59SElaine Zhang 		return priv->cpll_hz / 8;
140556591f59SElaine Zhang 	case CLK_50M_GMAC_IOBUF_VI:
140656591f59SElaine Zhang 		return priv->cpll_hz / 20;
140756591f59SElaine Zhang 	default:
140856591f59SElaine Zhang 		return -ENOENT;
140956591f59SElaine Zhang 	}
141056591f59SElaine Zhang 
141156591f59SElaine Zhang 	return DIV_TO_RATE(p_rate, div);
141256591f59SElaine Zhang }
141356591f59SElaine Zhang 
rv1126b_mac_set_rate(struct rv1126b_clk_priv * priv,ulong clk_id,ulong rate)141456591f59SElaine Zhang static ulong rv1126b_mac_set_rate(struct rv1126b_clk_priv *priv,
141556591f59SElaine Zhang 				  ulong clk_id, ulong rate)
141656591f59SElaine Zhang {
141756591f59SElaine Zhang 	struct rv1126b_cru *cru = priv->cru;
141856591f59SElaine Zhang 	int src_clk, div, p_rate;
141956591f59SElaine Zhang 
142056591f59SElaine Zhang 	switch (clk_id) {
142156591f59SElaine Zhang 	case CLK_GMAC_PTP_REF_SRC:
142256591f59SElaine Zhang 	case CLK_GMAC_PTP_REF:
142356591f59SElaine Zhang 		if (!(priv->cpll_hz % rate)) {
142456591f59SElaine Zhang 			src_clk = CLK_GMAC_PTP_REF_SRC_SEL_CPLL;
142556591f59SElaine Zhang 			p_rate = priv->cpll_hz;
142656591f59SElaine Zhang 		} else {
142756591f59SElaine Zhang 			src_clk = CLK_GMAC_PTP_REF_SRC_SEL_24M;
142856591f59SElaine Zhang 			p_rate = OSC_HZ;
142956591f59SElaine Zhang 		}
143056591f59SElaine Zhang 		div = DIV_ROUND_UP(p_rate, rate);
143156591f59SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[45],
143256591f59SElaine Zhang 			     CLK_GMAC_PTP_REF_SRC_DIV_MASK |
143356591f59SElaine Zhang 			     CLK_GMAC_PTP_REF_SRC_SEL_MASK,
143456591f59SElaine Zhang 			     (src_clk << CLK_GMAC_PTP_REF_SRC_SEL_SHIFT) |
143556591f59SElaine Zhang 			     ((div - 1) << CLK_GMAC_PTP_REF_SRC_DIV_SHIFT));
143656591f59SElaine Zhang 		break;
143756591f59SElaine Zhang 	case CLK_MAC_OUT2IO:
143856591f59SElaine Zhang 		if (!(priv->cpll_hz % rate)) {
143956591f59SElaine Zhang 			src_clk = CLK_MAC_OUT2IO_SEL_CPLL;
144056591f59SElaine Zhang 			p_rate = priv->cpll_hz;
144156591f59SElaine Zhang 		} else if (!(priv->gpll_hz % rate)) {
144256591f59SElaine Zhang 			src_clk = CLK_MAC_OUT2IO_SEL_GPLL;
144356591f59SElaine Zhang 			p_rate = priv->gpll_hz;
144456591f59SElaine Zhang 		} else {
144556591f59SElaine Zhang 			src_clk = CLK_MAC_OUT2IO_SEL_24M;
144656591f59SElaine Zhang 			p_rate = OSC_HZ;
144756591f59SElaine Zhang 		}
144856591f59SElaine Zhang 		div = DIV_ROUND_UP(p_rate, rate);
144956591f59SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[69],
145056591f59SElaine Zhang 			     CLK_MAC_OUT2IO_DIV_MASK | CLK_MAC_OUT2IO_SEL_MASK,
145156591f59SElaine Zhang 			     (src_clk << CLK_MAC_OUT2IO_SEL_SHIFT) |
145256591f59SElaine Zhang 			     ((div - 1) << CLK_MAC_OUT2IO_DIV_SHIFT));
145356591f59SElaine Zhang 		writel(0x01000000, &cru->clkgate_con[15]);
145456591f59SElaine Zhang 		break;
145556591f59SElaine Zhang 	case CLK_GMAC_125M:
145656591f59SElaine Zhang 		return rv1126b_mac_get_rate(priv, clk_id);;
145756591f59SElaine Zhang 	case CLK_50M_GMAC_IOBUF_VI:
145856591f59SElaine Zhang 		return rv1126b_mac_get_rate(priv, clk_id);;
145956591f59SElaine Zhang 	default:
146056591f59SElaine Zhang 		return -ENOENT;
146156591f59SElaine Zhang 	}
146256591f59SElaine Zhang 
146356591f59SElaine Zhang 	return rv1126b_mac_get_rate(priv, clk_id);
146456591f59SElaine Zhang }
146556591f59SElaine Zhang 
rv1126b_clk_get_rate(struct clk * clk)1466b991d4b5SXuhui Lin static ulong rv1126b_clk_get_rate(struct clk *clk)
1467b991d4b5SXuhui Lin {
1468b991d4b5SXuhui Lin 	struct rv1126b_clk_priv *priv = dev_get_priv(clk->dev);
1469b991d4b5SXuhui Lin 	ulong rate = 0;
1470b991d4b5SXuhui Lin 
1471b991d4b5SXuhui Lin 	if (!priv->gpll_hz) {
1472b991d4b5SXuhui Lin 		printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1473b991d4b5SXuhui Lin 		return -ENOENT;
1474b991d4b5SXuhui Lin 	}
1475b991d4b5SXuhui Lin 
1476b991d4b5SXuhui Lin 	switch (clk->id) {
1477b991d4b5SXuhui Lin 	case PLL_GPLL:
1478b991d4b5SXuhui Lin 		rate = rockchip_pll_get_rate(&rv1126b_pll_clks[GPLL], priv->cru,
1479b991d4b5SXuhui Lin 					     GPLL);
1480b991d4b5SXuhui Lin 		break;
1481b991d4b5SXuhui Lin 	case PLL_AUPLL:
1482b991d4b5SXuhui Lin 		rate = rockchip_pll_get_rate(&rv1126b_pll_clks[AUPLL],
1483b991d4b5SXuhui Lin 					     priv->cru, AUPLL);
1484b991d4b5SXuhui Lin 		break;
1485b991d4b5SXuhui Lin 	case PLL_CPLL:
1486b991d4b5SXuhui Lin 		rate = rockchip_pll_get_rate(&rv1126b_pll_clks[CPLL], priv->cru,
1487b991d4b5SXuhui Lin 					     CPLL);
1488b991d4b5SXuhui Lin 		break;
1489b991d4b5SXuhui Lin 	case ACLK_PERI_ROOT:
1490b991d4b5SXuhui Lin 	case PCLK_PERI_ROOT:
1491b991d4b5SXuhui Lin 	case ACLK_TOP_ROOT:
1492b991d4b5SXuhui Lin 	case PCLK_TOP_ROOT:
1493b991d4b5SXuhui Lin 	case PCLK_BUS_ROOT:
1494b991d4b5SXuhui Lin 	case BUSCLK_PMU_SRC:
1495b991d4b5SXuhui Lin 	case ACLK_BUS_ROOT:
1496b991d4b5SXuhui Lin 	case HCLK_BUS_ROOT:
1497b991d4b5SXuhui Lin 		rate = rv1126b_peri_get_clk(priv, clk->id);
1498b991d4b5SXuhui Lin 		break;
1499b991d4b5SXuhui Lin 	case PCLK_RKCE:
1500b991d4b5SXuhui Lin 	case HCLK_NS_RKCE:
1501b991d4b5SXuhui Lin 	case ACLK_RKCE_SRC:
1502b991d4b5SXuhui Lin 	case ACLK_NSRKCE:
1503b991d4b5SXuhui Lin 	case CLK_PKA_RKCE_SRC:
1504b991d4b5SXuhui Lin 	case CLK_PKA_NSRKCE:
1505b991d4b5SXuhui Lin 		rate = rv1126b_crypto_get_clk(priv, clk->id);
1506b991d4b5SXuhui Lin 		break;
1507b991d4b5SXuhui Lin 	case CCLK_SDMMC0:
1508b991d4b5SXuhui Lin 	case HCLK_SDMMC0:
1509b991d4b5SXuhui Lin 	case CCLK_SDMMC1:
1510b991d4b5SXuhui Lin 	case HCLK_SDMMC1:
1511b991d4b5SXuhui Lin 	case CCLK_EMMC:
1512b991d4b5SXuhui Lin 	case HCLK_EMMC:
1513b991d4b5SXuhui Lin 	case SCLK_2X_FSPI0:
1514b991d4b5SXuhui Lin 	case HCLK_FSPI0:
1515b991d4b5SXuhui Lin 	case HCLK_XIP_FSPI0:
1516b991d4b5SXuhui Lin 	case SCLK_1X_FSPI1:
1517b991d4b5SXuhui Lin 	case HCLK_FSPI1:
1518b991d4b5SXuhui Lin 	case HCLK_XIP_FSPI1:
1519b991d4b5SXuhui Lin 		rate = rv1126b_mmc_get_clk(priv, clk->id);
1520b991d4b5SXuhui Lin 		break;
1521b991d4b5SXuhui Lin 	case CLK_I2C0:
1522b991d4b5SXuhui Lin 	case CLK_I2C1:
1523b991d4b5SXuhui Lin 	case CLK_I2C3:
1524b991d4b5SXuhui Lin 	case CLK_I2C4:
1525b991d4b5SXuhui Lin 	case CLK_I2C5:
1526b991d4b5SXuhui Lin 	case CLK_I2C2:
1527b991d4b5SXuhui Lin 	case CLK_I2C_BUS_SRC:
1528b991d4b5SXuhui Lin 		rate = rv1126b_i2c_get_clk(priv, clk->id);
1529b991d4b5SXuhui Lin 		break;
1530b991d4b5SXuhui Lin 	case CLK_SPI0:
1531b991d4b5SXuhui Lin 	case CLK_SPI1:
1532b991d4b5SXuhui Lin 		rate = rv1126b_spi_get_clk(priv, clk->id);
1533b991d4b5SXuhui Lin 		break;
1534b991d4b5SXuhui Lin 	case CLK_PWM0:
1535b991d4b5SXuhui Lin 	case CLK_PWM2:
1536b991d4b5SXuhui Lin 	case CLK_PWM3:
1537b991d4b5SXuhui Lin 	case CLK_PWM1:
1538b991d4b5SXuhui Lin 		rate = rv1126b_pwm_get_clk(priv, clk->id);
1539b991d4b5SXuhui Lin 		break;
1540b991d4b5SXuhui Lin 	case CLK_SARADC0:
1541b991d4b5SXuhui Lin 	case CLK_SARADC0_SRC:
1542b991d4b5SXuhui Lin 	case CLK_SARADC1:
1543b991d4b5SXuhui Lin 	case CLK_SARADC1_SRC:
1544b991d4b5SXuhui Lin 	case CLK_SARADC2:
1545b991d4b5SXuhui Lin 	case CLK_SARADC2_SRC:
1546b991d4b5SXuhui Lin 	case CLK_TSADC:
1547b991d4b5SXuhui Lin 	case CLK_TSADC_PHYCTRL:
1548b991d4b5SXuhui Lin 		rate = rv1126b_adc_get_clk(priv, clk->id);
1549b991d4b5SXuhui Lin 		break;
1550b991d4b5SXuhui Lin 	case CLK_CM_FRAC0:
1551b991d4b5SXuhui Lin 	case CLK_CM_FRAC1:
1552b991d4b5SXuhui Lin 	case CLK_CM_FRAC2:
1553b991d4b5SXuhui Lin 	case CLK_UART_FRAC0:
1554b991d4b5SXuhui Lin 	case CLK_UART_FRAC1:
1555b991d4b5SXuhui Lin 	case CLK_AUDIO_FRAC0:
1556b991d4b5SXuhui Lin 	case CLK_AUDIO_FRAC1:
1557b991d4b5SXuhui Lin 		rate = rv1126b_frac_get_rate(priv, clk->id);
1558b991d4b5SXuhui Lin 		break;
1559b991d4b5SXuhui Lin 	case SCLK_UART0:
1560b991d4b5SXuhui Lin 	case SCLK_UART0_SRC:
1561b991d4b5SXuhui Lin 	case SCLK_UART1:
1562b991d4b5SXuhui Lin 	case SCLK_UART2:
1563b991d4b5SXuhui Lin 	case SCLK_UART3:
1564b991d4b5SXuhui Lin 	case SCLK_UART4:
1565b991d4b5SXuhui Lin 	case SCLK_UART5:
1566b991d4b5SXuhui Lin 	case SCLK_UART6:
1567b991d4b5SXuhui Lin 	case SCLK_UART7:
1568b991d4b5SXuhui Lin 		rate = rv1126b_uart_get_rate(priv, clk->id);
1569b991d4b5SXuhui Lin 		break;
1570b991d4b5SXuhui Lin 	case DCLK_DECOM:
1571b991d4b5SXuhui Lin 		rate = 400 * MHz;
1572b991d4b5SXuhui Lin 		break;
1573b991d4b5SXuhui Lin 	case TCLK_WDT_NS_SRC:
1574b991d4b5SXuhui Lin 	case TCLK_WDT_NS:
1575b991d4b5SXuhui Lin 	case TCLK_WDT_S:
1576b991d4b5SXuhui Lin 	case TCLK_WDT_HPMCU:
1577b991d4b5SXuhui Lin 	case TCLK_WDT_LPMCU:
1578b991d4b5SXuhui Lin 		rate = rv1126b_wdt_get_rate(priv, clk->id);
1579b991d4b5SXuhui Lin 		break;
1580d744c1e3SElaine Zhang 	case DCLK_VOP:
1581d744c1e3SElaine Zhang 		rate = rv1126b_vop_get_rate(priv, clk->id);
1582d744c1e3SElaine Zhang 		break;
158356591f59SElaine Zhang 	case CLK_GMAC_125M:
158456591f59SElaine Zhang 	case CLK_GMAC_PTP_REF_SRC:
158556591f59SElaine Zhang 	case CLK_50M_GMAC_IOBUF_VI:
158656591f59SElaine Zhang 	case CLK_MAC_OUT2IO:
158756591f59SElaine Zhang 	case CLK_GMAC_PTP_REF:
158856591f59SElaine Zhang 		rate = rv1126b_mac_get_rate(priv, clk->id);
158956591f59SElaine Zhang 		break;
1590d744c1e3SElaine Zhang 
1591b991d4b5SXuhui Lin 	default:
1592b991d4b5SXuhui Lin 		return -ENOENT;
1593b991d4b5SXuhui Lin 	}
1594b991d4b5SXuhui Lin 
1595b991d4b5SXuhui Lin 	return rate;
1596b991d4b5SXuhui Lin };
1597b991d4b5SXuhui Lin 
rv1126b_clk_set_rate(struct clk * clk,ulong rate)1598b991d4b5SXuhui Lin static ulong rv1126b_clk_set_rate(struct clk *clk, ulong rate)
1599b991d4b5SXuhui Lin {
1600b991d4b5SXuhui Lin 	struct rv1126b_clk_priv *priv = dev_get_priv(clk->dev);
1601b991d4b5SXuhui Lin 	ulong ret = 0;
1602b991d4b5SXuhui Lin 
1603b991d4b5SXuhui Lin 	if (!priv->gpll_hz) {
1604b991d4b5SXuhui Lin 		printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1605b991d4b5SXuhui Lin 		return -ENOENT;
1606b991d4b5SXuhui Lin 	}
1607b991d4b5SXuhui Lin 
1608b991d4b5SXuhui Lin 	switch (clk->id) {
1609b991d4b5SXuhui Lin 	case PLL_GPLL:
1610b991d4b5SXuhui Lin 		ret = rockchip_pll_set_rate(&rv1126b_pll_clks[GPLL], priv->cru,
1611b991d4b5SXuhui Lin 					    GPLL, rate);
1612b991d4b5SXuhui Lin 		break;
1613b991d4b5SXuhui Lin 	case PLL_AUPLL:
1614b991d4b5SXuhui Lin 		ret = rockchip_pll_set_rate(&rv1126b_pll_clks[AUPLL], priv->cru,
1615b991d4b5SXuhui Lin 					    AUPLL, rate);
1616b991d4b5SXuhui Lin 		break;
1617b991d4b5SXuhui Lin 	case PLL_CPLL:
1618b991d4b5SXuhui Lin 		ret = rockchip_pll_set_rate(&rv1126b_pll_clks[CPLL], priv->cru,
1619b991d4b5SXuhui Lin 					    CPLL, rate);
1620b991d4b5SXuhui Lin 		break;
1621b991d4b5SXuhui Lin 	case ACLK_PERI_ROOT:
1622b991d4b5SXuhui Lin 	case PCLK_PERI_ROOT:
1623b991d4b5SXuhui Lin 	case ACLK_TOP_ROOT:
1624b991d4b5SXuhui Lin 	case PCLK_TOP_ROOT:
1625b991d4b5SXuhui Lin 	case PCLK_BUS_ROOT:
1626b991d4b5SXuhui Lin 	case BUSCLK_PMU_SRC:
1627b991d4b5SXuhui Lin 	case ACLK_BUS_ROOT:
1628b991d4b5SXuhui Lin 	case HCLK_BUS_ROOT:
1629b991d4b5SXuhui Lin 		ret = rv1126b_peri_set_clk(priv, clk->id, rate);
1630b991d4b5SXuhui Lin 		break;
1631b991d4b5SXuhui Lin 	case PCLK_RKCE:
1632b991d4b5SXuhui Lin 	case HCLK_NS_RKCE:
1633b991d4b5SXuhui Lin 	case ACLK_RKCE_SRC:
1634b991d4b5SXuhui Lin 	case ACLK_NSRKCE:
1635b991d4b5SXuhui Lin 	case CLK_PKA_RKCE_SRC:
1636b991d4b5SXuhui Lin 	case CLK_PKA_NSRKCE:
1637b991d4b5SXuhui Lin 		ret = rv1126b_crypto_set_clk(priv, clk->id, rate);
1638b991d4b5SXuhui Lin 		break;
1639b991d4b5SXuhui Lin 	case CCLK_SDMMC0:
1640b991d4b5SXuhui Lin 	case HCLK_SDMMC0:
1641b991d4b5SXuhui Lin 	case CCLK_SDMMC1:
1642b991d4b5SXuhui Lin 	case HCLK_SDMMC1:
1643b991d4b5SXuhui Lin 	case CCLK_EMMC:
1644b991d4b5SXuhui Lin 	case HCLK_EMMC:
1645b991d4b5SXuhui Lin 	case SCLK_2X_FSPI0:
1646b991d4b5SXuhui Lin 	case HCLK_FSPI0:
1647b991d4b5SXuhui Lin 	case HCLK_XIP_FSPI0:
1648b991d4b5SXuhui Lin 	case SCLK_1X_FSPI1:
1649b991d4b5SXuhui Lin 	case HCLK_FSPI1:
1650b991d4b5SXuhui Lin 	case HCLK_XIP_FSPI1:
1651b991d4b5SXuhui Lin 		ret = rv1126b_mmc_set_clk(priv, clk->id, rate);
1652b991d4b5SXuhui Lin 		break;
1653b991d4b5SXuhui Lin 	case CLK_I2C0:
1654b991d4b5SXuhui Lin 	case CLK_I2C1:
1655b991d4b5SXuhui Lin 	case CLK_I2C3:
1656b991d4b5SXuhui Lin 	case CLK_I2C4:
1657b991d4b5SXuhui Lin 	case CLK_I2C5:
1658b991d4b5SXuhui Lin 	case CLK_I2C2:
1659b991d4b5SXuhui Lin 	case CLK_I2C_BUS_SRC:
1660b991d4b5SXuhui Lin 		ret = rv1126b_i2c_set_clk(priv, clk->id, rate);
1661b991d4b5SXuhui Lin 		break;
1662b991d4b5SXuhui Lin 	case CLK_SPI0:
1663b991d4b5SXuhui Lin 	case CLK_SPI1:
1664b991d4b5SXuhui Lin 		ret = rv1126b_spi_set_clk(priv, clk->id, rate);
1665b991d4b5SXuhui Lin 		break;
1666b991d4b5SXuhui Lin 	case CLK_PWM0:
1667b991d4b5SXuhui Lin 	case CLK_PWM2:
1668b991d4b5SXuhui Lin 	case CLK_PWM3:
1669b991d4b5SXuhui Lin 	case CLK_PWM1:
1670b991d4b5SXuhui Lin 		ret = rv1126b_pwm_set_clk(priv, clk->id, rate);
1671b991d4b5SXuhui Lin 		break;
1672b991d4b5SXuhui Lin 	case CLK_SARADC0:
1673b991d4b5SXuhui Lin 	case CLK_SARADC0_SRC:
1674b991d4b5SXuhui Lin 	case CLK_SARADC1:
1675b991d4b5SXuhui Lin 	case CLK_SARADC1_SRC:
1676b991d4b5SXuhui Lin 	case CLK_SARADC2:
1677b991d4b5SXuhui Lin 	case CLK_SARADC2_SRC:
1678b991d4b5SXuhui Lin 	case CLK_TSADC:
1679b991d4b5SXuhui Lin 	case CLK_TSADC_PHYCTRL:
1680b991d4b5SXuhui Lin 		ret = rv1126b_adc_set_clk(priv, clk->id, rate);
1681b991d4b5SXuhui Lin 		break;
1682b991d4b5SXuhui Lin 	case CLK_CM_FRAC0:
1683b991d4b5SXuhui Lin 	case CLK_CM_FRAC1:
1684b991d4b5SXuhui Lin 	case CLK_CM_FRAC2:
1685b991d4b5SXuhui Lin 	case CLK_UART_FRAC0:
1686b991d4b5SXuhui Lin 	case CLK_UART_FRAC1:
1687b991d4b5SXuhui Lin 	case CLK_AUDIO_FRAC0:
1688b991d4b5SXuhui Lin 	case CLK_AUDIO_FRAC1:
1689b991d4b5SXuhui Lin 		ret = rv1126b_frac_set_rate(priv, clk->id, rate);
1690b991d4b5SXuhui Lin 		break;
1691b991d4b5SXuhui Lin 	case SCLK_UART0:
1692b991d4b5SXuhui Lin 	case SCLK_UART0_SRC:
1693b991d4b5SXuhui Lin 	case SCLK_UART1:
1694b991d4b5SXuhui Lin 	case SCLK_UART2:
1695b991d4b5SXuhui Lin 	case SCLK_UART3:
1696b991d4b5SXuhui Lin 	case SCLK_UART4:
1697b991d4b5SXuhui Lin 	case SCLK_UART5:
1698b991d4b5SXuhui Lin 	case SCLK_UART6:
1699b991d4b5SXuhui Lin 	case SCLK_UART7:
1700b991d4b5SXuhui Lin 		ret = rv1126b_uart_set_rate(priv, clk->id, rate);
1701b991d4b5SXuhui Lin 		break;
1702b991d4b5SXuhui Lin 	case DCLK_DECOM:
1703b991d4b5SXuhui Lin 		break;
1704b991d4b5SXuhui Lin 	case TCLK_WDT_NS_SRC:
1705b991d4b5SXuhui Lin 	case TCLK_WDT_NS:
1706b991d4b5SXuhui Lin 	case TCLK_WDT_S:
1707b991d4b5SXuhui Lin 	case TCLK_WDT_HPMCU:
1708b991d4b5SXuhui Lin 	case TCLK_WDT_LPMCU:
170941bbe61eSElaine Zhang 		ret = rv1126b_wdt_set_rate(priv, clk->id, rate);
1710b991d4b5SXuhui Lin 		break;
1711d744c1e3SElaine Zhang 	case DCLK_VOP:
171241bbe61eSElaine Zhang 		ret = rv1126b_vop_set_rate(priv, clk->id, rate);
1713d744c1e3SElaine Zhang 		break;
171456591f59SElaine Zhang 	case CLK_GMAC_125M:
171556591f59SElaine Zhang 	case CLK_GMAC_PTP_REF_SRC:
171656591f59SElaine Zhang 	case CLK_50M_GMAC_IOBUF_VI:
171756591f59SElaine Zhang 	case CLK_MAC_OUT2IO:
171856591f59SElaine Zhang 	case CLK_GMAC_PTP_REF:
171956591f59SElaine Zhang 		ret = rv1126b_mac_set_rate(priv, clk->id, rate);
172056591f59SElaine Zhang 		break;
1721d744c1e3SElaine Zhang 
1722b991d4b5SXuhui Lin 	default:
1723b991d4b5SXuhui Lin 		return -ENOENT;
1724b991d4b5SXuhui Lin 	}
1725b991d4b5SXuhui Lin 
1726b991d4b5SXuhui Lin 	return ret;
1727b991d4b5SXuhui Lin };
1728b991d4b5SXuhui Lin 
rv1126b_clk_set_parent(struct clk * clk,struct clk * parent)1729b991d4b5SXuhui Lin static int rv1126b_clk_set_parent(struct clk *clk, struct clk *parent)
1730b991d4b5SXuhui Lin {
1731b991d4b5SXuhui Lin 	switch (clk->id) {
1732b991d4b5SXuhui Lin 	default:
1733b991d4b5SXuhui Lin 		return -ENOENT;
1734b991d4b5SXuhui Lin 	}
1735b991d4b5SXuhui Lin 
1736b991d4b5SXuhui Lin 	return 0;
1737b991d4b5SXuhui Lin }
1738b991d4b5SXuhui Lin 
rv1126b_clk_enable(struct clk * clk)17391be17b4cSElaine Zhang static int rv1126b_clk_enable(struct clk *clk)
17401be17b4cSElaine Zhang {
17411be17b4cSElaine Zhang 	ulong ret = 0;
17421be17b4cSElaine Zhang 
17431be17b4cSElaine Zhang 	switch (clk->id) {
17441be17b4cSElaine Zhang #ifdef CONFIG_SPL_BUILD
17451be17b4cSElaine Zhang 	case PCLK_KEY_READER_S:
17461be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(0, 0x1U, 13),
17471be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(0));
17481be17b4cSElaine Zhang 		break;
17491be17b4cSElaine Zhang 	case HCLK_KL_RKCE_S:
17501be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(0, 0x1U, 9),
17511be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(0));
17521be17b4cSElaine Zhang 		break;
17531be17b4cSElaine Zhang 	case HCLK_RKCE_S:
17541be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(0, 0x1U, 8),
17551be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(0));
17561be17b4cSElaine Zhang 		break;
17571be17b4cSElaine Zhang 	case HCLK_RKRNG_S:
17581be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(0, 0x1U, 14),
17591be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(2));
17601be17b4cSElaine Zhang 		break;
17611be17b4cSElaine Zhang 	case CLK_PKA_RKCE_S:
17621be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(0, 0x1U, 13),
17631be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(2));
17641be17b4cSElaine Zhang 		break;
17651be17b4cSElaine Zhang 	case ACLK_RKCE_S:
17661be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(0, 0x1U, 12),
17671be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(2));
17681be17b4cSElaine Zhang 		break;
17691be17b4cSElaine Zhang #endif
17701be17b4cSElaine Zhang 	default:
17713602da55SElaine Zhang 		return ret;
17721be17b4cSElaine Zhang 	}
17731be17b4cSElaine Zhang 	return ret;
17741be17b4cSElaine Zhang }
17751be17b4cSElaine Zhang 
rv1126b_clk_disable(struct clk * clk)17761be17b4cSElaine Zhang static int rv1126b_clk_disable(struct clk *clk)
17771be17b4cSElaine Zhang {
17781be17b4cSElaine Zhang 	ulong ret = 0;
17791be17b4cSElaine Zhang 
17801be17b4cSElaine Zhang 	switch (clk->id) {
17811be17b4cSElaine Zhang #ifdef CONFIG_SPL_BUILD
17821be17b4cSElaine Zhang 	case PCLK_KEY_READER_S:
17831be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(1, 0x1U, 13),
17841be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(0));
17851be17b4cSElaine Zhang 		break;
17861be17b4cSElaine Zhang 	case HCLK_KL_RKCE_S:
17871be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(1, 0x1U, 9),
17881be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(0));
17891be17b4cSElaine Zhang 		break;
17901be17b4cSElaine Zhang 	case HCLK_RKCE_S:
17911be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(1, 0x1U, 8),
17921be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(0));
17931be17b4cSElaine Zhang 		break;
17941be17b4cSElaine Zhang 	case HCLK_RKRNG_S:
17951be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(1, 0x1U, 14),
17961be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(2));
17971be17b4cSElaine Zhang 		break;
17981be17b4cSElaine Zhang 	case CLK_PKA_RKCE_S:
17991be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(1, 0x1U, 13),
18001be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(2));
18011be17b4cSElaine Zhang 		break;
18021be17b4cSElaine Zhang 	case ACLK_RKCE_S:
18031be17b4cSElaine Zhang 		ret = writel(BITS_WITH_WMASK(1, 0x1U, 12),
18041be17b4cSElaine Zhang 			     RV1126B_CRU_BASE + RV1126B_SBUSCLKGATE_CON(2));
18051be17b4cSElaine Zhang 		break;
18061be17b4cSElaine Zhang #endif
18071be17b4cSElaine Zhang 	default:
18083602da55SElaine Zhang 		return ret;
18091be17b4cSElaine Zhang 	}
18101be17b4cSElaine Zhang 	return ret;
18111be17b4cSElaine Zhang }
18121be17b4cSElaine Zhang 
1813b991d4b5SXuhui Lin static struct clk_ops rv1126b_clk_ops = {
1814b991d4b5SXuhui Lin 	.get_rate = rv1126b_clk_get_rate,
1815b991d4b5SXuhui Lin 	.set_rate = rv1126b_clk_set_rate,
1816b991d4b5SXuhui Lin #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1817b991d4b5SXuhui Lin 	.set_parent = rv1126b_clk_set_parent,
1818b991d4b5SXuhui Lin #endif
18191be17b4cSElaine Zhang 	.enable = rv1126b_clk_enable,
18201be17b4cSElaine Zhang 	.disable = rv1126b_clk_disable,
1821b991d4b5SXuhui Lin };
1822b991d4b5SXuhui Lin 
rv1126b_clk_init(struct rv1126b_clk_priv * priv)1823b991d4b5SXuhui Lin static void rv1126b_clk_init(struct rv1126b_clk_priv *priv)
1824b991d4b5SXuhui Lin {
1825b991d4b5SXuhui Lin 	int ret;
1826b991d4b5SXuhui Lin 
1827b991d4b5SXuhui Lin 	priv->sync_kernel = false;
1828b991d4b5SXuhui Lin 	priv->gpll_hz = rockchip_pll_get_rate(&rv1126b_pll_clks[GPLL],
1829b991d4b5SXuhui Lin 					      priv->cru, GPLL);
1830b991d4b5SXuhui Lin 	if (priv->gpll_hz != GPLL_HZ) {
1831b991d4b5SXuhui Lin 		ret = rockchip_pll_set_rate(&rv1126b_pll_clks[GPLL], priv->cru,
1832b991d4b5SXuhui Lin 					    GPLL, GPLL_HZ);
1833b991d4b5SXuhui Lin 		if (!ret)
1834b991d4b5SXuhui Lin 			priv->gpll_hz = GPLL_HZ;
1835b991d4b5SXuhui Lin 	}
1836b991d4b5SXuhui Lin 	priv->aupll_hz = rockchip_pll_get_rate(&rv1126b_pll_clks[AUPLL],
1837b991d4b5SXuhui Lin 					       priv->cru, AUPLL);
1838b991d4b5SXuhui Lin 	if (priv->aupll_hz != AUPLL_HZ) {
1839b991d4b5SXuhui Lin 		ret = rockchip_pll_set_rate(&rv1126b_pll_clks[AUPLL], priv->cru,
1840b991d4b5SXuhui Lin 					    AUPLL, AUPLL_HZ);
1841b991d4b5SXuhui Lin 		if (!ret)
1842b991d4b5SXuhui Lin 			priv->aupll_hz = AUPLL_HZ;
1843b991d4b5SXuhui Lin 	}
1844b991d4b5SXuhui Lin 	priv->cpll_hz = rockchip_pll_get_rate(&rv1126b_pll_clks[CPLL],
1845b991d4b5SXuhui Lin 					      priv->cru, CPLL);
1846b991d4b5SXuhui Lin 	if (priv->cpll_hz != CPLL_HZ) {
1847b991d4b5SXuhui Lin 		ret = rockchip_pll_set_rate(&rv1126b_pll_clks[CPLL], priv->cru,
1848b991d4b5SXuhui Lin 					    CPLL, CPLL_HZ);
1849b991d4b5SXuhui Lin 		if (!ret)
1850b991d4b5SXuhui Lin 			priv->cpll_hz = CPLL_HZ;
1851b991d4b5SXuhui Lin 	}
1852b991d4b5SXuhui Lin }
1853b991d4b5SXuhui Lin 
rv1126b_clk_probe(struct udevice * dev)1854b991d4b5SXuhui Lin static int rv1126b_clk_probe(struct udevice *dev)
1855b991d4b5SXuhui Lin {
1856b991d4b5SXuhui Lin 	struct rv1126b_clk_priv *priv = dev_get_priv(dev);
1857b991d4b5SXuhui Lin 	int ret;
1858b991d4b5SXuhui Lin 
1859b991d4b5SXuhui Lin #ifdef CONFIG_SPL_BUILD
1860b991d4b5SXuhui Lin 	/* fix gpll and some clks modify by maskrom */
1861*5683539dSElaine Zhang 	writel(BITS_WITH_WMASK(11, 0x1fU, 5),
1862b991d4b5SXuhui Lin 	       RV1126B_CRU_BASE + RV1126B_CLKSEL_CON(1));
1863b991d4b5SXuhui Lin 	writel(BITS_WITH_WMASK(1, 0x1U, 15),
1864b991d4b5SXuhui Lin 	       RV1126B_CRU_BASE + RV1126B_CLKSEL_CON(1));
1865b991d4b5SXuhui Lin 	writel(BITS_WITH_WMASK(5, 0x1fU, 5),
1866b991d4b5SXuhui Lin 	       RV1126B_CRU_BASE + RV1126B_CLKSEL_CON(2));
1867b991d4b5SXuhui Lin 	writel(BITS_WITH_WMASK(1, 0x7U, 0),
1868b991d4b5SXuhui Lin 	       RV1126B_CRU_BASE + RV1126B_CLKSEL_CON(60));
1869b991d4b5SXuhui Lin 	writel(BITS_WITH_WMASK(1, 0x7U, 6),
1870b991d4b5SXuhui Lin 	       RV1126B_CRU_BASE + RV1126B_PLL_CON(9));
1871b991d4b5SXuhui Lin 	writel(BITS_WITH_WMASK(1, 0x3U, 4),
1872b991d4b5SXuhui Lin 	       RV1126B_CRU_BASE + RV1126B_MODE_CON);
18734a251cbaSElaine Zhang 	/* Set clk_pka_rkce to 198M */
18744a251cbaSElaine Zhang 	writel(BITS_WITH_WMASK(1, 0x1U, 12),
18754a251cbaSElaine Zhang 	       RV1126B_CRU_BASE + RV1126B_CLKSEL_CON(50));
1876b991d4b5SXuhui Lin #endif
1877b991d4b5SXuhui Lin 
1878b991d4b5SXuhui Lin 	rv1126b_clk_init(priv);
1879b991d4b5SXuhui Lin 
1880b991d4b5SXuhui Lin 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1881b991d4b5SXuhui Lin 	ret = clk_set_defaults(dev);
1882b991d4b5SXuhui Lin 	if (ret)
1883b991d4b5SXuhui Lin 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
1884b991d4b5SXuhui Lin 	else
1885b991d4b5SXuhui Lin 		priv->sync_kernel = true;
1886b991d4b5SXuhui Lin 	return 0;
1887b991d4b5SXuhui Lin }
1888b991d4b5SXuhui Lin 
rv1126b_clk_ofdata_to_platdata(struct udevice * dev)1889b991d4b5SXuhui Lin static int rv1126b_clk_ofdata_to_platdata(struct udevice *dev)
1890b991d4b5SXuhui Lin {
1891b991d4b5SXuhui Lin 	struct rv1126b_clk_priv *priv = dev_get_priv(dev);
1892b991d4b5SXuhui Lin 
1893b991d4b5SXuhui Lin 	priv->cru = dev_read_addr_ptr(dev);
1894b991d4b5SXuhui Lin 
1895b991d4b5SXuhui Lin 	return 0;
1896b991d4b5SXuhui Lin }
1897b991d4b5SXuhui Lin 
rv1126b_clk_bind(struct udevice * dev)1898b991d4b5SXuhui Lin static int rv1126b_clk_bind(struct udevice *dev)
1899b991d4b5SXuhui Lin {
1900b991d4b5SXuhui Lin 	int ret;
1901b991d4b5SXuhui Lin 	struct udevice *sys_child, *sf_child;
1902b991d4b5SXuhui Lin 	struct sysreset_reg *priv;
1903b991d4b5SXuhui Lin 	struct softreset_reg *sf_priv;
1904b991d4b5SXuhui Lin 
1905b991d4b5SXuhui Lin 	/* The reset driver does not have a device node, so bind it here */
1906b991d4b5SXuhui Lin 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1907b991d4b5SXuhui Lin 				 &sys_child);
1908b991d4b5SXuhui Lin 	if (ret) {
1909b991d4b5SXuhui Lin 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1910b991d4b5SXuhui Lin 	} else {
1911b991d4b5SXuhui Lin 		priv = malloc(sizeof(struct sysreset_reg));
1912b991d4b5SXuhui Lin 		priv->glb_srst_fst_value = offsetof(struct rv1126b_cru,
1913b991d4b5SXuhui Lin 						    glb_srst_fst);
1914b991d4b5SXuhui Lin 		priv->glb_srst_snd_value = offsetof(struct rv1126b_cru,
1915b991d4b5SXuhui Lin 						    glb_srst_snd);
1916b991d4b5SXuhui Lin 		sys_child->priv = priv;
1917b991d4b5SXuhui Lin 	}
1918b991d4b5SXuhui Lin 
1919b991d4b5SXuhui Lin 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1920b991d4b5SXuhui Lin 					 dev_ofnode(dev), &sf_child);
1921b991d4b5SXuhui Lin 	if (ret) {
1922b991d4b5SXuhui Lin 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1923b991d4b5SXuhui Lin 	} else {
1924b991d4b5SXuhui Lin 		sf_priv = malloc(sizeof(struct softreset_reg));
1925b991d4b5SXuhui Lin 		sf_priv->sf_reset_offset = offsetof(struct rv1126b_cru,
1926b991d4b5SXuhui Lin 						    softrst_con[0]);
1927b991d4b5SXuhui Lin 		sf_priv->sf_reset_num = CLK_NR_SRST;
1928b991d4b5SXuhui Lin 		sf_child->priv = sf_priv;
1929b991d4b5SXuhui Lin 	}
1930b991d4b5SXuhui Lin 
1931b991d4b5SXuhui Lin 	return 0;
1932b991d4b5SXuhui Lin }
1933b991d4b5SXuhui Lin 
1934b991d4b5SXuhui Lin static const struct udevice_id rv1126b_clk_ids[] = {
1935b991d4b5SXuhui Lin 	{ .compatible = "rockchip,rv1126b-cru" },
1936b991d4b5SXuhui Lin 	{ }
1937b991d4b5SXuhui Lin };
1938b991d4b5SXuhui Lin 
1939b991d4b5SXuhui Lin U_BOOT_DRIVER(rockchip_rv1126b_cru) = {
1940b991d4b5SXuhui Lin 	.name		= "rockchip_rv1126b_cru",
1941b991d4b5SXuhui Lin 	.id		= UCLASS_CLK,
1942b991d4b5SXuhui Lin 	.of_match	= rv1126b_clk_ids,
1943b991d4b5SXuhui Lin 	.priv_auto_alloc_size = sizeof(struct rv1126b_clk_priv),
1944b991d4b5SXuhui Lin 	.ofdata_to_platdata = rv1126b_clk_ofdata_to_platdata,
1945b991d4b5SXuhui Lin 	.ops		= &rv1126b_clk_ops,
1946b991d4b5SXuhui Lin 	.bind		= rv1126b_clk_bind,
1947b991d4b5SXuhui Lin 	.probe		= rv1126b_clk_probe,
1948b991d4b5SXuhui Lin };
1949b991d4b5SXuhui Lin 
1950b991d4b5SXuhui Lin #ifndef CONFIG_SPL_BUILD
1951b991d4b5SXuhui Lin /**
1952b991d4b5SXuhui Lin  * soc_clk_dump() - Print clock frequencies
1953b991d4b5SXuhui Lin  * Returns zero on success
1954b991d4b5SXuhui Lin  *
1955b991d4b5SXuhui Lin  * Implementation for the clk dump command.
1956b991d4b5SXuhui Lin  */
soc_clk_dump(void)1957b991d4b5SXuhui Lin int soc_clk_dump(void)
1958b991d4b5SXuhui Lin {
1959b991d4b5SXuhui Lin 	struct udevice *cru_dev;
1960b991d4b5SXuhui Lin 	struct rv1126b_clk_priv *priv;
1961b991d4b5SXuhui Lin 	const struct rv1126b_clk_info *clk_dump;
1962b991d4b5SXuhui Lin 	struct clk clk;
1963b991d4b5SXuhui Lin 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1964b991d4b5SXuhui Lin 	unsigned long rate;
1965b991d4b5SXuhui Lin 	int i, ret;
1966b991d4b5SXuhui Lin 
1967b991d4b5SXuhui Lin 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1968b991d4b5SXuhui Lin 					  DM_GET_DRIVER(rockchip_rv1126b_cru),
1969b991d4b5SXuhui Lin 					  &cru_dev);
1970b991d4b5SXuhui Lin 	if (ret) {
1971b991d4b5SXuhui Lin 		printf("%s failed to get cru device\n", __func__);
1972b991d4b5SXuhui Lin 		return ret;
1973b991d4b5SXuhui Lin 	}
1974b991d4b5SXuhui Lin 
1975b991d4b5SXuhui Lin 	priv = dev_get_priv(cru_dev);
1976b991d4b5SXuhui Lin 	printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1977b991d4b5SXuhui Lin 	       priv->sync_kernel ? "sync kernel" : "uboot",
1978b991d4b5SXuhui Lin 	       priv->armclk_enter_hz / 1000,
1979b991d4b5SXuhui Lin 	       priv->armclk_init_hz / 1000,
1980b991d4b5SXuhui Lin 	       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1981b991d4b5SXuhui Lin 	       priv->set_armclk_rate ? " KHz" : "N/A");
1982b991d4b5SXuhui Lin 	for (i = 0; i < clk_count; i++) {
1983b991d4b5SXuhui Lin 		clk_dump = &clks_dump[i];
1984b991d4b5SXuhui Lin 		if (clk_dump->name) {
1985b991d4b5SXuhui Lin 			clk.id = clk_dump->id;
1986b991d4b5SXuhui Lin 			if (clk_dump->is_cru)
1987b991d4b5SXuhui Lin 				ret = clk_request(cru_dev, &clk);
1988b991d4b5SXuhui Lin 			if (ret < 0)
1989b991d4b5SXuhui Lin 				return ret;
1990b991d4b5SXuhui Lin 
1991b991d4b5SXuhui Lin 			rate = clk_get_rate(&clk);
1992b991d4b5SXuhui Lin 			clk_free(&clk);
1993b991d4b5SXuhui Lin 			if (i == 0) {
1994b991d4b5SXuhui Lin 				if (rate < 0)
1995b991d4b5SXuhui Lin 					printf("  %s %s\n", clk_dump->name,
1996b991d4b5SXuhui Lin 					       "unknown");
1997b991d4b5SXuhui Lin 				else
1998b991d4b5SXuhui Lin 					printf("  %s %lu KHz\n", clk_dump->name,
1999b991d4b5SXuhui Lin 					       rate / 1000);
2000b991d4b5SXuhui Lin 			} else {
2001b991d4b5SXuhui Lin 				if (rate < 0)
2002b991d4b5SXuhui Lin 					printf("  %s %s\n", clk_dump->name,
2003b991d4b5SXuhui Lin 					       "unknown");
2004b991d4b5SXuhui Lin 				else
2005b991d4b5SXuhui Lin 					printf("  %s %lu KHz\n", clk_dump->name,
2006b991d4b5SXuhui Lin 					       rate / 1000);
2007b991d4b5SXuhui Lin 			}
2008b991d4b5SXuhui Lin 		}
2009b991d4b5SXuhui Lin 	}
2010b991d4b5SXuhui Lin 
2011b991d4b5SXuhui Lin 	return 0;
2012b991d4b5SXuhui Lin }
2013b991d4b5SXuhui Lin #endif
2014