xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3128.c (revision b8fa3d2a17dce6006a8a5f46cbc978a19a3fdf82)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0
5  */
6 
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <syscon.h>
12 #include <asm/io.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/cru_rk3128.h>
15 #include <asm/arch/hardware.h>
16 #include <bitfield.h>
17 #include <dm/lists.h>
18 #include <dt-bindings/clock/rk3128-cru.h>
19 #include <linux/log2.h>
20 
21 DECLARE_GLOBAL_DATA_PTR;
22 
23 #define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
24 
25 #ifndef CONFIG_SPL_BUILD
26 #define RK3128_CLK_DUMP(_id, _name, _iscru)	\
27 {						\
28 	.id = _id,				\
29 	.name = _name,				\
30 	.is_cru = _iscru,			\
31 }
32 #endif
33 
34 static struct rockchip_pll_rate_table rk3128_pll_rates[] = {
35 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
36 #ifndef CONFIG_SPL_BUILD
37 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
38 	RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
39 	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
40 #endif
41 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
42 	RK3036_PLL_RATE(800000000, 1, 200, 6, 1, 1, 0),
43 	RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
44 	RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
45 	RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
46 	{ /* sentinel */ },
47 };
48 
49 #define RK3128_CPUCLK_RATE(_rate, _aclk_div, _pclk_div)		\
50 {								\
51 	.rate	= _rate##U,					\
52 	.aclk_div = _aclk_div,					\
53 	.pclk_div = _pclk_div,					\
54 }
55 
56 static struct rockchip_cpu_rate_table rk3128_cpu_rates[] = {
57 	RK3128_CPUCLK_RATE(1200000000, 1, 5),
58 	RK3128_CPUCLK_RATE(1008000000, 1, 5),
59 	RK3128_CPUCLK_RATE(816000000, 1, 3),
60 	RK3128_CPUCLK_RATE(600000000, 1, 3),
61 };
62 
63 #ifndef CONFIG_SPL_BUILD
64 static const struct rk3128_clk_info clks_dump[] = {
65 	RK3128_CLK_DUMP(PLL_APLL, "apll", true),
66 	RK3128_CLK_DUMP(PLL_DPLL, "dpll", true),
67 	RK3128_CLK_DUMP(PLL_CPLL, "cpll", true),
68 	RK3128_CLK_DUMP(PLL_GPLL, "gpll", true),
69 	RK3128_CLK_DUMP(ARMCLK, "armclk", true),
70 	RK3128_CLK_DUMP(ACLK_CPU, "aclk_cpu", true),
71 	RK3128_CLK_DUMP(HCLK_CPU, "hclk_cpu", true),
72 	RK3128_CLK_DUMP(PCLK_CPU, "pclk_cpu", true),
73 	RK3128_CLK_DUMP(ACLK_PERI, "aclk_peri", true),
74 	RK3128_CLK_DUMP(HCLK_PERI, "hclk_peri", true),
75 	RK3128_CLK_DUMP(PCLK_PERI, "pclk_peri", true),
76 };
77 #endif
78 
79 static struct rockchip_pll_clock rk3128_pll_clks[] = {
80 	[APLL] = PLL(pll_rk3036, PLL_APLL, RK2928_PLL_CON(0),
81 		     RK2928_MODE_CON, 0, 10, 0, rk3128_pll_rates),
82 	[DPLL] = PLL(pll_rk3036, PLL_DPLL, RK2928_PLL_CON(4),
83 		     RK2928_MODE_CON, 4, 10, 0, NULL),
84 	[CPLL] = PLL(pll_rk3036, PLL_CPLL, RK2928_PLL_CON(8),
85 		    RK2928_MODE_CON, 8, 10, 0, rk3128_pll_rates),
86 	[GPLL] = PLL(pll_rk3036, PLL_GPLL, RK2928_PLL_CON(12),
87 		     RK2928_MODE_CON, 12, 10, 0, rk3128_pll_rates),
88 };
89 
90 static ulong rk3128_armclk_set_clk(struct rk3128_clk_priv *priv, ulong hz)
91 {
92 	struct rk3128_cru *cru = priv->cru;
93 	const struct rockchip_cpu_rate_table *rate;
94 	ulong old_rate;
95 
96 	rate = rockchip_get_cpu_settings(rk3128_cpu_rates, hz);
97 	if (!rate) {
98 		printf("%s unsupported rate\n", __func__);
99 		return -EINVAL;
100 	}
101 
102 	/*
103 	 * select apll as cpu/core clock pll source and
104 	 * set up dependent divisors for PERI and ACLK clocks.
105 	 * core hz : apll = 1:1
106 	 */
107 	old_rate = rockchip_pll_get_rate(&rk3128_pll_clks[APLL],
108 					 priv->cru, APLL);
109 	if (old_rate > hz) {
110 		if (rockchip_pll_set_rate(&rk3128_pll_clks[APLL],
111 					  priv->cru, APLL, hz))
112 			return -EINVAL;
113 		rk_clrsetreg(&cru->cru_clksel_con[0],
114 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
115 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
116 			     0 << CORE_DIV_CON_SHIFT);
117 		rk_clrsetreg(&cru->cru_clksel_con[1],
118 			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
119 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
120 			     rate->pclk_div << CORE_DBG_DIV_SHIFT);
121 	} else if (old_rate < hz) {
122 		rk_clrsetreg(&cru->cru_clksel_con[1],
123 			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
124 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
125 			     rate->pclk_div << CORE_DBG_DIV_SHIFT);
126 		rk_clrsetreg(&cru->cru_clksel_con[0],
127 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
128 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
129 			     0 << CORE_DIV_CON_SHIFT);
130 		if (rockchip_pll_set_rate(&rk3128_pll_clks[APLL],
131 					  priv->cru, APLL, hz))
132 			return -EINVAL;
133 	}
134 
135 	return rockchip_pll_get_rate(&rk3128_pll_clks[APLL], priv->cru, APLL);
136 }
137 
138 static ulong rockchip_mmc_get_clk(struct rk3128_clk_priv *priv,
139 				  int periph)
140 {
141 	struct rk3128_cru *cru = priv->cru;
142 	uint src_rate;
143 	uint div, mux;
144 	u32 con;
145 
146 	switch (periph) {
147 	case HCLK_EMMC:
148 	case SCLK_EMMC:
149 	case SCLK_EMMC_SAMPLE:
150 		con = readl(&cru->cru_clksel_con[12]);
151 		mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT;
152 		div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
153 		break;
154 	case HCLK_SDMMC:
155 	case SCLK_SDMMC:
156 	case SCLK_SDMMC_SAMPLE:
157 		con = readl(&cru->cru_clksel_con[11]);
158 		mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT;
159 		div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT;
160 		break;
161 	case HCLK_SDIO:
162 	case SCLK_SDIO:
163 	case SCLK_SDIO_SAMPLE:
164 		con = readl(&cru->cru_clksel_con[12]);
165 		mux = (con & SDIO_PLL_MASK) >> SDIO_PLL_SHIFT;
166 		div = (con & SDIO_DIV_MASK) >> SDIO_DIV_SHIFT;
167 		break;
168 	default:
169 		return -EINVAL;
170 	}
171 
172 	src_rate = mux == EMMC_SEL_24M ? OSC_HZ : priv->gpll_hz;
173 	return DIV_TO_RATE(src_rate, div);
174 }
175 
176 static ulong rockchip_mmc_set_clk(struct rk3128_clk_priv *priv,
177 				  int periph, uint freq)
178 {
179 	struct rk3128_cru *cru = priv->cru;
180 	int src_clk_div;
181 	int mux;
182 
183 	/* mmc clock defaulg div 2 internal, need provide double in cru */
184 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, freq);
185 
186 	if (src_clk_div > 128) {
187 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq);
188 		mux = EMMC_SEL_24M;
189 	} else {
190 		mux = EMMC_SEL_GPLL;
191 	}
192 
193 	switch (periph) {
194 	case HCLK_EMMC:
195 	case SCLK_EMMC:
196 		rk_clrsetreg(&cru->cru_clksel_con[12],
197 			     EMMC_PLL_MASK | EMMC_DIV_MASK,
198 			     mux << EMMC_PLL_SHIFT |
199 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
200 		break;
201 	case HCLK_SDMMC:
202 	case SCLK_SDMMC:
203 		rk_clrsetreg(&cru->cru_clksel_con[11],
204 			     MMC0_PLL_MASK | MMC0_DIV_MASK,
205 			     mux << MMC0_PLL_SHIFT |
206 			     (src_clk_div - 1) << MMC0_DIV_SHIFT);
207 		break;
208 	case HCLK_SDIO:
209 	case SCLK_SDIO:
210 		rk_clrsetreg(&cru->cru_clksel_con[12],
211 			     SDIO_PLL_MASK | SDIO_DIV_MASK,
212 			     mux << SDIO_PLL_SHIFT |
213 			     (src_clk_div - 1) << SDIO_DIV_SHIFT);
214 		break;
215 	default:
216 		return -EINVAL;
217 	}
218 
219 	return rockchip_mmc_get_clk(priv, periph);
220 }
221 
222 static ulong rk3128_peri_get_clk(struct rk3128_clk_priv *priv, ulong clk_id)
223 {
224 	struct rk3128_cru *cru = priv->cru;
225 	u32 div, con, parent;
226 
227 	switch (clk_id) {
228 	case ACLK_PERI:
229 		con = readl(&cru->cru_clksel_con[10]);
230 		div = (con & ACLK_PERI_DIV_MASK) >> ACLK_PERI_DIV_SHIFT;
231 		parent = priv->gpll_hz;
232 		break;
233 	case PCLK_PERI:
234 	case PCLK_I2C0:
235 	case PCLK_I2C1:
236 	case PCLK_I2C2:
237 	case PCLK_I2C3:
238 	case PCLK_PWM:
239 		con = readl(&cru->cru_clksel_con[10]);
240 		div = (con & PCLK_PERI_DIV_MASK) >> PCLK_PERI_DIV_SHIFT;
241 		parent = rk3128_peri_get_clk(priv, ACLK_PERI);
242 		break;
243 	case HCLK_PERI:
244 		con = readl(&cru->cru_clksel_con[10]);
245 		div = (con & HCLK_PERI_DIV_MASK) >> HCLK_PERI_DIV_SHIFT;
246 		parent = rk3128_peri_get_clk(priv, ACLK_PERI);
247 		break;
248 	default:
249 		printf("do not support this peripheral bus\n");
250 		return -EINVAL;
251 	}
252 
253 	return DIV_TO_RATE(parent, div);
254 }
255 
256 static ulong rk3128_peri_set_clk(struct rk3128_clk_priv *priv,
257 				 ulong clk_id, uint hz)
258 {
259 	struct rk3128_cru *cru = priv->cru;
260 	int src_clk_div;
261 
262 	switch (clk_id) {
263 	case ACLK_PERI:
264 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
265 		assert(src_clk_div - 1 < 32);
266 		rk_clrsetreg(&cru->cru_clksel_con[10],
267 			     PERI_PLL_SEL_MASK | ACLK_PERI_DIV_MASK,
268 			     PERI_PLL_SEL_GPLL << PERI_PLL_SEL_SHIFT |
269 			     (src_clk_div - 1) << ACLK_PERI_DIV_SHIFT);
270 		break;
271 	case PCLK_I2C0:
272 	case PCLK_I2C1:
273 	case PCLK_I2C2:
274 	case PCLK_I2C3:
275 	case PCLK_PWM:
276 	case PCLK_PERI:
277 		src_clk_div = DIV_ROUND_UP(rk3128_peri_get_clk(priv,
278 							       ACLK_PERI),
279 					   hz);
280 		assert(src_clk_div - 1 < 3);
281 		rk_clrsetreg(&cru->cru_clksel_con[10],
282 			     PCLK_PERI_DIV_MASK,
283 			     (src_clk_div - 1) << PCLK_PERI_DIV_SHIFT);
284 		break;
285 	case HCLK_PERI:
286 		src_clk_div = DIV_ROUND_UP(rk3128_peri_get_clk(priv,
287 							       ACLK_PERI),
288 					   hz);
289 		assert(src_clk_div - 1 < 7);
290 		rk_clrsetreg(&cru->cru_clksel_con[10],
291 			     HCLK_PERI_DIV_MASK,
292 			     (src_clk_div - 1) << HCLK_PERI_DIV_SHIFT);
293 		break;
294 	default:
295 		printf("do not support this peripheral bus\n");
296 		return -EINVAL;
297 	}
298 
299 	return rk3128_peri_get_clk(priv, clk_id);
300 }
301 
302 static ulong rk3128_bus_get_clk(struct rk3128_clk_priv *priv, ulong clk_id)
303 {
304 	struct rk3128_cru *cru = priv->cru;
305 	u32 div, con, parent;
306 
307 	switch (clk_id) {
308 	case ACLK_CPU:
309 		con = readl(&cru->cru_clksel_con[0]);
310 		div = (con & ACLK_BUS_DIV_MASK) >> ACLK_BUS_DIV_SHIFT;
311 		parent = priv->gpll_hz;
312 		break;
313 	case PCLK_CPU:
314 		con = readl(&cru->cru_clksel_con[1]);
315 		div = (con & PCLK_BUS_DIV_MASK) >> PCLK_BUS_DIV_SHIFT;
316 		parent = rk3128_bus_get_clk(priv, ACLK_CPU);
317 		break;
318 	case HCLK_CPU:
319 		con = readl(&cru->cru_clksel_con[1]);
320 		div = (con & HCLK_BUS_DIV_MASK) >> HCLK_BUS_DIV_SHIFT;
321 		parent = rk3128_bus_get_clk(priv, ACLK_CPU);
322 		break;
323 	default:
324 		printf("do not support this peripheral bus\n");
325 		return -EINVAL;
326 	}
327 
328 	return DIV_TO_RATE(parent, div);
329 }
330 
331 static ulong rk3128_bus_set_clk(struct rk3128_clk_priv *priv,
332 				ulong clk_id, uint hz)
333 {
334 	struct rk3128_cru *cru = priv->cru;
335 	int src_clk_div;
336 
337 	switch (clk_id) {
338 	case ACLK_CPU:
339 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
340 		assert(src_clk_div - 1 < 32);
341 		rk_clrsetreg(&cru->cru_clksel_con[0],
342 			     BUS_PLL_SEL_MASK | ACLK_BUS_DIV_MASK,
343 			     BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
344 			     (src_clk_div - 1) << ACLK_BUS_DIV_SHIFT);
345 		break;
346 	case PCLK_CPU:
347 		src_clk_div = DIV_ROUND_UP(rk3128_bus_get_clk(priv,
348 							      ACLK_CPU),
349 					   hz);
350 		assert(src_clk_div - 1 < 3);
351 		rk_clrsetreg(&cru->cru_clksel_con[1],
352 			     PCLK_BUS_DIV_MASK,
353 			     (src_clk_div - 1) << PCLK_BUS_DIV_SHIFT);
354 		break;
355 	case HCLK_CPU:
356 		src_clk_div = DIV_ROUND_UP(rk3128_bus_get_clk(priv,
357 							      ACLK_CPU),
358 					   hz);
359 		assert(src_clk_div - 1 < 7);
360 		rk_clrsetreg(&cru->cru_clksel_con[1],
361 			     HCLK_BUS_DIV_MASK,
362 			     (src_clk_div - 1) << HCLK_BUS_DIV_SHIFT);
363 		break;
364 	default:
365 		printf("do not support this peripheral bus\n");
366 		return -EINVAL;
367 	}
368 
369 	return rk3128_bus_get_clk(priv, clk_id);
370 }
371 
372 #ifndef CONFIG_SPL_BUILD
373 static ulong rk3128_saradc_get_clk(struct rk3128_clk_priv *priv)
374 {
375 	struct rk3128_cru *cru = priv->cru;
376 	u32 div, val;
377 
378 	val = readl(&cru->cru_clksel_con[24]);
379 	div = bitfield_extract(val, SARADC_DIV_CON_SHIFT,
380 			       SARADC_DIV_CON_WIDTH);
381 
382 	return DIV_TO_RATE(OSC_HZ, div);
383 }
384 
385 static ulong rk3128_saradc_set_clk(struct rk3128_clk_priv *priv, uint hz)
386 {
387 	struct rk3128_cru *cru = priv->cru;
388 	int src_clk_div;
389 
390 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
391 	assert(src_clk_div < 128);
392 
393 	rk_clrsetreg(&cru->cru_clksel_con[24],
394 		     SARADC_DIV_CON_MASK,
395 		     src_clk_div << SARADC_DIV_CON_SHIFT);
396 
397 	return rk3128_saradc_get_clk(priv);
398 }
399 
400 #define RK3128_LCDC_PLL_LIMIT			600000000
401 
402 static ulong rk3128_vop_set_clk(struct rk3128_clk_priv *priv,
403 				ulong clk_id, uint hz)
404 {
405 	struct rk3128_cru *cru = priv->cru;
406 	int src_clk_div;
407 
408 	src_clk_div = GPLL_HZ / hz;
409 	assert(src_clk_div - 1 < 31);
410 
411 	switch (clk_id) {
412 	case ACLK_LCDC0:
413 	case ACLK_VIO0:
414 		rk_clrsetreg(&cru->cru_clksel_con[31],
415 			     VIO0_PLL_MASK | VIO0_DIV_MASK,
416 			     VIO0_SEL_GPLL << VIO0_PLL_SHIFT |
417 			     (src_clk_div - 1) << VIO0_DIV_SHIFT);
418 		break;
419 	case ACLK_VIO1:
420 		rk_clrsetreg(&cru->cru_clksel_con[31],
421 			     VIO1_PLL_MASK | VIO1_DIV_MASK,
422 			     VIO1_SEL_GPLL << VIO1_PLL_SHIFT |
423 			     (src_clk_div - 1) << VIO1_DIV_SHIFT);
424 		break;
425 	case DCLK_VOP:
426 		src_clk_div = DIV_ROUND_UP(RK3128_LCDC_PLL_LIMIT, hz);
427 		rockchip_pll_set_rate(&rk3128_pll_clks[CPLL],
428 				      priv->cru, CPLL, src_clk_div * hz);
429 		rk_clrsetreg(&cru->cru_clksel_con[27],
430 			      DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_CON_MASK,
431 			     DCLK_VOP_PLL_SEL_CPLL << DCLK_VOP_SEL_SHIFT |
432 			     (src_clk_div - 1) << DCLK_VOP_DIV_CON_SHIFT);
433 		break;
434 	default:
435 		printf("do not support this vop freq\n");
436 		return -EINVAL;
437 	}
438 
439 	return hz;
440 }
441 
442 static ulong rk3128_vop_get_rate(struct rk3128_clk_priv *priv, ulong clk_id)
443 {
444 	struct rk3128_cru *cru = priv->cru;
445 	u32 div, con, parent;
446 
447 	switch (clk_id) {
448 	case ACLK_LCDC0:
449 	case ACLK_VIO0:
450 		con = readl(&cru->cru_clksel_con[31]);
451 		div = con  & 0x1f;
452 		parent = GPLL_HZ;
453 		break;
454 	case ACLK_VIO1:
455 		con = readl(&cru->cru_clksel_con[31]);
456 		div = (con >> 8) & 0x1f;
457 		parent = GPLL_HZ;
458 		break;
459 	case DCLK_VOP:
460 		con = readl(&cru->cru_clksel_con[27]);
461 		div = (con & DCLK_VOP_DIV_CON_MASK) >> DCLK_VOP_DIV_CON_SHIFT;
462 		parent = rockchip_pll_get_rate(&rk3128_pll_clks[CPLL],
463 					       priv->cru, CPLL);
464 		break;
465 	default:
466 		return -ENOENT;
467 	}
468 	return DIV_TO_RATE(parent, div);
469 }
470 #endif
471 
472 static ulong rk3128_clk_get_rate(struct clk *clk)
473 {
474 	struct rk3128_clk_priv *priv = dev_get_priv(clk->dev);
475 	ulong rate = 0;
476 
477 	switch (clk->id) {
478 	case PLL_APLL:
479 	case PLL_DPLL:
480 	case PLL_CPLL:
481 	case PLL_GPLL:
482 		rate =  rockchip_pll_get_rate(&rk3128_pll_clks[clk->id - 1],
483 					      priv->cru, clk->id - 1);
484 		break;
485 	case ARMCLK:
486 		rate = rockchip_pll_get_rate(&rk3128_pll_clks[APLL],
487 					     priv->cru, APLL);
488 		break;
489 	case HCLK_EMMC:
490 	case SCLK_EMMC:
491 	case HCLK_SDMMC:
492 	case SCLK_SDMMC:
493 	case HCLK_SDIO:
494 	case SCLK_SDIO:
495 		rate = rockchip_mmc_get_clk(priv, clk->id);
496 		break;
497 	case ACLK_PERI:
498 	case HCLK_PERI:
499 	case PCLK_PERI:
500 	case PCLK_I2C0:
501 	case PCLK_I2C1:
502 	case PCLK_I2C2:
503 	case PCLK_I2C3:
504 	case PCLK_PWM:
505 		rate = rk3128_peri_get_clk(priv, clk->id);
506 		break;
507 	case ACLK_CPU:
508 	case HCLK_CPU:
509 	case PCLK_CPU:
510 		rate = rk3128_bus_get_clk(priv, clk->id);
511 		break;
512 #ifndef CONFIG_SPL_BUILD
513 	case SCLK_SARADC:
514 		rate = rk3128_saradc_get_clk(priv);
515 		break;
516 	case DCLK_VOP:
517 	case ACLK_VIO0:
518 	case ACLK_VIO1:
519 	case ACLK_LCDC0:
520 		rate = rk3128_vop_get_rate(priv, clk->id);
521 		break;
522 #endif
523 	default:
524 		return -ENOENT;
525 	}
526 	return rate;
527 }
528 
529 static ulong rk3128_clk_set_rate(struct clk *clk, ulong rate)
530 {
531 	struct rk3128_clk_priv *priv = dev_get_priv(clk->dev);
532 	ulong ret;
533 
534 	switch (clk->id) {
535 	case PLL_APLL:
536 	case PLL_DPLL:
537 	case PLL_CPLL:
538 		ret = rockchip_pll_set_rate(&rk3128_pll_clks[clk->id - 1],
539 					    priv->cru, clk->id - 1, rate);
540 	case PLL_GPLL:
541 		ret = rockchip_pll_set_rate(&rk3128_pll_clks[GPLL],
542 					    priv->cru, GPLL, rate);
543 		priv->gpll_hz = rate;
544 		break;
545 	case ARMCLK:
546 		ret = rk3128_armclk_set_clk(priv, rate);
547 		break;
548 	case HCLK_EMMC:
549 	case SCLK_EMMC:
550 	case SCLK_EMMC_SAMPLE:
551 	case HCLK_SDMMC:
552 	case SCLK_SDMMC:
553 	case SCLK_SDMMC_SAMPLE:
554 	case HCLK_SDIO:
555 	case SCLK_SDIO:
556 	case SCLK_SDIO_SAMPLE:
557 		ret = rockchip_mmc_set_clk(priv, clk->id, rate);
558 		break;
559 	case ACLK_PERI:
560 	case PCLK_PERI:
561 	case HCLK_PERI:
562 	case PCLK_I2C0:
563 	case PCLK_I2C1:
564 	case PCLK_I2C2:
565 	case PCLK_I2C3:
566 	case PCLK_PWM:
567 		ret = rk3128_peri_set_clk(priv, clk->id, rate);
568 		break;
569 	case ACLK_CPU:
570 	case HCLK_CPU:
571 	case PCLK_CPU:
572 		ret = rk3128_bus_set_clk(priv, clk->id, rate);
573 		break;
574 #ifndef CONFIG_SPL_BUILD
575 	case SCLK_SARADC:
576 		ret = rk3128_saradc_set_clk(priv, rate);
577 		break;
578 	case DCLK_VOP:
579 	case ACLK_VIO0:
580 	case ACLK_VIO1:
581 	case ACLK_LCDC0:
582 		ret = rk3128_vop_set_clk(priv, clk->id, rate);
583 		break;
584 #endif
585 	default:
586 		return -ENOENT;
587 	}
588 	return ret;
589 }
590 
591 static struct clk_ops rk3128_clk_ops = {
592 	.get_rate	= rk3128_clk_get_rate,
593 	.set_rate	= rk3128_clk_set_rate,
594 };
595 
596 static int rk3128_clk_ofdata_to_platdata(struct udevice *dev)
597 {
598 	struct rk3128_clk_priv *priv = dev_get_priv(dev);
599 
600 	priv->cru = dev_read_addr_ptr(dev);
601 
602 	return 0;
603 }
604 
605 static void rkclk_init(struct rk3128_clk_priv *priv)
606 {
607 	if (rockchip_pll_get_rate(&rk3128_pll_clks[APLL],
608 				  priv->cru, APLL) != APLL_HZ)
609 		rk3128_armclk_set_clk(priv, APLL_HZ);
610 
611 	priv->gpll_hz = rockchip_pll_get_rate(&rk3128_pll_clks[GPLL],
612 					      priv->cru, GPLL);
613 	rk3128_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ / 2);
614 	rk3128_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ / 2);
615 	rockchip_pll_set_rate(&rk3128_pll_clks[GPLL],
616 			      priv->cru, GPLL, GPLL_HZ);
617 	priv->gpll_hz = GPLL_HZ;
618 	rk_clrsetreg(&priv->cru->cru_clksel_con[2],
619 		     NANDC_PLL_SEL_MASK | NANDC_CLK_DIV_MASK,
620 		     NANDC_PLL_SEL_GPLL << NANDC_PLL_SEL_SHIFT |
621 		     3 << NANDC_CLK_DIV_SHIFT);
622 	rk3128_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ);
623 	rk3128_bus_set_clk(priv, HCLK_CPU, ACLK_BUS_HZ / 2);
624 	rk3128_bus_set_clk(priv, PCLK_CPU, ACLK_BUS_HZ / 2);
625 	rk3128_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ);
626 	rk3128_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2);
627 	rk3128_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2);
628 }
629 
630 static int rk3128_clk_probe(struct udevice *dev)
631 {
632 	struct rk3128_clk_priv *priv = dev_get_priv(dev);
633 
634 	rkclk_init(priv);
635 
636 	return 0;
637 }
638 
639 static int rk3128_clk_bind(struct udevice *dev)
640 {
641 	int ret;
642 	struct udevice *sys_child, *sf_child;
643 	struct sysreset_reg *priv;
644 	struct softreset_reg *sf_priv;
645 
646 	/* The reset driver does not have a device node, so bind it here */
647 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
648 				 &sys_child);
649 	if (ret) {
650 		debug("Warning: No sysreset driver: ret=%d\n", ret);
651 	} else {
652 		priv = malloc(sizeof(struct sysreset_reg));
653 		priv->glb_srst_fst_value = offsetof(struct rk3128_cru,
654 						    cru_glb_srst_fst_value);
655 		priv->glb_srst_snd_value = offsetof(struct rk3128_cru,
656 						    cru_glb_srst_snd_value);
657 		sys_child->priv = priv;
658 	}
659 
660 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
661 					 dev_ofnode(dev), &sf_child);
662 	if (ret) {
663 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
664 	} else {
665 		sf_priv = malloc(sizeof(struct softreset_reg));
666 		sf_priv->sf_reset_offset = offsetof(struct rk3128_cru,
667 						    cru_softrst_con[0]);
668 		sf_priv->sf_reset_num = 9;
669 		sf_child->priv = sf_priv;
670 	}
671 
672 	return 0;
673 }
674 
675 static const struct udevice_id rk3128_clk_ids[] = {
676 	{ .compatible = "rockchip,rk3128-cru" },
677 	{ .compatible = "rockchip,rk3126-cru" },
678 	{ }
679 };
680 
681 U_BOOT_DRIVER(rockchip_rk3128_cru) = {
682 	.name		= "clk_rk3128",
683 	.id		= UCLASS_CLK,
684 	.of_match	= rk3128_clk_ids,
685 	.priv_auto_alloc_size = sizeof(struct rk3128_clk_priv),
686 	.ofdata_to_platdata = rk3128_clk_ofdata_to_platdata,
687 	.ops		= &rk3128_clk_ops,
688 	.bind		= rk3128_clk_bind,
689 	.probe		= rk3128_clk_probe,
690 };
691 
692 #ifndef CONFIG_SPL_BUILD
693 /**
694  * soc_clk_dump() - Print clock frequencies
695  * Returns zero on success
696  *
697  * Implementation for the clk dump command.
698  */
699 int soc_clk_dump(void)
700 {
701 	struct udevice *cru_dev;
702 	const struct rk3128_clk_info *clk_dump;
703 	struct clk clk;
704 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
705 	unsigned long rate;
706 	int i, ret;
707 
708 	ret = uclass_get_device_by_driver(UCLASS_CLK,
709 					  DM_GET_DRIVER(rockchip_rk3128_cru),
710 					  &cru_dev);
711 	if (ret) {
712 		printf("%s failed to get cru device\n", __func__);
713 		return ret;
714 	}
715 
716 	printf("CLK:");
717 	for (i = 0; i < clk_count; i++) {
718 		clk_dump = &clks_dump[i];
719 		if (clk_dump->name) {
720 			clk.id = clk_dump->id;
721 			if (clk_dump->is_cru)
722 				ret = clk_request(cru_dev, &clk);
723 			if (ret < 0)
724 				return ret;
725 
726 			rate = clk_get_rate(&clk);
727 			clk_free(&clk);
728 			if (i == 0) {
729 				if (rate < 0)
730 					printf("%10s%20s\n", clk_dump->name,
731 					       "unknown");
732 				else
733 					printf("%10s%20lu Hz\n", clk_dump->name,
734 					       rate);
735 			} else {
736 				if (rate < 0)
737 					printf("%14s%20s\n", clk_dump->name,
738 					       "unknown");
739 				else
740 					printf("%14s%20lu Hz\n", clk_dump->name,
741 					       rate);
742 			}
743 		}
744 	}
745 
746 	return 0;
747 }
748 #endif
749 
750