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