xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk322x.c (revision 2a3fb7bb049d69d96f3bc7dae8caa756fdc8a613)
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_rk322x.h>
15 #include <asm/arch/hardware.h>
16 #include <dm/lists.h>
17 #include <dt-bindings/clock/rk3228-cru.h>
18 #include <linux/log2.h>
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 #define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
23 
24 #ifndef CONFIG_SPL_BUILD
25 #define RK322x_CLK_DUMP(_id, _name, _iscru)	\
26 {						\
27 	.id = _id,				\
28 	.name = _name,				\
29 	.is_cru = _iscru,			\
30 }
31 #endif
32 
33 static struct rockchip_pll_rate_table rk322x_pll_rates[] = {
34 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
35 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
36 #ifndef CONFIG_SPL_BUILD
37 	RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
38 	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
39 #endif
40 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
41 	RK3036_PLL_RATE(800000000, 1, 100, 3, 1, 1, 0),
42 	RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
43 #ifndef CONFIG_SPL_BUILD
44 	RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
45 	RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
46 	RK3036_PLL_RATE(400000000, 1, 50, 3, 1, 1, 0),
47 #endif
48 	{ /* sentinel */ },
49 };
50 
51 #define RK322x_CPUCLK_RATE(_rate, _aclk_div, _pclk_div)		\
52 {								\
53 	.rate	= _rate##U,					\
54 	.aclk_div = _aclk_div,					\
55 	.pclk_div = _pclk_div,					\
56 }
57 
58 static struct rockchip_cpu_rate_table rk322x_cpu_rates[] = {
59 	RK322x_CPUCLK_RATE(1200000000, 1, 5),
60 	RK322x_CPUCLK_RATE(1008000000, 1, 5),
61 	RK322x_CPUCLK_RATE(816000000, 1, 3),
62 	RK322x_CPUCLK_RATE(600000000, 1, 3),
63 };
64 
65 #ifndef CONFIG_SPL_BUILD
66 static const struct rk322x_clk_info clks_dump[] = {
67 	RK322x_CLK_DUMP(PLL_APLL, "apll", true),
68 	RK322x_CLK_DUMP(PLL_DPLL, "dpll", true),
69 	RK322x_CLK_DUMP(PLL_CPLL, "cpll", true),
70 	RK322x_CLK_DUMP(PLL_GPLL, "gpll", true),
71 	RK322x_CLK_DUMP(ARMCLK, "armclk", true),
72 	RK322x_CLK_DUMP(ACLK_CPU, "aclk_bus", true),
73 	RK322x_CLK_DUMP(HCLK_CPU, "hclk_bus", true),
74 	RK322x_CLK_DUMP(PCLK_CPU, "pclk_bus", true),
75 	RK322x_CLK_DUMP(ACLK_PERI, "aclk_peri", true),
76 	RK322x_CLK_DUMP(HCLK_PERI, "hclk_peri", true),
77 	RK322x_CLK_DUMP(PCLK_PERI, "pclk_peri", true),
78 };
79 #endif
80 
81 static struct rockchip_pll_clock rk322x_pll_clks[] = {
82 	[APLL] = PLL(pll_rk3036, PLL_APLL, RK2928_PLL_CON(0),
83 		     RK2928_MODE_CON, 0, 10, 0, rk322x_pll_rates),
84 	[DPLL] = PLL(pll_rk3036, PLL_DPLL, RK2928_PLL_CON(3),
85 		     RK2928_MODE_CON, 4, 10, 0, rk322x_pll_rates),
86 	[CPLL] = PLL(pll_rk3036, PLL_CPLL, RK2928_PLL_CON(6),
87 		    RK2928_MODE_CON, 8, 10, 0, rk322x_pll_rates),
88 	[GPLL] = PLL(pll_rk3036, PLL_GPLL, RK2928_PLL_CON(9),
89 		     RK2928_MODE_CON, 12, 10, 0, rk322x_pll_rates),
90 };
91 
92 static ulong rk322x_armclk_set_clk(struct rk322x_clk_priv *priv, ulong hz)
93 {
94 	struct rk322x_cru *cru = priv->cru;
95 	const struct rockchip_cpu_rate_table *rate;
96 	ulong old_rate;
97 
98 	rate = rockchip_get_cpu_settings(rk322x_cpu_rates, hz);
99 	if (!rate) {
100 		printf("%s unsupported rate\n", __func__);
101 		return -EINVAL;
102 	}
103 
104 	/*
105 	 * select apll as cpu/core clock pll source and
106 	 * set up dependent divisors for PERI and ACLK clocks.
107 	 * core hz : apll = 1:1
108 	 */
109 	old_rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
110 					 priv->cru, APLL);
111 	if (old_rate > hz) {
112 		if (rockchip_pll_set_rate(&rk322x_pll_clks[APLL],
113 					  priv->cru, APLL, hz))
114 			return -EINVAL;
115 		rk_clrsetreg(&cru->cru_clksel_con[0],
116 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
117 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
118 			     0 << CORE_DIV_CON_SHIFT);
119 		rk_clrsetreg(&cru->cru_clksel_con[1],
120 			     CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK,
121 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
122 			     rate->pclk_div << CORE_PERI_DIV_SHIFT);
123 	} else if (old_rate < hz) {
124 		rk_clrsetreg(&cru->cru_clksel_con[1],
125 			     CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK,
126 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
127 			     rate->pclk_div << CORE_PERI_DIV_SHIFT);
128 		rk_clrsetreg(&cru->cru_clksel_con[0],
129 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
130 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
131 			     0 << CORE_DIV_CON_SHIFT);
132 		if (rockchip_pll_set_rate(&rk322x_pll_clks[APLL],
133 					  priv->cru, APLL, hz))
134 			return -EINVAL;
135 	}
136 
137 	return rockchip_pll_get_rate(&rk322x_pll_clks[APLL], priv->cru, APLL);
138 }
139 
140 static ulong rk322x_mmc_get_clk(struct rk322x_clk_priv *priv,
141 				int periph)
142 {
143 	struct rk322x_cru *cru = priv->cru;
144 	uint src_rate;
145 	uint div, mux;
146 	u32 con;
147 
148 	switch (periph) {
149 	case HCLK_EMMC:
150 	case SCLK_EMMC:
151 	case SCLK_EMMC_SAMPLE:
152 		con = readl(&cru->cru_clksel_con[11]);
153 		mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT;
154 		con = readl(&cru->cru_clksel_con[12]);
155 		div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
156 		break;
157 	case HCLK_SDMMC:
158 	case SCLK_SDMMC:
159 	case SCLK_SDMMC_SAMPLE:
160 		con = readl(&cru->cru_clksel_con[11]);
161 		mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT;
162 		div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT;
163 		break;
164 	case SCLK_SDIO:
165 	case SCLK_SDIO_SAMPLE:
166 		con = readl(&cru->cru_clksel_con[11]);
167 		mux = (con & SDIO_PLL_MASK) >> SDIO_PLL_SHIFT;
168 		con = readl(&cru->cru_clksel_con[12]);
169 		div = (con & SDIO_DIV_MASK) >> SDIO_DIV_SHIFT;
170 		break;
171 	default:
172 		return -EINVAL;
173 	}
174 
175 	src_rate = mux == EMMC_SEL_24M ? OSC_HZ : priv->gpll_hz;
176 	return DIV_TO_RATE(src_rate, div) / 2;
177 }
178 
179 #ifndef CONFIG_SPL_BUILD
180 static ulong rk322x_mac_set_clk(struct rk322x_clk_priv *priv, uint freq)
181 {
182 	struct rk322x_cru *cru = priv->cru;
183 	ulong ret;
184 
185 	/*
186 	 * The gmac clock can be derived either from an external clock
187 	 * or can be generated from internally by a divider from SCLK_MAC.
188 	 */
189 	if (readl(&cru->cru_clksel_con[5]) & BIT(5)) {
190 		/* An external clock will always generate the right rate... */
191 		ret = freq;
192 	} else {
193 		u32 con = readl(&cru->cru_clksel_con[5]);
194 		ulong pll_rate;
195 		u8 div;
196 
197 		if ((con >> MAC_PLL_SEL_SHIFT) & MAC_PLL_SEL_MASK)
198 			pll_rate = priv->gpll_hz;
199 		else
200 			/* CPLL is not set */
201 			return -EPERM;
202 
203 		div = DIV_ROUND_UP(pll_rate, freq) - 1;
204 		if (div <= 0x1f)
205 			rk_clrsetreg(&cru->cru_clksel_con[5], CLK_MAC_DIV_MASK,
206 				     div << CLK_MAC_DIV_SHIFT);
207 		else
208 			debug("Unsupported div for gmac:%d\n", div);
209 
210 		return DIV_TO_RATE(pll_rate, div);
211 	}
212 
213 	return ret;
214 }
215 #endif
216 
217 static ulong rk322x_mmc_set_clk(struct rk322x_clk_priv *priv,
218 				int periph, uint freq)
219 {
220 	struct rk322x_cru *cru = priv->cru;
221 	int src_clk_div;
222 	int mux;
223 
224 	/* mmc clock defaulg div 2 internal, need provide double in cru */
225 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, freq);
226 
227 	if (src_clk_div > 128) {
228 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq);
229 		assert(src_clk_div - 1 < 128);
230 		mux = EMMC_SEL_24M;
231 	} else {
232 		mux = EMMC_SEL_GPLL;
233 	}
234 
235 	switch (periph) {
236 	case HCLK_EMMC:
237 	case SCLK_EMMC:
238 	case SCLK_EMMC_SAMPLE:
239 		rk_clrsetreg(&cru->cru_clksel_con[11],
240 			     EMMC_PLL_MASK,
241 			     mux << EMMC_PLL_SHIFT);
242 		rk_clrsetreg(&cru->cru_clksel_con[12],
243 			     EMMC_DIV_MASK,
244 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
245 		break;
246 	case HCLK_SDMMC:
247 	case SCLK_SDMMC:
248 	case SCLK_SDMMC_SAMPLE:
249 		rk_clrsetreg(&cru->cru_clksel_con[11],
250 			     MMC0_PLL_MASK | MMC0_DIV_MASK,
251 			     mux << MMC0_PLL_SHIFT |
252 			     (src_clk_div - 1) << MMC0_DIV_SHIFT);
253 		break;
254 	case SCLK_SDIO:
255 	case SCLK_SDIO_SAMPLE:
256 		rk_clrsetreg(&cru->cru_clksel_con[11],
257 			     SDIO_PLL_MASK,
258 			     mux << SDIO_PLL_SHIFT);
259 		rk_clrsetreg(&cru->cru_clksel_con[12],
260 			     SDIO_DIV_MASK,
261 			     (src_clk_div - 1) << SDIO_DIV_SHIFT);
262 		break;
263 	default:
264 		return -EINVAL;
265 	}
266 
267 	return rk322x_mmc_get_clk(priv, periph);
268 }
269 
270 static ulong rk322x_bus_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
271 {
272 	struct rk322x_cru *cru = priv->cru;
273 	u32 div, con, parent;
274 
275 	switch (clk_id) {
276 	case ACLK_CPU:
277 		con = readl(&cru->cru_clksel_con[0]);
278 		div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
279 		parent = priv->gpll_hz;
280 		break;
281 	case HCLK_CPU:
282 		con = readl(&cru->cru_clksel_con[1]);
283 		div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
284 		parent = rk322x_bus_get_clk(priv, ACLK_CPU);
285 		break;
286 	case PCLK_CPU:
287 	case PCLK_I2C0:
288 	case PCLK_I2C1:
289 	case PCLK_I2C2:
290 	case PCLK_I2C3:
291 	case PCLK_PWM:
292 		con = readl(&cru->cru_clksel_con[1]);
293 		div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
294 		parent = rk322x_bus_get_clk(priv, ACLK_CPU);
295 		break;
296 	default:
297 		return -ENOENT;
298 	}
299 
300 	return DIV_TO_RATE(parent, div);
301 }
302 
303 static ulong rk322x_bus_set_clk(struct rk322x_clk_priv *priv,
304 				ulong clk_id, ulong hz)
305 {
306 	struct rk322x_cru *cru = priv->cru;
307 	int src_clk_div;
308 
309 	/*
310 	 * select gpll as pd_bus bus clock source and
311 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
312 	 */
313 	switch (clk_id) {
314 	case ACLK_CPU:
315 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
316 		assert(src_clk_div - 1 < 32);
317 		rk_clrsetreg(&cru->cru_clksel_con[0],
318 			     BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
319 			     BUS_ACLK_PLL_SEL_GPLL << BUS_ACLK_PLL_SEL_SHIFT |
320 			     (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
321 		break;
322 	case HCLK_CPU:
323 		src_clk_div = DIV_ROUND_UP(rk322x_bus_get_clk(priv,
324 							      ACLK_CPU),
325 					   hz);
326 		assert(src_clk_div - 1 < 4);
327 		rk_clrsetreg(&cru->cru_clksel_con[1],
328 			     BUS_HCLK_DIV_MASK,
329 			     (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
330 		break;
331 	case PCLK_CPU:
332 		src_clk_div = DIV_ROUND_UP(rk322x_bus_get_clk(priv,
333 							      ACLK_CPU),
334 					   hz);
335 		assert(src_clk_div - 1 < 8);
336 		rk_clrsetreg(&cru->cru_clksel_con[1],
337 			     BUS_PCLK_DIV_MASK,
338 			     (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
339 		break;
340 	default:
341 		printf("do not support this bus freq\n");
342 		return -EINVAL;
343 	}
344 
345 	return rk322x_bus_get_clk(priv, clk_id);
346 }
347 
348 static ulong rk322x_peri_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
349 {
350 	struct rk322x_cru *cru = priv->cru;
351 	u32 div, con, parent;
352 
353 	switch (clk_id) {
354 	case ACLK_PERI:
355 		con = readl(&cru->cru_clksel_con[10]);
356 		div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
357 		parent = priv->gpll_hz;
358 		break;
359 	case HCLK_PERI:
360 		con = readl(&cru->cru_clksel_con[10]);
361 		div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
362 		parent = rk322x_peri_get_clk(priv, ACLK_PERI);
363 		break;
364 	case PCLK_PERI:
365 		con = readl(&cru->cru_clksel_con[10]);
366 		div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
367 		parent = rk322x_peri_get_clk(priv, ACLK_PERI);
368 		break;
369 	default:
370 		return -ENOENT;
371 	}
372 
373 	return DIV_TO_RATE(parent, div);
374 }
375 
376 static ulong rk322x_peri_set_clk(struct rk322x_clk_priv *priv,
377 				 ulong clk_id, ulong hz)
378 {
379 	struct rk322x_cru *cru = priv->cru;
380 	int src_clk_div;
381 
382 	/*
383 	 * select gpll as pd_bus bus clock source and
384 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
385 	 */
386 	switch (clk_id) {
387 	case ACLK_PERI:
388 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
389 		assert(src_clk_div - 1 < 32);
390 		rk_clrsetreg(&cru->cru_clksel_con[10],
391 			     PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
392 			     PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
393 			     (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
394 		break;
395 	case HCLK_PERI:
396 		src_clk_div = DIV_ROUND_UP(rk322x_peri_get_clk(priv,
397 							       ACLK_PERI),
398 					   hz);
399 		assert(src_clk_div - 1 < 4);
400 		rk_clrsetreg(&cru->cru_clksel_con[10],
401 			     PERI_HCLK_DIV_MASK,
402 			     (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
403 		break;
404 	case PCLK_PERI:
405 		src_clk_div = DIV_ROUND_UP(rk322x_peri_get_clk(priv,
406 							       ACLK_PERI),
407 					   hz);
408 		assert(src_clk_div - 1 < 8);
409 		rk_clrsetreg(&cru->cru_clksel_con[10],
410 			     PERI_PCLK_DIV_MASK,
411 			     (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
412 		break;
413 	default:
414 		printf("do not support this bus freq\n");
415 		return -EINVAL;
416 	}
417 
418 	return rk322x_peri_get_clk(priv, clk_id);
419 }
420 
421 static ulong rk322x_spi_get_clk(struct rk322x_clk_priv *priv)
422 {
423 	struct rk322x_cru *cru = priv->cru;
424 	u32 div, con, parent;
425 
426 	con = readl(&cru->cru_clksel_con[25]);
427 	div = (con & SPI_DIV_MASK) >> SPI_DIV_SHIFT;
428 	parent = priv->gpll_hz;
429 
430 	return DIV_TO_RATE(parent, div);
431 }
432 
433 static ulong rk322x_spi_set_clk(struct rk322x_clk_priv *priv, ulong hz)
434 {
435 	struct rk322x_cru *cru = priv->cru;
436 	int div;
437 
438 	div = DIV_ROUND_UP(priv->gpll_hz, hz);
439 	assert(div - 1 < 128);
440 	rk_clrsetreg(&cru->cru_clksel_con[25],
441 		     SPI_PLL_SEL_MASK | SPI_DIV_MASK,
442 		     SPI_PLL_SEL_GPLL << SPI_PLL_SEL_SHIFT |
443 		     (div - 1) << SPI_DIV_SHIFT);
444 	return rk322x_spi_get_clk(priv);
445 }
446 
447 #ifndef CONFIG_SPL_BUILD
448 static ulong rk322x_vop_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
449 {
450 	struct rk322x_cru *cru = priv->cru;
451 	u32 div, con, sel, parent;
452 
453 	switch (clk_id) {
454 	case ACLK_VOP:
455 		con = readl(&cru->cru_clksel_con[33]);
456 		div = (con & ACLK_VOP_DIV_CON_MASK) >> ACLK_VOP_DIV_CON_SHIFT;
457 		parent = priv->gpll_hz;
458 		break;
459 	case DCLK_VOP:
460 		con = readl(&cru->cru_clksel_con[27]);
461 		con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT;
462 		if (con) {
463 			sel = readl(&cru->cru_clksel_con[27]);
464 			sel = (sel & DCLK_LCDC_PLL_SEL_MASK) >>
465 				 DCLK_LCDC_PLL_SEL_SHIFT;
466 			if (sel)
467 				parent = priv->cpll_hz;
468 			else
469 				parent = priv->gpll_hz;
470 
471 			con = readl(&cru->cru_clksel_con[27]);
472 			div = (con & DCLK_LCDC_DIV_CON_MASK) >>
473 			      DCLK_LCDC_DIV_CON_SHIFT;
474 		} else {
475 			parent = priv->cpll_hz;
476 			div = 1;
477 		}
478 		break;
479 	default:
480 		return -ENOENT;
481 	}
482 
483 	return DIV_TO_RATE(parent, div);
484 }
485 
486 static ulong rk322x_vop_set_clk(struct rk322x_clk_priv *priv,
487 				ulong clk_id, uint hz)
488 {
489 	struct rk322x_cru *cru = priv->cru;
490 	int src_clk_div;
491 	u32 con, parent;
492 
493 	switch (clk_id) {
494 	case ACLK_VOP:
495 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
496 		assert(src_clk_div - 1 < 32);
497 		rk_clrsetreg(&cru->cru_clksel_con[33],
498 			     ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
499 			     ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
500 			     (src_clk_div - 1) << ACLK_VOP_DIV_CON_SHIFT);
501 		break;
502 	case DCLK_VOP:
503 		con = readl(&cru->cru_clksel_con[27]);
504 		con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT;
505 		if (con) {
506 			parent = readl(&cru->cru_clksel_con[27]);
507 			parent = (parent & DCLK_LCDC_PLL_SEL_MASK) >>
508 				 DCLK_LCDC_PLL_SEL_SHIFT;
509 			if (parent)
510 				src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz);
511 			else
512 				src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
513 
514 			assert(src_clk_div - 1 < 256);
515 			rk_clrsetreg(&cru->cru_clksel_con[27],
516 				     DCLK_LCDC_DIV_CON_MASK,
517 				     (src_clk_div - 1) <<
518 				     DCLK_LCDC_DIV_CON_SHIFT);
519 		}
520 		break;
521 	default:
522 		printf("do not support this vop freq\n");
523 		return -EINVAL;
524 	}
525 
526 	return rk322x_vop_get_clk(priv, clk_id);
527 }
528 
529 static ulong rk322x_crypto_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
530 {
531 	struct rk322x_cru *cru = priv->cru;
532 	u32 div, con, parent;
533 
534 	switch (clk_id) {
535 	case SCLK_CRYPTO:
536 		con = readl(&cru->cru_clksel_con[24]);
537 		div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
538 		parent = priv->gpll_hz;
539 		break;
540 	default:
541 		return -ENOENT;
542 	}
543 
544 	return DIV_TO_RATE(parent, div);
545 }
546 
547 static ulong rk322x_crypto_set_clk(struct rk322x_clk_priv *priv, ulong clk_id,
548 				   ulong hz)
549 {
550 	struct rk322x_cru *cru = priv->cru;
551 	int src_clk_div;
552 
553 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
554 	assert(src_clk_div - 1 <= 31);
555 
556 	/*
557 	 * select gpll as crypto clock source and
558 	 * set up dependent divisors for crypto clocks.
559 	 */
560 	switch (clk_id) {
561 	case SCLK_CRYPTO:
562 		rk_clrsetreg(&cru->cru_clksel_con[24],
563 			     CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
564 			     CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
565 			     (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
566 		break;
567 	default:
568 		printf("do not support this peri freq\n");
569 		return -EINVAL;
570 	}
571 
572 	return rk322x_crypto_get_clk(priv, clk_id);
573 }
574 #endif
575 
576 static ulong rk322x_clk_get_rate(struct clk *clk)
577 {
578 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
579 	ulong rate;
580 
581 	switch (clk->id) {
582 	case PLL_APLL:
583 	case PLL_DPLL:
584 	case PLL_CPLL:
585 	case PLL_GPLL:
586 		rate = rockchip_pll_get_rate(&rk322x_pll_clks[clk->id - 1],
587 					     priv->cru, clk->id - 1);
588 		break;
589 	case ARMCLK:
590 		rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
591 					     priv->cru, APLL);
592 		break;
593 	case HCLK_EMMC:
594 	case SCLK_EMMC:
595 	case SCLK_EMMC_SAMPLE:
596 	case HCLK_SDMMC:
597 	case SCLK_SDMMC:
598 	case SCLK_SDMMC_SAMPLE:
599 	case SCLK_SDIO:
600 	case SCLK_SDIO_SAMPLE:
601 		rate = rk322x_mmc_get_clk(priv, clk->id);
602 		break;
603 	case SCLK_SPI0:
604 		rate = rk322x_spi_get_clk(priv);
605 		break;
606 	case ACLK_CPU:
607 	case HCLK_CPU:
608 	case PCLK_CPU:
609 	case PCLK_I2C0:
610 	case PCLK_I2C1:
611 	case PCLK_I2C2:
612 	case PCLK_I2C3:
613 	case PCLK_PWM:
614 		rate = rk322x_bus_get_clk(priv, clk->id);
615 		break;
616 	case ACLK_PERI:
617 	case HCLK_PERI:
618 	case PCLK_PERI:
619 		rate = rk322x_peri_get_clk(priv, clk->id);
620 		break;
621 #ifndef CONFIG_SPL_BUILD
622 	case DCLK_VOP:
623 	case ACLK_VOP:
624 		rate = rk322x_vop_get_clk(priv, clk->id);
625 		break;
626 	case SCLK_CRYPTO:
627 		rate = rk322x_crypto_get_clk(priv, clk->id);
628 		break;
629 #endif
630 	default:
631 		return -ENOENT;
632 	}
633 
634 	return rate;
635 }
636 
637 static ulong rk322x_clk_set_rate(struct clk *clk, ulong rate)
638 {
639 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
640 	ulong ret = 0;
641 
642 	switch (clk->id) {
643 	case PLL_APLL:
644 	case PLL_DPLL:
645 		ret = rockchip_pll_set_rate(&rk322x_pll_clks[clk->id - 1],
646 					    priv->cru, clk->id - 1, rate);
647 		break;
648 	case PLL_CPLL:
649 		ret = rockchip_pll_set_rate(&rk322x_pll_clks[CPLL],
650 					    priv->cru, CPLL, rate);
651 		priv->cpll_hz = rate;
652 		break;
653 	case PLL_GPLL:
654 		ret = rockchip_pll_set_rate(&rk322x_pll_clks[GPLL],
655 					    priv->cru, GPLL, rate);
656 		priv->gpll_hz = rate;
657 		break;
658 	case ARMCLK:
659 		if (priv->armclk_hz)
660 			ret = rk322x_armclk_set_clk(priv, rate);
661 		priv->armclk_hz = rate;
662 		break;
663 	case HCLK_EMMC:
664 	case SCLK_EMMC:
665 	case SCLK_EMMC_SAMPLE:
666 	case HCLK_SDMMC:
667 	case SCLK_SDMMC:
668 	case SCLK_SDMMC_SAMPLE:
669 	case SCLK_SDIO:
670 	case SCLK_SDIO_SAMPLE:
671 		ret = rk322x_mmc_set_clk(priv, clk->id, rate);
672 		break;
673 	case SCLK_DDRC:
674 		ret = rockchip_pll_set_rate(&rk322x_pll_clks[DPLL],
675 					    priv->cru, DPLL, rate);
676 		break;
677 	case SCLK_SPI0:
678 		rate = rk322x_spi_set_clk(priv, rate);
679 		break;
680 	case ACLK_CPU:
681 	case HCLK_CPU:
682 	case PCLK_CPU:
683 		ret = rk322x_bus_set_clk(priv, clk->id, rate);
684 		break;
685 	case ACLK_PERI:
686 	case HCLK_PERI:
687 	case PCLK_PERI:
688 		ret = rk322x_peri_set_clk(priv, clk->id, rate);
689 		break;
690 #ifndef CONFIG_SPL_BUILD
691 	case SCLK_MAC:
692 		ret = rk322x_mac_set_clk(priv, rate);
693 		break;
694 	case DCLK_VOP:
695 	case ACLK_VOP:
696 		ret = rk322x_vop_set_clk(priv, clk->id, rate);
697 		break;
698 	case SCLK_CRYPTO:
699 		ret = rk322x_crypto_set_clk(priv, clk->id, rate);
700 		break;
701 #endif
702 	default:
703 		return -ENOENT;
704 	}
705 
706 	return ret;
707 }
708 
709 #ifndef CONFIG_SPL_BUILD
710 static int rk322x_gmac_set_parent(struct clk *clk, struct clk *parent)
711 {
712 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
713 	struct rk322x_cru *cru = priv->cru;
714 
715 	/*
716 	 * If the requested parent is in the same clock-controller and the id
717 	 * is SCLK_MAC_SRC ("sclk_gmac_src"), switch to the internal clock.
718 	 */
719 	if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_SRC)) {
720 		debug("%s: switching RGMII to SCLK_MAC_SRC\n", __func__);
721 		rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), 0);
722 		return 0;
723 	}
724 
725 	/*
726 	 * If the requested parent is in the same clock-controller and the id
727 	 * is SCLK_MAC_EXTCLK (sclk_mac_extclk), switch to the external clock.
728 	 */
729 	if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_EXTCLK)) {
730 		debug("%s: switching RGMII to SCLK_MAC_EXTCLK\n", __func__);
731 		rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), BIT(5));
732 		return 0;
733 	}
734 
735 	return -EINVAL;
736 }
737 
738 static int rk322x_gmac_extclk_set_parent(struct clk *clk, struct clk *parent)
739 {
740 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
741 	const char *clock_output_name;
742 	struct rk322x_cru *cru = priv->cru;
743 	int ret;
744 
745 	ret = dev_read_string_index(parent->dev, "clock-output-names",
746 				    parent->id, &clock_output_name);
747 	if (ret < 0)
748 		return -ENODATA;
749 
750 	if (!strcmp(clock_output_name, "ext_gmac")) {
751 		debug("%s: switching gmac extclk to ext_gmac\n", __func__);
752 		rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), 0);
753 		return 0;
754 	} else if (!strcmp(clock_output_name, "phy_50m_out")) {
755 		debug("%s: switching gmac extclk to phy_50m_out\n", __func__);
756 		rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), BIT(10));
757 		return 0;
758 	}
759 
760 	return -EINVAL;
761 }
762 
763 static int rk322x_lcdc_set_parent(struct clk *clk, struct clk *parent)
764 {
765 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
766 
767 	if (parent->id == HDMIPHY)
768 		rk_clrsetreg(&priv->cru->cru_clksel_con[27],
769 			     DCLK_LCDC_SEL_MASK,
770 			     DCLK_LCDC_SEL_HDMIPHY << DCLK_LCDC_SEL_SHIFT);
771 	else if (parent->id == PLL_CPLL)
772 		rk_clrsetreg(&priv->cru->cru_clksel_con[27],
773 			     DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK,
774 			     (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) |
775 			     (DCLK_LCDC_PLL_SEL_CPLL <<
776 			     DCLK_LCDC_PLL_SEL_SHIFT));
777 	else
778 		rk_clrsetreg(&priv->cru->cru_clksel_con[27],
779 			     DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK,
780 			     (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) |
781 			     (DCLK_LCDC_PLL_SEL_GPLL <<
782 			     DCLK_LCDC_PLL_SEL_SHIFT));
783 
784 	return 0;
785 }
786 #endif
787 
788 static int rk322x_clk_set_parent(struct clk *clk, struct clk *parent)
789 {
790 	switch (clk->id) {
791 #ifndef CONFIG_SPL_BUILD
792 	case SCLK_MAC:
793 		return rk322x_gmac_set_parent(clk, parent);
794 	case SCLK_MAC_EXTCLK:
795 		return rk322x_gmac_extclk_set_parent(clk, parent);
796 	case DCLK_VOP:
797 		return rk322x_lcdc_set_parent(clk, parent);
798 #endif
799 	}
800 
801 	debug("%s: unsupported clk %ld\n", __func__, clk->id);
802 	return -ENOENT;
803 }
804 
805 #define ROCKCHIP_MMC_DELAY_SEL		BIT(10)
806 #define ROCKCHIP_MMC_DEGREE_MASK	0x3
807 #define ROCKCHIP_MMC_DELAYNUM_OFFSET	2
808 #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
809 
810 #define PSECS_PER_SEC 1000000000000LL
811 /*
812  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
813  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
814  */
815 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
816 
817 int rk322x_mmc_get_phase(struct clk *clk)
818 {
819 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
820 	struct rk322x_cru *cru = priv->cru;
821 	u32 raw_value, delay_num;
822 	u16 degrees = 0;
823 	ulong rate;
824 
825 	rate = rk322x_clk_get_rate(clk);
826 
827 	if (rate < 0)
828 		return rate;
829 
830 	if (clk->id == SCLK_EMMC_SAMPLE)
831 		raw_value = readl(&cru->cru_emmc_con[1]);
832 	else if (clk->id == SCLK_SDMMC_SAMPLE)
833 		raw_value = readl(&cru->cru_sdmmc_con[1]);
834 	else
835 		raw_value = readl(&cru->cru_sdio_con[1]);
836 
837 	raw_value >>= 1;
838 	degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
839 
840 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
841 		/* degrees/delaynum * 10000 */
842 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
843 					36 * (rate / 1000000);
844 
845 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
846 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
847 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
848 	}
849 
850 	return degrees % 360;
851 }
852 
853 int rk322x_mmc_set_phase(struct clk *clk, u32 degrees)
854 {
855 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
856 	struct rk322x_cru *cru = priv->cru;
857 	u8 nineties, remainder, delay_num;
858 	u32 raw_value, delay;
859 	ulong rate;
860 
861 	rate = rk322x_clk_get_rate(clk);
862 
863 	if (rate < 0)
864 		return rate;
865 
866 	nineties = degrees / 90;
867 	remainder = (degrees % 90);
868 
869 	/*
870 	 * Convert to delay; do a little extra work to make sure we
871 	 * don't overflow 32-bit / 64-bit numbers.
872 	 */
873 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
874 	delay *= remainder;
875 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
876 				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
877 
878 	delay_num = (u8)min_t(u32, delay, 255);
879 
880 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
881 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
882 	raw_value |= nineties;
883 
884 	raw_value <<= 1;
885 	if (clk->id == SCLK_EMMC_SAMPLE)
886 		writel(raw_value | 0xffff0000, &cru->cru_emmc_con[1]);
887 	else if (clk->id == SCLK_SDMMC_SAMPLE)
888 		writel(raw_value | 0xffff0000, &cru->cru_sdmmc_con[1]);
889 	else
890 		writel(raw_value | 0xffff0000, &cru->cru_sdio_con[1]);
891 
892 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
893 	      degrees, delay_num, raw_value, rk322x_mmc_get_phase(clk));
894 
895 	return 0;
896 }
897 
898 static int rk322x_clk_get_phase(struct clk *clk)
899 {
900 	int ret;
901 
902 	debug("%s %ld\n", __func__, clk->id);
903 	switch (clk->id) {
904 	case SCLK_EMMC_SAMPLE:
905 	case SCLK_SDMMC_SAMPLE:
906 	case SCLK_SDIO_SAMPLE:
907 		ret = rk322x_mmc_get_phase(clk);
908 		break;
909 	default:
910 		return -ENOENT;
911 	}
912 
913 	return ret;
914 }
915 
916 static int rk322x_clk_set_phase(struct clk *clk, int degrees)
917 {
918 	int ret;
919 
920 	debug("%s %ld\n", __func__, clk->id);
921 	switch (clk->id) {
922 	case SCLK_EMMC_SAMPLE:
923 	case SCLK_SDMMC_SAMPLE:
924 	case SCLK_SDIO_SAMPLE:
925 		ret = rk322x_mmc_set_phase(clk, degrees);
926 		break;
927 	default:
928 		return -ENOENT;
929 	}
930 
931 	return ret;
932 }
933 
934 static struct clk_ops rk322x_clk_ops = {
935 	.get_rate	= rk322x_clk_get_rate,
936 	.set_rate	= rk322x_clk_set_rate,
937 	.set_parent	= rk322x_clk_set_parent,
938 	.get_phase	= rk322x_clk_get_phase,
939 	.set_phase	= rk322x_clk_set_phase,
940 };
941 
942 static int rk322x_clk_ofdata_to_platdata(struct udevice *dev)
943 {
944 	struct rk322x_clk_priv *priv = dev_get_priv(dev);
945 
946 	priv->cru = dev_read_addr_ptr(dev);
947 
948 	return 0;
949 }
950 
951 #ifndef CONFIG_TPL_BUILD
952 static void rkclk_init(struct rk322x_clk_priv *priv)
953 {
954 	struct rk322x_cru *cru = priv->cru;
955 
956 	if (rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
957 				  priv->cru, APLL) != APLL_HZ)
958 		rk322x_armclk_set_clk(priv, APLL_HZ);
959 
960 	priv->gpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[GPLL],
961 					      priv->cru, GPLL);
962 	priv->cpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[CPLL],
963 					      priv->cru, CPLL);
964 
965 	/* before set pll set child div first */
966 	rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ / 4);
967 	rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ / 4);
968 	rk322x_mmc_set_clk(priv, SCLK_EMMC, 50000000);
969 	rk322x_mmc_set_clk(priv, SCLK_SDMMC, 50000000);
970 	rk322x_mmc_set_clk(priv, SCLK_SDIO, 50000000);
971 	rk_clrsetreg(&cru->cru_clksel_con[2], (0x1 << 14) |
972 		     (0x1f << 8), (1 << 14) | (0xb << 8));
973 	rk_clrsetreg(&cru->cru_clksel_con[23], (0x1f << 0) | (0x1f << 8),
974 		     (0x1f << 0) | (5 << 8));
975 	rk_clrsetreg(&cru->cru_clksel_con[33],
976 		     ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
977 		     ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
978 		     3 << ACLK_VOP_DIV_CON_SHIFT);
979 	rk_clrsetreg(&cru->cru_clksel_con[22], 0x1f << 0, 5 << 0);
980 	rk_clrsetreg(&cru->cru_clksel_con[24], 0x1f << 0, 0xb << 0);
981 	rk_clrsetreg(&cru->cru_clksel_con[28], (0x1f << 8) | (0x1f << 0),
982 		     (5 << 8) | (5 << 0));
983 	rk_clrsetreg(&cru->cru_clksel_con[31], (0x1f << 8) | (0x1f << 0),
984 		     (5 << 8) | (5 << 0));
985 	rk_clrsetreg(&cru->cru_clksel_con[32], 0x1f << 0, 5 << 0);
986 	rk_clrsetreg(&cru->cru_clksel_con[33], (0x1f << 8) | (0x1f << 0),
987 		     (5 << 8) | (5 << 0));
988 	rk_clrsetreg(&cru->cru_clksel_con[34], (0x1f << 8) | (0x1f << 0),
989 		     (5 << 8) | (3 << 0));
990 
991 	rockchip_pll_set_rate(&rk322x_pll_clks[GPLL],
992 			      priv->cru, GPLL, GPLL_HZ);
993 	priv->gpll_hz = GPLL_HZ;
994 
995 	rockchip_pll_set_rate(&rk322x_pll_clks[CPLL],
996 			      priv->cru, CPLL, CPLL_HZ);
997 	priv->cpll_hz = CPLL_HZ;
998 
999 	rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ);
1000 	rk322x_bus_set_clk(priv, HCLK_CPU, ACLK_BUS_HZ / 2);
1001 	rk322x_bus_set_clk(priv, PCLK_CPU, ACLK_BUS_HZ / 2);
1002 	rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ);
1003 	rk322x_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2);
1004 	rk322x_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2);
1005 	/*rk322x_mmc_set_clk(priv, SCLK_EMMC, rate);*/
1006 
1007 	/* set usbphy and hdmiphy from phy */
1008 	rk_clrsetreg(&cru->cru_misc_con, (0x1 << 13) |
1009 		     (0x1 << 15), (0 << 15) | (0 << 13));
1010 }
1011 #endif
1012 
1013 static int rk322x_clk_probe(struct udevice *dev)
1014 {
1015 #ifndef CONFIG_TPL_BUILD
1016 	struct rk322x_clk_priv *priv = dev_get_priv(dev);
1017 	int ret = 0;
1018 
1019 	priv->sync_kernel = false;
1020 	if (!priv->armclk_enter_hz)
1021 		priv->armclk_enter_hz =
1022 		rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
1023 				      priv->cru, APLL);
1024 	rkclk_init(priv);
1025 	if (!priv->armclk_init_hz)
1026 		priv->armclk_init_hz =
1027 		rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
1028 				      priv->cru, APLL);
1029 	ret = clk_set_defaults(dev);
1030 	if (ret)
1031 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
1032 	else
1033 		priv->sync_kernel = true;
1034 #endif
1035 	return 0;
1036 }
1037 
1038 static int rk322x_clk_bind(struct udevice *dev)
1039 {
1040 	int ret;
1041 	struct udevice *sys_child, *sf_child;
1042 	struct sysreset_reg *priv;
1043 	struct softreset_reg *sf_priv;
1044 
1045 	/* The reset driver does not have a device node, so bind it here */
1046 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1047 				 &sys_child);
1048 	if (ret) {
1049 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1050 	} else {
1051 		priv = malloc(sizeof(struct sysreset_reg));
1052 		priv->glb_srst_fst_value = offsetof(struct rk322x_cru,
1053 						    cru_glb_srst_fst_value);
1054 		priv->glb_srst_snd_value = offsetof(struct rk322x_cru,
1055 						    cru_glb_srst_snd_value);
1056 		sys_child->priv = priv;
1057 	}
1058 
1059 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1060 					 dev_ofnode(dev), &sf_child);
1061 	if (ret) {
1062 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1063 	} else {
1064 		sf_priv = malloc(sizeof(struct softreset_reg));
1065 		sf_priv->sf_reset_offset = offsetof(struct rk322x_cru,
1066 						    cru_softrst_con[0]);
1067 		sf_priv->sf_reset_num = 9;
1068 		sf_child->priv = sf_priv;
1069 	}
1070 
1071 	return 0;
1072 }
1073 
1074 static const struct udevice_id rk322x_clk_ids[] = {
1075 	{ .compatible = "rockchip,rk3228-cru" },
1076 	{ }
1077 };
1078 
1079 U_BOOT_DRIVER(rockchip_rk322x_cru) = {
1080 	.name		= "clk_rk322x",
1081 	.id		= UCLASS_CLK,
1082 	.of_match	= rk322x_clk_ids,
1083 	.priv_auto_alloc_size = sizeof(struct rk322x_clk_priv),
1084 	.ofdata_to_platdata = rk322x_clk_ofdata_to_platdata,
1085 	.ops		= &rk322x_clk_ops,
1086 	.bind		= rk322x_clk_bind,
1087 	.probe		= rk322x_clk_probe,
1088 };
1089 
1090 #ifndef CONFIG_SPL_BUILD
1091 /**
1092  * soc_clk_dump() - Print clock frequencies
1093  * Returns zero on success
1094  *
1095  * Implementation for the clk dump command.
1096  */
1097 int soc_clk_dump(void)
1098 {
1099 	struct udevice *cru_dev;
1100 	struct rk322x_clk_priv *priv;
1101 	const struct rk322x_clk_info *clk_dump;
1102 	struct clk clk;
1103 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1104 	unsigned long rate;
1105 	int i, ret;
1106 
1107 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1108 					  DM_GET_DRIVER(rockchip_rk322x_cru),
1109 					  &cru_dev);
1110 	if (ret) {
1111 		printf("%s failed to get cru device\n", __func__);
1112 		return ret;
1113 	}
1114 
1115 	priv = dev_get_priv(cru_dev);
1116 	printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1117 	       priv->sync_kernel ? "sync kernel" : "uboot",
1118 	       priv->armclk_enter_hz / 1000,
1119 	       priv->armclk_init_hz / 1000,
1120 	       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1121 	       priv->set_armclk_rate ? " KHz" : "N/A");
1122 	for (i = 0; i < clk_count; i++) {
1123 		clk_dump = &clks_dump[i];
1124 		if (clk_dump->name) {
1125 			clk.id = clk_dump->id;
1126 			if (clk_dump->is_cru)
1127 				ret = clk_request(cru_dev, &clk);
1128 			if (ret < 0)
1129 				return ret;
1130 
1131 			rate = clk_get_rate(&clk);
1132 			clk_free(&clk);
1133 			if (i == 0) {
1134 				if (rate < 0)
1135 					printf("  %s %s\n", clk_dump->name,
1136 					       "unknown");
1137 				else
1138 					printf("  %s %lu KHz\n", clk_dump->name,
1139 					       rate / 1000);
1140 			} else {
1141 				if (rate < 0)
1142 					printf("  %s %s\n", clk_dump->name,
1143 					       "unknown");
1144 				else
1145 					printf("  %s %lu KHz\n", clk_dump->name,
1146 					       rate / 1000);
1147 			}
1148 		}
1149 	}
1150 
1151 	return 0;
1152 }
1153 #endif
1154 
1155