xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3308.c (revision 23ba6841ccdaeb51290dc49d4e32f175bd3baa34)
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_tsadc_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;
315 
316 	con = readl(&cru->clksel_con[33]);
317 	div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
318 
319 	return DIV_TO_RATE(OSC_HZ, div);
320 }
321 
322 static ulong rk3308_tsadc_set_clk(struct clk *clk, uint hz)
323 {
324 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
325 	struct rk3308_cru *cru = priv->cru;
326 	int src_clk_div;
327 
328 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
329 	assert(src_clk_div - 1 <= 2047);
330 
331 	rk_clrsetreg(&cru->clksel_con[33],
332 		     CLK_SARADC_DIV_CON_MASK,
333 		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
334 
335 	return rk3308_tsadc_get_clk(clk);
336 }
337 
338 static ulong rk3308_spi_get_clk(struct clk *clk)
339 {
340 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
341 	struct rk3308_cru *cru = priv->cru;
342 	u32 div, con, con_id;
343 
344 	switch (clk->id) {
345 	case SCLK_SPI0:
346 		con_id = 30;
347 		break;
348 	case SCLK_SPI1:
349 		con_id = 31;
350 		break;
351 	case SCLK_SPI2:
352 		con_id = 32;
353 		break;
354 	default:
355 		printf("do not support this spi bus\n");
356 		return -EINVAL;
357 	}
358 
359 	con = readl(&cru->clksel_con[con_id]);
360 	div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
361 
362 	return DIV_TO_RATE(priv->dpll_hz, div);
363 }
364 
365 static ulong rk3308_spi_set_clk(struct clk *clk, uint hz)
366 {
367 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
368 	struct rk3308_cru *cru = priv->cru;
369 	u32 src_clk_div, con_id;
370 
371 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
372 	assert(src_clk_div - 1 <= 127);
373 
374 	switch (clk->id) {
375 	case SCLK_SPI0:
376 		con_id = 30;
377 		break;
378 	case SCLK_SPI1:
379 		con_id = 31;
380 		break;
381 	case SCLK_SPI2:
382 		con_id = 32;
383 		break;
384 	default:
385 		printf("do not support this spi bus\n");
386 		return -EINVAL;
387 	}
388 
389 	rk_clrsetreg(&cru->clksel_con[con_id],
390 		     CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
391 		     CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
392 		     (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
393 
394 	return rk3308_spi_get_clk(clk);
395 }
396 
397 static ulong rk3308_pwm_get_clk(struct clk *clk)
398 {
399 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
400 	struct rk3308_cru *cru = priv->cru;
401 	u32 div, con;
402 
403 	con = readl(&cru->clksel_con[29]);
404 	div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
405 
406 	return DIV_TO_RATE(priv->dpll_hz, div);
407 }
408 
409 static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz)
410 {
411 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
412 	struct rk3308_cru *cru = priv->cru;
413 	int src_clk_div;
414 
415 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
416 	assert(src_clk_div - 1 <= 127);
417 
418 	rk_clrsetreg(&cru->clksel_con[29],
419 		     CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
420 		     CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
421 		     (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
422 
423 	return rk3308_pwm_get_clk(clk);
424 }
425 
426 static ulong rk3308_vop_get_clk(struct clk *clk)
427 {
428 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
429 	struct rk3308_cru *cru = priv->cru;
430 	u32 div, pll_sel, vol_sel, con, parent;
431 
432 	con = readl(&cru->clksel_con[8]);
433 	vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
434 	pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT;
435 	div = con & DCLK_VOP_DIV_MASK;
436 
437 	if (vol_sel == DCLK_VOP_SEL_24M) {
438 		parent = OSC_HZ;
439 	} else if (vol_sel == DCLK_VOP_SEL_DIVOUT) {
440 		switch (pll_sel) {
441 		case DCLK_VOP_PLL_SEL_DPLL:
442 			parent = priv->dpll_hz;
443 			break;
444 		case DCLK_VOP_PLL_SEL_VPLL0:
445 			parent = priv->vpll0_hz;
446 			break;
447 		case DCLK_VOP_PLL_SEL_VPLL1:
448 			parent = priv->vpll0_hz;
449 			break;
450 		default:
451 			printf("do not support this vop pll sel\n");
452 			return -EINVAL;
453 		}
454 	} else {
455 		printf("do not support this vop sel\n");
456 		return -EINVAL;
457 	}
458 
459 	return DIV_TO_RATE(parent, div);
460 }
461 
462 static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz)
463 {
464 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
465 	struct rk3308_cru *cru = priv->cru;
466 	ulong pll_rate, now, best_rate = 0;
467 	u32 i, div, best_div = 0, best_sel = 0;
468 
469 	for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) {
470 		switch (i) {
471 		case DCLK_VOP_PLL_SEL_DPLL:
472 			pll_rate = priv->dpll_hz;
473 			break;
474 		case DCLK_VOP_PLL_SEL_VPLL0:
475 			pll_rate = priv->vpll0_hz;
476 			break;
477 		case DCLK_VOP_PLL_SEL_VPLL1:
478 			pll_rate = priv->vpll1_hz;
479 			break;
480 		default:
481 			printf("do not support this vop pll sel\n");
482 			return -EINVAL;
483 		}
484 
485 		div = DIV_ROUND_UP(pll_rate, hz);
486 		if (div > 255)
487 			continue;
488 		now = pll_rate / div;
489 		if (abs(hz - now) < abs(hz - best_rate)) {
490 			best_rate = now;
491 			best_div = div;
492 			best_sel = i;
493 		}
494 		debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
495 		      pll_rate, best_rate, best_div, best_sel);
496 	}
497 
498 	if (best_rate != hz && hz == OSC_HZ) {
499 		rk_clrsetreg(&cru->clksel_con[8],
500 			     DCLK_VOP_SEL_MASK,
501 			     DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT);
502 	} else if (best_rate) {
503 		rk_clrsetreg(&cru->clksel_con[8],
504 			     DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
505 			     DCLK_VOP_DIV_MASK,
506 			     DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT |
507 			     best_sel << DCLK_VOP_PLL_SEL_SHIFT |
508 			     (best_div - 1) << DCLK_VOP_DIV_SHIFT);
509 	} else {
510 		printf("do not support this vop freq\n");
511 		return -EINVAL;
512 	}
513 
514 	return rk3308_vop_get_clk(clk);
515 }
516 
517 static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
518 {
519 	struct rk3308_cru *cru = priv->cru;
520 	u32 div, con, parent = priv->dpll_hz;
521 
522 	switch (clk_id) {
523 	case ACLK_BUS:
524 		con = readl(&cru->clksel_con[5]);
525 		div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
526 		break;
527 	case HCLK_BUS:
528 		con = readl(&cru->clksel_con[6]);
529 		div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
530 		break;
531 	case PCLK_BUS:
532 		con = readl(&cru->clksel_con[6]);
533 		div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
534 		break;
535 	default:
536 		return -ENOENT;
537 	}
538 
539 	return DIV_TO_RATE(parent, div);
540 }
541 
542 static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
543 				ulong hz)
544 {
545 	struct rk3308_cru *cru = priv->cru;
546 	int src_clk_div;
547 
548 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
549 	assert(src_clk_div - 1 <= 31);
550 
551 	/*
552 	 * select dpll as pd_bus bus clock source and
553 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
554 	 */
555 	switch (clk_id) {
556 	case ACLK_BUS:
557 		rk_clrsetreg(&cru->clksel_con[5],
558 			     BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
559 			     BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
560 			     (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
561 		break;
562 	case HCLK_BUS:
563 		rk_clrsetreg(&cru->clksel_con[6],
564 			     BUS_HCLK_DIV_MASK,
565 			     (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
566 		break;
567 	case PCLK_BUS:
568 		rk_clrsetreg(&cru->clksel_con[6],
569 			     BUS_PCLK_DIV_MASK,
570 			     (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
571 		break;
572 	default:
573 		printf("do not support this bus freq\n");
574 		return -EINVAL;
575 	}
576 
577 	return rk3308_bus_get_clk(priv, clk_id);
578 }
579 
580 static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
581 {
582 	struct rk3308_cru *cru = priv->cru;
583 	u32 div, con, parent = priv->dpll_hz;
584 
585 	switch (clk_id) {
586 	case ACLK_PERI:
587 		con = readl(&cru->clksel_con[36]);
588 		div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
589 		break;
590 	case HCLK_PERI:
591 		con = readl(&cru->clksel_con[37]);
592 		div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
593 		break;
594 	case PCLK_PERI:
595 		con = readl(&cru->clksel_con[37]);
596 		div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
597 		break;
598 	default:
599 		return -ENOENT;
600 	}
601 
602 	return DIV_TO_RATE(parent, div);
603 }
604 
605 static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
606 				 ulong hz)
607 {
608 	struct rk3308_cru *cru = priv->cru;
609 	int src_clk_div;
610 
611 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
612 	assert(src_clk_div - 1 <= 31);
613 
614 	/*
615 	 * select dpll as pd_peri bus clock source and
616 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
617 	 */
618 	switch (clk_id) {
619 	case ACLK_PERI:
620 		rk_clrsetreg(&cru->clksel_con[36],
621 			     PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
622 			     PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT |
623 			     (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
624 		break;
625 	case HCLK_PERI:
626 		rk_clrsetreg(&cru->clksel_con[37],
627 			     PERI_HCLK_DIV_MASK,
628 			     (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
629 		break;
630 	case PCLK_PERI:
631 		rk_clrsetreg(&cru->clksel_con[37],
632 			     PERI_PCLK_DIV_MASK,
633 			     (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
634 		break;
635 	default:
636 		printf("do not support this peri freq\n");
637 		return -EINVAL;
638 	}
639 
640 	return rk3308_peri_get_clk(priv, clk_id);
641 }
642 
643 static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
644 {
645 	struct rk3308_cru *cru = priv->cru;
646 	u32 div, con, parent = priv->vpll0_hz;
647 
648 	switch (clk_id) {
649 	case HCLK_AUDIO:
650 		con = readl(&cru->clksel_con[45]);
651 		div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT;
652 		break;
653 	case PCLK_AUDIO:
654 		con = readl(&cru->clksel_con[45]);
655 		div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT;
656 		break;
657 	default:
658 		return -ENOENT;
659 	}
660 
661 	return DIV_TO_RATE(parent, div);
662 }
663 
664 static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
665 				  ulong hz)
666 {
667 	struct rk3308_cru *cru = priv->cru;
668 	int src_clk_div;
669 
670 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
671 	assert(src_clk_div - 1 <= 31);
672 
673 	/*
674 	 * select vpll0 as audio bus clock source and
675 	 * set up dependent divisors for HCLK and PCLK clocks.
676 	 */
677 	switch (clk_id) {
678 	case HCLK_AUDIO:
679 		rk_clrsetreg(&cru->clksel_con[45],
680 			     AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK,
681 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
682 			     (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT);
683 		break;
684 	case PCLK_AUDIO:
685 		rk_clrsetreg(&cru->clksel_con[45],
686 			     AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK,
687 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
688 			     (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT);
689 		break;
690 	default:
691 		printf("do not support this audio freq\n");
692 		return -EINVAL;
693 	}
694 
695 	return rk3308_peri_get_clk(priv, clk_id);
696 }
697 
698 static ulong rk3308_clk_get_rate(struct clk *clk)
699 {
700 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
701 	ulong rate = 0;
702 
703 	debug("%s id:%ld\n", __func__, clk->id);
704 
705 	switch (clk->id) {
706 	case PLL_APLL:
707 	case ARMCLK:
708 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
709 					     priv->cru, APLL);
710 		break;
711 	case PLL_DPLL:
712 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
713 					     priv->cru, DPLL);
714 		break;
715 	case PLL_VPLL0:
716 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
717 					     priv->cru, VPLL0);
718 		break;
719 	case PLL_VPLL1:
720 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
721 					     priv->cru, VPLL1);
722 		break;
723 	case HCLK_SDMMC:
724 	case HCLK_EMMC:
725 	case SCLK_SDMMC:
726 	case SCLK_EMMC:
727 	case SCLK_EMMC_SAMPLE:
728 		rate = rk3308_mmc_get_clk(clk);
729 		break;
730 	case SCLK_I2C0:
731 	case SCLK_I2C1:
732 	case SCLK_I2C2:
733 	case SCLK_I2C3:
734 		rate = rk3308_i2c_get_clk(clk);
735 		break;
736 	case SCLK_SARADC:
737 		rate = rk3308_saradc_get_clk(clk);
738 		break;
739 	case SCLK_TSADC:
740 		rate = rk3308_tsadc_get_clk(clk);
741 		break;
742 	case SCLK_SPI0:
743 	case SCLK_SPI1:
744 		rate = rk3308_spi_get_clk(clk);
745 		break;
746 	case SCLK_PWM:
747 		rate = rk3308_pwm_get_clk(clk);
748 		break;
749 	case DCLK_VOP:
750 		rate = rk3308_vop_get_clk(clk);
751 		break;
752 	case ACLK_BUS:
753 	case HCLK_BUS:
754 	case PCLK_BUS:
755 		rate = rk3308_bus_get_clk(priv, clk->id);
756 		break;
757 	case ACLK_PERI:
758 	case HCLK_PERI:
759 	case PCLK_PERI:
760 		rate = rk3308_peri_get_clk(priv, clk->id);
761 		break;
762 	case HCLK_AUDIO:
763 	case PCLK_AUDIO:
764 		rate = rk3308_audio_get_clk(priv, clk->id);
765 		break;
766 	default:
767 		return -ENOENT;
768 	}
769 
770 	return rate;
771 }
772 
773 static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
774 {
775 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
776 	ulong ret = 0;
777 
778 	debug("%s %ld %ld\n", __func__, clk->id, rate);
779 
780 	switch (clk->id) {
781 	case PLL_DPLL:
782 		ret = rockchip_pll_set_rate(&rk3308_pll_clks[DPLL], priv->cru,
783 					    DPLL, rate);
784 		priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
785 						      priv->cru, DPLL);
786 		break;
787 	case ARMCLK:
788 		if (priv->armclk_hz)
789 			rk3308_armclk_set_clk(priv, rate);
790 		priv->armclk_hz = rate;
791 		break;
792 	case HCLK_SDMMC:
793 	case HCLK_EMMC:
794 	case SCLK_SDMMC:
795 	case SCLK_EMMC:
796 		ret = rk3308_mmc_set_clk(clk, rate);
797 		break;
798 	case SCLK_I2C0:
799 	case SCLK_I2C1:
800 	case SCLK_I2C2:
801 	case SCLK_I2C3:
802 		ret = rk3308_i2c_set_clk(clk, rate);
803 		break;
804 	case SCLK_SARADC:
805 		ret = rk3308_saradc_set_clk(clk, rate);
806 		break;
807 	case SCLK_TSADC:
808 		ret = rk3308_tsadc_set_clk(clk, rate);
809 		break;
810 	case SCLK_SPI0:
811 	case SCLK_SPI1:
812 		ret = rk3308_spi_set_clk(clk, rate);
813 		break;
814 	case SCLK_PWM:
815 		ret = rk3308_pwm_set_clk(clk, rate);
816 		break;
817 	case DCLK_VOP:
818 		ret = rk3308_vop_set_clk(clk, rate);
819 		break;
820 	case ACLK_BUS:
821 	case HCLK_BUS:
822 	case PCLK_BUS:
823 		rate = rk3308_bus_set_clk(priv, clk->id, rate);
824 		break;
825 	case ACLK_PERI:
826 	case HCLK_PERI:
827 	case PCLK_PERI:
828 		rate = rk3308_peri_set_clk(priv, clk->id, rate);
829 		break;
830 	case HCLK_AUDIO:
831 	case PCLK_AUDIO:
832 		rate = rk3308_audio_set_clk(priv, clk->id, rate);
833 		break;
834 	default:
835 		return -ENOENT;
836 	}
837 
838 	return ret;
839 }
840 
841 #define ROCKCHIP_MMC_DELAY_SEL		BIT(11)
842 #define ROCKCHIP_MMC_DEGREE_OFFSET	1
843 #define ROCKCHIP_MMC_DEGREE_MASK	(0x3 << ROCKCHIP_MMC_DEGREE_OFFSET)
844 #define ROCKCHIP_MMC_DELAYNUM_OFFSET	3
845 #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
846 
847 #define PSECS_PER_SEC 1000000000000LL
848 /*
849  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
850  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
851  */
852 #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
853 
854 int rockchip_mmc_get_phase(struct clk *clk)
855 {
856 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
857 	struct rk3308_cru *cru = priv->cru;
858 	u32 raw_value, delay_num;
859 	u16 degrees = 0;
860 	ulong rate;
861 
862 	rate = rk3308_clk_get_rate(clk);
863 
864 	if (rate < 0)
865 		return rate;
866 
867 	if (clk->id == SCLK_EMMC_SAMPLE)
868 		raw_value = readl(&cru->emmc_con[1]);
869 	else
870 		raw_value = readl(&cru->sdmmc_con[1]);
871 
872 	raw_value &= ROCKCHIP_MMC_DEGREE_MASK;
873 	degrees = (raw_value >>  ROCKCHIP_MMC_DEGREE_OFFSET) * 90;
874 
875 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
876 		/* degrees/delaynum * 10000 */
877 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
878 					36 * (rate / 1000000);
879 
880 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
881 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
882 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
883 	}
884 
885 	return degrees % 360;
886 
887 }
888 
889 int rockchip_mmc_set_phase(struct clk *clk, u32 degrees)
890 {
891 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
892 	struct rk3308_cru *cru = priv->cru;
893 	u8 nineties, remainder, delay_num;
894 	u32 raw_value, delay;
895 	ulong rate;
896 
897 	rate = rk3308_clk_get_rate(clk);
898 
899 	if (rate < 0)
900 		return rate;
901 
902 	nineties = degrees / 90;
903 	remainder = (degrees % 90);
904 
905 	/*
906 	 * Convert to delay; do a little extra work to make sure we
907 	 * don't overflow 32-bit / 64-bit numbers.
908 	 */
909 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
910 	delay *= remainder;
911 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
912 				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
913 
914 	delay_num = (u8)min_t(u32, delay, 255);
915 
916 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
917 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
918 	raw_value |= nineties << ROCKCHIP_MMC_DEGREE_OFFSET;
919 
920 	if (clk->id == SCLK_EMMC_SAMPLE)
921 		writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
922 	else
923 		writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
924 
925 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
926 	      degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk));
927 
928 	return 0;
929 
930 }
931 
932 static int rk3308_clk_get_phase(struct clk *clk)
933 {
934 	int ret;
935 
936 	switch (clk->id) {
937 	case SCLK_EMMC_SAMPLE:
938 	case SCLK_SDMMC_SAMPLE:
939 		ret = rockchip_mmc_get_phase(clk);
940 		break;
941 	default:
942 		return -ENOENT;
943 	}
944 
945 	return ret;
946 }
947 
948 static int rk3308_clk_set_phase(struct clk *clk, int degrees)
949 {
950 	int ret;
951 
952 	switch (clk->id) {
953 	case SCLK_EMMC_SAMPLE:
954 	case SCLK_SDMMC_SAMPLE:
955 		ret = rockchip_mmc_set_phase(clk, degrees);
956 		break;
957 	default:
958 		return -ENOENT;
959 	}
960 
961 	return ret;
962 }
963 
964 static struct clk_ops rk3308_clk_ops = {
965 	.get_rate = rk3308_clk_get_rate,
966 	.set_rate = rk3308_clk_set_rate,
967 	.get_phase	= rk3308_clk_get_phase,
968 	.set_phase	= rk3308_clk_set_phase,
969 };
970 
971 static void rk3308_clk_init(struct udevice *dev)
972 {
973 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
974 	int ret;
975 
976 	if (rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
977 				  priv->cru, APLL) != APLL_HZ) {
978 		ret = rk3308_armclk_set_clk(priv, APLL_HZ);
979 		if (ret < 0)
980 			printf("%s failed to set armclk rate\n", __func__);
981 	}
982 
983 	rk3308_clk_get_pll_rate(priv);
984 
985 	rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ);
986 	rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ);
987 	rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ);
988 
989 	rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ);
990 	rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ);
991 	rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ);
992 
993 	rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ);
994 	rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ);
995 }
996 
997 static int rk3308_clk_probe(struct udevice *dev)
998 {
999 	int ret;
1000 
1001 	rk3308_clk_init(dev);
1002 
1003 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1004 	ret = clk_set_defaults(dev);
1005 	if (ret)
1006 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
1007 
1008 	return 0;
1009 }
1010 
1011 static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
1012 {
1013 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
1014 
1015 	priv->cru = dev_read_addr_ptr(dev);
1016 
1017 	return 0;
1018 }
1019 
1020 static int rk3308_clk_bind(struct udevice *dev)
1021 {
1022 	int ret;
1023 	struct udevice *sys_child, *sf_child;
1024 	struct sysreset_reg *priv;
1025 	struct softreset_reg *sf_priv;
1026 
1027 	/* The reset driver does not have a device node, so bind it here */
1028 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1029 				 &sys_child);
1030 	if (ret) {
1031 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1032 	} else {
1033 		priv = malloc(sizeof(struct sysreset_reg));
1034 		priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
1035 						    glb_srst_fst);
1036 		priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
1037 						    glb_srst_snd);
1038 		sys_child->priv = priv;
1039 	}
1040 
1041 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1042 					 dev_ofnode(dev), &sf_child);
1043 	if (ret) {
1044 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1045 	} else {
1046 		sf_priv = malloc(sizeof(struct softreset_reg));
1047 		sf_priv->sf_reset_offset = offsetof(struct rk3308_cru,
1048 						    softrst_con[0]);
1049 		sf_priv->sf_reset_num = 12;
1050 		sf_child->priv = sf_priv;
1051 	}
1052 
1053 	return 0;
1054 }
1055 
1056 static const struct udevice_id rk3308_clk_ids[] = {
1057 	{ .compatible = "rockchip,rk3308-cru" },
1058 	{ }
1059 };
1060 
1061 U_BOOT_DRIVER(rockchip_rk3308_cru) = {
1062 	.name		= "rockchip_rk3308_cru",
1063 	.id		= UCLASS_CLK,
1064 	.of_match	= rk3308_clk_ids,
1065 	.priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
1066 	.ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
1067 	.ops		= &rk3308_clk_ops,
1068 	.bind		= rk3308_clk_bind,
1069 	.probe		= rk3308_clk_probe,
1070 };
1071 
1072 /**
1073  * soc_clk_dump() - Print clock frequencies
1074  * Returns zero on success
1075  *
1076  * Implementation for the clk dump command.
1077  */
1078 int soc_clk_dump(void)
1079 {
1080 	struct udevice *cru_dev;
1081 	const struct rk3308_clk_info *clk_dump;
1082 	struct clk clk;
1083 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1084 	unsigned long rate;
1085 	int i, ret;
1086 
1087 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1088 					  DM_GET_DRIVER(rockchip_rk3308_cru),
1089 					  &cru_dev);
1090 	if (ret) {
1091 		printf("%s failed to get cru device\n", __func__);
1092 		return ret;
1093 	}
1094 
1095 	printf("CLK:\n");
1096 	for (i = 0; i < clk_count; i++) {
1097 		clk_dump = &clks_dump[i];
1098 		if (clk_dump->name) {
1099 			clk.id = clk_dump->id;
1100 			ret = clk_request(cru_dev, &clk);
1101 			if (ret < 0)
1102 				return ret;
1103 
1104 			rate = clk_get_rate(&clk);
1105 			clk_free(&clk);
1106 			if (i == 0) {
1107 				if (rate < 0)
1108 					printf("%s %s\n", clk_dump->name,
1109 					       "unknown");
1110 				else
1111 					printf("%s %lu KHz\n", clk_dump->name,
1112 					       rate / 1000);
1113 			} else {
1114 				if (rate < 0)
1115 					printf("%s %s\n", clk_dump->name,
1116 					       "unknown");
1117 				else
1118 					printf("%s %lu KHz\n", clk_dump->name,
1119 					       rate / 1000);
1120 			}
1121 		}
1122 	}
1123 
1124 	return 0;
1125 }
1126