xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3308.c (revision b8fa3d2a17dce6006a8a5f46cbc978a19a3fdf82)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0
5  */
6 #include <common.h>
7 #include <bitfield.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <div64.h>
11 #include <errno.h>
12 #include <syscon.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/cru_rk3308.h>
15 #include <asm/arch/hardware.h>
16 #include <asm/io.h>
17 #include <dm/lists.h>
18 #include <dt-bindings/clock/rk3308-cru.h>
19 
20 DECLARE_GLOBAL_DATA_PTR;
21 
22 enum {
23 	VCO_MAX_HZ	= 3200U * 1000000,
24 	VCO_MIN_HZ	= 800 * 1000000,
25 	OUTPUT_MAX_HZ	= 3200U * 1000000,
26 	OUTPUT_MIN_HZ	= 24 * 1000000,
27 };
28 
29 #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
30 
31 #define RK3308_CLK_DUMP(_id, _name)		\
32 {						\
33 	.id = _id,				\
34 	.name = _name,				\
35 }
36 
37 #define RK3308_CPUCLK_RATE(_rate, _aclk_div, _pclk_div)		\
38 {								\
39 	.rate	= _rate##U,					\
40 	.aclk_div = _aclk_div,					\
41 	.pclk_div = _pclk_div,					\
42 }
43 
44 static struct rockchip_pll_rate_table rk3308_pll_rates[] = {
45 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
46 	RK3036_PLL_RATE(1300000000, 6, 325, 1, 1, 1, 0),
47 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
48 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
49 	RK3036_PLL_RATE(748000000, 2, 187, 3, 1, 1, 0),
50 };
51 
52 static struct rockchip_cpu_rate_table rk3308_cpu_rates[] = {
53 	RK3308_CPUCLK_RATE(1200000000, 1, 5),
54 	RK3308_CPUCLK_RATE(1008000000, 1, 5),
55 	RK3308_CPUCLK_RATE(816000000, 1, 3),
56 	RK3308_CPUCLK_RATE(600000000, 1, 3),
57 };
58 
59 static const struct rk3308_clk_info clks_dump[] = {
60 	RK3308_CLK_DUMP(PLL_APLL, "apll"),
61 	RK3308_CLK_DUMP(PLL_DPLL, "dpll"),
62 	RK3308_CLK_DUMP(PLL_VPLL0, "vpll0"),
63 	RK3308_CLK_DUMP(PLL_VPLL1, "vpll1"),
64 	RK3308_CLK_DUMP(ACLK_BUS, "aclk_bus"),
65 	RK3308_CLK_DUMP(HCLK_BUS, "hclk_bus"),
66 	RK3308_CLK_DUMP(PCLK_BUS, "pclk_bus"),
67 	RK3308_CLK_DUMP(ACLK_PERI, "aclk_peri"),
68 	RK3308_CLK_DUMP(HCLK_PERI, "hclk_peri"),
69 	RK3308_CLK_DUMP(PCLK_PERI, "pclk_peri"),
70 	RK3308_CLK_DUMP(HCLK_AUDIO, "hclk_audio"),
71 	RK3308_CLK_DUMP(PCLK_AUDIO, "pclk_audio"),
72 };
73 
74 static struct rockchip_pll_clock rk3308_pll_clks[] = {
75 	[APLL] = PLL(pll_rk3328, PLL_APLL, RK3308_PLL_CON(0),
76 		     RK3308_MODE_CON, 0, 10, 0, rk3308_pll_rates),
77 	[DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3308_PLL_CON(8),
78 		     RK3308_MODE_CON, 2, 10, 0, NULL),
79 	[VPLL0] = PLL(pll_rk3328, PLL_VPLL0, RK3308_PLL_CON(16),
80 		      RK3308_MODE_CON, 4, 10, 0, NULL),
81 	[VPLL1] = PLL(pll_rk3328, PLL_VPLL1, RK3308_PLL_CON(24),
82 		      RK3308_MODE_CON, 6, 10, 0, NULL),
83 };
84 
85 static ulong rk3308_armclk_set_clk(struct rk3308_clk_priv *priv, ulong hz)
86 {
87 	struct rk3308_cru *cru = priv->cru;
88 	const struct rockchip_cpu_rate_table *rate;
89 	ulong old_rate;
90 
91 	rate = rockchip_get_cpu_settings(rk3308_cpu_rates, hz);
92 	if (!rate) {
93 		printf("%s unsupport rate\n", __func__);
94 		return -EINVAL;
95 	}
96 
97 	/*
98 	 * select apll as cpu/core clock pll source and
99 	 * set up dependent divisors for PERI and ACLK clocks.
100 	 * core hz : apll = 1:1
101 	 */
102 	old_rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
103 					 priv->cru, APLL);
104 	if (old_rate > hz) {
105 		if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
106 					  priv->cru, APLL, hz))
107 			return -EINVAL;
108 		rk_clrsetreg(&cru->clksel_con[0],
109 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
110 			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
111 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
112 			     rate->pclk_div << CORE_DBG_DIV_SHIFT |
113 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
114 			     0 << CORE_DIV_CON_SHIFT);
115 	} else if (old_rate < hz) {
116 		rk_clrsetreg(&cru->clksel_con[0],
117 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
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 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
122 			     0 << CORE_DIV_CON_SHIFT);
123 		if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
124 					  priv->cru, APLL, hz))
125 			return -EINVAL;
126 	}
127 
128 	return rockchip_pll_get_rate(&rk3308_pll_clks[APLL], priv->cru, APLL);
129 }
130 
131 static void rk3308_clk_get_pll_rate(struct rk3308_clk_priv *priv)
132 {
133 	if (!priv->dpll_hz)
134 		priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
135 						      priv->cru, DPLL);
136 	if (!priv->vpll0_hz)
137 		priv->vpll0_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
138 						       priv->cru, VPLL0);
139 	if (!priv->vpll1_hz)
140 		priv->vpll1_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
141 						       priv->cru, VPLL1);
142 }
143 
144 static ulong rk3308_i2c_get_clk(struct clk *clk)
145 {
146 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
147 	struct rk3308_cru *cru = priv->cru;
148 	u32 div, con, con_id;
149 
150 	switch (clk->id) {
151 	case SCLK_I2C0:
152 		con_id = 25;
153 		break;
154 	case SCLK_I2C1:
155 		con_id = 26;
156 		break;
157 	case SCLK_I2C2:
158 		con_id = 27;
159 		break;
160 	case SCLK_I2C3:
161 		con_id = 28;
162 		break;
163 	default:
164 		printf("do not support this i2c bus\n");
165 		return -EINVAL;
166 	}
167 
168 	con = readl(&cru->clksel_con[con_id]);
169 	div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
170 
171 	return DIV_TO_RATE(priv->dpll_hz, div);
172 }
173 
174 static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz)
175 {
176 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
177 	struct rk3308_cru *cru = priv->cru;
178 	u32 src_clk_div, con_id;
179 
180 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
181 	assert(src_clk_div - 1 <= 127);
182 
183 	switch (clk->id) {
184 	case SCLK_I2C0:
185 		con_id = 25;
186 		break;
187 	case SCLK_I2C1:
188 		con_id = 26;
189 		break;
190 	case SCLK_I2C2:
191 		con_id = 27;
192 		break;
193 	case SCLK_I2C3:
194 		con_id = 28;
195 		break;
196 	default:
197 		printf("do not support this i2c bus\n");
198 		return -EINVAL;
199 	}
200 	rk_clrsetreg(&cru->clksel_con[con_id],
201 		     CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK,
202 		     CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT |
203 		     (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT);
204 
205 	return rk3308_i2c_get_clk(clk);
206 }
207 
208 static ulong rk3308_mmc_get_clk(struct clk *clk)
209 {
210 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
211 	struct rk3308_cru *cru = priv->cru;
212 	u32 div, con, con_id;
213 
214 	switch (clk->id) {
215 	case HCLK_SDMMC:
216 	case SCLK_SDMMC:
217 		con_id = 39;
218 		break;
219 	case HCLK_EMMC:
220 	case SCLK_EMMC:
221 	case SCLK_EMMC_SAMPLE:
222 		con_id = 41;
223 		break;
224 	default:
225 		return -EINVAL;
226 	}
227 
228 	con = readl(&cru->clksel_con[con_id]);
229 	div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
230 
231 	if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
232 	    == EMMC_SEL_24M)
233 		return DIV_TO_RATE(OSC_HZ, div) / 2;
234 	else
235 		return DIV_TO_RATE(priv->vpll0_hz, div) / 2;
236 }
237 
238 static ulong rk3308_mmc_set_clk(struct clk *clk, ulong set_rate)
239 {
240 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
241 	struct rk3308_cru *cru = priv->cru;
242 	int src_clk_div;
243 	u32 con_id;
244 
245 	debug("%s %ld %ld\n", __func__, clk->id, set_rate);
246 
247 	switch (clk->id) {
248 	case HCLK_SDMMC:
249 	case SCLK_SDMMC:
250 		con_id = 39;
251 		break;
252 	case HCLK_EMMC:
253 	case SCLK_EMMC:
254 		con_id = 41;
255 		break;
256 	default:
257 		return -EINVAL;
258 	}
259 	/* Select clk_sdmmc/emmc source from VPLL0 by default */
260 	/* mmc clock defaulg div 2 internal, need provide double in cru */
261 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz / 2, set_rate);
262 
263 	if (src_clk_div > 127) {
264 		/* use 24MHz source for 400KHz clock */
265 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
266 		rk_clrsetreg(&cru->clksel_con[con_id],
267 			     EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
268 			     EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
269 			     EMMC_SEL_24M << EMMC_PLL_SHIFT |
270 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
271 	} else {
272 		rk_clrsetreg(&cru->clksel_con[con_id],
273 			     EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
274 			     EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
275 			     EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT |
276 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
277 	}
278 
279 	return rk3308_mmc_get_clk(clk);
280 }
281 
282 static ulong rk3308_saradc_get_clk(struct clk *clk)
283 {
284 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
285 	struct rk3308_cru *cru = priv->cru;
286 	u32 div, con;
287 
288 	con = readl(&cru->clksel_con[34]);
289 	div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
290 
291 	return DIV_TO_RATE(OSC_HZ, div);
292 }
293 
294 static ulong rk3308_saradc_set_clk(struct clk *clk, uint hz)
295 {
296 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
297 	struct rk3308_cru *cru = priv->cru;
298 	int src_clk_div;
299 
300 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
301 	assert(src_clk_div - 1 <= 2047);
302 
303 	rk_clrsetreg(&cru->clksel_con[34],
304 		     CLK_SARADC_DIV_CON_MASK,
305 		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
306 
307 	return rk3308_saradc_get_clk(clk);
308 }
309 
310 static ulong rk3308_spi_get_clk(struct clk *clk)
311 {
312 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
313 	struct rk3308_cru *cru = priv->cru;
314 	u32 div, con, con_id;
315 
316 	switch (clk->id) {
317 	case SCLK_SPI0:
318 		con_id = 30;
319 		break;
320 	case SCLK_SPI1:
321 		con_id = 31;
322 		break;
323 	case SCLK_SPI2:
324 		con_id = 32;
325 		break;
326 	default:
327 		printf("do not support this spi bus\n");
328 		return -EINVAL;
329 	}
330 
331 	con = readl(&cru->clksel_con[con_id]);
332 	div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
333 
334 	return DIV_TO_RATE(priv->dpll_hz, div);
335 }
336 
337 static ulong rk3308_spi_set_clk(struct clk *clk, uint hz)
338 {
339 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
340 	struct rk3308_cru *cru = priv->cru;
341 	u32 src_clk_div, con_id;
342 
343 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
344 	assert(src_clk_div - 1 <= 127);
345 
346 	switch (clk->id) {
347 	case SCLK_SPI0:
348 		con_id = 30;
349 		break;
350 	case SCLK_SPI1:
351 		con_id = 31;
352 		break;
353 	case SCLK_SPI2:
354 		con_id = 32;
355 		break;
356 	default:
357 		printf("do not support this spi bus\n");
358 		return -EINVAL;
359 	}
360 
361 	rk_clrsetreg(&cru->clksel_con[con_id],
362 		     CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
363 		     CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
364 		     (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
365 
366 	return rk3308_spi_get_clk(clk);
367 }
368 
369 static ulong rk3308_pwm_get_clk(struct clk *clk)
370 {
371 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
372 	struct rk3308_cru *cru = priv->cru;
373 	u32 div, con;
374 
375 	con = readl(&cru->clksel_con[29]);
376 	div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
377 
378 	return DIV_TO_RATE(priv->dpll_hz, div);
379 }
380 
381 static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz)
382 {
383 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
384 	struct rk3308_cru *cru = priv->cru;
385 	int src_clk_div;
386 
387 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
388 	assert(src_clk_div - 1 <= 127);
389 
390 	rk_clrsetreg(&cru->clksel_con[29],
391 		     CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
392 		     CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
393 		     (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
394 
395 	return rk3308_pwm_get_clk(clk);
396 }
397 
398 static ulong rk3308_vop_get_clk(struct clk *clk)
399 {
400 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
401 	struct rk3308_cru *cru = priv->cru;
402 	u32 div, pll_sel, vol_sel, con, parent;
403 
404 	con = readl(&cru->clksel_con[8]);
405 	vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
406 	pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT;
407 	div = con & DCLK_VOP_DIV_MASK;
408 
409 	if (vol_sel == DCLK_VOP_SEL_24M) {
410 		parent = OSC_HZ;
411 	} else if (vol_sel == DCLK_VOP_SEL_DIVOUT) {
412 		switch (pll_sel) {
413 		case DCLK_VOP_PLL_SEL_DPLL:
414 			parent = priv->dpll_hz;
415 			break;
416 		case DCLK_VOP_PLL_SEL_VPLL0:
417 			parent = priv->vpll0_hz;
418 			break;
419 		case DCLK_VOP_PLL_SEL_VPLL1:
420 			parent = priv->vpll0_hz;
421 			break;
422 		default:
423 			printf("do not support this vop pll sel\n");
424 			return -EINVAL;
425 		}
426 	} else {
427 		printf("do not support this vop sel\n");
428 		return -EINVAL;
429 	}
430 
431 	return DIV_TO_RATE(parent, div);
432 }
433 
434 static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz)
435 {
436 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
437 	struct rk3308_cru *cru = priv->cru;
438 	ulong pll_rate, now, best_rate = 0;
439 	u32 i, div, best_div = 0, best_sel = 0;
440 
441 	for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) {
442 		switch (i) {
443 		case DCLK_VOP_PLL_SEL_DPLL:
444 			pll_rate = priv->dpll_hz;
445 			break;
446 		case DCLK_VOP_PLL_SEL_VPLL0:
447 			pll_rate = priv->vpll0_hz;
448 			break;
449 		case DCLK_VOP_PLL_SEL_VPLL1:
450 			pll_rate = priv->vpll1_hz;
451 			break;
452 		default:
453 			printf("do not support this vop pll sel\n");
454 			return -EINVAL;
455 		}
456 
457 		div = DIV_ROUND_UP(pll_rate, hz);
458 		if (div > 255)
459 			continue;
460 		now = pll_rate / div;
461 		if (abs(hz - now) < abs(hz - best_rate)) {
462 			best_rate = now;
463 			best_div = div;
464 			best_sel = i;
465 		}
466 		debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
467 		      pll_rate, best_rate, best_div, best_sel);
468 	}
469 
470 	if (best_rate != hz && hz == OSC_HZ) {
471 		rk_clrsetreg(&cru->clksel_con[8],
472 			     DCLK_VOP_SEL_MASK,
473 			     DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT);
474 	} else if (best_rate) {
475 		rk_clrsetreg(&cru->clksel_con[8],
476 			     DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
477 			     DCLK_VOP_DIV_MASK,
478 			     DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT |
479 			     best_sel << DCLK_VOP_PLL_SEL_SHIFT |
480 			     (best_div - 1) << DCLK_VOP_DIV_SHIFT);
481 	} else {
482 		printf("do not support this vop freq\n");
483 		return -EINVAL;
484 	}
485 
486 	return rk3308_vop_get_clk(clk);
487 }
488 
489 static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
490 {
491 	struct rk3308_cru *cru = priv->cru;
492 	u32 div, con, parent = priv->dpll_hz;
493 
494 	switch (clk_id) {
495 	case ACLK_BUS:
496 		con = readl(&cru->clksel_con[5]);
497 		div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
498 		break;
499 	case HCLK_BUS:
500 		con = readl(&cru->clksel_con[6]);
501 		div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
502 		break;
503 	case PCLK_BUS:
504 		con = readl(&cru->clksel_con[6]);
505 		div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
506 		break;
507 	default:
508 		return -ENOENT;
509 	}
510 
511 	return DIV_TO_RATE(parent, div);
512 }
513 
514 static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
515 				ulong hz)
516 {
517 	struct rk3308_cru *cru = priv->cru;
518 	int src_clk_div;
519 
520 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
521 	assert(src_clk_div - 1 <= 31);
522 
523 	/*
524 	 * select dpll as pd_bus bus clock source and
525 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
526 	 */
527 	switch (clk_id) {
528 	case ACLK_BUS:
529 		rk_clrsetreg(&cru->clksel_con[5],
530 			     BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
531 			     BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
532 			     (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
533 		break;
534 	case HCLK_BUS:
535 		rk_clrsetreg(&cru->clksel_con[6],
536 			     BUS_HCLK_DIV_MASK,
537 			     (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
538 		break;
539 	case PCLK_BUS:
540 		rk_clrsetreg(&cru->clksel_con[6],
541 			     BUS_PCLK_DIV_MASK,
542 			     (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
543 		break;
544 	default:
545 		printf("do not support this bus freq\n");
546 		return -EINVAL;
547 	}
548 
549 	return rk3308_bus_get_clk(priv, clk_id);
550 }
551 
552 static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
553 {
554 	struct rk3308_cru *cru = priv->cru;
555 	u32 div, con, parent = priv->dpll_hz;
556 
557 	switch (clk_id) {
558 	case ACLK_PERI:
559 		con = readl(&cru->clksel_con[36]);
560 		div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
561 		break;
562 	case HCLK_PERI:
563 		con = readl(&cru->clksel_con[37]);
564 		div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
565 		break;
566 	case PCLK_PERI:
567 		con = readl(&cru->clksel_con[37]);
568 		div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
569 		break;
570 	default:
571 		return -ENOENT;
572 	}
573 
574 	return DIV_TO_RATE(parent, div);
575 }
576 
577 static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
578 				 ulong hz)
579 {
580 	struct rk3308_cru *cru = priv->cru;
581 	int src_clk_div;
582 
583 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
584 	assert(src_clk_div - 1 <= 31);
585 
586 	/*
587 	 * select dpll as pd_peri bus clock source and
588 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
589 	 */
590 	switch (clk_id) {
591 	case ACLK_PERI:
592 		rk_clrsetreg(&cru->clksel_con[36],
593 			     PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
594 			     PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT |
595 			     (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
596 		break;
597 	case HCLK_PERI:
598 		rk_clrsetreg(&cru->clksel_con[37],
599 			     PERI_HCLK_DIV_MASK,
600 			     (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
601 		break;
602 	case PCLK_PERI:
603 		rk_clrsetreg(&cru->clksel_con[37],
604 			     PERI_PCLK_DIV_MASK,
605 			     (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
606 		break;
607 	default:
608 		printf("do not support this peri freq\n");
609 		return -EINVAL;
610 	}
611 
612 	return rk3308_peri_get_clk(priv, clk_id);
613 }
614 
615 static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
616 {
617 	struct rk3308_cru *cru = priv->cru;
618 	u32 div, con, parent = priv->vpll0_hz;
619 
620 	switch (clk_id) {
621 	case HCLK_AUDIO:
622 		con = readl(&cru->clksel_con[45]);
623 		div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT;
624 		break;
625 	case PCLK_AUDIO:
626 		con = readl(&cru->clksel_con[45]);
627 		div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT;
628 		break;
629 	default:
630 		return -ENOENT;
631 	}
632 
633 	return DIV_TO_RATE(parent, div);
634 }
635 
636 static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
637 				  ulong hz)
638 {
639 	struct rk3308_cru *cru = priv->cru;
640 	int src_clk_div;
641 
642 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
643 	assert(src_clk_div - 1 <= 31);
644 
645 	/*
646 	 * select vpll0 as audio bus clock source and
647 	 * set up dependent divisors for HCLK and PCLK clocks.
648 	 */
649 	switch (clk_id) {
650 	case HCLK_AUDIO:
651 		rk_clrsetreg(&cru->clksel_con[45],
652 			     AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK,
653 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
654 			     (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT);
655 		break;
656 	case PCLK_AUDIO:
657 		rk_clrsetreg(&cru->clksel_con[45],
658 			     AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK,
659 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
660 			     (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT);
661 		break;
662 	default:
663 		printf("do not support this audio freq\n");
664 		return -EINVAL;
665 	}
666 
667 	return rk3308_peri_get_clk(priv, clk_id);
668 }
669 
670 static ulong rk3308_clk_get_rate(struct clk *clk)
671 {
672 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
673 	ulong rate = 0;
674 
675 	debug("%s id:%ld\n", __func__, clk->id);
676 
677 	switch (clk->id) {
678 	case PLL_APLL:
679 	case ARMCLK:
680 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
681 					     priv->cru, APLL);
682 		break;
683 	case PLL_DPLL:
684 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
685 					     priv->cru, DPLL);
686 		break;
687 	case PLL_VPLL0:
688 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
689 					     priv->cru, VPLL0);
690 		break;
691 	case PLL_VPLL1:
692 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
693 					     priv->cru, VPLL1);
694 		break;
695 	case HCLK_SDMMC:
696 	case HCLK_EMMC:
697 	case SCLK_SDMMC:
698 	case SCLK_EMMC:
699 	case SCLK_EMMC_SAMPLE:
700 		rate = rk3308_mmc_get_clk(clk);
701 		break;
702 	case SCLK_I2C0:
703 	case SCLK_I2C1:
704 	case SCLK_I2C2:
705 	case SCLK_I2C3:
706 		rate = rk3308_i2c_get_clk(clk);
707 		break;
708 	case SCLK_SARADC:
709 		rate = rk3308_saradc_get_clk(clk);
710 		break;
711 	case SCLK_SPI0:
712 	case SCLK_SPI1:
713 		rate = rk3308_spi_get_clk(clk);
714 		break;
715 	case SCLK_PWM:
716 		rate = rk3308_pwm_get_clk(clk);
717 		break;
718 	case DCLK_VOP:
719 		rate = rk3308_vop_get_clk(clk);
720 		break;
721 	case ACLK_BUS:
722 	case HCLK_BUS:
723 	case PCLK_BUS:
724 		rate = rk3308_bus_get_clk(priv, clk->id);
725 		break;
726 	case ACLK_PERI:
727 	case HCLK_PERI:
728 	case PCLK_PERI:
729 		rate = rk3308_peri_get_clk(priv, clk->id);
730 		break;
731 	case HCLK_AUDIO:
732 	case PCLK_AUDIO:
733 		rate = rk3308_audio_get_clk(priv, clk->id);
734 		break;
735 	default:
736 		return -ENOENT;
737 	}
738 
739 	return rate;
740 }
741 
742 static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
743 {
744 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
745 	ulong ret = 0;
746 
747 	debug("%s %ld %ld\n", __func__, clk->id, rate);
748 
749 	switch (clk->id) {
750 	case PLL_DPLL:
751 		ret = rockchip_pll_set_rate(&rk3308_pll_clks[DPLL], priv->cru,
752 					    DPLL, rate);
753 		priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
754 						      priv->cru, DPLL);
755 		break;
756 	case ARMCLK:
757 		if (priv->armclk_hz)
758 			rk3308_armclk_set_clk(priv, rate);
759 		priv->armclk_hz = rate;
760 		break;
761 	case HCLK_SDMMC:
762 	case HCLK_EMMC:
763 	case SCLK_SDMMC:
764 	case SCLK_EMMC:
765 		ret = rk3308_mmc_set_clk(clk, rate);
766 		break;
767 	case SCLK_I2C0:
768 	case SCLK_I2C1:
769 	case SCLK_I2C2:
770 	case SCLK_I2C3:
771 		ret = rk3308_i2c_set_clk(clk, rate);
772 		break;
773 	case SCLK_SARADC:
774 		ret = rk3308_saradc_set_clk(clk, rate);
775 		break;
776 	case SCLK_SPI0:
777 	case SCLK_SPI1:
778 		ret = rk3308_spi_set_clk(clk, rate);
779 		break;
780 	case SCLK_PWM:
781 		ret = rk3308_pwm_set_clk(clk, rate);
782 		break;
783 	case DCLK_VOP:
784 		ret = rk3308_vop_set_clk(clk, rate);
785 		break;
786 	case ACLK_BUS:
787 	case HCLK_BUS:
788 	case PCLK_BUS:
789 		rate = rk3308_bus_set_clk(priv, clk->id, rate);
790 		break;
791 	case ACLK_PERI:
792 	case HCLK_PERI:
793 	case PCLK_PERI:
794 		rate = rk3308_peri_set_clk(priv, clk->id, rate);
795 		break;
796 	case HCLK_AUDIO:
797 	case PCLK_AUDIO:
798 		rate = rk3308_audio_set_clk(priv, clk->id, rate);
799 		break;
800 	default:
801 		return -ENOENT;
802 	}
803 
804 	return ret;
805 }
806 
807 #define ROCKCHIP_MMC_DELAY_SEL		BIT(11)
808 #define ROCKCHIP_MMC_DEGREE_OFFSET	1
809 #define ROCKCHIP_MMC_DEGREE_MASK	(0x3 << ROCKCHIP_MMC_DEGREE_OFFSET)
810 #define ROCKCHIP_MMC_DELAYNUM_OFFSET	3
811 #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
812 
813 #define PSECS_PER_SEC 1000000000000LL
814 /*
815  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
816  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
817  */
818 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
819 
820 int rockchip_mmc_get_phase(struct clk *clk)
821 {
822 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
823 	struct rk3308_cru *cru = priv->cru;
824 	u32 raw_value, delay_num;
825 	u16 degrees = 0;
826 	ulong rate;
827 
828 	rate = rk3308_clk_get_rate(clk);
829 
830 	if (rate < 0)
831 		return rate;
832 
833 	if (clk->id == SCLK_EMMC_SAMPLE)
834 		raw_value = readl(&cru->emmc_con[1]);
835 	else
836 		raw_value = readl(&cru->sdmmc_con[1]);
837 
838 	raw_value &= ROCKCHIP_MMC_DEGREE_MASK;
839 	degrees = (raw_value >>  ROCKCHIP_MMC_DEGREE_OFFSET) * 90;
840 
841 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
842 		/* degrees/delaynum * 10000 */
843 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
844 					36 * (rate / 1000000);
845 
846 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
847 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
848 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
849 	}
850 
851 	return degrees % 360;
852 
853 }
854 
855 int rockchip_mmc_set_phase(struct clk *clk, u32 degrees)
856 {
857 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
858 	struct rk3308_cru *cru = priv->cru;
859 	u8 nineties, remainder, delay_num;
860 	u32 raw_value, delay;
861 	ulong rate;
862 
863 	rate = rk3308_clk_get_rate(clk);
864 
865 	if (rate < 0)
866 		return rate;
867 
868 	nineties = degrees / 90;
869 	remainder = (degrees % 90);
870 
871 	/*
872 	 * Convert to delay; do a little extra work to make sure we
873 	 * don't overflow 32-bit / 64-bit numbers.
874 	 */
875 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
876 	delay *= remainder;
877 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
878 				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
879 
880 	delay_num = (u8)min_t(u32, delay, 255);
881 
882 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
883 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
884 	raw_value |= nineties << ROCKCHIP_MMC_DEGREE_OFFSET;
885 
886 	if (clk->id == SCLK_EMMC_SAMPLE)
887 		writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
888 	else
889 		writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
890 
891 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
892 	      degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk));
893 
894 	return 0;
895 
896 }
897 
898 static int rk3308_clk_get_phase(struct clk *clk)
899 {
900 	int ret;
901 
902 	switch (clk->id) {
903 	case SCLK_EMMC_SAMPLE:
904 	case SCLK_SDMMC_SAMPLE:
905 		ret = rockchip_mmc_get_phase(clk);
906 		break;
907 	default:
908 		return -ENOENT;
909 	}
910 
911 	return ret;
912 }
913 
914 static int rk3308_clk_set_phase(struct clk *clk, int degrees)
915 {
916 	int ret;
917 
918 	switch (clk->id) {
919 	case SCLK_EMMC_SAMPLE:
920 	case SCLK_SDMMC_SAMPLE:
921 		ret = rockchip_mmc_set_phase(clk, degrees);
922 		break;
923 	default:
924 		return -ENOENT;
925 	}
926 
927 	return ret;
928 }
929 
930 static struct clk_ops rk3308_clk_ops = {
931 	.get_rate = rk3308_clk_get_rate,
932 	.set_rate = rk3308_clk_set_rate,
933 	.get_phase	= rk3308_clk_get_phase,
934 	.set_phase	= rk3308_clk_set_phase,
935 };
936 
937 static void rk3308_clk_init(struct udevice *dev)
938 {
939 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
940 	int ret;
941 
942 	if (rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
943 				  priv->cru, APLL) != APLL_HZ) {
944 		ret = rk3308_armclk_set_clk(priv, APLL_HZ);
945 		if (ret < 0)
946 			printf("%s failed to set armclk rate\n", __func__);
947 	}
948 
949 	rk3308_clk_get_pll_rate(priv);
950 
951 	rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ);
952 	rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ);
953 	rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ);
954 
955 	rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ);
956 	rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ);
957 	rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ);
958 
959 	rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ);
960 	rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ);
961 }
962 
963 static int rk3308_clk_probe(struct udevice *dev)
964 {
965 	int ret;
966 
967 	rk3308_clk_init(dev);
968 
969 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
970 	ret = clk_set_defaults(dev);
971 	if (ret)
972 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
973 
974 	return 0;
975 }
976 
977 static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
978 {
979 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
980 
981 	priv->cru = dev_read_addr_ptr(dev);
982 
983 	return 0;
984 }
985 
986 static int rk3308_clk_bind(struct udevice *dev)
987 {
988 	int ret;
989 	struct udevice *sys_child, *sf_child;
990 	struct sysreset_reg *priv;
991 	struct softreset_reg *sf_priv;
992 
993 	/* The reset driver does not have a device node, so bind it here */
994 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
995 				 &sys_child);
996 	if (ret) {
997 		debug("Warning: No sysreset driver: ret=%d\n", ret);
998 	} else {
999 		priv = malloc(sizeof(struct sysreset_reg));
1000 		priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
1001 						    glb_srst_fst);
1002 		priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
1003 						    glb_srst_snd);
1004 		sys_child->priv = priv;
1005 	}
1006 
1007 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1008 					 dev_ofnode(dev), &sf_child);
1009 	if (ret) {
1010 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1011 	} else {
1012 		sf_priv = malloc(sizeof(struct softreset_reg));
1013 		sf_priv->sf_reset_offset = offsetof(struct rk3308_cru,
1014 						    softrst_con[0]);
1015 		sf_priv->sf_reset_num = 12;
1016 		sf_child->priv = sf_priv;
1017 	}
1018 
1019 	return 0;
1020 }
1021 
1022 static const struct udevice_id rk3308_clk_ids[] = {
1023 	{ .compatible = "rockchip,rk3308-cru" },
1024 	{ }
1025 };
1026 
1027 U_BOOT_DRIVER(rockchip_rk3308_cru) = {
1028 	.name		= "rockchip_rk3308_cru",
1029 	.id		= UCLASS_CLK,
1030 	.of_match	= rk3308_clk_ids,
1031 	.priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
1032 	.ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
1033 	.ops		= &rk3308_clk_ops,
1034 	.bind		= rk3308_clk_bind,
1035 	.probe		= rk3308_clk_probe,
1036 };
1037 
1038 /**
1039  * soc_clk_dump() - Print clock frequencies
1040  * Returns zero on success
1041  *
1042  * Implementation for the clk dump command.
1043  */
1044 int soc_clk_dump(void)
1045 {
1046 	struct udevice *cru_dev;
1047 	const struct rk3308_clk_info *clk_dump;
1048 	struct clk clk;
1049 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1050 	unsigned long rate;
1051 	int i, ret;
1052 
1053 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1054 					  DM_GET_DRIVER(rockchip_rk3308_cru),
1055 					  &cru_dev);
1056 	if (ret) {
1057 		printf("%s failed to get cru device\n", __func__);
1058 		return ret;
1059 	}
1060 
1061 	printf("CLK:\n");
1062 	for (i = 0; i < clk_count; i++) {
1063 		clk_dump = &clks_dump[i];
1064 		if (clk_dump->name) {
1065 			clk.id = clk_dump->id;
1066 			ret = clk_request(cru_dev, &clk);
1067 			if (ret < 0)
1068 				return ret;
1069 
1070 			rate = clk_get_rate(&clk);
1071 			clk_free(&clk);
1072 			if (i == 0) {
1073 				if (rate < 0)
1074 					printf("%s %s\n", clk_dump->name,
1075 					       "unknown");
1076 				else
1077 					printf("%s %lu KHz\n", clk_dump->name,
1078 					       rate / 1000);
1079 			} else {
1080 				if (rate < 0)
1081 					printf("%s %s\n", clk_dump->name,
1082 					       "unknown");
1083 				else
1084 					printf("%s %lu KHz\n", clk_dump->name,
1085 					       rate / 1000);
1086 			}
1087 		}
1088 	}
1089 
1090 	return 0;
1091 }
1092