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