xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3506.c (revision d50ae2019e8c020d508dcfe7bf68a933dbd70e9e)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2023 Rockchip Electronics Co., Ltd
4  * Author: Finley Xiao <finley.xiao@rock-chips.com>
5  */
6 
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <syscon.h>
11 #include <asm/arch/clock.h>
12 #include <asm/arch/cru_rk3506.h>
13 #include <asm/arch/grf_rk3506.h>
14 #include <asm/arch/hardware.h>
15 #include <asm/io.h>
16 #include <dm/lists.h>
17 #include <dt-bindings/clock/rockchip,rk3506-cru.h>
18 
19 DECLARE_GLOBAL_DATA_PTR;
20 
21 #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
22 
23 /*
24  * [FRAC PLL]: GPLL, V0PLL, V1PLL
25  *   - VCO Frequency: 950MHz to 3800MHZ
26  *   - Output Frequency: 19MHz to 3800MHZ
27  *   - refdiv: 1 to 63 (Int Mode), 1 to 2 (Frac Mode)
28  *   - fbdiv: 16 to 3800 (Int Mode), 20 to 380 (Frac Mode)
29  *   - post1div: 1 to 7
30  *   - post2div: 1 to 7
31  */
32 static struct rockchip_pll_rate_table rk3506_pll_rates[] = {
33 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
34 	RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
35 	RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
36 	RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
37 	RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
38 	RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
39 	RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
40 	RK3036_PLL_RATE(1350000000, 4, 225, 1, 1, 1, 0),
41 	RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
42 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
43 	RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
44 	RK3036_PLL_RATE(1179648000, 1, 49, 1, 1, 0, 2550137),
45 	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
46 	RK3036_PLL_RATE(1000000000, 3, 125, 1, 1, 1, 0),
47 	RK3036_PLL_RATE(993484800, 1, 41, 1, 1, 0, 6630355),
48 	RK3036_PLL_RATE(983040000, 1, 40, 1, 1, 0, 16106127),
49 	RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0),
50 	RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
51 	RK3036_PLL_RATE(903168000, 1, 75, 2, 1, 0, 4429185),
52 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
53 	RK3036_PLL_RATE(800000000, 3, 200, 2, 1, 1, 0),
54 	RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0),
55 	RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
56 	RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
57 	RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0),
58 	RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
59 	RK3036_PLL_RATE(96000000, 1, 48, 6, 2, 1, 0),
60 	{ /* sentinel */ },
61 };
62 
63 static struct rockchip_pll_clock rk3506_pll_clks[] = {
64 	[GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3506_PLL_CON(0),
65 		     RK3506_MODE_CON, 0, 10, 0, rk3506_pll_rates),
66 	[V0PLL] = PLL(pll_rk3328, PLL_V0PLL, RK3506_PLL_CON(8),
67 		     RK3506_MODE_CON, 2, 10, 0, rk3506_pll_rates),
68 	[V1PLL] = PLL(pll_rk3328, PLL_V1PLL, RK3506_PLL_CON(16),
69 		     RK3506_MODE_CON, 4, 10, 0, rk3506_pll_rates),
70 };
71 
72 #define RK3506_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg)	\
73 {								\
74 	.rate = _rate##U,					\
75 	.aclk_div = _aclk_m_core,				\
76 	.pclk_div = _pclk_dbg,					\
77 }
78 
79 /* SIGN-OFF: aclk_core: 500M, pclk_core: 125M, */
80 static struct rockchip_cpu_rate_table rk3506_cpu_rates[] = {
81 	RK3506_CPUCLK_RATE(1179648000, 1, 6),
82 	RK3506_CPUCLK_RATE(903168000, 1, 5),
83 	RK3506_CPUCLK_RATE(800000000, 1, 4),
84 	RK3506_CPUCLK_RATE(589824000, 1, 3),
85 	RK3506_CPUCLK_RATE(400000000, 1, 2),
86 	RK3506_CPUCLK_RATE(200000000, 1, 1),
87 	{ /* sentinel */ },
88 };
89 
90 #ifndef CONFIG_SPL_BUILD
91 #define RK3506_CLK_DUMP(_id, _name)		\
92 {						\
93 	.id = _id,				\
94 	.name = _name,				\
95 }
96 
97 static const struct rk3506_clk_info clks_dump[] = {
98 	RK3506_CLK_DUMP(PLL_GPLL, "gpll"),
99 	RK3506_CLK_DUMP(PLL_V0PLL, "v0pll"),
100 	RK3506_CLK_DUMP(PLL_V1PLL, "v1pll"),
101 	RK3506_CLK_DUMP(CLK_GPLL_DIV, "clk_gpll_div"),
102 	RK3506_CLK_DUMP(CLK_GPLL_DIV_100M, "clk_gpll_div_100m"),
103 	RK3506_CLK_DUMP(CLK_V0PLL_DIV, "clk_v0pll_div"),
104 	RK3506_CLK_DUMP(CLK_V1PLL_DIV, "clk_v1pll_div"),
105 	RK3506_CLK_DUMP(ACLK_BUS_ROOT, "aclk_bus_root"),
106 	RK3506_CLK_DUMP(HCLK_BUS_ROOT, "hclk_bus_root"),
107 	RK3506_CLK_DUMP(PCLK_BUS_ROOT, "pclk_bus_root"),
108 	RK3506_CLK_DUMP(ACLK_HSPERI_ROOT, "aclk_hsperi_root"),
109 	RK3506_CLK_DUMP(HCLK_LSPERI_ROOT, "hclk_ksperi_root"),
110 };
111 
112 /**
113  * soc_clk_dump() - Print clock frequencies
114  * Returns zero on success
115  *
116  * Implementation for the clk dump command.
117  */
118 int soc_clk_dump(void)
119 {
120 	const struct rk3506_clk_info *clk_dump;
121 	struct rk3506_clk_priv *priv;
122 	struct udevice *cru_dev;
123 	struct clk clk;
124 	ulong clk_count = ARRAY_SIZE(clks_dump);
125 	ulong rate;
126 	int i, ret;
127 	u32 sel;
128 
129 	ret = uclass_get_device_by_driver(UCLASS_CLK,
130 					  DM_GET_DRIVER(rockchip_rk3506_cru),
131 					  &cru_dev);
132 	if (ret) {
133 		printf("%s failed to get cru device\n", __func__);
134 		return ret;
135 	}
136 
137 	priv = dev_get_priv(cru_dev);
138 	sel = (readl(&priv->cru->clksel_con[15]) &
139 	       CLK_CORE_SRC_PVTMUX_SEL_MASK) >>
140 	       CLK_CORE_SRC_PVTMUX_SEL_SHIFT;
141 	if (sel == CLK_CORE_PVTPLL_SRC)
142 		printf("CLK: (arm clk use pvtpll, rate = 1200M)\n");
143 	else
144 		printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
145 		       priv->sync_kernel ? "sync kernel" : "uboot",
146 		       priv->armclk_enter_hz / 1000,
147 		       priv->armclk_init_hz / 1000,
148 		       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
149 		       priv->set_armclk_rate ? " KHz" : "N/A");
150 	for (i = 0; i < clk_count; i++) {
151 		clk_dump = &clks_dump[i];
152 		if (clk_dump->name) {
153 			clk.id = clk_dump->id;
154 			ret = clk_request(cru_dev, &clk);
155 			if (ret < 0)
156 				return ret;
157 
158 			rate = clk_get_rate(&clk);
159 			clk_free(&clk);
160 			if (i == 0) {
161 				if (rate < 0)
162 					printf("  %s %s\n", clk_dump->name,
163 					       "unknown");
164 				else
165 					printf("  %s %lu KHz\n", clk_dump->name,
166 					       rate / 1000);
167 			} else {
168 				if (rate < 0)
169 					printf("  %s %s\n", clk_dump->name,
170 					       "unknown");
171 				else
172 					printf("  %s %lu KHz\n", clk_dump->name,
173 					       rate / 1000);
174 			}
175 		}
176 	}
177 
178 	return 0;
179 }
180 #endif
181 
182 static int rk3506_armclk_get_rate(struct rk3506_clk_priv *priv)
183 {
184 	struct rk3506_cru *cru = priv->cru;
185 	u32 sel, con, div;
186 	ulong prate;
187 
188 	con = readl(&cru->clksel_con[15]);
189 	sel = (con & CLK_CORE_SRC_SEL_MASK) >> CLK_CORE_SRC_SEL_SHIFT;
190 	div = (con & CLK_CORE_SRC_DIV_MASK) >> CLK_CORE_SRC_DIV_SHIFT;
191 
192 	if (sel == CLK_CORE_SEL_GPLL)
193 		prate = priv->gpll_hz;
194 	else if (sel ==  CLK_CORE_SEL_V0PLL)
195 		prate = priv->v0pll_hz;
196 	else if (sel ==  CLK_CORE_SEL_V1PLL)
197 		prate = priv->v1pll_hz;
198 	else
199 		return -EINVAL;
200 
201 	return DIV_TO_RATE(prate, div);
202 }
203 
204 static int rk3506_armclk_set_rate(struct rk3506_clk_priv *priv, ulong new_rate)
205 {
206 	const struct rockchip_cpu_rate_table *rate;
207 	struct rk3506_cru *cru = priv->cru;
208 	ulong old_rate, prate;
209 	u32 con, sel, div, old_div;
210 
211 	rate = rockchip_get_cpu_settings(rk3506_cpu_rates, new_rate);
212 	if (!rate) {
213 		printf("%s unsupported rate\n", __func__);
214 		return -EINVAL;
215 	}
216 
217 	/*
218 	 * set up dependent divisors for PCLK and ACLK clocks.
219 	 */
220 	old_rate = rk3506_armclk_get_rate(priv);
221 	if (new_rate >= old_rate) {
222 		rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK,
223 			     rate->aclk_div << ACLK_CORE_DIV_SHIFT);
224 		rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK,
225 			     rate->pclk_div << PCLK_CORE_DIV_SHIFT);
226 	}
227 
228 	if (new_rate == 589824000 || new_rate == 1179648000) {
229 		sel = CLK_CORE_SEL_V0PLL;
230 		div = DIV_ROUND_UP(priv->v0pll_hz, new_rate);
231 		prate = priv->v0pll_hz;
232 	} else if (new_rate == 903168000) {
233 		sel = CLK_CORE_SEL_V1PLL;
234 		div = DIV_ROUND_UP(priv->v1pll_hz, new_rate);
235 		prate = priv->v1pll_hz;
236 	} else {
237 		sel = CLK_CORE_SEL_GPLL;
238 		div = DIV_ROUND_UP(priv->gpll_hz, new_rate);
239 		prate = priv->gpll_hz;
240 	}
241 	assert(div - 1 <= 31);
242 
243 	con = readl(&cru->clksel_con[15]);
244 	old_div = (con & CLK_CORE_SRC_DIV_MASK) >> CLK_CORE_SRC_DIV_SHIFT;
245 	if (DIV_TO_RATE(prate, old_div) > new_rate) {
246 		rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK,
247 			     (div - 1) << CLK_CORE_SRC_DIV_SHIFT);
248 		rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK,
249 			     sel << CLK_CORE_SRC_SEL_SHIFT);
250 	} else {
251 		rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK,
252 			     sel << CLK_CORE_SRC_SEL_SHIFT);
253 		rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK,
254 			     (div - 1) << CLK_CORE_SRC_DIV_SHIFT);
255 	}
256 
257 	if (new_rate < old_rate) {
258 		rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK,
259 			     rate->aclk_div << ACLK_CORE_DIV_SHIFT);
260 		rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK,
261 			     rate->pclk_div << PCLK_CORE_DIV_SHIFT);
262 	}
263 
264 	return 0;
265 }
266 
267 static ulong rk3506_pll_div_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
268 {
269 	struct rk3506_cru *cru = priv->cru;
270 	u32 con, div;
271 	ulong prate;
272 
273 	switch (clk_id) {
274 	case CLK_GPLL_DIV:
275 		con = readl(&cru->clksel_con[0]);
276 		div = (con & CLK_GPLL_DIV_MASK) >> CLK_GPLL_DIV_SHIFT;
277 		prate = priv->gpll_hz;
278 		break;
279 	case CLK_GPLL_DIV_100M:
280 		con = readl(&cru->clksel_con[0]);
281 		div = (con & CLK_GPLL_DIV_100M_MASK) >> CLK_GPLL_DIV_100M_SHIFT;
282 		prate = priv->gpll_div_hz;
283 		break;
284 	case CLK_V0PLL_DIV:
285 		con = readl(&cru->clksel_con[1]);
286 		div = (con & CLK_V0PLL_DIV_MASK) >> CLK_V0PLL_DIV_SHIFT;
287 		prate = priv->v0pll_hz;
288 		break;
289 	case CLK_V1PLL_DIV:
290 		con = readl(&cru->clksel_con[1]);
291 		div = (con & CLK_V1PLL_DIV_MASK) >> CLK_V1PLL_DIV_SHIFT;
292 		prate = priv->v1pll_hz;
293 		break;
294 	default:
295 		return -ENOENT;
296 	}
297 
298 	return DIV_TO_RATE(prate, div);
299 }
300 
301 static ulong rk3506_pll_div_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
302 				 ulong rate)
303 {
304 	struct rk3506_cru *cru = priv->cru;
305 	u32 div;
306 
307 	switch (clk_id) {
308 	case CLK_GPLL_DIV:
309 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
310 		assert(div - 1 <= 15);
311 		rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_MASK,
312 			     ((div - 1) << CLK_GPLL_DIV_SHIFT));
313 		break;
314 	case CLK_GPLL_DIV_100M:
315 		div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
316 		assert(div - 1 <= 15);
317 		rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_100M_MASK,
318 			     ((div - 1) << CLK_GPLL_DIV_100M_SHIFT));
319 		break;
320 	case CLK_V0PLL_DIV:
321 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
322 		assert(div - 1 <= 15);
323 		rk_clrsetreg(&cru->clksel_con[1], CLK_V0PLL_DIV_MASK,
324 			     ((div - 1) << CLK_V0PLL_DIV_SHIFT));
325 		break;
326 	case CLK_V1PLL_DIV:
327 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
328 		assert(div - 1 <= 15);
329 		rk_clrsetreg(&cru->clksel_con[1], CLK_V1PLL_DIV_MASK,
330 			     ((div - 1) << CLK_V1PLL_DIV_SHIFT));
331 		break;
332 	default:
333 		return -ENOENT;
334 	}
335 
336 	return rk3506_pll_div_get_rate(priv, clk_id);
337 }
338 
339 static ulong rk3506_bus_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
340 {
341 	struct rk3506_cru *cru = priv->cru;
342 	u32 sel, con, div;
343 	ulong prate;
344 
345 	switch (clk_id) {
346 	case ACLK_BUS_ROOT:
347 		con = readl(&cru->clksel_con[21]);
348 		sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT;
349 		div = (con & ACLK_BUS_DIV_MASK) >> ACLK_BUS_DIV_SHIFT;
350 		break;
351 	case HCLK_BUS_ROOT:
352 		con = readl(&cru->clksel_con[21]);
353 		sel = (con & HCLK_BUS_SEL_MASK) >> HCLK_BUS_SEL_SHIFT;
354 		div = (con & HCLK_BUS_DIV_MASK) >> HCLK_BUS_DIV_SHIFT;
355 		break;
356 	case PCLK_BUS_ROOT:
357 		con = readl(&cru->clksel_con[22]);
358 		sel = (con & PCLK_BUS_SEL_MASK) >> PCLK_BUS_SEL_SHIFT;
359 		div = (con & PCLK_BUS_DIV_MASK) >> PCLK_BUS_DIV_SHIFT;
360 		break;
361 	default:
362 		return -ENOENT;
363 	}
364 
365 	if (sel == ACLK_BUS_SEL_GPLL_DIV)
366 		prate = priv->gpll_div_hz;
367 	else if (sel == ACLK_BUS_SEL_V0PLL_DIV)
368 		prate = priv->v0pll_div_hz;
369 	else if (sel == ACLK_BUS_SEL_V1PLL_DIV)
370 		prate = priv->v1pll_div_hz;
371 	else
372 		return -EINVAL;
373 
374 	return DIV_TO_RATE(prate, div);
375 }
376 
377 static ulong rk3506_bus_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
378 				 ulong rate)
379 {
380 	struct rk3506_cru *cru = priv->cru;
381 	u32 sel, div;
382 
383 	if (priv->v0pll_div_hz % rate == 0) {
384 		sel = ACLK_BUS_SEL_V0PLL_DIV;
385 		div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
386 	} else if (priv->v1pll_div_hz % rate == 0) {
387 		sel= ACLK_BUS_SEL_V1PLL_DIV;
388 		div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
389 	} else {
390 		sel= ACLK_BUS_SEL_GPLL_DIV;
391 		div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
392 	}
393 	assert(div - 1 <= 31);
394 
395 	switch (clk_id) {
396 	case ACLK_BUS_ROOT:
397 		rk_clrsetreg(&cru->clksel_con[21],
398 			     ACLK_BUS_DIV_MASK | ACLK_BUS_SEL_MASK,
399 			     (sel << ACLK_BUS_SEL_SHIFT) |
400 			     ((div - 1) << ACLK_BUS_DIV_SHIFT));
401 		break;
402 	case HCLK_BUS_ROOT:
403 		rk_clrsetreg(&cru->clksel_con[21],
404 			     HCLK_BUS_SEL_MASK | HCLK_BUS_DIV_MASK,
405 			     (sel << HCLK_BUS_SEL_SHIFT) |
406 			     ((div - 1) << HCLK_BUS_DIV_SHIFT));
407 		break;
408 	case PCLK_BUS_ROOT:
409 		rk_clrsetreg(&cru->clksel_con[22],
410 			     PCLK_BUS_SEL_MASK | PCLK_BUS_DIV_MASK,
411 			     (sel << PCLK_BUS_SEL_SHIFT) |
412 			     ((div - 1) << PCLK_BUS_DIV_SHIFT));
413 		break;
414 	default:
415 		return -ENOENT;
416 	}
417 
418 	return rk3506_bus_get_rate(priv, clk_id);
419 }
420 
421 static ulong rk3506_peri_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
422 {
423 	struct rk3506_cru *cru = priv->cru;
424 	u32 sel, con, div;
425 	ulong prate;
426 
427 	switch (clk_id) {
428 	case ACLK_HSPERI_ROOT:
429 		con = readl(&cru->clksel_con[49]);
430 		sel = (con & ACLK_HSPERI_SEL_MASK) >> ACLK_HSPERI_SEL_SHIFT;
431 		div = (con & ACLK_HSPERI_DIV_MASK) >> ACLK_HSPERI_DIV_SHIFT;
432 		break;
433 	case HCLK_LSPERI_ROOT:
434 		con = readl(&cru->clksel_con[29]);
435 		sel = (con & HCLK_LSPERI_SEL_MASK) >> HCLK_LSPERI_SEL_SHIFT;
436 		div = (con & HCLK_LSPERI_DIV_MASK) >> HCLK_LSPERI_DIV_SHIFT;
437 		break;
438 	default:
439 		return -ENOENT;
440 	}
441 
442 	if (sel == ACLK_HSPERI_SEL_GPLL_DIV)
443 		prate = priv->gpll_div_hz;
444 	else if (sel == ACLK_HSPERI_SEL_V0PLL_DIV)
445 		prate = priv->v0pll_div_hz;
446 	else if (sel == ACLK_HSPERI_SEL_V1PLL_DIV)
447 		prate = priv->v1pll_div_hz;
448 	else
449 		return -EINVAL;
450 
451 	return DIV_TO_RATE(prate, div);
452 }
453 
454 static ulong rk3506_peri_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
455 				  ulong rate)
456 {
457 	struct rk3506_cru *cru = priv->cru;
458 	u32 sel, div;
459 
460 	if (priv->v0pll_div_hz % rate == 0) {
461 		sel = ACLK_BUS_SEL_V0PLL_DIV;
462 		div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
463 	} else if (priv->v1pll_div_hz % rate == 0) {
464 		sel = ACLK_BUS_SEL_V1PLL_DIV;
465 		div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
466 	} else {
467 		sel = ACLK_BUS_SEL_GPLL_DIV;
468 		div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
469 	}
470 	assert(div - 1 <= 31);
471 
472 	switch (clk_id) {
473 	case ACLK_HSPERI_ROOT:
474 		rk_clrsetreg(&cru->clksel_con[49],
475 			     ACLK_HSPERI_SEL_MASK | ACLK_HSPERI_DIV_MASK,
476 			     (sel << ACLK_HSPERI_SEL_SHIFT) |
477 			     ((div - 1) << ACLK_HSPERI_DIV_SHIFT));
478 		break;
479 	case HCLK_LSPERI_ROOT:
480 		rk_clrsetreg(&cru->clksel_con[29],
481 			     HCLK_LSPERI_SEL_MASK | HCLK_LSPERI_DIV_MASK,
482 			     (sel << HCLK_LSPERI_SEL_SHIFT) |
483 			     ((div - 1) << HCLK_LSPERI_DIV_SHIFT));
484 		break;
485 	default:
486 		return -ENOENT;
487 	}
488 
489 	return rk3506_peri_get_rate(priv, clk_id);
490 }
491 
492 static ulong rk3506_sdmmc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
493 {
494 	struct rk3506_cru *cru = priv->cru;
495 	u32 sel, con, div;
496 	ulong prate;
497 
498 	con = readl(&cru->clksel_con[49]);
499 	sel = (con & CCLK_SDMMC_SEL_MASK) >> CCLK_SDMMC_SEL_SHIFT;
500 	div = (con & CCLK_SDMMC_DIV_MASK) >> CCLK_SDMMC_DIV_SHIFT;
501 
502 	if (sel == CCLK_SDMMC_SEL_24M)
503 		prate = OSC_HZ;
504 	else if (sel == CCLK_SDMMC_SEL_GPLL)
505 		prate = priv->gpll_hz;
506 	else if (sel == CCLK_SDMMC_SEL_V0PLL)
507 		prate = priv->v0pll_hz;
508 	else if (sel == CCLK_SDMMC_SEL_V1PLL)
509 		prate = priv->v1pll_hz;
510 	else
511 		return -EINVAL;
512 
513 	return DIV_TO_RATE(prate, div);
514 }
515 
516 static ulong rk3506_sdmmc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
517 				  ulong rate)
518 {
519 	struct rk3506_cru *cru = priv->cru;
520 	u32 sel, div;
521 
522 	if (OSC_HZ % rate == 0) {
523 		sel = CCLK_SDMMC_SEL_24M;
524 		div = DIV_ROUND_UP(OSC_HZ, rate);
525 	} else if (priv->v0pll_hz % rate == 0) {
526 		sel = CCLK_SDMMC_SEL_V0PLL;
527 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
528 	} else if (priv->v1pll_hz % rate == 0) {
529 		sel= CCLK_SDMMC_SEL_V1PLL;
530 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
531 	} else {
532 		sel= CCLK_SDMMC_SEL_GPLL;
533 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
534 	}
535 	assert(div - 1 <= 63);
536 
537 	rk_clrsetreg(&cru->clksel_con[49],
538 		     CCLK_SDMMC_SEL_MASK | CCLK_SDMMC_DIV_MASK,
539 		     (sel << CCLK_SDMMC_SEL_SHIFT) |
540 		     ((div - 1) << CCLK_SDMMC_DIV_SHIFT));
541 
542 	return rk3506_sdmmc_get_rate(priv, clk_id);
543 }
544 
545 static ulong rk3506_saradc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
546 {
547 	struct rk3506_cru *cru = priv->cru;
548 	u32 div, con, sel;
549 	ulong prate;
550 
551 	con = readl(&cru->clksel_con[54]);
552 	div = (con & CLK_SARADC_DIV_MASK) >> CLK_SARADC_DIV_SHIFT;
553 	sel = (con & CLK_SARADC_SEL_MASK) >> CLK_SARADC_SEL_SHIFT;
554 
555 	if (sel == CLK_SARADC_SEL_24M)
556 		prate = OSC_HZ;
557 	else if (sel == CLK_SARADC_SEL_400K)
558 		prate = 400000;
559 	else if (sel == CLK_SARADC_SEL_32K)
560 		prate = 32000;
561 	else
562 		return -EINVAL;
563 
564 	return DIV_TO_RATE(prate, div);
565 }
566 
567 static ulong rk3506_saradc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
568 				    ulong rate)
569 {
570 	struct rk3506_cru *cru = priv->cru;
571 	u32 div, sel;
572 
573 	if (32000 % rate == 0) {
574 		sel = CLK_SARADC_SEL_32K;
575 		div = 1;
576 	} else if (400000 % rate == 0) {
577 		sel = CLK_SARADC_SEL_400K;
578 		div = 1;
579 	} else {
580 		sel= CLK_SARADC_SEL_24M;
581 		div = DIV_ROUND_UP(OSC_HZ, rate);
582 	}
583 	assert(div - 1 <= 15);
584 
585 	rk_clrsetreg(&cru->clksel_con[54],
586 		     CLK_SARADC_SEL_MASK | CLK_SARADC_DIV_MASK,
587 		     (sel << CLK_SARADC_SEL_SHIFT) |
588 		     ((div - 1) << CLK_SARADC_DIV_SHIFT));
589 
590 	return rk3506_saradc_get_rate(priv, clk_id);
591 }
592 
593 static ulong rk3506_tsadc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
594 {
595 	struct rk3506_cru *cru = priv->cru;
596 	u32 div, con;
597 
598 	con = readl(&cru->clksel_con[61]);
599 	switch (clk_id) {
600 	case CLK_TSADC_TSEN:
601 		div = (con & CLK_TSADC_TSEN_DIV_MASK) >> CLK_TSADC_TSEN_DIV_SHIFT;
602 		break;
603 	case CLK_TSADC:
604 		div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT;
605 		break;
606 	default:
607 		return -ENOENT;
608 	}
609 
610 	return DIV_TO_RATE(OSC_HZ, div);
611 }
612 
613 static ulong rk3506_tsadc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
614 				   ulong rate)
615 {
616 	struct rk3506_cru *cru = priv->cru;
617 	u32 div;
618 
619 	switch (clk_id) {
620 	case CLK_TSADC_TSEN:
621 		div = DIV_ROUND_UP(OSC_HZ, rate);
622 		assert(div - 1 <= 7);
623 		rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_TSEN_DIV_MASK,
624 			     (div - 1) << CLK_TSADC_TSEN_DIV_SHIFT);
625 		break;
626 	case CLK_TSADC:
627 		div = DIV_ROUND_UP(OSC_HZ, rate);
628 		assert(div - 1 <= 255);
629 		rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_DIV_MASK,
630 			     (div - 1) << CLK_TSADC_DIV_SHIFT);
631 		break;
632 	default:
633 		return -ENOENT;
634 	}
635 
636 
637 	return rk3506_tsadc_get_rate(priv, clk_id);
638 }
639 
640 static ulong rk3506_i2c_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
641 {
642 	struct rk3506_cru *cru = priv->cru;
643 	u32 sel, con, div;
644 	ulong prate;
645 
646 	switch (clk_id) {
647 	case CLK_I2C0:
648 		con = readl(&cru->clksel_con[32]);
649 		sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT;
650 		div = (con & CLK_I2C0_DIV_MASK) >> CLK_I2C0_DIV_SHIFT;
651 	case CLK_I2C1:
652 		con = readl(&cru->clksel_con[32]);
653 		sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT;
654 		div = (con & CLK_I2C1_DIV_MASK) >> CLK_I2C1_DIV_SHIFT;
655 	case CLK_I2C2:
656 		con = readl(&cru->clksel_con[33]);
657 		sel = (con & CLK_I2C2_SEL_MASK) >> CLK_I2C2_SEL_SHIFT;
658 		div = (con & CLK_I2C2_DIV_MASK) >> CLK_I2C2_DIV_SHIFT;
659 		break;
660 	default:
661 		return -ENOENT;
662 	}
663 
664 	if (sel == CLK_I2C_SEL_GPLL)
665 		prate = priv->gpll_hz;
666 	else if (sel == CLK_I2C_SEL_V0PLL)
667 		prate = priv->v0pll_hz;
668 	else if (sel == CLK_I2C_SEL_V1PLL)
669 		prate = priv->v1pll_hz;
670 	else
671 		return -EINVAL;
672 
673 	return DIV_TO_RATE(prate, div);
674 }
675 
676 static ulong rk3506_i2c_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
677 				 ulong rate)
678 {
679 	struct rk3506_cru *cru = priv->cru;
680 	u32 sel, div;
681 
682 	if (priv->v0pll_hz % rate == 0) {
683 		sel = CLK_I2C_SEL_V0PLL;
684 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
685 	} else if (priv->v1pll_hz % rate == 0) {
686 		sel = CLK_I2C_SEL_V1PLL;
687 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
688 	} else {
689 		sel = CLK_I2C_SEL_GPLL;
690 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
691 	}
692 	assert(div - 1 <= 15);
693 
694 	switch (clk_id) {
695 	case CLK_I2C0:
696 		rk_clrsetreg(&cru->clksel_con[32],
697 			     CLK_I2C0_SEL_MASK | CLK_I2C0_DIV_MASK,
698 			     (sel << CLK_I2C0_SEL_SHIFT) |
699 			     ((div - 1) << CLK_I2C0_DIV_SHIFT));
700 		break;
701 	case CLK_I2C1:
702 		rk_clrsetreg(&cru->clksel_con[32],
703 			     CLK_I2C1_SEL_MASK | CLK_I2C1_DIV_MASK,
704 			     (sel << CLK_I2C1_SEL_SHIFT) |
705 			     ((div - 1) << CLK_I2C1_DIV_SHIFT));
706 		break;
707 	case CLK_I2C2:
708 		rk_clrsetreg(&cru->clksel_con[33],
709 			     CLK_I2C2_SEL_MASK | CLK_I2C2_DIV_MASK,
710 			     (sel << CLK_I2C2_SEL_SHIFT) |
711 			     ((div - 1) << CLK_I2C2_DIV_SHIFT));
712 		break;
713 	default:
714 		return -ENOENT;
715 	}
716 
717 
718 	return rk3506_i2c_get_rate(priv, clk_id);
719 }
720 
721 static ulong rk3506_pwm_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
722 {
723 	struct rk3506_cru *cru = priv->cru;
724 	u32 sel, con, div;
725 	ulong prate;
726 
727 	switch (clk_id) {
728 	case CLK_PWM0:
729 		con = readl(&cru->pmuclksel_con[0]);
730 		div = (con & CLK_PWM0_DIV_MASK) >> CLK_PWM0_DIV_SHIFT;
731 		prate = priv->gpll_div_100mhz;
732 		break;
733 	case CLK_PWM1:
734 		con = readl(&cru->clksel_con[33]);
735 		sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
736 		div = (con & CLK_PWM1_DIV_MASK) >> CLK_PWM1_DIV_SHIFT;
737 		if (sel == CLK_PWM1_SEL_GPLL_DIV)
738 			prate = priv->gpll_div_hz;
739 		else if (sel == CLK_PWM1_SEL_V0PLL_DIV)
740 			prate = priv->v0pll_div_hz;
741 		else if (sel == CLK_PWM1_SEL_V1PLL_DIV)
742 			prate = priv->v1pll_div_hz;
743 		else
744 			return -EINVAL;
745 		break;
746 	default:
747 		return -ENOENT;
748 	}
749 
750 	return DIV_TO_RATE(prate, div);
751 }
752 
753 static ulong rk3506_pwm_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
754 				 ulong rate)
755 {
756 	struct rk3506_cru *cru = priv->cru;
757 	u32 sel, div;
758 
759 	switch (clk_id) {
760 	case CLK_PWM0:
761 		div = DIV_ROUND_UP(priv->gpll_div_100mhz, rate);
762 		assert(div - 1 <= 15);
763 		rk_clrsetreg(&cru->pmuclksel_con[0], CLK_PWM0_DIV_MASK,
764 			     (div - 1) << CLK_PWM0_DIV_SHIFT);
765 		break;
766 	case CLK_PWM1:
767 		if (priv->v0pll_hz % rate == 0) {
768 			sel = CLK_PWM1_SEL_V0PLL_DIV;
769 			div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
770 		} else if (priv->v1pll_hz % rate == 0) {
771 			sel = CLK_PWM1_SEL_V1PLL_DIV;
772 			div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
773 		} else {
774 			sel = CLK_PWM1_SEL_GPLL_DIV;
775 			div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
776 		}
777 		assert(div - 1 <= 15);
778 		rk_clrsetreg(&cru->clksel_con[33],
779 			     CLK_PWM1_SEL_MASK | CLK_PWM1_DIV_MASK,
780 			     (sel << CLK_PWM1_SEL_SHIFT) |
781 			     ((div - 1) << CLK_PWM1_DIV_SHIFT));
782 		break;
783 	default:
784 		return -ENOENT;
785 	}
786 
787 	return rk3506_pwm_get_rate(priv, clk_id);
788 }
789 
790 static ulong rk3506_spi_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
791 {
792 	struct rk3506_cru *cru = priv->cru;
793 	u32 sel, con, div;
794 	ulong prate;
795 
796 	switch (clk_id) {
797 	case CLK_SPI0:
798 		con = readl(&cru->clksel_con[34]);
799 		sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
800 		div = (con & CLK_SPI0_DIV_MASK) >> CLK_SPI0_DIV_SHIFT;
801 		break;
802 	case CLK_SPI1:
803 		con = readl(&cru->clksel_con[34]);
804 		sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT;
805 		div = (con & CLK_SPI1_DIV_MASK) >> CLK_SPI1_DIV_SHIFT;
806 		break;
807 	default:
808 		return -ENOENT;
809 	}
810 
811 	if (sel == CLK_SPI_SEL_24M)
812 		prate = OSC_HZ;
813 	else if (sel == CLK_SPI_SEL_GPLL_DIV)
814 		prate = priv->gpll_div_hz;
815 	else if (sel == CLK_SPI_SEL_V0PLL_DIV)
816 		prate = priv->v0pll_div_hz;
817 	else if (sel == CLK_SPI_SEL_V1PLL_DIV)
818 		prate = priv->v1pll_div_hz;
819 	else
820 		return -EINVAL;
821 
822 	return DIV_TO_RATE(prate, div);
823 }
824 
825 static ulong rk3506_spi_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
826 				 ulong rate)
827 {
828 	struct rk3506_cru *cru = priv->cru;
829 	u32 sel, div;
830 
831 	if (OSC_HZ % rate == 0) {
832 		sel = CLK_SPI_SEL_24M;
833 		div = DIV_ROUND_UP(OSC_HZ, rate);
834 	} else if (priv->v0pll_div_hz % rate == 0) {
835 		sel = CLK_SPI_SEL_V0PLL_DIV;
836 		div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
837 	} else if (priv->v1pll_div_hz % rate == 0) {
838 		sel = CLK_SPI_SEL_V1PLL_DIV;
839 		div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
840 	} else {
841 		sel = CLK_SPI_SEL_GPLL_DIV;
842 		div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
843 	}
844 	assert(div - 1 <= 15);
845 
846 	switch (clk_id) {
847 	case CLK_SPI0:
848 		rk_clrsetreg(&cru->clksel_con[34],
849 			     CLK_SPI0_SEL_MASK | CLK_SPI0_DIV_MASK,
850 			     (sel << CLK_SPI0_SEL_SHIFT) |
851 			     ((div - 1) << CLK_SPI0_DIV_SHIFT));
852 		break;
853 	case CLK_SPI1:
854 		rk_clrsetreg(&cru->clksel_con[34],
855 			     CLK_SPI1_SEL_MASK | CLK_SPI1_DIV_MASK,
856 			     (sel << CLK_SPI1_SEL_SHIFT) |
857 			     ((div - 1) << CLK_SPI1_DIV_SHIFT));
858 		break;
859 	default:
860 		return -ENOENT;
861 	}
862 
863 	return rk3506_spi_get_rate(priv, clk_id);
864 }
865 
866 static ulong rk3506_fspi_get_rate(struct rk3506_clk_priv *priv)
867 {
868 	struct rk3506_cru *cru = priv->cru;
869 	u32 div, sel, con, prate;
870 
871 	con = readl(&cru->clksel_con[50]);
872 	div = (con & SCLK_FSPI_DIV_MASK) >> SCLK_FSPI_DIV_SHIFT;
873 	sel = (con & SCLK_FSPI_SEL_MASK) >> SCLK_FSPI_SEL_SHIFT;
874 	if (sel == SCLK_FSPI_SEL_24M)
875 		prate = OSC_HZ;
876 	else if (sel == SCLK_FSPI_SEL_GPLL)
877 		prate = priv->gpll_hz;
878 	else if (sel == SCLK_FSPI_SEL_V0PLL)
879 		prate = priv->v0pll_hz;
880 	else if (sel == SCLK_FSPI_SEL_V1PLL)
881 		prate = priv->v1pll_hz;
882 	else
883 		return -EINVAL;
884 
885 	return DIV_TO_RATE(prate, div);
886 }
887 
888 static ulong rk3506_fspi_set_rate(struct rk3506_clk_priv *priv, ulong rate)
889 {
890 	struct rk3506_cru *cru = priv->cru;
891 	int div, sel;
892 
893 	if (OSC_HZ % rate == 0) {
894 		sel = SCLK_FSPI_SEL_24M;
895 		div = DIV_ROUND_UP(OSC_HZ, rate);
896 	} else if ((priv->v0pll_hz % rate) == 0) {
897 		sel = SCLK_FSPI_SEL_V0PLL;
898 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
899 	} else if ((priv->v1pll_hz % rate) == 0) {
900 		sel = SCLK_FSPI_SEL_V1PLL;
901 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
902 	} else {
903 		sel = SCLK_FSPI_SEL_GPLL;
904 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
905 	}
906 	assert(div - 1 <= 31);
907 
908 	rk_clrsetreg(&cru->clksel_con[50],
909 		     SCLK_FSPI_SEL_MASK | SCLK_FSPI_DIV_MASK,
910 		     sel << SCLK_FSPI_SEL_SHIFT |
911 		     (div - 1) << SCLK_FSPI_DIV_SHIFT);
912 
913 	return rk3506_fspi_get_rate(priv);
914 }
915 
916 static ulong rk3506_vop_dclk_get_rate(struct rk3506_clk_priv *priv)
917 {
918 	struct rk3506_cru *cru = priv->cru;
919 	u32 div, sel, con, prate;
920 
921 	con = readl(&cru->clksel_con[60]);
922 	div = (con & DCLK_VOP_DIV_MASK) >> DCLK_VOP_DIV_SHIFT;
923 	sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
924 
925 	if (sel == DCLK_VOP_SEL_24M)
926 		prate = OSC_HZ;
927 	else if (sel == DCLK_VOP_SEL_GPLL)
928 		prate = priv->gpll_hz;
929 	else if (sel == DCLK_VOP_SEL_V0PLL)
930 		prate = priv->v0pll_hz;
931 	else if (sel == DCLK_VOP_SEL_V1PLL)
932 		prate = priv->v1pll_hz;
933 	else
934 		return -EINVAL;
935 
936 	return DIV_TO_RATE(prate, div);
937 }
938 
939 static ulong rk3506_vop_dclk_set_rate(struct rk3506_clk_priv *priv, ulong rate)
940 {
941 	struct rk3506_cru *cru = priv->cru;
942 	int div, sel;
943 
944 	if (OSC_HZ % rate == 0) {
945 		sel = DCLK_VOP_SEL_24M;
946 		div = DIV_ROUND_UP(OSC_HZ, rate);
947 	} else if ((priv->v0pll_hz % rate) == 0) {
948 		sel = DCLK_VOP_SEL_V0PLL;
949 		div = DIV_ROUND_UP(priv->v0pll_hz, rate);
950 	} else if ((priv->v1pll_hz % rate) == 0) {
951 		sel = DCLK_VOP_SEL_V1PLL;
952 		div = DIV_ROUND_UP(priv->v1pll_hz, rate);
953 	} else {
954 		sel = DCLK_VOP_SEL_GPLL;
955 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
956 	}
957 	assert(div - 1 <= 255);
958 
959 	rk_clrsetreg(&cru->clksel_con[60],
960 		     DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK,
961 		     sel << DCLK_VOP_SEL_SHIFT |
962 		     (div - 1) << DCLK_VOP_DIV_SHIFT);
963 
964 	return rk3506_vop_dclk_get_rate(priv);
965 }
966 
967 static ulong rk3506_mac_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
968 {
969 	struct rk3506_cru *cru = priv->cru;
970 	u32 div, con;
971 
972 	switch (clk_id) {
973 	case CLK_MAC0:
974 	case CLK_MAC1:
975 		con = readl(&cru->clksel_con[50]);
976 		div = (con & CLK_MAC_DIV_MASK) >> CLK_MAC_DIV_SHIFT;
977 		break;
978 	case CLK_MAC_OUT:
979 		con = readl(&cru->pmuclksel_con[0]);
980 		div = (con & CLK_MAC_OUT_DIV_MASK) >> CLK_MAC_OUT_DIV_SHIFT;
981 	default:
982 		return -ENOENT;
983 	}
984 
985 	return DIV_TO_RATE(priv->gpll_hz, div);
986 }
987 
988 static ulong rk3506_mac_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
989 				 ulong rate)
990 {
991 	struct rk3506_cru *cru = priv->cru;
992 	u32 div;
993 
994 	switch (clk_id) {
995 	case CLK_MAC0:
996 	case CLK_MAC1:
997 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
998 		rk_clrsetreg(&cru->clksel_con[50], CLK_MAC_DIV_MASK,
999 			     ((div - 1) << CLK_MAC_DIV_SHIFT));
1000 		break;
1001 	case CLK_MAC_OUT:
1002 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1003 		rk_clrsetreg(&cru->pmuclksel_con[0], CLK_MAC_OUT_DIV_MASK,
1004 			     ((div - 1) << CLK_MAC_OUT_DIV_SHIFT));
1005 	default:
1006 		return -ENOENT;
1007 	}
1008 
1009 	return rk3506_mac_get_rate(priv, clk_id);
1010 }
1011 
1012 static ulong rk3506_clk_get_rate(struct clk *clk)
1013 {
1014 	struct rk3506_clk_priv *priv = dev_get_priv(clk->dev);
1015 	ulong rate = 0;
1016 
1017 	if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) {
1018 		printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n",
1019 		       __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz);
1020 		return -ENOENT;
1021 	}
1022 
1023 	switch (clk->id) {
1024 	case PLL_GPLL:
1025 		rate = priv->gpll_hz;
1026 		break;
1027 	case PLL_V0PLL:
1028 		rate = priv->v0pll_hz;
1029 		break;
1030 	case PLL_V1PLL:
1031 		rate = priv->v1pll_hz;
1032 		break;
1033 	case ARMCLK:
1034 		rate = rk3506_armclk_get_rate(priv);
1035 		break;
1036 	case CLK_GPLL_DIV:
1037 	case CLK_GPLL_DIV_100M:
1038 	case CLK_V0PLL_DIV:
1039 	case CLK_V1PLL_DIV:
1040 		rate = rk3506_pll_div_get_rate(priv, clk->id);
1041 		break;
1042 	case ACLK_BUS_ROOT:
1043 	case HCLK_BUS_ROOT:
1044 	case PCLK_BUS_ROOT:
1045 		rate = rk3506_bus_get_rate(priv, clk->id);
1046 		break;
1047 	case ACLK_HSPERI_ROOT:
1048 	case HCLK_LSPERI_ROOT:
1049 		rate = rk3506_peri_get_rate(priv, clk->id);
1050 		break;
1051 	case HCLK_SDMMC:
1052 	case CCLK_SRC_SDMMC:
1053 		rate = rk3506_sdmmc_get_rate(priv, clk->id);
1054 		break;
1055 	case CLK_SARADC:
1056 		rate = rk3506_saradc_get_rate(priv, clk->id);
1057 		break;
1058 	case CLK_TSADC:
1059 	case CLK_TSADC_TSEN:
1060 		rate = rk3506_tsadc_get_rate(priv, clk->id);
1061 		break;
1062 	case CLK_I2C0:
1063 	case CLK_I2C1:
1064 	case CLK_I2C2:
1065 		rate = rk3506_i2c_get_rate(priv, clk->id);
1066 		break;
1067 	case CLK_PWM0:
1068 	case CLK_PWM1:
1069 		rate = rk3506_pwm_get_rate(priv, clk->id);
1070 		break;
1071 	case CLK_SPI0:
1072 	case CLK_SPI1:
1073 		rate = rk3506_spi_get_rate(priv, clk->id);
1074 		break;
1075 	case SCLK_FSPI:
1076 		rate = rk3506_fspi_get_rate(priv);
1077 		break;
1078 	case DCLK_VOP:
1079 		rate = rk3506_vop_dclk_get_rate(priv);
1080 		break;
1081 	case CLK_MAC0:
1082 	case CLK_MAC1:
1083 	case CLK_MAC_OUT:
1084 		rate = rk3506_mac_get_rate(priv, clk->id);
1085 		break;
1086 	default:
1087 		return -ENOENT;
1088 	}
1089 
1090 	return rate;
1091 };
1092 
1093 static ulong rk3506_clk_set_rate(struct clk *clk, ulong rate)
1094 {
1095 	struct rk3506_clk_priv *priv = dev_get_priv(clk->dev);
1096 	ulong ret = 0;
1097 
1098 	if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) {
1099 		printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n",
1100 		       __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz);
1101 		return -ENOENT;
1102 	}
1103 
1104 	debug("%s: id=%ld, rate=%ld\n", __func__, clk->id, rate);
1105 
1106 	switch (clk->id) {
1107 	case ARMCLK:
1108 		if (priv->armclk_hz)
1109 			rk3506_armclk_set_rate(priv, rate);
1110 		priv->armclk_hz = rate;
1111 		break;
1112 	case CLK_GPLL_DIV:
1113 	case CLK_GPLL_DIV_100M:
1114 	case CLK_V0PLL_DIV:
1115 	case CLK_V1PLL_DIV:
1116 		ret = rk3506_pll_div_set_rate(priv, clk->id, rate);
1117 		break;
1118 	case ACLK_BUS_ROOT:
1119 	case HCLK_BUS_ROOT:
1120 	case PCLK_BUS_ROOT:
1121 		ret = rk3506_bus_set_rate(priv, clk->id, rate);
1122 		break;
1123 	case ACLK_HSPERI_ROOT:
1124 	case HCLK_LSPERI_ROOT:
1125 		ret = rk3506_peri_set_rate(priv, clk->id, rate);
1126 		break;
1127 	case HCLK_SDMMC:
1128 	case CCLK_SRC_SDMMC:
1129 		ret = rk3506_sdmmc_set_rate(priv, clk->id, rate);
1130 		break;
1131 	case CLK_SARADC:
1132 		ret = rk3506_saradc_set_rate(priv, clk->id, rate);
1133 		break;
1134 	case CLK_TSADC:
1135 	case CLK_TSADC_TSEN:
1136 		ret = rk3506_tsadc_set_rate(priv, clk->id, rate);
1137 		break;
1138 	case CLK_I2C0:
1139 	case CLK_I2C1:
1140 	case CLK_I2C2:
1141 		ret = rk3506_i2c_set_rate(priv, clk->id, rate);
1142 		break;
1143 	case CLK_PWM0:
1144 	case CLK_PWM1:
1145 		ret = rk3506_pwm_set_rate(priv, clk->id, rate);
1146 		break;
1147 	case CLK_SPI0:
1148 	case CLK_SPI1:
1149 		ret = rk3506_spi_set_rate(priv, clk->id, rate);
1150 		break;
1151 	case HCLK_FSPI:
1152 	case SCLK_FSPI:
1153 		ret = rk3506_fspi_set_rate(priv, rate);
1154 		break;
1155 	case DCLK_VOP:
1156 		ret = rk3506_vop_dclk_set_rate(priv, rate);
1157 		break;
1158 	case CLK_MAC0:
1159 	case CLK_MAC1:
1160 	case CLK_MAC_OUT:
1161 		ret = rk3506_mac_set_rate(priv, clk->id, rate);
1162 		break;
1163 	default:
1164 		return -ENOENT;
1165 	}
1166 
1167 	return ret;
1168 };
1169 
1170 static struct clk_ops rk3506_clk_ops = {
1171 	.get_rate = rk3506_clk_get_rate,
1172 	.set_rate = rk3506_clk_set_rate,
1173 };
1174 
1175 static void rk3506_clk_init(struct rk3506_clk_priv *priv)
1176 {
1177 	priv->sync_kernel = false;
1178 
1179 	if (!priv->gpll_hz) {
1180 		priv->gpll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[GPLL],
1181 						      priv->cru, GPLL);
1182 		priv->gpll_hz = roundup(priv->gpll_hz, 1000);
1183 	}
1184 	if (!priv->v0pll_hz) {
1185 		priv->v0pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V0PLL],
1186 						       priv->cru, V0PLL);
1187 		priv->v0pll_hz = roundup(priv->v0pll_hz, 1000);
1188 	}
1189 	if (!priv->v1pll_hz) {
1190 		priv->v1pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V1PLL],
1191 						       priv->cru, V1PLL);
1192 		priv->v1pll_hz = roundup(priv->v1pll_hz, 1000);
1193 	}
1194 	if (!priv->gpll_div_hz) {
1195 		priv->gpll_div_hz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV);
1196 		priv->gpll_div_hz = roundup(priv->gpll_div_hz, 1000);
1197 	}
1198 	if (!priv->gpll_div_100mhz) {
1199 		priv->gpll_div_100mhz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV_100M);
1200 		priv->gpll_div_100mhz = roundup(priv->gpll_div_100mhz, 1000);
1201 	}
1202 	if (!priv->v0pll_div_hz) {
1203 		priv->v0pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V0PLL_DIV);
1204 		priv->v0pll_div_hz = roundup(priv->v0pll_div_hz, 1000);
1205 	}
1206 	if (!priv->v1pll_div_hz) {
1207 		priv->v1pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V1PLL_DIV);
1208 		priv->v1pll_div_hz = roundup(priv->v1pll_div_hz, 1000);
1209 	}
1210 
1211 	if (!priv->armclk_enter_hz) {
1212 		priv->armclk_enter_hz = rk3506_armclk_get_rate(priv);
1213 		priv->armclk_init_hz = priv->armclk_enter_hz;
1214 	}
1215 }
1216 
1217 static int rk3506_clk_probe(struct udevice *dev)
1218 {
1219 	struct rk3506_clk_priv *priv = dev_get_priv(dev);
1220 	int ret;
1221 
1222 	rk3506_clk_init(priv);
1223 
1224 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1225 	ret = clk_set_defaults(dev);
1226 	if (ret)
1227 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
1228 	else
1229 		priv->sync_kernel = true;
1230 
1231 	return 0;
1232 }
1233 
1234 static int rk3506_clk_ofdata_to_platdata(struct udevice *dev)
1235 {
1236 	struct rk3506_clk_priv *priv = dev_get_priv(dev);
1237 
1238 	priv->cru = dev_read_addr_ptr(dev);
1239 
1240 	return 0;
1241 }
1242 
1243 static int rk3506_clk_bind(struct udevice *dev)
1244 {
1245 	struct udevice *sys_child, *sf_child;
1246 	struct softreset_reg *sf_priv;
1247 	struct sysreset_reg *priv;
1248 	int ret;
1249 
1250 	/* The reset driver does not have a device node, so bind it here */
1251 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1252 				 &sys_child);
1253 	if (ret) {
1254 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1255 	} else {
1256 		priv = malloc(sizeof(struct sysreset_reg));
1257 		priv->glb_srst_fst_value = offsetof(struct rk3506_cru,
1258 						    glb_srst_fst);
1259 		priv->glb_srst_snd_value = offsetof(struct rk3506_cru,
1260 						    glb_srst_snd);
1261 		sys_child->priv = priv;
1262 	}
1263 
1264 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1265 					 dev_ofnode(dev), &sf_child);
1266 	if (ret) {
1267 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1268 	} else {
1269 		sf_priv = malloc(sizeof(struct softreset_reg));
1270 		sf_priv->sf_reset_offset = offsetof(struct rk3506_cru,
1271 						    softrst_con[0]);
1272 		sf_priv->sf_reset_num = 23;
1273 		sf_child->priv = sf_priv;
1274 	}
1275 
1276 	return 0;
1277 }
1278 
1279 static const struct udevice_id rk3506_clk_ids[] = {
1280 	{ .compatible = "rockchip,rk3506-cru" },
1281 	{ }
1282 };
1283 
1284 U_BOOT_DRIVER(rockchip_rk3506_cru) = {
1285 	.name		= "rockchip_rk3506_cru",
1286 	.id		= UCLASS_CLK,
1287 	.of_match	= rk3506_clk_ids,
1288 	.priv_auto_alloc_size = sizeof(struct rk3506_clk_priv),
1289 	.ofdata_to_platdata = rk3506_clk_ofdata_to_platdata,
1290 	.ops		= &rk3506_clk_ops,
1291 	.bind		= rk3506_clk_bind,
1292 	.probe		= rk3506_clk_probe,
1293 };
1294