xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3308.c (revision 0c8b06ef74f1da4f6d51974c0d3d9d4bf7ed7e2e)
154d254feSAndy Yan /*
254d254feSAndy Yan  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
354d254feSAndy Yan  *
454d254feSAndy Yan  * SPDX-License-Identifier:	GPL-2.0
554d254feSAndy Yan  */
654d254feSAndy Yan #include <common.h>
754d254feSAndy Yan #include <bitfield.h>
854d254feSAndy Yan #include <clk-uclass.h>
954d254feSAndy Yan #include <dm.h>
101e180a56SFinley Xiao #include <div64.h>
1154d254feSAndy Yan #include <errno.h>
1254d254feSAndy Yan #include <syscon.h>
1354d254feSAndy Yan #include <asm/arch/clock.h>
1454d254feSAndy Yan #include <asm/arch/cru_rk3308.h>
1554d254feSAndy Yan #include <asm/arch/hardware.h>
1654d254feSAndy Yan #include <asm/io.h>
1754d254feSAndy Yan #include <dm/lists.h>
1854d254feSAndy Yan #include <dt-bindings/clock/rk3308-cru.h>
1954d254feSAndy Yan 
2054d254feSAndy Yan DECLARE_GLOBAL_DATA_PTR;
2154d254feSAndy Yan 
2254d254feSAndy Yan enum {
2354d254feSAndy Yan 	VCO_MAX_HZ	= 3200U * 1000000,
2454d254feSAndy Yan 	VCO_MIN_HZ	= 800 * 1000000,
2554d254feSAndy Yan 	OUTPUT_MAX_HZ	= 3200U * 1000000,
2654d254feSAndy Yan 	OUTPUT_MIN_HZ	= 24 * 1000000,
2754d254feSAndy Yan };
2854d254feSAndy Yan 
2954d254feSAndy Yan #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
3054d254feSAndy Yan 
31efdbac34SFinley Xiao #define RK3308_CLK_DUMP(_id, _name)		\
32efdbac34SFinley Xiao {						\
33efdbac34SFinley Xiao 	.id = _id,				\
34efdbac34SFinley Xiao 	.name = _name,				\
35efdbac34SFinley Xiao }
36efdbac34SFinley Xiao 
3703a6c029SFinley Xiao #define RK3308_CPUCLK_RATE(_rate, _aclk_div, _pclk_div)		\
3803a6c029SFinley Xiao {								\
3903a6c029SFinley Xiao 	.rate	= _rate##U,					\
4003a6c029SFinley Xiao 	.aclk_div = _aclk_div,					\
4103a6c029SFinley Xiao 	.pclk_div = _pclk_div,					\
4203a6c029SFinley Xiao }
4303a6c029SFinley Xiao 
4427ee7641SFinley Xiao static struct rockchip_pll_rate_table rk3308_pll_rates[] = {
451e180a56SFinley Xiao 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
4627ee7641SFinley Xiao 	RK3036_PLL_RATE(1300000000, 6, 325, 1, 1, 1, 0),
4727ee7641SFinley Xiao 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
4827ee7641SFinley Xiao 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
4927ee7641SFinley Xiao 	RK3036_PLL_RATE(748000000, 2, 187, 3, 1, 1, 0),
5054d254feSAndy Yan };
5154d254feSAndy Yan 
5203a6c029SFinley Xiao static struct rockchip_cpu_rate_table rk3308_cpu_rates[] = {
5303a6c029SFinley Xiao 	RK3308_CPUCLK_RATE(1200000000, 1, 5),
5403a6c029SFinley Xiao 	RK3308_CPUCLK_RATE(1008000000, 1, 5),
5503a6c029SFinley Xiao 	RK3308_CPUCLK_RATE(816000000, 1, 3),
5603a6c029SFinley Xiao 	RK3308_CPUCLK_RATE(600000000, 1, 3),
57e04b9c6bSJoseph Chen 	RK3308_CPUCLK_RATE(408000000, 1, 1),
5803a6c029SFinley Xiao };
5903a6c029SFinley Xiao 
60efdbac34SFinley Xiao static const struct rk3308_clk_info clks_dump[] = {
61efdbac34SFinley Xiao 	RK3308_CLK_DUMP(PLL_APLL, "apll"),
62e8ca7128SFinley Xiao 	RK3308_CLK_DUMP(PLL_DPLL, "dpll"),
63efdbac34SFinley Xiao 	RK3308_CLK_DUMP(PLL_VPLL0, "vpll0"),
64efdbac34SFinley Xiao 	RK3308_CLK_DUMP(PLL_VPLL1, "vpll1"),
65efdbac34SFinley Xiao 	RK3308_CLK_DUMP(ACLK_BUS, "aclk_bus"),
66efdbac34SFinley Xiao 	RK3308_CLK_DUMP(HCLK_BUS, "hclk_bus"),
67efdbac34SFinley Xiao 	RK3308_CLK_DUMP(PCLK_BUS, "pclk_bus"),
68efdbac34SFinley Xiao 	RK3308_CLK_DUMP(ACLK_PERI, "aclk_peri"),
69efdbac34SFinley Xiao 	RK3308_CLK_DUMP(HCLK_PERI, "hclk_peri"),
70efdbac34SFinley Xiao 	RK3308_CLK_DUMP(PCLK_PERI, "pclk_peri"),
71efdbac34SFinley Xiao 	RK3308_CLK_DUMP(HCLK_AUDIO, "hclk_audio"),
72efdbac34SFinley Xiao 	RK3308_CLK_DUMP(PCLK_AUDIO, "pclk_audio"),
73efdbac34SFinley Xiao };
74efdbac34SFinley Xiao 
7527ee7641SFinley Xiao static struct rockchip_pll_clock rk3308_pll_clks[] = {
7627ee7641SFinley Xiao 	[APLL] = PLL(pll_rk3328, PLL_APLL, RK3308_PLL_CON(0),
7727ee7641SFinley Xiao 		     RK3308_MODE_CON, 0, 10, 0, rk3308_pll_rates),
7827ee7641SFinley Xiao 	[DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3308_PLL_CON(8),
7927ee7641SFinley Xiao 		     RK3308_MODE_CON, 2, 10, 0, NULL),
8027ee7641SFinley Xiao 	[VPLL0] = PLL(pll_rk3328, PLL_VPLL0, RK3308_PLL_CON(16),
8127ee7641SFinley Xiao 		      RK3308_MODE_CON, 4, 10, 0, NULL),
8227ee7641SFinley Xiao 	[VPLL1] = PLL(pll_rk3328, PLL_VPLL1, RK3308_PLL_CON(24),
8327ee7641SFinley Xiao 		      RK3308_MODE_CON, 6, 10, 0, NULL),
8427ee7641SFinley Xiao };
8527ee7641SFinley Xiao 
861bbed247SFinley Xiao /*
871bbed247SFinley Xiao  *
881bbed247SFinley Xiao  * rational_best_approximation(31415, 10000,
891bbed247SFinley Xiao  *		(1 << 8) - 1, (1 << 5) - 1, &n, &d);
901bbed247SFinley Xiao  *
911bbed247SFinley Xiao  * you may look at given_numerator as a fixed point number,
921bbed247SFinley Xiao  * with the fractional part size described in given_denominator.
931bbed247SFinley Xiao  *
941bbed247SFinley Xiao  * for theoretical background, see:
951bbed247SFinley Xiao  * http://en.wikipedia.org/wiki/Continued_fraction
961bbed247SFinley Xiao  */
rational_best_approximation(unsigned long given_numerator,unsigned long given_denominator,unsigned long max_numerator,unsigned long max_denominator,unsigned long * best_numerator,unsigned long * best_denominator)971bbed247SFinley Xiao static void rational_best_approximation(unsigned long given_numerator,
981bbed247SFinley Xiao 					unsigned long given_denominator,
991bbed247SFinley Xiao 					unsigned long max_numerator,
1001bbed247SFinley Xiao 					unsigned long max_denominator,
1011bbed247SFinley Xiao 					unsigned long *best_numerator,
1021bbed247SFinley Xiao 					unsigned long *best_denominator)
1031bbed247SFinley Xiao {
1041bbed247SFinley Xiao 	unsigned long n, d, n0, d0, n1, d1;
1051bbed247SFinley Xiao 
1061bbed247SFinley Xiao 	n = given_numerator;
1071bbed247SFinley Xiao 	d = given_denominator;
1081bbed247SFinley Xiao 	n0 = 0;
1091bbed247SFinley Xiao 	d1 = 0;
1101bbed247SFinley Xiao 	n1 = 1;
1111bbed247SFinley Xiao 	d0 = 1;
1121bbed247SFinley Xiao 	for (;;) {
1131bbed247SFinley Xiao 		unsigned long t, a;
1141bbed247SFinley Xiao 
1151bbed247SFinley Xiao 		if (n1 > max_numerator || d1 > max_denominator) {
1161bbed247SFinley Xiao 			n1 = n0;
1171bbed247SFinley Xiao 			d1 = d0;
1181bbed247SFinley Xiao 			break;
1191bbed247SFinley Xiao 		}
1201bbed247SFinley Xiao 		if (d == 0)
1211bbed247SFinley Xiao 			break;
1221bbed247SFinley Xiao 		t = d;
1231bbed247SFinley Xiao 		a = n / d;
1241bbed247SFinley Xiao 		d = n % d;
1251bbed247SFinley Xiao 		n = t;
1261bbed247SFinley Xiao 		t = n0 + a * n1;
1271bbed247SFinley Xiao 		n0 = n1;
1281bbed247SFinley Xiao 		n1 = t;
1291bbed247SFinley Xiao 		t = d0 + a * d1;
1301bbed247SFinley Xiao 		d0 = d1;
1311bbed247SFinley Xiao 		d1 = t;
1321bbed247SFinley Xiao 	}
1331bbed247SFinley Xiao 	*best_numerator = n1;
1341bbed247SFinley Xiao 	*best_denominator = d1;
1351bbed247SFinley Xiao }
1361bbed247SFinley Xiao 
rk3308_armclk_set_clk(struct rk3308_clk_priv * priv,ulong hz)13703a6c029SFinley Xiao static ulong rk3308_armclk_set_clk(struct rk3308_clk_priv *priv, ulong hz)
13803a6c029SFinley Xiao {
13903a6c029SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
14003a6c029SFinley Xiao 	const struct rockchip_cpu_rate_table *rate;
14103a6c029SFinley Xiao 	ulong old_rate;
14203a6c029SFinley Xiao 
14303a6c029SFinley Xiao 	rate = rockchip_get_cpu_settings(rk3308_cpu_rates, hz);
14403a6c029SFinley Xiao 	if (!rate) {
14503a6c029SFinley Xiao 		printf("%s unsupport rate\n", __func__);
14603a6c029SFinley Xiao 		return -EINVAL;
14703a6c029SFinley Xiao 	}
14803a6c029SFinley Xiao 
14903a6c029SFinley Xiao 	/*
15003a6c029SFinley Xiao 	 * select apll as cpu/core clock pll source and
15103a6c029SFinley Xiao 	 * set up dependent divisors for PERI and ACLK clocks.
15203a6c029SFinley Xiao 	 * core hz : apll = 1:1
15303a6c029SFinley Xiao 	 */
15403a6c029SFinley Xiao 	old_rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
15503a6c029SFinley Xiao 					 priv->cru, APLL);
15603a6c029SFinley Xiao 	if (old_rate > hz) {
15703a6c029SFinley Xiao 		if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
15803a6c029SFinley Xiao 					  priv->cru, APLL, hz))
15903a6c029SFinley Xiao 			return -EINVAL;
16003a6c029SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[0],
16103a6c029SFinley Xiao 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
16203a6c029SFinley Xiao 			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
16303a6c029SFinley Xiao 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
16403a6c029SFinley Xiao 			     rate->pclk_div << CORE_DBG_DIV_SHIFT |
16503a6c029SFinley Xiao 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
16603a6c029SFinley Xiao 			     0 << CORE_DIV_CON_SHIFT);
16703a6c029SFinley Xiao 	} else if (old_rate < hz) {
16803a6c029SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[0],
16903a6c029SFinley Xiao 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK |
17003a6c029SFinley Xiao 			     CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
17103a6c029SFinley Xiao 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
17203a6c029SFinley Xiao 			     rate->pclk_div << CORE_DBG_DIV_SHIFT |
17303a6c029SFinley Xiao 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
17403a6c029SFinley Xiao 			     0 << CORE_DIV_CON_SHIFT);
17503a6c029SFinley Xiao 		if (rockchip_pll_set_rate(&rk3308_pll_clks[APLL],
17603a6c029SFinley Xiao 					  priv->cru, APLL, hz))
17703a6c029SFinley Xiao 			return -EINVAL;
17803a6c029SFinley Xiao 	}
17903a6c029SFinley Xiao 
18003a6c029SFinley Xiao 	return rockchip_pll_get_rate(&rk3308_pll_clks[APLL], priv->cru, APLL);
18103a6c029SFinley Xiao }
18203a6c029SFinley Xiao 
rk3308_clk_get_pll_rate(struct rk3308_clk_priv * priv)1837b1c1c4bSFinley Xiao static void rk3308_clk_get_pll_rate(struct rk3308_clk_priv *priv)
1847b1c1c4bSFinley Xiao {
1857b1c1c4bSFinley Xiao 	if (!priv->dpll_hz)
18627ee7641SFinley Xiao 		priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
18727ee7641SFinley Xiao 						      priv->cru, DPLL);
1887b1c1c4bSFinley Xiao 	if (!priv->vpll0_hz)
18927ee7641SFinley Xiao 		priv->vpll0_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
19027ee7641SFinley Xiao 						       priv->cru, VPLL0);
1917b1c1c4bSFinley Xiao 	if (!priv->vpll1_hz)
19227ee7641SFinley Xiao 		priv->vpll1_hz = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
19327ee7641SFinley Xiao 						       priv->cru, VPLL1);
1947b1c1c4bSFinley Xiao }
1957b1c1c4bSFinley Xiao 
rk3308_i2c_get_clk(struct clk * clk)196fc4a6bd4SFinley Xiao static ulong rk3308_i2c_get_clk(struct clk *clk)
19754d254feSAndy Yan {
198fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
199fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
20054d254feSAndy Yan 	u32 div, con, con_id;
20154d254feSAndy Yan 
202fc4a6bd4SFinley Xiao 	switch (clk->id) {
20354d254feSAndy Yan 	case SCLK_I2C0:
20454d254feSAndy Yan 		con_id = 25;
20554d254feSAndy Yan 		break;
20654d254feSAndy Yan 	case SCLK_I2C1:
20754d254feSAndy Yan 		con_id = 26;
20854d254feSAndy Yan 		break;
20954d254feSAndy Yan 	case SCLK_I2C2:
21054d254feSAndy Yan 		con_id = 27;
21154d254feSAndy Yan 		break;
21254d254feSAndy Yan 	case SCLK_I2C3:
21354d254feSAndy Yan 		con_id = 28;
21454d254feSAndy Yan 		break;
21554d254feSAndy Yan 	default:
21654d254feSAndy Yan 		printf("do not support this i2c bus\n");
21754d254feSAndy Yan 		return -EINVAL;
21854d254feSAndy Yan 	}
21954d254feSAndy Yan 
22054d254feSAndy Yan 	con = readl(&cru->clksel_con[con_id]);
22154d254feSAndy Yan 	div = con >> CLK_I2C_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK;
22254d254feSAndy Yan 
223fc4a6bd4SFinley Xiao 	return DIV_TO_RATE(priv->dpll_hz, div);
22454d254feSAndy Yan }
22554d254feSAndy Yan 
rk3308_i2c_set_clk(struct clk * clk,uint hz)226fc4a6bd4SFinley Xiao static ulong rk3308_i2c_set_clk(struct clk *clk, uint hz)
22754d254feSAndy Yan {
228fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
229fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
23054d254feSAndy Yan 	u32 src_clk_div, con_id;
23154d254feSAndy Yan 
2324e6d5752SFinley Xiao 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
233e27c054aSFinley Xiao 	assert(src_clk_div - 1 <= 127);
23454d254feSAndy Yan 
235fc4a6bd4SFinley Xiao 	switch (clk->id) {
23654d254feSAndy Yan 	case SCLK_I2C0:
23754d254feSAndy Yan 		con_id = 25;
23854d254feSAndy Yan 		break;
23954d254feSAndy Yan 	case SCLK_I2C1:
24054d254feSAndy Yan 		con_id = 26;
24154d254feSAndy Yan 		break;
24254d254feSAndy Yan 	case SCLK_I2C2:
24354d254feSAndy Yan 		con_id = 27;
24454d254feSAndy Yan 		break;
24554d254feSAndy Yan 	case SCLK_I2C3:
24654d254feSAndy Yan 		con_id = 28;
24754d254feSAndy Yan 		break;
24854d254feSAndy Yan 	default:
24954d254feSAndy Yan 		printf("do not support this i2c bus\n");
25054d254feSAndy Yan 		return -EINVAL;
25154d254feSAndy Yan 	}
25254d254feSAndy Yan 	rk_clrsetreg(&cru->clksel_con[con_id],
25354d254feSAndy Yan 		     CLK_I2C_PLL_SEL_MASK | CLK_I2C_DIV_CON_MASK,
25454d254feSAndy Yan 		     CLK_I2C_PLL_SEL_DPLL << CLK_I2C_PLL_SEL_SHIFT |
25554d254feSAndy Yan 		     (src_clk_div - 1) << CLK_I2C_DIV_CON_SHIFT);
25654d254feSAndy Yan 
257fc4a6bd4SFinley Xiao 	return rk3308_i2c_get_clk(clk);
25854d254feSAndy Yan }
25954d254feSAndy Yan 
rk3308_mac_set_clk(struct clk * clk,uint hz)260200683eaSDavid Wu static ulong rk3308_mac_set_clk(struct clk *clk, uint hz)
261200683eaSDavid Wu {
262200683eaSDavid Wu 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
263200683eaSDavid Wu 	struct rk3308_cru *cru = priv->cru;
264200683eaSDavid Wu 	u32 con = readl(&cru->clksel_con[43]);
265200683eaSDavid Wu 	ulong pll_rate;
266200683eaSDavid Wu 	u8 div;
267200683eaSDavid Wu 
268200683eaSDavid Wu 	if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL0)
269200683eaSDavid Wu 		pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
270200683eaSDavid Wu 						 priv->cru, VPLL0);
271200683eaSDavid Wu 	else if ((con >> MAC_PLL_SHIFT) & MAC_SEL_VPLL1)
272200683eaSDavid Wu 		pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
273200683eaSDavid Wu 						 priv->cru, VPLL1);
274200683eaSDavid Wu 	else
275200683eaSDavid Wu 		pll_rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
276200683eaSDavid Wu 						 priv->cru, DPLL);
277200683eaSDavid Wu 
278200683eaSDavid Wu 	/*default set 50MHZ for gmac*/
279200683eaSDavid Wu 	if (!hz)
280200683eaSDavid Wu 		hz = 50000000;
281200683eaSDavid Wu 
282200683eaSDavid Wu 	div = DIV_ROUND_UP(pll_rate, hz) - 1;
283200683eaSDavid Wu 	assert(div < 32);
284200683eaSDavid Wu 	rk_clrsetreg(&cru->clksel_con[43], MAC_DIV_MASK,
285200683eaSDavid Wu 		     div << MAC_DIV_SHIFT);
286200683eaSDavid Wu 
287200683eaSDavid Wu 	return DIV_TO_RATE(pll_rate, div);
288200683eaSDavid Wu }
289200683eaSDavid Wu 
rk3308_mac_set_speed_clk(struct clk * clk,uint hz)290200683eaSDavid Wu static int rk3308_mac_set_speed_clk(struct clk *clk, uint hz)
291200683eaSDavid Wu {
292200683eaSDavid Wu 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
293200683eaSDavid Wu 	struct rk3308_cru *cru = priv->cru;
294200683eaSDavid Wu 
295200683eaSDavid Wu 	if (hz != 2500000 && hz != 25000000) {
296200683eaSDavid Wu 		debug("Unsupported mac speed:%d\n", hz);
297200683eaSDavid Wu 		return -EINVAL;
298200683eaSDavid Wu 	}
299200683eaSDavid Wu 
300200683eaSDavid Wu 	rk_clrsetreg(&cru->clksel_con[43], MAC_CLK_SPEED_SEL_MASK,
301200683eaSDavid Wu 		     ((hz == 2500000) ? 0 : 1) << MAC_CLK_SPEED_SEL_SHIFT);
302200683eaSDavid Wu 
303200683eaSDavid Wu 	return 0;
304200683eaSDavid Wu }
305200683eaSDavid Wu 
rk3308_mmc_get_clk(struct clk * clk)306fc4a6bd4SFinley Xiao static ulong rk3308_mmc_get_clk(struct clk *clk)
30754d254feSAndy Yan {
308fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
309fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
31054d254feSAndy Yan 	u32 div, con, con_id;
31154d254feSAndy Yan 
312fc4a6bd4SFinley Xiao 	switch (clk->id) {
31354d254feSAndy Yan 	case HCLK_SDMMC:
31454d254feSAndy Yan 	case SCLK_SDMMC:
31554d254feSAndy Yan 		con_id = 39;
31654d254feSAndy Yan 		break;
31754d254feSAndy Yan 	case HCLK_EMMC:
31854d254feSAndy Yan 	case SCLK_EMMC:
31954d254feSAndy Yan 	case SCLK_EMMC_SAMPLE:
32054d254feSAndy Yan 		con_id = 41;
32154d254feSAndy Yan 		break;
32254d254feSAndy Yan 	default:
32354d254feSAndy Yan 		return -EINVAL;
32454d254feSAndy Yan 	}
32554d254feSAndy Yan 
32654d254feSAndy Yan 	con = readl(&cru->clksel_con[con_id]);
32754d254feSAndy Yan 	div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
32854d254feSAndy Yan 
32954d254feSAndy Yan 	if ((con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT
33054d254feSAndy Yan 	    == EMMC_SEL_24M)
33154d254feSAndy Yan 		return DIV_TO_RATE(OSC_HZ, div) / 2;
33254d254feSAndy Yan 	else
333fc4a6bd4SFinley Xiao 		return DIV_TO_RATE(priv->vpll0_hz, div) / 2;
33454d254feSAndy Yan }
33554d254feSAndy Yan 
rk3308_mmc_set_clk(struct clk * clk,ulong set_rate)336fc4a6bd4SFinley Xiao static ulong rk3308_mmc_set_clk(struct clk *clk, ulong set_rate)
33754d254feSAndy Yan {
338fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
339fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
34054d254feSAndy Yan 	int src_clk_div;
34154d254feSAndy Yan 	u32 con_id;
34254d254feSAndy Yan 
343fc4a6bd4SFinley Xiao 	debug("%s %ld %ld\n", __func__, clk->id, set_rate);
34454d254feSAndy Yan 
345fc4a6bd4SFinley Xiao 	switch (clk->id) {
34654d254feSAndy Yan 	case HCLK_SDMMC:
34754d254feSAndy Yan 	case SCLK_SDMMC:
34854d254feSAndy Yan 		con_id = 39;
34954d254feSAndy Yan 		break;
35054d254feSAndy Yan 	case HCLK_EMMC:
35154d254feSAndy Yan 	case SCLK_EMMC:
35254d254feSAndy Yan 		con_id = 41;
35354d254feSAndy Yan 		break;
35454d254feSAndy Yan 	default:
35554d254feSAndy Yan 		return -EINVAL;
35654d254feSAndy Yan 	}
35754d254feSAndy Yan 	/* Select clk_sdmmc/emmc source from VPLL0 by default */
35854d254feSAndy Yan 	/* mmc clock defaulg div 2 internal, need provide double in cru */
359fc4a6bd4SFinley Xiao 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz / 2, set_rate);
36054d254feSAndy Yan 
36154d254feSAndy Yan 	if (src_clk_div > 127) {
36254d254feSAndy Yan 		/* use 24MHz source for 400KHz clock */
36354d254feSAndy Yan 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate);
36454d254feSAndy Yan 		rk_clrsetreg(&cru->clksel_con[con_id],
36554d254feSAndy Yan 			     EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
36654d254feSAndy Yan 			     EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
36754d254feSAndy Yan 			     EMMC_SEL_24M << EMMC_PLL_SHIFT |
36854d254feSAndy Yan 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
36954d254feSAndy Yan 	} else {
37054d254feSAndy Yan 		rk_clrsetreg(&cru->clksel_con[con_id],
37154d254feSAndy Yan 			     EMMC_PLL_MASK | EMMC_DIV_MASK | EMMC_CLK_SEL_MASK,
37254d254feSAndy Yan 			     EMMC_CLK_SEL_EMMC << EMMC_CLK_SEL_SHIFT |
37354d254feSAndy Yan 			     EMMC_SEL_VPLL0 << EMMC_PLL_SHIFT |
37454d254feSAndy Yan 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
37554d254feSAndy Yan 	}
37654d254feSAndy Yan 
377fc4a6bd4SFinley Xiao 	return rk3308_mmc_get_clk(clk);
37854d254feSAndy Yan }
37954d254feSAndy Yan 
rk3308_saradc_get_clk(struct clk * clk)380fc4a6bd4SFinley Xiao static ulong rk3308_saradc_get_clk(struct clk *clk)
38154d254feSAndy Yan {
382fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
383fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
38454d254feSAndy Yan 	u32 div, con;
38554d254feSAndy Yan 
38654d254feSAndy Yan 	con = readl(&cru->clksel_con[34]);
38754d254feSAndy Yan 	div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
38854d254feSAndy Yan 
38954d254feSAndy Yan 	return DIV_TO_RATE(OSC_HZ, div);
39054d254feSAndy Yan }
39154d254feSAndy Yan 
rk3308_saradc_set_clk(struct clk * clk,uint hz)392fc4a6bd4SFinley Xiao static ulong rk3308_saradc_set_clk(struct clk *clk, uint hz)
39354d254feSAndy Yan {
394fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
395fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
39654d254feSAndy Yan 	int src_clk_div;
39754d254feSAndy Yan 
3984e6d5752SFinley Xiao 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
399e27c054aSFinley Xiao 	assert(src_clk_div - 1 <= 2047);
40054d254feSAndy Yan 
40154d254feSAndy Yan 	rk_clrsetreg(&cru->clksel_con[34],
40254d254feSAndy Yan 		     CLK_SARADC_DIV_CON_MASK,
40354d254feSAndy Yan 		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
40454d254feSAndy Yan 
405fc4a6bd4SFinley Xiao 	return rk3308_saradc_get_clk(clk);
40654d254feSAndy Yan }
40754d254feSAndy Yan 
rk3308_tsadc_get_clk(struct clk * clk)408cb3c37fcSElaine Zhang static ulong rk3308_tsadc_get_clk(struct clk *clk)
409cb3c37fcSElaine Zhang {
410cb3c37fcSElaine Zhang 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
411cb3c37fcSElaine Zhang 	struct rk3308_cru *cru = priv->cru;
412cb3c37fcSElaine Zhang 	u32 div, con;
413cb3c37fcSElaine Zhang 
414cb3c37fcSElaine Zhang 	con = readl(&cru->clksel_con[33]);
415cb3c37fcSElaine Zhang 	div = con >> CLK_SARADC_DIV_CON_SHIFT & CLK_SARADC_DIV_CON_MASK;
416cb3c37fcSElaine Zhang 
417cb3c37fcSElaine Zhang 	return DIV_TO_RATE(OSC_HZ, div);
418cb3c37fcSElaine Zhang }
419cb3c37fcSElaine Zhang 
rk3308_tsadc_set_clk(struct clk * clk,uint hz)420cb3c37fcSElaine Zhang static ulong rk3308_tsadc_set_clk(struct clk *clk, uint hz)
421cb3c37fcSElaine Zhang {
422cb3c37fcSElaine Zhang 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
423cb3c37fcSElaine Zhang 	struct rk3308_cru *cru = priv->cru;
424cb3c37fcSElaine Zhang 	int src_clk_div;
425cb3c37fcSElaine Zhang 
426cb3c37fcSElaine Zhang 	src_clk_div = DIV_ROUND_UP(OSC_HZ, hz);
427cb3c37fcSElaine Zhang 	assert(src_clk_div - 1 <= 2047);
428cb3c37fcSElaine Zhang 
429cb3c37fcSElaine Zhang 	rk_clrsetreg(&cru->clksel_con[33],
430cb3c37fcSElaine Zhang 		     CLK_SARADC_DIV_CON_MASK,
431cb3c37fcSElaine Zhang 		     (src_clk_div - 1) << CLK_SARADC_DIV_CON_SHIFT);
432cb3c37fcSElaine Zhang 
433cb3c37fcSElaine Zhang 	return rk3308_tsadc_get_clk(clk);
434cb3c37fcSElaine Zhang }
435cb3c37fcSElaine Zhang 
rk3308_spi_get_clk(struct clk * clk)436fc4a6bd4SFinley Xiao static ulong rk3308_spi_get_clk(struct clk *clk)
43754d254feSAndy Yan {
438fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
439fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
44054d254feSAndy Yan 	u32 div, con, con_id;
44154d254feSAndy Yan 
442fc4a6bd4SFinley Xiao 	switch (clk->id) {
44354d254feSAndy Yan 	case SCLK_SPI0:
44454d254feSAndy Yan 		con_id = 30;
44554d254feSAndy Yan 		break;
44654d254feSAndy Yan 	case SCLK_SPI1:
44754d254feSAndy Yan 		con_id = 31;
44854d254feSAndy Yan 		break;
44954d254feSAndy Yan 	case SCLK_SPI2:
45054d254feSAndy Yan 		con_id = 32;
45154d254feSAndy Yan 		break;
45254d254feSAndy Yan 	default:
45354d254feSAndy Yan 		printf("do not support this spi bus\n");
45454d254feSAndy Yan 		return -EINVAL;
45554d254feSAndy Yan 	}
45654d254feSAndy Yan 
45754d254feSAndy Yan 	con = readl(&cru->clksel_con[con_id]);
45854d254feSAndy Yan 	div = con >> CLK_SPI_DIV_CON_SHIFT & CLK_SPI_DIV_CON_MASK;
45954d254feSAndy Yan 
460fc4a6bd4SFinley Xiao 	return DIV_TO_RATE(priv->dpll_hz, div);
46154d254feSAndy Yan }
46254d254feSAndy Yan 
rk3308_spi_set_clk(struct clk * clk,uint hz)463fc4a6bd4SFinley Xiao static ulong rk3308_spi_set_clk(struct clk *clk, uint hz)
46454d254feSAndy Yan {
465fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
466fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
46754d254feSAndy Yan 	u32 src_clk_div, con_id;
46854d254feSAndy Yan 
4694e6d5752SFinley Xiao 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
470e27c054aSFinley Xiao 	assert(src_clk_div - 1 <= 127);
47154d254feSAndy Yan 
472fc4a6bd4SFinley Xiao 	switch (clk->id) {
47354d254feSAndy Yan 	case SCLK_SPI0:
47454d254feSAndy Yan 		con_id = 30;
47554d254feSAndy Yan 		break;
47654d254feSAndy Yan 	case SCLK_SPI1:
47754d254feSAndy Yan 		con_id = 31;
47854d254feSAndy Yan 		break;
47954d254feSAndy Yan 	case SCLK_SPI2:
48054d254feSAndy Yan 		con_id = 32;
48154d254feSAndy Yan 		break;
48254d254feSAndy Yan 	default:
48354d254feSAndy Yan 		printf("do not support this spi bus\n");
48454d254feSAndy Yan 		return -EINVAL;
48554d254feSAndy Yan 	}
48654d254feSAndy Yan 
48754d254feSAndy Yan 	rk_clrsetreg(&cru->clksel_con[con_id],
48854d254feSAndy Yan 		     CLK_SPI_PLL_SEL_MASK | CLK_SPI_DIV_CON_MASK,
48954d254feSAndy Yan 		     CLK_SPI_PLL_SEL_DPLL << CLK_SPI_PLL_SEL_SHIFT |
49054d254feSAndy Yan 		     (src_clk_div - 1) << CLK_SPI_DIV_CON_SHIFT);
49154d254feSAndy Yan 
492fc4a6bd4SFinley Xiao 	return rk3308_spi_get_clk(clk);
49354d254feSAndy Yan }
49454d254feSAndy Yan 
rk3308_pwm_get_clk(struct clk * clk)495fc4a6bd4SFinley Xiao static ulong rk3308_pwm_get_clk(struct clk *clk)
49654d254feSAndy Yan {
497fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
498fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
49954d254feSAndy Yan 	u32 div, con;
50054d254feSAndy Yan 
50154d254feSAndy Yan 	con = readl(&cru->clksel_con[29]);
50254d254feSAndy Yan 	div = con >> CLK_PWM_DIV_CON_SHIFT & CLK_PWM_DIV_CON_MASK;
50354d254feSAndy Yan 
504fc4a6bd4SFinley Xiao 	return DIV_TO_RATE(priv->dpll_hz, div);
50554d254feSAndy Yan }
50654d254feSAndy Yan 
rk3308_pwm_set_clk(struct clk * clk,uint hz)507fc4a6bd4SFinley Xiao static ulong rk3308_pwm_set_clk(struct clk *clk, uint hz)
50854d254feSAndy Yan {
509fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
510fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
51154d254feSAndy Yan 	int src_clk_div;
51254d254feSAndy Yan 
5134e6d5752SFinley Xiao 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
514e27c054aSFinley Xiao 	assert(src_clk_div - 1 <= 127);
51554d254feSAndy Yan 
51654d254feSAndy Yan 	rk_clrsetreg(&cru->clksel_con[29],
51754d254feSAndy Yan 		     CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK,
51854d254feSAndy Yan 		     CLK_PWM_PLL_SEL_DPLL << CLK_PWM_PLL_SEL_SHIFT |
51954d254feSAndy Yan 		     (src_clk_div - 1) << CLK_PWM_DIV_CON_SHIFT);
52054d254feSAndy Yan 
521fc4a6bd4SFinley Xiao 	return rk3308_pwm_get_clk(clk);
52254d254feSAndy Yan }
52354d254feSAndy Yan 
rk3308_vop_get_clk(struct clk * clk)524fc4a6bd4SFinley Xiao static ulong rk3308_vop_get_clk(struct clk *clk)
525ec20593dSFinley Xiao {
526fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
527fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
528ec20593dSFinley Xiao 	u32 div, pll_sel, vol_sel, con, parent;
529ec20593dSFinley Xiao 
530ec20593dSFinley Xiao 	con = readl(&cru->clksel_con[8]);
531ec20593dSFinley Xiao 	vol_sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
532ec20593dSFinley Xiao 	pll_sel = (con & DCLK_VOP_PLL_SEL_MASK) >> DCLK_VOP_PLL_SEL_SHIFT;
533ec20593dSFinley Xiao 	div = con & DCLK_VOP_DIV_MASK;
534ec20593dSFinley Xiao 
535ec20593dSFinley Xiao 	if (vol_sel == DCLK_VOP_SEL_24M) {
536ec20593dSFinley Xiao 		parent = OSC_HZ;
537ec20593dSFinley Xiao 	} else if (vol_sel == DCLK_VOP_SEL_DIVOUT) {
538ec20593dSFinley Xiao 		switch (pll_sel) {
539ec20593dSFinley Xiao 		case DCLK_VOP_PLL_SEL_DPLL:
5407b1c1c4bSFinley Xiao 			parent = priv->dpll_hz;
541ec20593dSFinley Xiao 			break;
542ec20593dSFinley Xiao 		case DCLK_VOP_PLL_SEL_VPLL0:
5437b1c1c4bSFinley Xiao 			parent = priv->vpll0_hz;
544ec20593dSFinley Xiao 			break;
545ec20593dSFinley Xiao 		case DCLK_VOP_PLL_SEL_VPLL1:
5467b1c1c4bSFinley Xiao 			parent = priv->vpll0_hz;
547ec20593dSFinley Xiao 			break;
548ec20593dSFinley Xiao 		default:
549ec20593dSFinley Xiao 			printf("do not support this vop pll sel\n");
550ec20593dSFinley Xiao 			return -EINVAL;
551ec20593dSFinley Xiao 		}
552ec20593dSFinley Xiao 	} else {
553ec20593dSFinley Xiao 		printf("do not support this vop sel\n");
554ec20593dSFinley Xiao 		return -EINVAL;
555ec20593dSFinley Xiao 	}
556ec20593dSFinley Xiao 
557ec20593dSFinley Xiao 	return DIV_TO_RATE(parent, div);
558ec20593dSFinley Xiao }
559ec20593dSFinley Xiao 
rk3308_vop_set_clk(struct clk * clk,ulong hz)560fc4a6bd4SFinley Xiao static ulong rk3308_vop_set_clk(struct clk *clk, ulong hz)
561ec20593dSFinley Xiao {
562fc4a6bd4SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
563fc4a6bd4SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
564ec20593dSFinley Xiao 	ulong pll_rate, now, best_rate = 0;
565ec20593dSFinley Xiao 	u32 i, div, best_div = 0, best_sel = 0;
566ec20593dSFinley Xiao 
567ec20593dSFinley Xiao 	for (i = 0; i <= DCLK_VOP_PLL_SEL_VPLL1; i++) {
568ec20593dSFinley Xiao 		switch (i) {
569ec20593dSFinley Xiao 		case DCLK_VOP_PLL_SEL_DPLL:
570fc4a6bd4SFinley Xiao 			pll_rate = priv->dpll_hz;
571ec20593dSFinley Xiao 			break;
572ec20593dSFinley Xiao 		case DCLK_VOP_PLL_SEL_VPLL0:
573fc4a6bd4SFinley Xiao 			pll_rate = priv->vpll0_hz;
574ec20593dSFinley Xiao 			break;
575ec20593dSFinley Xiao 		case DCLK_VOP_PLL_SEL_VPLL1:
576fc4a6bd4SFinley Xiao 			pll_rate = priv->vpll1_hz;
577ec20593dSFinley Xiao 			break;
578ec20593dSFinley Xiao 		default:
579ec20593dSFinley Xiao 			printf("do not support this vop pll sel\n");
580ec20593dSFinley Xiao 			return -EINVAL;
581ec20593dSFinley Xiao 		}
582ec20593dSFinley Xiao 
583ec20593dSFinley Xiao 		div = DIV_ROUND_UP(pll_rate, hz);
584ec20593dSFinley Xiao 		if (div > 255)
585ec20593dSFinley Xiao 			continue;
586ec20593dSFinley Xiao 		now = pll_rate / div;
587ec20593dSFinley Xiao 		if (abs(hz - now) < abs(hz - best_rate)) {
588ec20593dSFinley Xiao 			best_rate = now;
589ec20593dSFinley Xiao 			best_div = div;
590ec20593dSFinley Xiao 			best_sel = i;
591ec20593dSFinley Xiao 		}
592ec20593dSFinley Xiao 		debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
593ec20593dSFinley Xiao 		      pll_rate, best_rate, best_div, best_sel);
594ec20593dSFinley Xiao 	}
595ec20593dSFinley Xiao 
596ec20593dSFinley Xiao 	if (best_rate != hz && hz == OSC_HZ) {
597ec20593dSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[8],
598ec20593dSFinley Xiao 			     DCLK_VOP_SEL_MASK,
599ec20593dSFinley Xiao 			     DCLK_VOP_SEL_24M << DCLK_VOP_SEL_SHIFT);
600ec20593dSFinley Xiao 	} else if (best_rate) {
601ec20593dSFinley Xiao 		rk_clrsetreg(&cru->clksel_con[8],
602ec20593dSFinley Xiao 			     DCLK_VOP_SEL_MASK | DCLK_VOP_PLL_SEL_MASK |
603ec20593dSFinley Xiao 			     DCLK_VOP_DIV_MASK,
604ec20593dSFinley Xiao 			     DCLK_VOP_SEL_DIVOUT << DCLK_VOP_SEL_SHIFT |
605ec20593dSFinley Xiao 			     best_sel << DCLK_VOP_PLL_SEL_SHIFT |
606ec20593dSFinley Xiao 			     (best_div - 1) << DCLK_VOP_DIV_SHIFT);
607ec20593dSFinley Xiao 	} else {
608ec20593dSFinley Xiao 		printf("do not support this vop freq\n");
609ec20593dSFinley Xiao 		return -EINVAL;
610ec20593dSFinley Xiao 	}
611ec20593dSFinley Xiao 
612fc4a6bd4SFinley Xiao 	return rk3308_vop_get_clk(clk);
613ec20593dSFinley Xiao }
614ec20593dSFinley Xiao 
rk3308_bus_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)6156c96c4c3SFinley Xiao static ulong rk3308_bus_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
6166c96c4c3SFinley Xiao {
6176c96c4c3SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
6186c96c4c3SFinley Xiao 	u32 div, con, parent = priv->dpll_hz;
6196c96c4c3SFinley Xiao 
6206c96c4c3SFinley Xiao 	switch (clk_id) {
6216c96c4c3SFinley Xiao 	case ACLK_BUS:
6226c96c4c3SFinley Xiao 		con = readl(&cru->clksel_con[5]);
6236c96c4c3SFinley Xiao 		div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
6246c96c4c3SFinley Xiao 		break;
6256c96c4c3SFinley Xiao 	case HCLK_BUS:
6266c96c4c3SFinley Xiao 		con = readl(&cru->clksel_con[6]);
6276c96c4c3SFinley Xiao 		div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
6286c96c4c3SFinley Xiao 		break;
6296c96c4c3SFinley Xiao 	case PCLK_BUS:
630221585fbSElaine Zhang 	case PCLK_WDT:
6316c96c4c3SFinley Xiao 		con = readl(&cru->clksel_con[6]);
6326c96c4c3SFinley Xiao 		div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
6336c96c4c3SFinley Xiao 		break;
6346c96c4c3SFinley Xiao 	default:
6356c96c4c3SFinley Xiao 		return -ENOENT;
6366c96c4c3SFinley Xiao 	}
6376c96c4c3SFinley Xiao 
6386c96c4c3SFinley Xiao 	return DIV_TO_RATE(parent, div);
6396c96c4c3SFinley Xiao }
6406c96c4c3SFinley Xiao 
rk3308_bus_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)6416c96c4c3SFinley Xiao static ulong rk3308_bus_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
6426c96c4c3SFinley Xiao 				ulong hz)
6436c96c4c3SFinley Xiao {
6446c96c4c3SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
6456c96c4c3SFinley Xiao 	int src_clk_div;
6466c96c4c3SFinley Xiao 
6476c96c4c3SFinley Xiao 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
648e27c054aSFinley Xiao 	assert(src_clk_div - 1 <= 31);
6496c96c4c3SFinley Xiao 
6506c96c4c3SFinley Xiao 	/*
6516c96c4c3SFinley Xiao 	 * select dpll as pd_bus bus clock source and
6526c96c4c3SFinley Xiao 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
6536c96c4c3SFinley Xiao 	 */
6546c96c4c3SFinley Xiao 	switch (clk_id) {
6556c96c4c3SFinley Xiao 	case ACLK_BUS:
6566c96c4c3SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[5],
6576c96c4c3SFinley Xiao 			     BUS_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
6586c96c4c3SFinley Xiao 			     BUS_PLL_SEL_DPLL << BUS_PLL_SEL_SHIFT |
6596c96c4c3SFinley Xiao 			     (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
6606c96c4c3SFinley Xiao 		break;
6616c96c4c3SFinley Xiao 	case HCLK_BUS:
6626c96c4c3SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[6],
6636c96c4c3SFinley Xiao 			     BUS_HCLK_DIV_MASK,
6646c96c4c3SFinley Xiao 			     (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
6656c96c4c3SFinley Xiao 		break;
6666c96c4c3SFinley Xiao 	case PCLK_BUS:
6676c96c4c3SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[6],
6686c96c4c3SFinley Xiao 			     BUS_PCLK_DIV_MASK,
6696c96c4c3SFinley Xiao 			     (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
6706c96c4c3SFinley Xiao 		break;
6716c96c4c3SFinley Xiao 	default:
6726c96c4c3SFinley Xiao 		printf("do not support this bus freq\n");
6736c96c4c3SFinley Xiao 		return -EINVAL;
6746c96c4c3SFinley Xiao 	}
6756c96c4c3SFinley Xiao 
6766c96c4c3SFinley Xiao 	return rk3308_bus_get_clk(priv, clk_id);
6776c96c4c3SFinley Xiao }
6786c96c4c3SFinley Xiao 
rk3308_peri_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)6796c96c4c3SFinley Xiao static ulong rk3308_peri_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
6806c96c4c3SFinley Xiao {
6816c96c4c3SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
6826c96c4c3SFinley Xiao 	u32 div, con, parent = priv->dpll_hz;
6836c96c4c3SFinley Xiao 
6846c96c4c3SFinley Xiao 	switch (clk_id) {
6856c96c4c3SFinley Xiao 	case ACLK_PERI:
6866c96c4c3SFinley Xiao 		con = readl(&cru->clksel_con[36]);
6876c96c4c3SFinley Xiao 		div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
6886c96c4c3SFinley Xiao 		break;
6896c96c4c3SFinley Xiao 	case HCLK_PERI:
6906c96c4c3SFinley Xiao 		con = readl(&cru->clksel_con[37]);
6916c96c4c3SFinley Xiao 		div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
6926c96c4c3SFinley Xiao 		break;
6936c96c4c3SFinley Xiao 	case PCLK_PERI:
6946c96c4c3SFinley Xiao 		con = readl(&cru->clksel_con[37]);
6956c96c4c3SFinley Xiao 		div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
6966c96c4c3SFinley Xiao 		break;
6976c96c4c3SFinley Xiao 	default:
6986c96c4c3SFinley Xiao 		return -ENOENT;
6996c96c4c3SFinley Xiao 	}
7006c96c4c3SFinley Xiao 
7016c96c4c3SFinley Xiao 	return DIV_TO_RATE(parent, div);
7026c96c4c3SFinley Xiao }
7036c96c4c3SFinley Xiao 
rk3308_peri_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)7046c96c4c3SFinley Xiao static ulong rk3308_peri_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
7056c96c4c3SFinley Xiao 				 ulong hz)
7066c96c4c3SFinley Xiao {
7076c96c4c3SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
7086c96c4c3SFinley Xiao 	int src_clk_div;
7096c96c4c3SFinley Xiao 
7106c96c4c3SFinley Xiao 	src_clk_div = DIV_ROUND_UP(priv->dpll_hz, hz);
711e27c054aSFinley Xiao 	assert(src_clk_div - 1 <= 31);
7126c96c4c3SFinley Xiao 
7136c96c4c3SFinley Xiao 	/*
7146c96c4c3SFinley Xiao 	 * select dpll as pd_peri bus clock source and
7156c96c4c3SFinley Xiao 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
7166c96c4c3SFinley Xiao 	 */
7176c96c4c3SFinley Xiao 	switch (clk_id) {
7186c96c4c3SFinley Xiao 	case ACLK_PERI:
7196c96c4c3SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[36],
7206c96c4c3SFinley Xiao 			     PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
7216c96c4c3SFinley Xiao 			     PERI_PLL_DPLL << PERI_PLL_SEL_SHIFT |
7226c96c4c3SFinley Xiao 			     (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
7236c96c4c3SFinley Xiao 		break;
7246c96c4c3SFinley Xiao 	case HCLK_PERI:
7256c96c4c3SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[37],
7266c96c4c3SFinley Xiao 			     PERI_HCLK_DIV_MASK,
7276c96c4c3SFinley Xiao 			     (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
7286c96c4c3SFinley Xiao 		break;
7296c96c4c3SFinley Xiao 	case PCLK_PERI:
7306c96c4c3SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[37],
7316c96c4c3SFinley Xiao 			     PERI_PCLK_DIV_MASK,
7326c96c4c3SFinley Xiao 			     (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
7336c96c4c3SFinley Xiao 		break;
7346c96c4c3SFinley Xiao 	default:
7356c96c4c3SFinley Xiao 		printf("do not support this peri freq\n");
7366c96c4c3SFinley Xiao 		return -EINVAL;
7376c96c4c3SFinley Xiao 	}
7386c96c4c3SFinley Xiao 
7396c96c4c3SFinley Xiao 	return rk3308_peri_get_clk(priv, clk_id);
7406c96c4c3SFinley Xiao }
7416c96c4c3SFinley Xiao 
rk3308_audio_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)7426c96c4c3SFinley Xiao static ulong rk3308_audio_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
7436c96c4c3SFinley Xiao {
7446c96c4c3SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
7456c96c4c3SFinley Xiao 	u32 div, con, parent = priv->vpll0_hz;
7466c96c4c3SFinley Xiao 
7476c96c4c3SFinley Xiao 	switch (clk_id) {
7486c96c4c3SFinley Xiao 	case HCLK_AUDIO:
7496c96c4c3SFinley Xiao 		con = readl(&cru->clksel_con[45]);
7506c96c4c3SFinley Xiao 		div = (con & AUDIO_HCLK_DIV_MASK) >> AUDIO_HCLK_DIV_SHIFT;
7516c96c4c3SFinley Xiao 		break;
7526c96c4c3SFinley Xiao 	case PCLK_AUDIO:
7536c96c4c3SFinley Xiao 		con = readl(&cru->clksel_con[45]);
7546c96c4c3SFinley Xiao 		div = (con & AUDIO_PCLK_DIV_MASK) >> AUDIO_PCLK_DIV_SHIFT;
7556c96c4c3SFinley Xiao 		break;
7566c96c4c3SFinley Xiao 	default:
7576c96c4c3SFinley Xiao 		return -ENOENT;
7586c96c4c3SFinley Xiao 	}
7596c96c4c3SFinley Xiao 
7606c96c4c3SFinley Xiao 	return DIV_TO_RATE(parent, div);
7616c96c4c3SFinley Xiao }
7626c96c4c3SFinley Xiao 
rk3308_audio_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)7636c96c4c3SFinley Xiao static ulong rk3308_audio_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
7646c96c4c3SFinley Xiao 				  ulong hz)
7656c96c4c3SFinley Xiao {
7666c96c4c3SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
7676c96c4c3SFinley Xiao 	int src_clk_div;
7686c96c4c3SFinley Xiao 
7696c96c4c3SFinley Xiao 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
770e27c054aSFinley Xiao 	assert(src_clk_div - 1 <= 31);
7716c96c4c3SFinley Xiao 
7726c96c4c3SFinley Xiao 	/*
7736c96c4c3SFinley Xiao 	 * select vpll0 as audio bus clock source and
7746c96c4c3SFinley Xiao 	 * set up dependent divisors for HCLK and PCLK clocks.
7756c96c4c3SFinley Xiao 	 */
7766c96c4c3SFinley Xiao 	switch (clk_id) {
7776c96c4c3SFinley Xiao 	case HCLK_AUDIO:
7786c96c4c3SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[45],
7796c96c4c3SFinley Xiao 			     AUDIO_PLL_SEL_MASK | AUDIO_HCLK_DIV_MASK,
7806c96c4c3SFinley Xiao 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
7816c96c4c3SFinley Xiao 			     (src_clk_div - 1) << AUDIO_HCLK_DIV_SHIFT);
7826c96c4c3SFinley Xiao 		break;
7836c96c4c3SFinley Xiao 	case PCLK_AUDIO:
7846c96c4c3SFinley Xiao 		rk_clrsetreg(&cru->clksel_con[45],
7856c96c4c3SFinley Xiao 			     AUDIO_PLL_SEL_MASK | AUDIO_PCLK_DIV_MASK,
7866c96c4c3SFinley Xiao 			     AUDIO_PLL_VPLL0 << AUDIO_PLL_SEL_SHIFT |
7876c96c4c3SFinley Xiao 			     (src_clk_div - 1) << AUDIO_PCLK_DIV_SHIFT);
7886c96c4c3SFinley Xiao 		break;
7896c96c4c3SFinley Xiao 	default:
7906c96c4c3SFinley Xiao 		printf("do not support this audio freq\n");
7916c96c4c3SFinley Xiao 		return -EINVAL;
7926c96c4c3SFinley Xiao 	}
7936c96c4c3SFinley Xiao 
7946c96c4c3SFinley Xiao 	return rk3308_peri_get_clk(priv, clk_id);
7956c96c4c3SFinley Xiao }
7966c96c4c3SFinley Xiao 
rk3308_crypto_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)7970cde5925SElaine Zhang static ulong rk3308_crypto_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
7980cde5925SElaine Zhang {
7990cde5925SElaine Zhang 	struct rk3308_cru *cru = priv->cru;
8000cde5925SElaine Zhang 	u32 div, con, parent;
8010cde5925SElaine Zhang 
8020cde5925SElaine Zhang 	switch (clk_id) {
8030cde5925SElaine Zhang 	case SCLK_CRYPTO:
8040cde5925SElaine Zhang 		con = readl(&cru->clksel_con[7]);
8050cde5925SElaine Zhang 		div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
8060cde5925SElaine Zhang 		parent = priv->vpll0_hz;
8070cde5925SElaine Zhang 		break;
8080cde5925SElaine Zhang 	case SCLK_CRYPTO_APK:
8090cde5925SElaine Zhang 		con = readl(&cru->clksel_con[7]);
8100cde5925SElaine Zhang 		div = (con & CRYPTO_APK_DIV_MASK) >> CRYPTO_APK_DIV_SHIFT;
8110cde5925SElaine Zhang 		parent = priv->vpll0_hz;
8120cde5925SElaine Zhang 		break;
8130cde5925SElaine Zhang 	default:
8140cde5925SElaine Zhang 		return -ENOENT;
8150cde5925SElaine Zhang 	}
8160cde5925SElaine Zhang 
8170cde5925SElaine Zhang 	return DIV_TO_RATE(parent, div);
8180cde5925SElaine Zhang }
8190cde5925SElaine Zhang 
rk3308_crypto_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)8200cde5925SElaine Zhang static ulong rk3308_crypto_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
8210cde5925SElaine Zhang 				   ulong hz)
8220cde5925SElaine Zhang {
8230cde5925SElaine Zhang 	struct rk3308_cru *cru = priv->cru;
8240cde5925SElaine Zhang 	int src_clk_div;
8250cde5925SElaine Zhang 
8260cde5925SElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
8270cde5925SElaine Zhang 	assert(src_clk_div - 1 <= 31);
8280cde5925SElaine Zhang 
8290cde5925SElaine Zhang 	/*
8300cde5925SElaine Zhang 	 * select gpll as crypto clock source and
8310cde5925SElaine Zhang 	 * set up dependent divisors for crypto clocks.
8320cde5925SElaine Zhang 	 */
8330cde5925SElaine Zhang 	switch (clk_id) {
8340cde5925SElaine Zhang 	case SCLK_CRYPTO:
8350cde5925SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[7],
8360cde5925SElaine Zhang 			     CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
8370cde5925SElaine Zhang 			     CRYPTO_PLL_SEL_VPLL0 << CRYPTO_PLL_SEL_SHIFT |
8380cde5925SElaine Zhang 			     (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
8390cde5925SElaine Zhang 		break;
8400cde5925SElaine Zhang 	case SCLK_CRYPTO_APK:
8410cde5925SElaine Zhang 		rk_clrsetreg(&cru->clksel_con[7],
8420cde5925SElaine Zhang 			     CRYPTO_APK_PLL_SEL_MASK | CRYPTO_APK_DIV_MASK,
8430cde5925SElaine Zhang 			     CRYPTO_PLL_SEL_VPLL0 << CRYPTO_APK_SEL_SHIFT |
8440cde5925SElaine Zhang 			     (src_clk_div - 1) << CRYPTO_APK_DIV_SHIFT);
8450cde5925SElaine Zhang 		break;
8460cde5925SElaine Zhang 	default:
8470cde5925SElaine Zhang 		printf("do not support this peri freq\n");
8480cde5925SElaine Zhang 		return -EINVAL;
8490cde5925SElaine Zhang 	}
8500cde5925SElaine Zhang 
8510cde5925SElaine Zhang 	return rk3308_crypto_get_clk(priv, clk_id);
8520cde5925SElaine Zhang }
8530cde5925SElaine Zhang 
rk3308_rtc32k_get_clk(struct rk3308_clk_priv * priv,ulong clk_id)8541bbed247SFinley Xiao static ulong rk3308_rtc32k_get_clk(struct rk3308_clk_priv *priv, ulong clk_id)
8551bbed247SFinley Xiao {
8561bbed247SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
8571bbed247SFinley Xiao 	unsigned long m, n;
8581bbed247SFinley Xiao 	u32 con, fracdiv;
8591bbed247SFinley Xiao 
8601bbed247SFinley Xiao 	con = readl(&cru->clksel_con[2]);
8611bbed247SFinley Xiao 	if ((con & CLK_RTC32K_SEL_MASK) >> CLK_RTC32K_SEL_SHIFT !=
8621bbed247SFinley Xiao 	    CLK_RTC32K_FRAC_DIV)
8631bbed247SFinley Xiao 		return -EINVAL;
8641bbed247SFinley Xiao 
8651bbed247SFinley Xiao 	fracdiv = readl(&cru->clksel_con[3]);
8661bbed247SFinley Xiao 	m = fracdiv & CLK_RTC32K_FRAC_NUMERATOR_MASK;
8671bbed247SFinley Xiao 	m >>= CLK_RTC32K_FRAC_NUMERATOR_SHIFT;
8681bbed247SFinley Xiao 	n = fracdiv & CLK_RTC32K_FRAC_DENOMINATOR_MASK;
8691bbed247SFinley Xiao 	n >>= CLK_RTC32K_FRAC_DENOMINATOR_SHIFT;
8701bbed247SFinley Xiao 
8711bbed247SFinley Xiao 	return OSC_HZ * m / n;
8721bbed247SFinley Xiao }
8731bbed247SFinley Xiao 
rk3308_rtc32k_set_clk(struct rk3308_clk_priv * priv,ulong clk_id,ulong hz)8741bbed247SFinley Xiao static ulong rk3308_rtc32k_set_clk(struct rk3308_clk_priv *priv, ulong clk_id,
8751bbed247SFinley Xiao 				   ulong hz)
8761bbed247SFinley Xiao {
8771bbed247SFinley Xiao 	struct rk3308_cru *cru = priv->cru;
8781bbed247SFinley Xiao 	unsigned long m, n, val;
8791bbed247SFinley Xiao 
8801bbed247SFinley Xiao 	rational_best_approximation(hz, OSC_HZ,
8811bbed247SFinley Xiao 				    GENMASK(16 - 1, 0),
8821bbed247SFinley Xiao 				    GENMASK(16 - 1, 0),
8831bbed247SFinley Xiao 				    &m, &n);
8841bbed247SFinley Xiao 	val = m << CLK_RTC32K_FRAC_NUMERATOR_SHIFT | n;
8851bbed247SFinley Xiao 	writel(val, &cru->clksel_con[3]);
886daf1d5f9SElaine Zhang 	rk_clrsetreg(&cru->clksel_con[2], CLK_RTC32K_SEL_MASK,
8871bbed247SFinley Xiao 		     CLK_RTC32K_FRAC_DIV << CLK_RTC32K_SEL_SHIFT);
8881bbed247SFinley Xiao 
8891bbed247SFinley Xiao 	return rk3308_rtc32k_get_clk(priv, clk_id);
8901bbed247SFinley Xiao }
8911bbed247SFinley Xiao 
rk3308_sclk_sfc_get_clk(struct rk3308_clk_priv * priv)892d0999afbSFinley Xiao static ulong rk3308_sclk_sfc_get_clk(struct rk3308_clk_priv *priv)
893d0999afbSFinley Xiao {
894d0999afbSFinley Xiao 	struct rk3308_cru *cru = priv->cru;
895d0999afbSFinley Xiao 	u32 div, con, sel, parent;
896d0999afbSFinley Xiao 
897d0999afbSFinley Xiao 	con = readl(&cru->clksel_con[42]);
898d0999afbSFinley Xiao 	div = (con & SCLK_SFC_DIV_MASK) >> SCLK_SFC_DIV_SHIFT;
899d0999afbSFinley Xiao 	sel = (con & SCLK_SFC_SEL_MASK) >> SCLK_SFC_SEL_SHIFT;
900d0999afbSFinley Xiao 
901d0999afbSFinley Xiao 	if (sel == SCLK_SFC_SEL_DPLL)
902d0999afbSFinley Xiao 		parent = priv->dpll_hz;
903d0999afbSFinley Xiao 	else if (sel == SCLK_SFC_SEL_VPLL0)
904d0999afbSFinley Xiao 		parent = priv->vpll0_hz;
905d0999afbSFinley Xiao 	else if (sel == SCLK_SFC_SEL_VPLL1)
906d0999afbSFinley Xiao 		parent = priv->vpll1_hz;
907d0999afbSFinley Xiao 	else
908d0999afbSFinley Xiao 		return -EINVAL;
909d0999afbSFinley Xiao 
910d0999afbSFinley Xiao 	return DIV_TO_RATE(parent, div);
911d0999afbSFinley Xiao }
912d0999afbSFinley Xiao 
rk3308_sclk_sfc_set_clk(struct rk3308_clk_priv * priv,uint hz)913d0999afbSFinley Xiao static ulong rk3308_sclk_sfc_set_clk(struct rk3308_clk_priv *priv, uint hz)
914d0999afbSFinley Xiao {
915d0999afbSFinley Xiao 	struct rk3308_cru *cru = priv->cru;
916d0999afbSFinley Xiao 	int src_clk_div;
917d0999afbSFinley Xiao 
918d0999afbSFinley Xiao 	src_clk_div = DIV_ROUND_UP(priv->vpll0_hz, hz);
919d0999afbSFinley Xiao 	assert(src_clk_div - 1 <= 127);
920d0999afbSFinley Xiao 
921d0999afbSFinley Xiao 	rk_clrsetreg(&cru->clksel_con[42],
922d0999afbSFinley Xiao 		     SCLK_SFC_SEL_MASK | SCLK_SFC_DIV_MASK,
923d0999afbSFinley Xiao 		     SCLK_SFC_SEL_VPLL0 << SCLK_SFC_SEL_SHIFT |
924d0999afbSFinley Xiao 		     (src_clk_div - 1) << SCLK_SFC_DIV_SHIFT);
925d0999afbSFinley Xiao 
926d0999afbSFinley Xiao 	return rk3308_sclk_sfc_get_clk(priv);
927d0999afbSFinley Xiao }
928d0999afbSFinley Xiao 
rk3308_clk_get_rate(struct clk * clk)92954d254feSAndy Yan static ulong rk3308_clk_get_rate(struct clk *clk)
93054d254feSAndy Yan {
9311e180a56SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
93254d254feSAndy Yan 	ulong rate = 0;
93354d254feSAndy Yan 
93454d254feSAndy Yan 	debug("%s id:%ld\n", __func__, clk->id);
93554d254feSAndy Yan 
93654d254feSAndy Yan 	switch (clk->id) {
9371e180a56SFinley Xiao 	case PLL_APLL:
93803a6c029SFinley Xiao 	case ARMCLK:
93927ee7641SFinley Xiao 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
94027ee7641SFinley Xiao 					     priv->cru, APLL);
9411e180a56SFinley Xiao 		break;
9421e180a56SFinley Xiao 	case PLL_DPLL:
94327ee7641SFinley Xiao 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
94427ee7641SFinley Xiao 					     priv->cru, DPLL);
9451e180a56SFinley Xiao 		break;
9461e180a56SFinley Xiao 	case PLL_VPLL0:
94727ee7641SFinley Xiao 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL0],
94827ee7641SFinley Xiao 					     priv->cru, VPLL0);
9491e180a56SFinley Xiao 		break;
9501e180a56SFinley Xiao 	case PLL_VPLL1:
95127ee7641SFinley Xiao 		rate = rockchip_pll_get_rate(&rk3308_pll_clks[VPLL1],
95227ee7641SFinley Xiao 					     priv->cru, VPLL1);
9531e180a56SFinley Xiao 		break;
95454d254feSAndy Yan 	case HCLK_SDMMC:
95554d254feSAndy Yan 	case HCLK_EMMC:
95654d254feSAndy Yan 	case SCLK_SDMMC:
95754d254feSAndy Yan 	case SCLK_EMMC:
95854d254feSAndy Yan 	case SCLK_EMMC_SAMPLE:
959fc4a6bd4SFinley Xiao 		rate = rk3308_mmc_get_clk(clk);
96054d254feSAndy Yan 		break;
96154d254feSAndy Yan 	case SCLK_I2C0:
96254d254feSAndy Yan 	case SCLK_I2C1:
96354d254feSAndy Yan 	case SCLK_I2C2:
96454d254feSAndy Yan 	case SCLK_I2C3:
965fc4a6bd4SFinley Xiao 		rate = rk3308_i2c_get_clk(clk);
96654d254feSAndy Yan 		break;
96754d254feSAndy Yan 	case SCLK_SARADC:
968fc4a6bd4SFinley Xiao 		rate = rk3308_saradc_get_clk(clk);
96954d254feSAndy Yan 		break;
970cb3c37fcSElaine Zhang 	case SCLK_TSADC:
971cb3c37fcSElaine Zhang 		rate = rk3308_tsadc_get_clk(clk);
972cb3c37fcSElaine Zhang 		break;
97354d254feSAndy Yan 	case SCLK_SPI0:
97454d254feSAndy Yan 	case SCLK_SPI1:
975fc4a6bd4SFinley Xiao 		rate = rk3308_spi_get_clk(clk);
97654d254feSAndy Yan 		break;
977a8d570efSZhiZhan Chen 	case SCLK_PWM0:
978a8d570efSZhiZhan Chen 	case SCLK_PWM1:
979a8d570efSZhiZhan Chen 	case SCLK_PWM2:
980fc4a6bd4SFinley Xiao 		rate = rk3308_pwm_get_clk(clk);
98154d254feSAndy Yan 		break;
982ec20593dSFinley Xiao 	case DCLK_VOP:
983fc4a6bd4SFinley Xiao 		rate = rk3308_vop_get_clk(clk);
984ec20593dSFinley Xiao 		break;
9856c96c4c3SFinley Xiao 	case ACLK_BUS:
9866c96c4c3SFinley Xiao 	case HCLK_BUS:
9876c96c4c3SFinley Xiao 	case PCLK_BUS:
988221585fbSElaine Zhang 	case PCLK_WDT:
9896c96c4c3SFinley Xiao 		rate = rk3308_bus_get_clk(priv, clk->id);
9906c96c4c3SFinley Xiao 		break;
9916c96c4c3SFinley Xiao 	case ACLK_PERI:
9926c96c4c3SFinley Xiao 	case HCLK_PERI:
9936c96c4c3SFinley Xiao 	case PCLK_PERI:
9946c96c4c3SFinley Xiao 		rate = rk3308_peri_get_clk(priv, clk->id);
9956c96c4c3SFinley Xiao 		break;
9966c96c4c3SFinley Xiao 	case HCLK_AUDIO:
9976c96c4c3SFinley Xiao 	case PCLK_AUDIO:
9986c96c4c3SFinley Xiao 		rate = rk3308_audio_get_clk(priv, clk->id);
9996c96c4c3SFinley Xiao 		break;
10000cde5925SElaine Zhang 	case SCLK_CRYPTO:
10010cde5925SElaine Zhang 	case SCLK_CRYPTO_APK:
10020cde5925SElaine Zhang 		rate = rk3308_crypto_get_clk(priv, clk->id);
10030cde5925SElaine Zhang 		break;
10041bbed247SFinley Xiao 	case SCLK_RTC32K:
10051bbed247SFinley Xiao 		rate = rk3308_rtc32k_get_clk(priv, clk->id);
10061bbed247SFinley Xiao 		break;
1007d0999afbSFinley Xiao 	case SCLK_SFC:
1008d0999afbSFinley Xiao 		rate = rk3308_sclk_sfc_get_clk(priv);
1009d0999afbSFinley Xiao 		break;
101054d254feSAndy Yan 	default:
101154d254feSAndy Yan 		return -ENOENT;
101254d254feSAndy Yan 	}
101354d254feSAndy Yan 
101454d254feSAndy Yan 	return rate;
101554d254feSAndy Yan }
101654d254feSAndy Yan 
rk3308_clk_set_rate(struct clk * clk,ulong rate)101754d254feSAndy Yan static ulong rk3308_clk_set_rate(struct clk *clk, ulong rate)
101854d254feSAndy Yan {
10191e180a56SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
102054d254feSAndy Yan 	ulong ret = 0;
102154d254feSAndy Yan 
102254d254feSAndy Yan 	debug("%s %ld %ld\n", __func__, clk->id, rate);
10231e180a56SFinley Xiao 
102454d254feSAndy Yan 	switch (clk->id) {
10251e180a56SFinley Xiao 	case PLL_DPLL:
102627ee7641SFinley Xiao 		ret = rockchip_pll_set_rate(&rk3308_pll_clks[DPLL], priv->cru,
102727ee7641SFinley Xiao 					    DPLL, rate);
102827ee7641SFinley Xiao 		priv->dpll_hz = rockchip_pll_get_rate(&rk3308_pll_clks[DPLL],
102927ee7641SFinley Xiao 						      priv->cru, DPLL);
10301e180a56SFinley Xiao 		break;
103103a6c029SFinley Xiao 	case ARMCLK:
1032*0c8b06efSJoseph Chen 		/*
1033*0c8b06efSJoseph Chen 		 * Why add `rate < rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
1034*0c8b06efSJoseph Chen 		 *					 priv->cru, APLL)` ?
1035*0c8b06efSJoseph Chen 		 *
1036*0c8b06efSJoseph Chen 		 * rockchip_wtemp_dvfs.c may decrease the arm freq, don't
1037*0c8b06efSJoseph Chen 		 * limit this decrease operation here.
1038*0c8b06efSJoseph Chen 		 */
1039*0c8b06efSJoseph Chen 		if (priv->armclk_hz ||
1040*0c8b06efSJoseph Chen 			(rate < rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
1041*0c8b06efSJoseph Chen 						      priv->cru, APLL)))
104203a6c029SFinley Xiao 			rk3308_armclk_set_clk(priv, rate);
104303a6c029SFinley Xiao 		priv->armclk_hz = rate;
104403a6c029SFinley Xiao 		break;
104554d254feSAndy Yan 	case HCLK_SDMMC:
104654d254feSAndy Yan 	case HCLK_EMMC:
104754d254feSAndy Yan 	case SCLK_SDMMC:
104854d254feSAndy Yan 	case SCLK_EMMC:
1049fc4a6bd4SFinley Xiao 		ret = rk3308_mmc_set_clk(clk, rate);
105054d254feSAndy Yan 		break;
105154d254feSAndy Yan 	case SCLK_I2C0:
105254d254feSAndy Yan 	case SCLK_I2C1:
105354d254feSAndy Yan 	case SCLK_I2C2:
105454d254feSAndy Yan 	case SCLK_I2C3:
1055fc4a6bd4SFinley Xiao 		ret = rk3308_i2c_set_clk(clk, rate);
105654d254feSAndy Yan 		break;
1057200683eaSDavid Wu 	case SCLK_MAC:
1058200683eaSDavid Wu 		ret = rk3308_mac_set_clk(clk, rate);
1059200683eaSDavid Wu 		break;
1060200683eaSDavid Wu 	case SCLK_MAC_RMII:
1061200683eaSDavid Wu 		ret = rk3308_mac_set_speed_clk(clk, rate);
1062200683eaSDavid Wu 		break;
106354d254feSAndy Yan 	case SCLK_SARADC:
1064fc4a6bd4SFinley Xiao 		ret = rk3308_saradc_set_clk(clk, rate);
106554d254feSAndy Yan 		break;
1066cb3c37fcSElaine Zhang 	case SCLK_TSADC:
1067cb3c37fcSElaine Zhang 		ret = rk3308_tsadc_set_clk(clk, rate);
1068cb3c37fcSElaine Zhang 		break;
106954d254feSAndy Yan 	case SCLK_SPI0:
107054d254feSAndy Yan 	case SCLK_SPI1:
1071fc4a6bd4SFinley Xiao 		ret = rk3308_spi_set_clk(clk, rate);
107254d254feSAndy Yan 		break;
1073a8d570efSZhiZhan Chen 	case SCLK_PWM0:
1074a8d570efSZhiZhan Chen 	case SCLK_PWM1:
1075a8d570efSZhiZhan Chen 	case SCLK_PWM2:
1076fc4a6bd4SFinley Xiao 		ret = rk3308_pwm_set_clk(clk, rate);
107754d254feSAndy Yan 		break;
1078ec20593dSFinley Xiao 	case DCLK_VOP:
1079fc4a6bd4SFinley Xiao 		ret = rk3308_vop_set_clk(clk, rate);
1080ec20593dSFinley Xiao 		break;
10816c96c4c3SFinley Xiao 	case ACLK_BUS:
10826c96c4c3SFinley Xiao 	case HCLK_BUS:
10836c96c4c3SFinley Xiao 	case PCLK_BUS:
10846c96c4c3SFinley Xiao 		rate = rk3308_bus_set_clk(priv, clk->id, rate);
10856c96c4c3SFinley Xiao 		break;
10866c96c4c3SFinley Xiao 	case ACLK_PERI:
10876c96c4c3SFinley Xiao 	case HCLK_PERI:
10886c96c4c3SFinley Xiao 	case PCLK_PERI:
10896c96c4c3SFinley Xiao 		rate = rk3308_peri_set_clk(priv, clk->id, rate);
10906c96c4c3SFinley Xiao 		break;
10916c96c4c3SFinley Xiao 	case HCLK_AUDIO:
10926c96c4c3SFinley Xiao 	case PCLK_AUDIO:
10936c96c4c3SFinley Xiao 		rate = rk3308_audio_set_clk(priv, clk->id, rate);
10946c96c4c3SFinley Xiao 		break;
10950cde5925SElaine Zhang 	case SCLK_CRYPTO:
10960cde5925SElaine Zhang 	case SCLK_CRYPTO_APK:
10970cde5925SElaine Zhang 		ret = rk3308_crypto_set_clk(priv, clk->id, rate);
10980cde5925SElaine Zhang 		break;
10991bbed247SFinley Xiao 	case SCLK_RTC32K:
11001bbed247SFinley Xiao 		ret = rk3308_rtc32k_set_clk(priv, clk->id, rate);
11011bbed247SFinley Xiao 		break;
1102d0999afbSFinley Xiao 	case SCLK_SFC:
1103d0999afbSFinley Xiao 		ret = rk3308_sclk_sfc_set_clk(priv, rate);
1104d0999afbSFinley Xiao 		break;
110554d254feSAndy Yan 	default:
110654d254feSAndy Yan 		return -ENOENT;
110754d254feSAndy Yan 	}
110854d254feSAndy Yan 
110954d254feSAndy Yan 	return ret;
111054d254feSAndy Yan }
111154d254feSAndy Yan 
111254d254feSAndy Yan #define ROCKCHIP_MMC_DELAY_SEL		BIT(11)
111354d254feSAndy Yan #define ROCKCHIP_MMC_DEGREE_OFFSET	1
111454d254feSAndy Yan #define ROCKCHIP_MMC_DEGREE_MASK	(0x3 << ROCKCHIP_MMC_DEGREE_OFFSET)
111554d254feSAndy Yan #define ROCKCHIP_MMC_DELAYNUM_OFFSET	3
111654d254feSAndy Yan #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
111754d254feSAndy Yan 
111854d254feSAndy Yan #define PSECS_PER_SEC 1000000000000LL
111954d254feSAndy Yan /*
112054d254feSAndy Yan  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
112154d254feSAndy Yan  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
112254d254feSAndy Yan  */
112354d254feSAndy Yan #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
112454d254feSAndy Yan 
rockchip_mmc_get_phase(struct clk * clk)112554d254feSAndy Yan int rockchip_mmc_get_phase(struct clk *clk)
112654d254feSAndy Yan {
112754d254feSAndy Yan 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
112854d254feSAndy Yan 	struct rk3308_cru *cru = priv->cru;
112954d254feSAndy Yan 	u32 raw_value, delay_num;
113054d254feSAndy Yan 	u16 degrees = 0;
113154d254feSAndy Yan 	ulong rate;
113254d254feSAndy Yan 
113354d254feSAndy Yan 	rate = rk3308_clk_get_rate(clk);
113454d254feSAndy Yan 
113554d254feSAndy Yan 	if (rate < 0)
113654d254feSAndy Yan 		return rate;
113754d254feSAndy Yan 
113854d254feSAndy Yan 	if (clk->id == SCLK_EMMC_SAMPLE)
113954d254feSAndy Yan 		raw_value = readl(&cru->emmc_con[1]);
114054d254feSAndy Yan 	else
114154d254feSAndy Yan 		raw_value = readl(&cru->sdmmc_con[1]);
114254d254feSAndy Yan 
114354d254feSAndy Yan 	raw_value &= ROCKCHIP_MMC_DEGREE_MASK;
114454d254feSAndy Yan 	degrees = (raw_value >>  ROCKCHIP_MMC_DEGREE_OFFSET) * 90;
114554d254feSAndy Yan 
114654d254feSAndy Yan 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
114754d254feSAndy Yan 		/* degrees/delaynum * 10000 */
114854d254feSAndy Yan 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
114954d254feSAndy Yan 					36 * (rate / 1000000);
115054d254feSAndy Yan 
115154d254feSAndy Yan 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
115254d254feSAndy Yan 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
115354d254feSAndy Yan 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
115454d254feSAndy Yan 	}
115554d254feSAndy Yan 
115654d254feSAndy Yan 	return degrees % 360;
115754d254feSAndy Yan 
115854d254feSAndy Yan }
115954d254feSAndy Yan 
rockchip_mmc_set_phase(struct clk * clk,u32 degrees)116054d254feSAndy Yan int rockchip_mmc_set_phase(struct clk *clk, u32 degrees)
116154d254feSAndy Yan {
116254d254feSAndy Yan 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
116354d254feSAndy Yan 	struct rk3308_cru *cru = priv->cru;
116454d254feSAndy Yan 	u8 nineties, remainder, delay_num;
116554d254feSAndy Yan 	u32 raw_value, delay;
116654d254feSAndy Yan 	ulong rate;
116754d254feSAndy Yan 
116854d254feSAndy Yan 	rate = rk3308_clk_get_rate(clk);
116954d254feSAndy Yan 
117054d254feSAndy Yan 	if (rate < 0)
117154d254feSAndy Yan 		return rate;
117254d254feSAndy Yan 
117354d254feSAndy Yan 	nineties = degrees / 90;
117454d254feSAndy Yan 	remainder = (degrees % 90);
117554d254feSAndy Yan 
117654d254feSAndy Yan 	/*
117754d254feSAndy Yan 	 * Convert to delay; do a little extra work to make sure we
117854d254feSAndy Yan 	 * don't overflow 32-bit / 64-bit numbers.
117954d254feSAndy Yan 	 */
118054d254feSAndy Yan 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
118154d254feSAndy Yan 	delay *= remainder;
118254d254feSAndy Yan 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
118354d254feSAndy Yan 				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
118454d254feSAndy Yan 
118554d254feSAndy Yan 	delay_num = (u8)min_t(u32, delay, 255);
118654d254feSAndy Yan 
118754d254feSAndy Yan 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
118854d254feSAndy Yan 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
118954d254feSAndy Yan 	raw_value |= nineties << ROCKCHIP_MMC_DEGREE_OFFSET;
119054d254feSAndy Yan 
119154d254feSAndy Yan 	if (clk->id == SCLK_EMMC_SAMPLE)
119254d254feSAndy Yan 		writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
119354d254feSAndy Yan 	else
119454d254feSAndy Yan 		writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
119554d254feSAndy Yan 
119654d254feSAndy Yan 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
119754d254feSAndy Yan 	      degrees, delay_num, raw_value, rockchip_mmc_get_phase(clk));
119854d254feSAndy Yan 
119954d254feSAndy Yan 	return 0;
120054d254feSAndy Yan 
120154d254feSAndy Yan }
120254d254feSAndy Yan 
rk3308_clk_get_phase(struct clk * clk)120354d254feSAndy Yan static int rk3308_clk_get_phase(struct clk *clk)
120454d254feSAndy Yan {
120554d254feSAndy Yan 	int ret;
120654d254feSAndy Yan 
120754d254feSAndy Yan 	switch (clk->id) {
120854d254feSAndy Yan 	case SCLK_EMMC_SAMPLE:
120954d254feSAndy Yan 	case SCLK_SDMMC_SAMPLE:
121054d254feSAndy Yan 		ret = rockchip_mmc_get_phase(clk);
121154d254feSAndy Yan 		break;
121254d254feSAndy Yan 	default:
121354d254feSAndy Yan 		return -ENOENT;
121454d254feSAndy Yan 	}
121554d254feSAndy Yan 
121654d254feSAndy Yan 	return ret;
121754d254feSAndy Yan }
121854d254feSAndy Yan 
rk3308_clk_set_phase(struct clk * clk,int degrees)121954d254feSAndy Yan static int rk3308_clk_set_phase(struct clk *clk, int degrees)
122054d254feSAndy Yan {
122154d254feSAndy Yan 	int ret;
122254d254feSAndy Yan 
122354d254feSAndy Yan 	switch (clk->id) {
122454d254feSAndy Yan 	case SCLK_EMMC_SAMPLE:
122554d254feSAndy Yan 	case SCLK_SDMMC_SAMPLE:
122654d254feSAndy Yan 		ret = rockchip_mmc_set_phase(clk, degrees);
122754d254feSAndy Yan 		break;
122854d254feSAndy Yan 	default:
122954d254feSAndy Yan 		return -ENOENT;
123054d254feSAndy Yan 	}
123154d254feSAndy Yan 
123254d254feSAndy Yan 	return ret;
123354d254feSAndy Yan }
123454d254feSAndy Yan 
rk3308_mac_set_parent(struct clk * clk,struct clk * parent)1235200683eaSDavid Wu static int __maybe_unused rk3308_mac_set_parent(struct clk *clk, struct clk *parent)
1236200683eaSDavid Wu {
1237200683eaSDavid Wu 	struct rk3308_clk_priv *priv = dev_get_priv(clk->dev);
1238200683eaSDavid Wu 
1239200683eaSDavid Wu 	/*
1240200683eaSDavid Wu 	 * If the requested parent is in the same clock-controller and
1241200683eaSDavid Wu 	 * the id is SCLK_MAC_SRC, switch to the internal clock.
1242200683eaSDavid Wu 	 */
1243200683eaSDavid Wu 	if (parent->id == SCLK_MAC_SRC) {
1244200683eaSDavid Wu 		debug("%s: switching RMII to SCLK_MAC\n", __func__);
1245200683eaSDavid Wu 		rk_clrreg(&priv->cru->clksel_con[43], BIT(14));
1246200683eaSDavid Wu 	} else {
1247200683eaSDavid Wu 		debug("%s: switching RMII to CLKIN\n", __func__);
1248200683eaSDavid Wu 		rk_setreg(&priv->cru->clksel_con[43], BIT(14));
1249200683eaSDavid Wu 	}
1250200683eaSDavid Wu 
1251200683eaSDavid Wu 	return 0;
1252200683eaSDavid Wu }
1253200683eaSDavid Wu 
rk3308_clk_set_parent(struct clk * clk,struct clk * parent)1254200683eaSDavid Wu static int __maybe_unused rk3308_clk_set_parent(struct clk *clk, struct clk *parent)
1255200683eaSDavid Wu {
1256200683eaSDavid Wu 	switch (clk->id) {
1257200683eaSDavid Wu 	case SCLK_MAC:
1258200683eaSDavid Wu 		return rk3308_mac_set_parent(clk, parent);
1259200683eaSDavid Wu 	default:
1260200683eaSDavid Wu 		break;
1261200683eaSDavid Wu 	}
1262200683eaSDavid Wu 
1263200683eaSDavid Wu 	debug("%s: unsupported clk %ld\n", __func__, clk->id);
1264200683eaSDavid Wu 	return -ENOENT;
1265200683eaSDavid Wu }
1266200683eaSDavid Wu 
126754d254feSAndy Yan static struct clk_ops rk3308_clk_ops = {
126854d254feSAndy Yan 	.get_rate = rk3308_clk_get_rate,
126954d254feSAndy Yan 	.set_rate = rk3308_clk_set_rate,
127054d254feSAndy Yan 	.get_phase	= rk3308_clk_get_phase,
127154d254feSAndy Yan 	.set_phase	= rk3308_clk_set_phase,
1272200683eaSDavid Wu #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1273200683eaSDavid Wu 	.set_parent = rk3308_clk_set_parent,
1274200683eaSDavid Wu #endif
127554d254feSAndy Yan };
127654d254feSAndy Yan 
rk3308_clk_init(struct udevice * dev)127794058cdfSFinley Xiao static void rk3308_clk_init(struct udevice *dev)
127894058cdfSFinley Xiao {
127994058cdfSFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
128094058cdfSFinley Xiao 	int ret;
128194058cdfSFinley Xiao 
128294058cdfSFinley Xiao 	if (rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
128394058cdfSFinley Xiao 				  priv->cru, APLL) != APLL_HZ) {
128494058cdfSFinley Xiao 		ret = rk3308_armclk_set_clk(priv, APLL_HZ);
128594058cdfSFinley Xiao 		if (ret < 0)
128694058cdfSFinley Xiao 			printf("%s failed to set armclk rate\n", __func__);
128794058cdfSFinley Xiao 	}
128894058cdfSFinley Xiao 
128994058cdfSFinley Xiao 	rk3308_clk_get_pll_rate(priv);
129094058cdfSFinley Xiao 
129194058cdfSFinley Xiao 	rk3308_bus_set_clk(priv, ACLK_BUS, BUS_ACLK_HZ);
129294058cdfSFinley Xiao 	rk3308_bus_set_clk(priv, HCLK_BUS, BUS_HCLK_HZ);
129394058cdfSFinley Xiao 	rk3308_bus_set_clk(priv, PCLK_BUS, BUS_PCLK_HZ);
129494058cdfSFinley Xiao 
129594058cdfSFinley Xiao 	rk3308_peri_set_clk(priv, ACLK_PERI, PERI_ACLK_HZ);
129694058cdfSFinley Xiao 	rk3308_peri_set_clk(priv, HCLK_PERI, PERI_HCLK_HZ);
129794058cdfSFinley Xiao 	rk3308_peri_set_clk(priv, PCLK_PERI, PERI_PCLK_HZ);
129894058cdfSFinley Xiao 
129994058cdfSFinley Xiao 	rk3308_audio_set_clk(priv, HCLK_AUDIO, AUDIO_HCLK_HZ);
130094058cdfSFinley Xiao 	rk3308_audio_set_clk(priv, PCLK_AUDIO, AUDIO_PCLK_HZ);
130194058cdfSFinley Xiao }
130294058cdfSFinley Xiao 
rk3308_clk_probe(struct udevice * dev)130354d254feSAndy Yan static int rk3308_clk_probe(struct udevice *dev)
130454d254feSAndy Yan {
130521ab40a8SFinley Xiao 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
130694058cdfSFinley Xiao 	int ret;
130794058cdfSFinley Xiao 
1308093fdd9fSElaine Zhang 	priv->sync_kernel = false;
1309093fdd9fSElaine Zhang 	if (!priv->armclk_enter_hz)
1310093fdd9fSElaine Zhang 		priv->armclk_enter_hz =
1311093fdd9fSElaine Zhang 		rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
1312093fdd9fSElaine Zhang 				      priv->cru, APLL);
131394058cdfSFinley Xiao 	rk3308_clk_init(dev);
1314093fdd9fSElaine Zhang 	if (!priv->armclk_init_hz)
1315093fdd9fSElaine Zhang 		priv->armclk_init_hz =
1316093fdd9fSElaine Zhang 		rockchip_pll_get_rate(&rk3308_pll_clks[APLL],
1317093fdd9fSElaine Zhang 				      priv->cru, APLL);
131894058cdfSFinley Xiao 
131994058cdfSFinley Xiao 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
132094058cdfSFinley Xiao 	ret = clk_set_defaults(dev);
132194058cdfSFinley Xiao 	if (ret)
132294058cdfSFinley Xiao 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
1323093fdd9fSElaine Zhang 	else
1324093fdd9fSElaine Zhang 		priv->sync_kernel = true;
132554d254feSAndy Yan 
132654d254feSAndy Yan 	return 0;
132754d254feSAndy Yan }
132854d254feSAndy Yan 
rk3308_clk_ofdata_to_platdata(struct udevice * dev)132954d254feSAndy Yan static int rk3308_clk_ofdata_to_platdata(struct udevice *dev)
133054d254feSAndy Yan {
133154d254feSAndy Yan 	struct rk3308_clk_priv *priv = dev_get_priv(dev);
133254d254feSAndy Yan 
133354d254feSAndy Yan 	priv->cru = dev_read_addr_ptr(dev);
133454d254feSAndy Yan 
133554d254feSAndy Yan 	return 0;
133654d254feSAndy Yan }
133754d254feSAndy Yan 
rk3308_clk_bind(struct udevice * dev)133854d254feSAndy Yan static int rk3308_clk_bind(struct udevice *dev)
133954d254feSAndy Yan {
134054d254feSAndy Yan 	int ret;
134154d254feSAndy Yan 	struct udevice *sys_child, *sf_child;
134254d254feSAndy Yan 	struct sysreset_reg *priv;
134354d254feSAndy Yan 	struct softreset_reg *sf_priv;
134454d254feSAndy Yan 
134554d254feSAndy Yan 	/* The reset driver does not have a device node, so bind it here */
134654d254feSAndy Yan 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
134754d254feSAndy Yan 				 &sys_child);
134854d254feSAndy Yan 	if (ret) {
134954d254feSAndy Yan 		debug("Warning: No sysreset driver: ret=%d\n", ret);
135054d254feSAndy Yan 	} else {
135154d254feSAndy Yan 		priv = malloc(sizeof(struct sysreset_reg));
135254d254feSAndy Yan 		priv->glb_srst_fst_value = offsetof(struct rk3308_cru,
135354d254feSAndy Yan 						    glb_srst_fst);
135454d254feSAndy Yan 		priv->glb_srst_snd_value = offsetof(struct rk3308_cru,
135554d254feSAndy Yan 						    glb_srst_snd);
135654d254feSAndy Yan 		sys_child->priv = priv;
135754d254feSAndy Yan 	}
135854d254feSAndy Yan 
135954d254feSAndy Yan 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
136054d254feSAndy Yan 					 dev_ofnode(dev), &sf_child);
136154d254feSAndy Yan 	if (ret) {
136254d254feSAndy Yan 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
136354d254feSAndy Yan 	} else {
136454d254feSAndy Yan 		sf_priv = malloc(sizeof(struct softreset_reg));
136554d254feSAndy Yan 		sf_priv->sf_reset_offset = offsetof(struct rk3308_cru,
136654d254feSAndy Yan 						    softrst_con[0]);
136754d254feSAndy Yan 		sf_priv->sf_reset_num = 12;
136854d254feSAndy Yan 		sf_child->priv = sf_priv;
136954d254feSAndy Yan 	}
137054d254feSAndy Yan 
137154d254feSAndy Yan 	return 0;
137254d254feSAndy Yan }
137354d254feSAndy Yan 
137454d254feSAndy Yan static const struct udevice_id rk3308_clk_ids[] = {
137554d254feSAndy Yan 	{ .compatible = "rockchip,rk3308-cru" },
137654d254feSAndy Yan 	{ }
137754d254feSAndy Yan };
137854d254feSAndy Yan 
137954d254feSAndy Yan U_BOOT_DRIVER(rockchip_rk3308_cru) = {
138054d254feSAndy Yan 	.name		= "rockchip_rk3308_cru",
138154d254feSAndy Yan 	.id		= UCLASS_CLK,
138254d254feSAndy Yan 	.of_match	= rk3308_clk_ids,
138354d254feSAndy Yan 	.priv_auto_alloc_size = sizeof(struct rk3308_clk_priv),
138454d254feSAndy Yan 	.ofdata_to_platdata = rk3308_clk_ofdata_to_platdata,
138554d254feSAndy Yan 	.ops		= &rk3308_clk_ops,
138654d254feSAndy Yan 	.bind		= rk3308_clk_bind,
138754d254feSAndy Yan 	.probe		= rk3308_clk_probe,
138854d254feSAndy Yan };
1389efdbac34SFinley Xiao 
1390efdbac34SFinley Xiao /**
1391efdbac34SFinley Xiao  * soc_clk_dump() - Print clock frequencies
1392efdbac34SFinley Xiao  * Returns zero on success
1393efdbac34SFinley Xiao  *
1394efdbac34SFinley Xiao  * Implementation for the clk dump command.
1395efdbac34SFinley Xiao  */
soc_clk_dump(void)1396efdbac34SFinley Xiao int soc_clk_dump(void)
1397efdbac34SFinley Xiao {
1398efdbac34SFinley Xiao 	struct udevice *cru_dev;
1399093fdd9fSElaine Zhang 	struct rk3308_clk_priv *priv;
1400efdbac34SFinley Xiao 	const struct rk3308_clk_info *clk_dump;
1401efdbac34SFinley Xiao 	struct clk clk;
1402efdbac34SFinley Xiao 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1403efdbac34SFinley Xiao 	unsigned long rate;
1404efdbac34SFinley Xiao 	int i, ret;
1405efdbac34SFinley Xiao 
1406efdbac34SFinley Xiao 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1407efdbac34SFinley Xiao 					  DM_GET_DRIVER(rockchip_rk3308_cru),
1408efdbac34SFinley Xiao 					  &cru_dev);
1409efdbac34SFinley Xiao 	if (ret) {
1410efdbac34SFinley Xiao 		printf("%s failed to get cru device\n", __func__);
1411efdbac34SFinley Xiao 		return ret;
1412efdbac34SFinley Xiao 	}
1413efdbac34SFinley Xiao 
1414093fdd9fSElaine Zhang 	priv = dev_get_priv(cru_dev);
1415093fdd9fSElaine Zhang 	printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1416093fdd9fSElaine Zhang 	       priv->sync_kernel ? "sync kernel" : "uboot",
1417093fdd9fSElaine Zhang 	       priv->armclk_enter_hz / 1000,
1418093fdd9fSElaine Zhang 	       priv->armclk_init_hz / 1000,
1419093fdd9fSElaine Zhang 	       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1420093fdd9fSElaine Zhang 	       priv->set_armclk_rate ? " KHz" : "N/A");
1421efdbac34SFinley Xiao 	for (i = 0; i < clk_count; i++) {
1422efdbac34SFinley Xiao 		clk_dump = &clks_dump[i];
1423efdbac34SFinley Xiao 		if (clk_dump->name) {
1424efdbac34SFinley Xiao 			clk.id = clk_dump->id;
1425efdbac34SFinley Xiao 			ret = clk_request(cru_dev, &clk);
1426efdbac34SFinley Xiao 			if (ret < 0)
1427efdbac34SFinley Xiao 				return ret;
1428efdbac34SFinley Xiao 
1429efdbac34SFinley Xiao 			rate = clk_get_rate(&clk);
1430efdbac34SFinley Xiao 			clk_free(&clk);
1431efdbac34SFinley Xiao 			if (i == 0) {
1432efdbac34SFinley Xiao 				if (rate < 0)
14334ffb5e6cSFinley Xiao 					printf("  %s %s\n", clk_dump->name,
1434efdbac34SFinley Xiao 					       "unknown");
1435efdbac34SFinley Xiao 				else
14364ffb5e6cSFinley Xiao 					printf("  %s %lu KHz\n", clk_dump->name,
14374ffb5e6cSFinley Xiao 					       rate / 1000);
1438efdbac34SFinley Xiao 			} else {
1439efdbac34SFinley Xiao 				if (rate < 0)
14404ffb5e6cSFinley Xiao 					printf("  %s %s\n", clk_dump->name,
1441efdbac34SFinley Xiao 					       "unknown");
1442efdbac34SFinley Xiao 				else
14434ffb5e6cSFinley Xiao 					printf("  %s %lu KHz\n", clk_dump->name,
14444ffb5e6cSFinley Xiao 					       rate / 1000);
1445efdbac34SFinley Xiao 			}
1446efdbac34SFinley Xiao 		}
1447efdbac34SFinley Xiao 	}
1448efdbac34SFinley Xiao 
1449efdbac34SFinley Xiao 	return 0;
1450efdbac34SFinley Xiao }
1451