xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk322x.c (revision 56e11a8cc32c299b10a419837ecb45defdeb5fdb)
1045029cbSKever Yang /*
2045029cbSKever Yang  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3045029cbSKever Yang  *
4045029cbSKever Yang  * SPDX-License-Identifier:	GPL-2.0
5045029cbSKever Yang  */
6045029cbSKever Yang 
7045029cbSKever Yang #include <common.h>
8045029cbSKever Yang #include <clk-uclass.h>
9045029cbSKever Yang #include <dm.h>
10045029cbSKever Yang #include <errno.h>
11045029cbSKever Yang #include <syscon.h>
12045029cbSKever Yang #include <asm/io.h>
13045029cbSKever Yang #include <asm/arch/clock.h>
14045029cbSKever Yang #include <asm/arch/cru_rk322x.h>
15045029cbSKever Yang #include <asm/arch/hardware.h>
16045029cbSKever Yang #include <dm/lists.h>
17045029cbSKever Yang #include <dt-bindings/clock/rk3228-cru.h>
18045029cbSKever Yang #include <linux/log2.h>
19045029cbSKever Yang 
20045029cbSKever Yang DECLARE_GLOBAL_DATA_PTR;
21045029cbSKever Yang 
22045029cbSKever Yang #define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
23045029cbSKever Yang 
24809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
25809e91fdSElaine Zhang #define RK322x_CLK_DUMP(_id, _name, _iscru)	\
26809e91fdSElaine Zhang {						\
27809e91fdSElaine Zhang 	.id = _id,				\
28809e91fdSElaine Zhang 	.name = _name,				\
29809e91fdSElaine Zhang 	.is_cru = _iscru,			\
30809e91fdSElaine Zhang }
31809e91fdSElaine Zhang #endif
32045029cbSKever Yang 
33809e91fdSElaine Zhang static struct rockchip_pll_rate_table rk322x_pll_rates[] = {
34809e91fdSElaine Zhang 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
35809e91fdSElaine Zhang 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
36809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
37809e91fdSElaine Zhang 	RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
38809e91fdSElaine Zhang 	RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
39809e91fdSElaine Zhang #endif
40809e91fdSElaine Zhang 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
41809e91fdSElaine Zhang 	RK3036_PLL_RATE(800000000, 1, 100, 3, 1, 1, 0),
42809e91fdSElaine Zhang 	RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
43809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
44809e91fdSElaine Zhang 	RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
45809e91fdSElaine Zhang 	RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
46809e91fdSElaine Zhang 	RK3036_PLL_RATE(400000000, 1, 50, 3, 1, 1, 0),
47809e91fdSElaine Zhang #endif
48809e91fdSElaine Zhang 	{ /* sentinel */ },
49809e91fdSElaine Zhang };
50045029cbSKever Yang 
51809e91fdSElaine Zhang #define RK322x_CPUCLK_RATE(_rate, _aclk_div, _pclk_div)		\
52809e91fdSElaine Zhang {								\
53809e91fdSElaine Zhang 	.rate	= _rate##U,					\
54809e91fdSElaine Zhang 	.aclk_div = _aclk_div,					\
55809e91fdSElaine Zhang 	.pclk_div = _pclk_div,					\
56045029cbSKever Yang }
57045029cbSKever Yang 
58809e91fdSElaine Zhang static struct rockchip_cpu_rate_table rk322x_cpu_rates[] = {
59809e91fdSElaine Zhang 	RK322x_CPUCLK_RATE(1200000000, 1, 5),
60809e91fdSElaine Zhang 	RK322x_CPUCLK_RATE(1008000000, 1, 5),
61809e91fdSElaine Zhang 	RK322x_CPUCLK_RATE(816000000, 1, 3),
62809e91fdSElaine Zhang 	RK322x_CPUCLK_RATE(600000000, 1, 3),
63809e91fdSElaine Zhang };
64809e91fdSElaine Zhang 
65809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
66809e91fdSElaine Zhang static const struct rk322x_clk_info clks_dump[] = {
67809e91fdSElaine Zhang 	RK322x_CLK_DUMP(PLL_APLL, "apll", true),
68809e91fdSElaine Zhang 	RK322x_CLK_DUMP(PLL_DPLL, "dpll", true),
69809e91fdSElaine Zhang 	RK322x_CLK_DUMP(PLL_CPLL, "cpll", true),
70809e91fdSElaine Zhang 	RK322x_CLK_DUMP(PLL_GPLL, "gpll", true),
71809e91fdSElaine Zhang 	RK322x_CLK_DUMP(ARMCLK, "armclk", true),
72809e91fdSElaine Zhang 	RK322x_CLK_DUMP(ACLK_CPU, "aclk_bus", true),
73809e91fdSElaine Zhang 	RK322x_CLK_DUMP(HCLK_CPU, "hclk_bus", true),
74809e91fdSElaine Zhang 	RK322x_CLK_DUMP(PCLK_CPU, "pclk_bus", true),
75809e91fdSElaine Zhang 	RK322x_CLK_DUMP(ACLK_PERI, "aclk_peri", true),
76809e91fdSElaine Zhang 	RK322x_CLK_DUMP(HCLK_PERI, "hclk_peri", true),
77809e91fdSElaine Zhang 	RK322x_CLK_DUMP(PCLK_PERI, "pclk_peri", true),
78809e91fdSElaine Zhang };
79809e91fdSElaine Zhang #endif
80809e91fdSElaine Zhang 
81809e91fdSElaine Zhang static struct rockchip_pll_clock rk322x_pll_clks[] = {
82809e91fdSElaine Zhang 	[APLL] = PLL(pll_rk3036, PLL_APLL, RK2928_PLL_CON(0),
83809e91fdSElaine Zhang 		     RK2928_MODE_CON, 0, 10, 0, rk322x_pll_rates),
84809e91fdSElaine Zhang 	[DPLL] = PLL(pll_rk3036, PLL_DPLL, RK2928_PLL_CON(3),
85809e91fdSElaine Zhang 		     RK2928_MODE_CON, 4, 10, 0, rk322x_pll_rates),
86809e91fdSElaine Zhang 	[CPLL] = PLL(pll_rk3036, PLL_CPLL, RK2928_PLL_CON(6),
87809e91fdSElaine Zhang 		    RK2928_MODE_CON, 8, 10, 0, rk322x_pll_rates),
88809e91fdSElaine Zhang 	[GPLL] = PLL(pll_rk3036, PLL_GPLL, RK2928_PLL_CON(9),
89809e91fdSElaine Zhang 		     RK2928_MODE_CON, 12, 10, 0, rk322x_pll_rates),
90809e91fdSElaine Zhang };
91809e91fdSElaine Zhang 
rk322x_armclk_set_clk(struct rk322x_clk_priv * priv,ulong hz)92809e91fdSElaine Zhang static ulong rk322x_armclk_set_clk(struct rk322x_clk_priv *priv, ulong hz)
93045029cbSKever Yang {
94809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
95809e91fdSElaine Zhang 	const struct rockchip_cpu_rate_table *rate;
96809e91fdSElaine Zhang 	ulong old_rate;
97045029cbSKever Yang 
98809e91fdSElaine Zhang 	rate = rockchip_get_cpu_settings(rk322x_cpu_rates, hz);
99809e91fdSElaine Zhang 	if (!rate) {
100809e91fdSElaine Zhang 		printf("%s unsupported rate\n", __func__);
101809e91fdSElaine Zhang 		return -EINVAL;
102809e91fdSElaine Zhang 	}
103045029cbSKever Yang 
104045029cbSKever Yang 	/*
105045029cbSKever Yang 	 * select apll as cpu/core clock pll source and
106045029cbSKever Yang 	 * set up dependent divisors for PERI and ACLK clocks.
107045029cbSKever Yang 	 * core hz : apll = 1:1
108045029cbSKever Yang 	 */
109809e91fdSElaine Zhang 	old_rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
110809e91fdSElaine Zhang 					 priv->cru, APLL);
111809e91fdSElaine Zhang 	if (old_rate > hz) {
112809e91fdSElaine Zhang 		if (rockchip_pll_set_rate(&rk322x_pll_clks[APLL],
113809e91fdSElaine Zhang 					  priv->cru, APLL, hz))
114809e91fdSElaine Zhang 			return -EINVAL;
115045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[0],
116045029cbSKever Yang 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
117045029cbSKever Yang 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
118045029cbSKever Yang 			     0 << CORE_DIV_CON_SHIFT);
119045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[1],
120045029cbSKever Yang 			     CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK,
121809e91fdSElaine Zhang 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
122809e91fdSElaine Zhang 			     rate->pclk_div << CORE_PERI_DIV_SHIFT);
123809e91fdSElaine Zhang 	} else if (old_rate < hz) {
124045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[1],
125809e91fdSElaine Zhang 			     CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK,
126809e91fdSElaine Zhang 			     rate->aclk_div << CORE_ACLK_DIV_SHIFT |
127809e91fdSElaine Zhang 			     rate->pclk_div << CORE_PERI_DIV_SHIFT);
128809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[0],
129809e91fdSElaine Zhang 			     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
130809e91fdSElaine Zhang 			     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
131809e91fdSElaine Zhang 			     0 << CORE_DIV_CON_SHIFT);
132809e91fdSElaine Zhang 		if (rockchip_pll_set_rate(&rk322x_pll_clks[APLL],
133809e91fdSElaine Zhang 					  priv->cru, APLL, hz))
134809e91fdSElaine Zhang 			return -EINVAL;
135045029cbSKever Yang 	}
136045029cbSKever Yang 
137809e91fdSElaine Zhang 	return rockchip_pll_get_rate(&rk322x_pll_clks[APLL], priv->cru, APLL);
138045029cbSKever Yang }
139045029cbSKever Yang 
rk322x_mmc_get_clk(struct rk322x_clk_priv * priv,int periph)140809e91fdSElaine Zhang static ulong rk322x_mmc_get_clk(struct rk322x_clk_priv *priv,
141045029cbSKever Yang 				int periph)
142045029cbSKever Yang {
143809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
144045029cbSKever Yang 	uint src_rate;
145045029cbSKever Yang 	uint div, mux;
146045029cbSKever Yang 	u32 con;
147045029cbSKever Yang 
148045029cbSKever Yang 	switch (periph) {
149045029cbSKever Yang 	case HCLK_EMMC:
150045029cbSKever Yang 	case SCLK_EMMC:
1516c639845SKever Yang 	case SCLK_EMMC_SAMPLE:
152045029cbSKever Yang 		con = readl(&cru->cru_clksel_con[11]);
153045029cbSKever Yang 		mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT;
154045029cbSKever Yang 		con = readl(&cru->cru_clksel_con[12]);
155045029cbSKever Yang 		div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
156045029cbSKever Yang 		break;
157045029cbSKever Yang 	case HCLK_SDMMC:
158045029cbSKever Yang 	case SCLK_SDMMC:
159809e91fdSElaine Zhang 	case SCLK_SDMMC_SAMPLE:
160045029cbSKever Yang 		con = readl(&cru->cru_clksel_con[11]);
161045029cbSKever Yang 		mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT;
162045029cbSKever Yang 		div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT;
163045029cbSKever Yang 		break;
164809e91fdSElaine Zhang 	case SCLK_SDIO:
165809e91fdSElaine Zhang 	case SCLK_SDIO_SAMPLE:
166809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[11]);
167809e91fdSElaine Zhang 		mux = (con & SDIO_PLL_MASK) >> SDIO_PLL_SHIFT;
168809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[12]);
169809e91fdSElaine Zhang 		div = (con & SDIO_DIV_MASK) >> SDIO_DIV_SHIFT;
170809e91fdSElaine Zhang 		break;
171045029cbSKever Yang 	default:
172045029cbSKever Yang 		return -EINVAL;
173045029cbSKever Yang 	}
174045029cbSKever Yang 
175809e91fdSElaine Zhang 	src_rate = mux == EMMC_SEL_24M ? OSC_HZ : priv->gpll_hz;
1763a94d75dSKever Yang 	return DIV_TO_RATE(src_rate, div) / 2;
177045029cbSKever Yang }
178045029cbSKever Yang 
179809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
rk322x_mac_set_clk(struct rk322x_clk_priv * priv,uint freq)180809e91fdSElaine Zhang static ulong rk322x_mac_set_clk(struct rk322x_clk_priv *priv, uint freq)
18158996dfcSDavid Wu {
182809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
18358996dfcSDavid Wu 	ulong ret;
18458996dfcSDavid Wu 
18558996dfcSDavid Wu 	/*
18658996dfcSDavid Wu 	 * The gmac clock can be derived either from an external clock
18758996dfcSDavid Wu 	 * or can be generated from internally by a divider from SCLK_MAC.
18858996dfcSDavid Wu 	 */
18958996dfcSDavid Wu 	if (readl(&cru->cru_clksel_con[5]) & BIT(5)) {
19058996dfcSDavid Wu 		/* An external clock will always generate the right rate... */
19158996dfcSDavid Wu 		ret = freq;
19258996dfcSDavid Wu 	} else {
19358996dfcSDavid Wu 		u32 con = readl(&cru->cru_clksel_con[5]);
19458996dfcSDavid Wu 		ulong pll_rate;
19558996dfcSDavid Wu 		u8 div;
19658996dfcSDavid Wu 
1974b495484SDavid Wu 		if (con & MAC_PLL_SEL_MASK)
198809e91fdSElaine Zhang 			pll_rate = priv->gpll_hz;
19958996dfcSDavid Wu 		else
20058996dfcSDavid Wu 			/* CPLL is not set */
20158996dfcSDavid Wu 			return -EPERM;
20258996dfcSDavid Wu 
20358996dfcSDavid Wu 		div = DIV_ROUND_UP(pll_rate, freq) - 1;
20458996dfcSDavid Wu 		if (div <= 0x1f)
20558996dfcSDavid Wu 			rk_clrsetreg(&cru->cru_clksel_con[5], CLK_MAC_DIV_MASK,
20658996dfcSDavid Wu 				     div << CLK_MAC_DIV_SHIFT);
20758996dfcSDavid Wu 		else
20858996dfcSDavid Wu 			debug("Unsupported div for gmac:%d\n", div);
20958996dfcSDavid Wu 
21058996dfcSDavid Wu 		return DIV_TO_RATE(pll_rate, div);
21158996dfcSDavid Wu 	}
21258996dfcSDavid Wu 
21358996dfcSDavid Wu 	return ret;
21458996dfcSDavid Wu }
215809e91fdSElaine Zhang #endif
21658996dfcSDavid Wu 
rk322x_mmc_set_clk(struct rk322x_clk_priv * priv,int periph,uint freq)217809e91fdSElaine Zhang static ulong rk322x_mmc_set_clk(struct rk322x_clk_priv *priv,
218045029cbSKever Yang 				int periph, uint freq)
219045029cbSKever Yang {
220809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
221045029cbSKever Yang 	int src_clk_div;
222045029cbSKever Yang 	int mux;
223045029cbSKever Yang 
2243a94d75dSKever Yang 	/* mmc clock defaulg div 2 internal, need provide double in cru */
225809e91fdSElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, freq);
226045029cbSKever Yang 
227217273cdSKever Yang 	if (src_clk_div > 128) {
2283a94d75dSKever Yang 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq);
229217273cdSKever Yang 		assert(src_clk_div - 1 < 128);
230045029cbSKever Yang 		mux = EMMC_SEL_24M;
231045029cbSKever Yang 	} else {
232045029cbSKever Yang 		mux = EMMC_SEL_GPLL;
233045029cbSKever Yang 	}
234045029cbSKever Yang 
235045029cbSKever Yang 	switch (periph) {
236045029cbSKever Yang 	case HCLK_EMMC:
237045029cbSKever Yang 	case SCLK_EMMC:
2386c639845SKever Yang 	case SCLK_EMMC_SAMPLE:
239045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[11],
240045029cbSKever Yang 			     EMMC_PLL_MASK,
241045029cbSKever Yang 			     mux << EMMC_PLL_SHIFT);
242045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[12],
243045029cbSKever Yang 			     EMMC_DIV_MASK,
244045029cbSKever Yang 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
245045029cbSKever Yang 		break;
246045029cbSKever Yang 	case HCLK_SDMMC:
247045029cbSKever Yang 	case SCLK_SDMMC:
248809e91fdSElaine Zhang 	case SCLK_SDMMC_SAMPLE:
249045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[11],
250045029cbSKever Yang 			     MMC0_PLL_MASK | MMC0_DIV_MASK,
251045029cbSKever Yang 			     mux << MMC0_PLL_SHIFT |
252045029cbSKever Yang 			     (src_clk_div - 1) << MMC0_DIV_SHIFT);
253045029cbSKever Yang 		break;
254809e91fdSElaine Zhang 	case SCLK_SDIO:
255809e91fdSElaine Zhang 	case SCLK_SDIO_SAMPLE:
256809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[11],
257809e91fdSElaine Zhang 			     SDIO_PLL_MASK,
258809e91fdSElaine Zhang 			     mux << SDIO_PLL_SHIFT);
259809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[12],
260809e91fdSElaine Zhang 			     SDIO_DIV_MASK,
261809e91fdSElaine Zhang 			     (src_clk_div - 1) << SDIO_DIV_SHIFT);
262809e91fdSElaine Zhang 		break;
263045029cbSKever Yang 	default:
264045029cbSKever Yang 		return -EINVAL;
265045029cbSKever Yang 	}
266045029cbSKever Yang 
267809e91fdSElaine Zhang 	return rk322x_mmc_get_clk(priv, periph);
268045029cbSKever Yang }
269045029cbSKever Yang 
rk322x_bus_get_clk(struct rk322x_clk_priv * priv,ulong clk_id)270809e91fdSElaine Zhang static ulong rk322x_bus_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
271045029cbSKever Yang {
272809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
273809e91fdSElaine Zhang 	u32 div, con, parent;
274045029cbSKever Yang 
275809e91fdSElaine Zhang 	switch (clk_id) {
276809e91fdSElaine Zhang 	case ACLK_CPU:
277eecd6f34SZhangbin Tong 		con = readl(&cru->cru_clksel_con[0]);
278809e91fdSElaine Zhang 		div = (con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT;
279809e91fdSElaine Zhang 		parent = priv->gpll_hz;
280809e91fdSElaine Zhang 		break;
281809e91fdSElaine Zhang 	case HCLK_CPU:
282eecd6f34SZhangbin Tong 		con = readl(&cru->cru_clksel_con[1]);
283809e91fdSElaine Zhang 		div = (con & BUS_HCLK_DIV_MASK) >> BUS_HCLK_DIV_SHIFT;
284809e91fdSElaine Zhang 		parent = rk322x_bus_get_clk(priv, ACLK_CPU);
285809e91fdSElaine Zhang 		break;
286809e91fdSElaine Zhang 	case PCLK_CPU:
287809e91fdSElaine Zhang 	case PCLK_I2C0:
288809e91fdSElaine Zhang 	case PCLK_I2C1:
289809e91fdSElaine Zhang 	case PCLK_I2C2:
290809e91fdSElaine Zhang 	case PCLK_I2C3:
291809e91fdSElaine Zhang 	case PCLK_PWM:
292809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[1]);
293809e91fdSElaine Zhang 		div = (con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT;
294809e91fdSElaine Zhang 		parent = rk322x_bus_get_clk(priv, ACLK_CPU);
295809e91fdSElaine Zhang 		break;
296809e91fdSElaine Zhang 	default:
297809e91fdSElaine Zhang 		return -ENOENT;
298eecd6f34SZhangbin Tong 	}
299eecd6f34SZhangbin Tong 
300809e91fdSElaine Zhang 	return DIV_TO_RATE(parent, div);
301809e91fdSElaine Zhang }
302809e91fdSElaine Zhang 
rk322x_bus_set_clk(struct rk322x_clk_priv * priv,ulong clk_id,ulong hz)303809e91fdSElaine Zhang static ulong rk322x_bus_set_clk(struct rk322x_clk_priv *priv,
304809e91fdSElaine Zhang 				ulong clk_id, ulong hz)
305809e91fdSElaine Zhang {
306809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
307809e91fdSElaine Zhang 	int src_clk_div;
308809e91fdSElaine Zhang 
309809e91fdSElaine Zhang 	/*
310809e91fdSElaine Zhang 	 * select gpll as pd_bus bus clock source and
311809e91fdSElaine Zhang 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
312809e91fdSElaine Zhang 	 */
313809e91fdSElaine Zhang 	switch (clk_id) {
314809e91fdSElaine Zhang 	case ACLK_CPU:
315809e91fdSElaine Zhang 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
3160598134aSKever Yang 		assert(src_clk_div - 1 < 32);
317809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[0],
318809e91fdSElaine Zhang 			     BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
319809e91fdSElaine Zhang 			     BUS_ACLK_PLL_SEL_GPLL << BUS_ACLK_PLL_SEL_SHIFT |
320809e91fdSElaine Zhang 			     (src_clk_div - 1) << BUS_ACLK_DIV_SHIFT);
321809e91fdSElaine Zhang 		break;
322809e91fdSElaine Zhang 	case HCLK_CPU:
323809e91fdSElaine Zhang 		src_clk_div = DIV_ROUND_UP(rk322x_bus_get_clk(priv,
324809e91fdSElaine Zhang 							      ACLK_CPU),
325809e91fdSElaine Zhang 					   hz);
3260598134aSKever Yang 		assert(src_clk_div - 1 < 4);
327809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[1],
328809e91fdSElaine Zhang 			     BUS_HCLK_DIV_MASK,
329809e91fdSElaine Zhang 			     (src_clk_div - 1) << BUS_HCLK_DIV_SHIFT);
330809e91fdSElaine Zhang 		break;
331809e91fdSElaine Zhang 	case PCLK_CPU:
332809e91fdSElaine Zhang 		src_clk_div = DIV_ROUND_UP(rk322x_bus_get_clk(priv,
333809e91fdSElaine Zhang 							      ACLK_CPU),
334809e91fdSElaine Zhang 					   hz);
3350598134aSKever Yang 		assert(src_clk_div - 1 < 8);
336809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[1],
337809e91fdSElaine Zhang 			     BUS_PCLK_DIV_MASK,
338809e91fdSElaine Zhang 			     (src_clk_div - 1) << BUS_PCLK_DIV_SHIFT);
339809e91fdSElaine Zhang 		break;
340809e91fdSElaine Zhang 	default:
341809e91fdSElaine Zhang 		printf("do not support this bus freq\n");
342809e91fdSElaine Zhang 		return -EINVAL;
343809e91fdSElaine Zhang 	}
344809e91fdSElaine Zhang 
345809e91fdSElaine Zhang 	return rk322x_bus_get_clk(priv, clk_id);
346809e91fdSElaine Zhang }
347809e91fdSElaine Zhang 
rk322x_peri_get_clk(struct rk322x_clk_priv * priv,ulong clk_id)348809e91fdSElaine Zhang static ulong rk322x_peri_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
349809e91fdSElaine Zhang {
350809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
351809e91fdSElaine Zhang 	u32 div, con, parent;
352809e91fdSElaine Zhang 
353809e91fdSElaine Zhang 	switch (clk_id) {
354809e91fdSElaine Zhang 	case ACLK_PERI:
355809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[10]);
356809e91fdSElaine Zhang 		div = (con & PERI_ACLK_DIV_MASK) >> PERI_ACLK_DIV_SHIFT;
357809e91fdSElaine Zhang 		parent = priv->gpll_hz;
358809e91fdSElaine Zhang 		break;
359809e91fdSElaine Zhang 	case HCLK_PERI:
360809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[10]);
361809e91fdSElaine Zhang 		div = (con & PERI_HCLK_DIV_MASK) >> PERI_HCLK_DIV_SHIFT;
362809e91fdSElaine Zhang 		parent = rk322x_peri_get_clk(priv, ACLK_PERI);
363809e91fdSElaine Zhang 		break;
364809e91fdSElaine Zhang 	case PCLK_PERI:
365809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[10]);
366809e91fdSElaine Zhang 		div = (con & PERI_PCLK_DIV_MASK) >> PERI_PCLK_DIV_SHIFT;
367809e91fdSElaine Zhang 		parent = rk322x_peri_get_clk(priv, ACLK_PERI);
368809e91fdSElaine Zhang 		break;
369809e91fdSElaine Zhang 	default:
370809e91fdSElaine Zhang 		return -ENOENT;
371809e91fdSElaine Zhang 	}
372809e91fdSElaine Zhang 
373809e91fdSElaine Zhang 	return DIV_TO_RATE(parent, div);
374809e91fdSElaine Zhang }
375809e91fdSElaine Zhang 
rk322x_peri_set_clk(struct rk322x_clk_priv * priv,ulong clk_id,ulong hz)376809e91fdSElaine Zhang static ulong rk322x_peri_set_clk(struct rk322x_clk_priv *priv,
377809e91fdSElaine Zhang 				 ulong clk_id, ulong hz)
378809e91fdSElaine Zhang {
379809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
380809e91fdSElaine Zhang 	int src_clk_div;
381809e91fdSElaine Zhang 
382809e91fdSElaine Zhang 	/*
383809e91fdSElaine Zhang 	 * select gpll as pd_bus bus clock source and
384809e91fdSElaine Zhang 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
385809e91fdSElaine Zhang 	 */
386809e91fdSElaine Zhang 	switch (clk_id) {
387809e91fdSElaine Zhang 	case ACLK_PERI:
388809e91fdSElaine Zhang 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
3890598134aSKever Yang 		assert(src_clk_div - 1 < 32);
390809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[10],
391809e91fdSElaine Zhang 			     PERI_PLL_SEL_MASK | PERI_ACLK_DIV_MASK,
392809e91fdSElaine Zhang 			     PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
393809e91fdSElaine Zhang 			     (src_clk_div - 1) << PERI_ACLK_DIV_SHIFT);
394809e91fdSElaine Zhang 		break;
395809e91fdSElaine Zhang 	case HCLK_PERI:
396809e91fdSElaine Zhang 		src_clk_div = DIV_ROUND_UP(rk322x_peri_get_clk(priv,
397809e91fdSElaine Zhang 							       ACLK_PERI),
398809e91fdSElaine Zhang 					   hz);
3990598134aSKever Yang 		assert(src_clk_div - 1 < 4);
400809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[10],
401809e91fdSElaine Zhang 			     PERI_HCLK_DIV_MASK,
402809e91fdSElaine Zhang 			     (src_clk_div - 1) << PERI_HCLK_DIV_SHIFT);
403809e91fdSElaine Zhang 		break;
404809e91fdSElaine Zhang 	case PCLK_PERI:
405809e91fdSElaine Zhang 		src_clk_div = DIV_ROUND_UP(rk322x_peri_get_clk(priv,
406809e91fdSElaine Zhang 							       ACLK_PERI),
407809e91fdSElaine Zhang 					   hz);
4080598134aSKever Yang 		assert(src_clk_div - 1 < 8);
409809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[10],
410809e91fdSElaine Zhang 			     PERI_PCLK_DIV_MASK,
411809e91fdSElaine Zhang 			     (src_clk_div - 1) << PERI_PCLK_DIV_SHIFT);
412809e91fdSElaine Zhang 		break;
413809e91fdSElaine Zhang 	default:
414809e91fdSElaine Zhang 		printf("do not support this bus freq\n");
415809e91fdSElaine Zhang 		return -EINVAL;
416809e91fdSElaine Zhang 	}
417809e91fdSElaine Zhang 
418809e91fdSElaine Zhang 	return rk322x_peri_get_clk(priv, clk_id);
419809e91fdSElaine Zhang }
420809e91fdSElaine Zhang 
rk322x_spi_get_clk(struct rk322x_clk_priv * priv)421403d8d4cSElaine Zhang static ulong rk322x_spi_get_clk(struct rk322x_clk_priv *priv)
422403d8d4cSElaine Zhang {
423403d8d4cSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
424403d8d4cSElaine Zhang 	u32 div, con, parent;
425403d8d4cSElaine Zhang 
426403d8d4cSElaine Zhang 	con = readl(&cru->cru_clksel_con[25]);
427403d8d4cSElaine Zhang 	div = (con & SPI_DIV_MASK) >> SPI_DIV_SHIFT;
428403d8d4cSElaine Zhang 	parent = priv->gpll_hz;
429403d8d4cSElaine Zhang 
430403d8d4cSElaine Zhang 	return DIV_TO_RATE(parent, div);
431403d8d4cSElaine Zhang }
432403d8d4cSElaine Zhang 
rk322x_spi_set_clk(struct rk322x_clk_priv * priv,ulong hz)433403d8d4cSElaine Zhang static ulong rk322x_spi_set_clk(struct rk322x_clk_priv *priv, ulong hz)
434403d8d4cSElaine Zhang {
435403d8d4cSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
436403d8d4cSElaine Zhang 	int div;
437403d8d4cSElaine Zhang 
438403d8d4cSElaine Zhang 	div = DIV_ROUND_UP(priv->gpll_hz, hz);
439403d8d4cSElaine Zhang 	assert(div - 1 < 128);
440403d8d4cSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[25],
441403d8d4cSElaine Zhang 		     SPI_PLL_SEL_MASK | SPI_DIV_MASK,
442403d8d4cSElaine Zhang 		     SPI_PLL_SEL_GPLL << SPI_PLL_SEL_SHIFT |
443403d8d4cSElaine Zhang 		     (div - 1) << SPI_DIV_SHIFT);
444403d8d4cSElaine Zhang 	return rk322x_spi_get_clk(priv);
445403d8d4cSElaine Zhang }
446403d8d4cSElaine Zhang 
447809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
rk322x_vop_get_clk(struct rk322x_clk_priv * priv,ulong clk_id)448809e91fdSElaine Zhang static ulong rk322x_vop_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
449809e91fdSElaine Zhang {
450809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
451809e91fdSElaine Zhang 	u32 div, con, sel, parent;
452809e91fdSElaine Zhang 
453809e91fdSElaine Zhang 	switch (clk_id) {
454809e91fdSElaine Zhang 	case ACLK_VOP:
455809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[33]);
456809e91fdSElaine Zhang 		div = (con & ACLK_VOP_DIV_CON_MASK) >> ACLK_VOP_DIV_CON_SHIFT;
457809e91fdSElaine Zhang 		parent = priv->gpll_hz;
458809e91fdSElaine Zhang 		break;
459809e91fdSElaine Zhang 	case DCLK_VOP:
460809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[27]);
461809e91fdSElaine Zhang 		con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT;
462809e91fdSElaine Zhang 		if (con) {
463809e91fdSElaine Zhang 			sel = readl(&cru->cru_clksel_con[27]);
464809e91fdSElaine Zhang 			sel = (sel & DCLK_LCDC_PLL_SEL_MASK) >>
465809e91fdSElaine Zhang 				 DCLK_LCDC_PLL_SEL_SHIFT;
466809e91fdSElaine Zhang 			if (sel)
467809e91fdSElaine Zhang 				parent = priv->cpll_hz;
468809e91fdSElaine Zhang 			else
469809e91fdSElaine Zhang 				parent = priv->gpll_hz;
470809e91fdSElaine Zhang 
471809e91fdSElaine Zhang 			con = readl(&cru->cru_clksel_con[27]);
472809e91fdSElaine Zhang 			div = (con & DCLK_LCDC_DIV_CON_MASK) >>
473809e91fdSElaine Zhang 			      DCLK_LCDC_DIV_CON_SHIFT;
474809e91fdSElaine Zhang 		} else {
475809e91fdSElaine Zhang 			parent = priv->cpll_hz;
476809e91fdSElaine Zhang 			div = 1;
477809e91fdSElaine Zhang 		}
478809e91fdSElaine Zhang 		break;
479809e91fdSElaine Zhang 	default:
480809e91fdSElaine Zhang 		return -ENOENT;
481809e91fdSElaine Zhang 	}
482809e91fdSElaine Zhang 
483809e91fdSElaine Zhang 	return DIV_TO_RATE(parent, div);
484809e91fdSElaine Zhang }
485809e91fdSElaine Zhang 
rk322x_vop_set_clk(struct rk322x_clk_priv * priv,ulong clk_id,uint hz)486809e91fdSElaine Zhang static ulong rk322x_vop_set_clk(struct rk322x_clk_priv *priv,
487809e91fdSElaine Zhang 				ulong clk_id, uint hz)
488809e91fdSElaine Zhang {
489809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
490809e91fdSElaine Zhang 	int src_clk_div;
491809e91fdSElaine Zhang 	u32 con, parent;
492809e91fdSElaine Zhang 
493809e91fdSElaine Zhang 	switch (clk_id) {
494809e91fdSElaine Zhang 	case ACLK_VOP:
495dcb78704SElaine Zhang 		src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
496dcb78704SElaine Zhang 		assert(src_clk_div - 1 < 32);
497809e91fdSElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[33],
498809e91fdSElaine Zhang 			     ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
499809e91fdSElaine Zhang 			     ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
500809e91fdSElaine Zhang 			     (src_clk_div - 1) << ACLK_VOP_DIV_CON_SHIFT);
501809e91fdSElaine Zhang 		break;
502809e91fdSElaine Zhang 	case DCLK_VOP:
503809e91fdSElaine Zhang 		con = readl(&cru->cru_clksel_con[27]);
504809e91fdSElaine Zhang 		con = (con & DCLK_LCDC_SEL_MASK) >> DCLK_LCDC_SEL_SHIFT;
505809e91fdSElaine Zhang 		if (con) {
506809e91fdSElaine Zhang 			parent = readl(&cru->cru_clksel_con[27]);
507809e91fdSElaine Zhang 			parent = (parent & DCLK_LCDC_PLL_SEL_MASK) >>
508809e91fdSElaine Zhang 				 DCLK_LCDC_PLL_SEL_SHIFT;
509809e91fdSElaine Zhang 			if (parent)
510809e91fdSElaine Zhang 				src_clk_div = DIV_ROUND_UP(priv->cpll_hz, hz);
511809e91fdSElaine Zhang 			else
512809e91fdSElaine Zhang 				src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
513809e91fdSElaine Zhang 
514dcb78704SElaine Zhang 			assert(src_clk_div - 1 < 256);
515809e91fdSElaine Zhang 			rk_clrsetreg(&cru->cru_clksel_con[27],
516809e91fdSElaine Zhang 				     DCLK_LCDC_DIV_CON_MASK,
517809e91fdSElaine Zhang 				     (src_clk_div - 1) <<
518809e91fdSElaine Zhang 				     DCLK_LCDC_DIV_CON_SHIFT);
519809e91fdSElaine Zhang 		}
520809e91fdSElaine Zhang 		break;
521809e91fdSElaine Zhang 	default:
522809e91fdSElaine Zhang 		printf("do not support this vop freq\n");
523809e91fdSElaine Zhang 		return -EINVAL;
524809e91fdSElaine Zhang 	}
525809e91fdSElaine Zhang 
526809e91fdSElaine Zhang 	return rk322x_vop_get_clk(priv, clk_id);
527809e91fdSElaine Zhang }
528a7c5f873SElaine Zhang 
rk322x_crypto_get_clk(struct rk322x_clk_priv * priv,ulong clk_id)529a7c5f873SElaine Zhang static ulong rk322x_crypto_get_clk(struct rk322x_clk_priv *priv, ulong clk_id)
530a7c5f873SElaine Zhang {
531a7c5f873SElaine Zhang 	struct rk322x_cru *cru = priv->cru;
532a7c5f873SElaine Zhang 	u32 div, con, parent;
533a7c5f873SElaine Zhang 
534a7c5f873SElaine Zhang 	switch (clk_id) {
535a7c5f873SElaine Zhang 	case SCLK_CRYPTO:
536a7c5f873SElaine Zhang 		con = readl(&cru->cru_clksel_con[24]);
537a7c5f873SElaine Zhang 		div = (con & CRYPTO_DIV_MASK) >> CRYPTO_DIV_SHIFT;
538a7c5f873SElaine Zhang 		parent = priv->gpll_hz;
539a7c5f873SElaine Zhang 		break;
540a7c5f873SElaine Zhang 	default:
541a7c5f873SElaine Zhang 		return -ENOENT;
542a7c5f873SElaine Zhang 	}
543a7c5f873SElaine Zhang 
544a7c5f873SElaine Zhang 	return DIV_TO_RATE(parent, div);
545a7c5f873SElaine Zhang }
546a7c5f873SElaine Zhang 
rk322x_crypto_set_clk(struct rk322x_clk_priv * priv,ulong clk_id,ulong hz)547a7c5f873SElaine Zhang static ulong rk322x_crypto_set_clk(struct rk322x_clk_priv *priv, ulong clk_id,
548a7c5f873SElaine Zhang 				   ulong hz)
549a7c5f873SElaine Zhang {
550a7c5f873SElaine Zhang 	struct rk322x_cru *cru = priv->cru;
551a7c5f873SElaine Zhang 	int src_clk_div;
552a7c5f873SElaine Zhang 
553a7c5f873SElaine Zhang 	src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
554a7c5f873SElaine Zhang 	assert(src_clk_div - 1 <= 31);
555a7c5f873SElaine Zhang 
556a7c5f873SElaine Zhang 	/*
557a7c5f873SElaine Zhang 	 * select gpll as crypto clock source and
558a7c5f873SElaine Zhang 	 * set up dependent divisors for crypto clocks.
559a7c5f873SElaine Zhang 	 */
560a7c5f873SElaine Zhang 	switch (clk_id) {
561a7c5f873SElaine Zhang 	case SCLK_CRYPTO:
562a7c5f873SElaine Zhang 		rk_clrsetreg(&cru->cru_clksel_con[24],
563a7c5f873SElaine Zhang 			     CRYPTO_PLL_SEL_MASK | CRYPTO_DIV_MASK,
564a7c5f873SElaine Zhang 			     CRYPTO_PLL_SEL_GPLL << CRYPTO_PLL_SEL_SHIFT |
565a7c5f873SElaine Zhang 			     (src_clk_div - 1) << CRYPTO_DIV_SHIFT);
566a7c5f873SElaine Zhang 		break;
567a7c5f873SElaine Zhang 	default:
568a7c5f873SElaine Zhang 		printf("do not support this peri freq\n");
569a7c5f873SElaine Zhang 		return -EINVAL;
570a7c5f873SElaine Zhang 	}
571a7c5f873SElaine Zhang 
572a7c5f873SElaine Zhang 	return rk322x_crypto_get_clk(priv, clk_id);
573a7c5f873SElaine Zhang }
574809e91fdSElaine Zhang #endif
575809e91fdSElaine Zhang 
rk322x_clk_get_rate(struct clk * clk)576045029cbSKever Yang static ulong rk322x_clk_get_rate(struct clk *clk)
577045029cbSKever Yang {
578045029cbSKever Yang 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
579809e91fdSElaine Zhang 	ulong rate;
580045029cbSKever Yang 
581045029cbSKever Yang 	switch (clk->id) {
582809e91fdSElaine Zhang 	case PLL_APLL:
583809e91fdSElaine Zhang 	case PLL_DPLL:
584809e91fdSElaine Zhang 	case PLL_CPLL:
585809e91fdSElaine Zhang 	case PLL_GPLL:
586809e91fdSElaine Zhang 		rate = rockchip_pll_get_rate(&rk322x_pll_clks[clk->id - 1],
587809e91fdSElaine Zhang 					     priv->cru, clk->id - 1);
588809e91fdSElaine Zhang 		break;
589809e91fdSElaine Zhang 	case ARMCLK:
590809e91fdSElaine Zhang 		rate = rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
591809e91fdSElaine Zhang 					     priv->cru, APLL);
592045029cbSKever Yang 		break;
593045029cbSKever Yang 	case HCLK_EMMC:
594045029cbSKever Yang 	case SCLK_EMMC:
595809e91fdSElaine Zhang 	case SCLK_EMMC_SAMPLE:
596045029cbSKever Yang 	case HCLK_SDMMC:
597045029cbSKever Yang 	case SCLK_SDMMC:
598809e91fdSElaine Zhang 	case SCLK_SDMMC_SAMPLE:
599809e91fdSElaine Zhang 	case SCLK_SDIO:
600809e91fdSElaine Zhang 	case SCLK_SDIO_SAMPLE:
601809e91fdSElaine Zhang 		rate = rk322x_mmc_get_clk(priv, clk->id);
602045029cbSKever Yang 		break;
603403d8d4cSElaine Zhang 	case SCLK_SPI0:
604403d8d4cSElaine Zhang 		rate = rk322x_spi_get_clk(priv);
605403d8d4cSElaine Zhang 		break;
606809e91fdSElaine Zhang 	case ACLK_CPU:
607809e91fdSElaine Zhang 	case HCLK_CPU:
608809e91fdSElaine Zhang 	case PCLK_CPU:
609809e91fdSElaine Zhang 	case PCLK_I2C0:
610809e91fdSElaine Zhang 	case PCLK_I2C1:
611809e91fdSElaine Zhang 	case PCLK_I2C2:
612809e91fdSElaine Zhang 	case PCLK_I2C3:
613809e91fdSElaine Zhang 	case PCLK_PWM:
614809e91fdSElaine Zhang 		rate = rk322x_bus_get_clk(priv, clk->id);
615eecd6f34SZhangbin Tong 		break;
616809e91fdSElaine Zhang 	case ACLK_PERI:
617809e91fdSElaine Zhang 	case HCLK_PERI:
618809e91fdSElaine Zhang 	case PCLK_PERI:
619809e91fdSElaine Zhang 		rate = rk322x_peri_get_clk(priv, clk->id);
620809e91fdSElaine Zhang 		break;
621809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
622809e91fdSElaine Zhang 	case DCLK_VOP:
623809e91fdSElaine Zhang 	case ACLK_VOP:
624809e91fdSElaine Zhang 		rate = rk322x_vop_get_clk(priv, clk->id);
625809e91fdSElaine Zhang 		break;
626a7c5f873SElaine Zhang 	case SCLK_CRYPTO:
627a7c5f873SElaine Zhang 		rate = rk322x_crypto_get_clk(priv, clk->id);
628a7c5f873SElaine Zhang 		break;
629809e91fdSElaine Zhang #endif
630045029cbSKever Yang 	default:
631045029cbSKever Yang 		return -ENOENT;
632045029cbSKever Yang 	}
633045029cbSKever Yang 
634045029cbSKever Yang 	return rate;
635045029cbSKever Yang }
636045029cbSKever Yang 
rk322x_clk_set_rate(struct clk * clk,ulong rate)637045029cbSKever Yang static ulong rk322x_clk_set_rate(struct clk *clk, ulong rate)
638045029cbSKever Yang {
639045029cbSKever Yang 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
6402401c256SElaine Zhang 	ulong ret = 0;
641045029cbSKever Yang 
642045029cbSKever Yang 	switch (clk->id) {
643809e91fdSElaine Zhang 	case PLL_APLL:
644809e91fdSElaine Zhang 	case PLL_DPLL:
645809e91fdSElaine Zhang 		ret = rockchip_pll_set_rate(&rk322x_pll_clks[clk->id - 1],
646809e91fdSElaine Zhang 					    priv->cru, clk->id - 1, rate);
647045029cbSKever Yang 		break;
648809e91fdSElaine Zhang 	case PLL_CPLL:
649809e91fdSElaine Zhang 		ret = rockchip_pll_set_rate(&rk322x_pll_clks[CPLL],
650809e91fdSElaine Zhang 					    priv->cru, CPLL, rate);
651809e91fdSElaine Zhang 		priv->cpll_hz = rate;
65258996dfcSDavid Wu 		break;
65358996dfcSDavid Wu 	case PLL_GPLL:
654809e91fdSElaine Zhang 		ret = rockchip_pll_set_rate(&rk322x_pll_clks[GPLL],
655809e91fdSElaine Zhang 					    priv->cru, GPLL, rate);
656809e91fdSElaine Zhang 		priv->gpll_hz = rate;
657809e91fdSElaine Zhang 		break;
658809e91fdSElaine Zhang 	case ARMCLK:
6592401c256SElaine Zhang 		if (priv->armclk_hz)
660809e91fdSElaine Zhang 			ret = rk322x_armclk_set_clk(priv, rate);
6612401c256SElaine Zhang 		priv->armclk_hz = rate;
662809e91fdSElaine Zhang 		break;
663809e91fdSElaine Zhang 	case HCLK_EMMC:
664809e91fdSElaine Zhang 	case SCLK_EMMC:
665809e91fdSElaine Zhang 	case SCLK_EMMC_SAMPLE:
666809e91fdSElaine Zhang 	case HCLK_SDMMC:
667809e91fdSElaine Zhang 	case SCLK_SDMMC:
668809e91fdSElaine Zhang 	case SCLK_SDMMC_SAMPLE:
669809e91fdSElaine Zhang 	case SCLK_SDIO:
670809e91fdSElaine Zhang 	case SCLK_SDIO_SAMPLE:
671809e91fdSElaine Zhang 		ret = rk322x_mmc_set_clk(priv, clk->id, rate);
672809e91fdSElaine Zhang 		break;
673809e91fdSElaine Zhang 	case SCLK_DDRC:
674809e91fdSElaine Zhang 		ret = rockchip_pll_set_rate(&rk322x_pll_clks[DPLL],
675809e91fdSElaine Zhang 					    priv->cru, DPLL, rate);
676809e91fdSElaine Zhang 		break;
677403d8d4cSElaine Zhang 	case SCLK_SPI0:
678403d8d4cSElaine Zhang 		rate = rk322x_spi_set_clk(priv, rate);
679403d8d4cSElaine Zhang 		break;
680809e91fdSElaine Zhang 	case ACLK_CPU:
681809e91fdSElaine Zhang 	case HCLK_CPU:
682809e91fdSElaine Zhang 	case PCLK_CPU:
683809e91fdSElaine Zhang 		ret = rk322x_bus_set_clk(priv, clk->id, rate);
684809e91fdSElaine Zhang 		break;
685809e91fdSElaine Zhang 	case ACLK_PERI:
686809e91fdSElaine Zhang 	case HCLK_PERI:
687809e91fdSElaine Zhang 	case PCLK_PERI:
688809e91fdSElaine Zhang 		ret = rk322x_peri_set_clk(priv, clk->id, rate);
689809e91fdSElaine Zhang 		break;
690809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
691*56e11a8cSDavid Wu 	case SCLK_MAC_SRC:
692809e91fdSElaine Zhang 	case SCLK_MAC:
693809e91fdSElaine Zhang 		ret = rk322x_mac_set_clk(priv, rate);
694809e91fdSElaine Zhang 		break;
695809e91fdSElaine Zhang 	case DCLK_VOP:
696809e91fdSElaine Zhang 	case ACLK_VOP:
697809e91fdSElaine Zhang 		ret = rk322x_vop_set_clk(priv, clk->id, rate);
698809e91fdSElaine Zhang 		break;
699a7c5f873SElaine Zhang 	case SCLK_CRYPTO:
700a7c5f873SElaine Zhang 		ret = rk322x_crypto_set_clk(priv, clk->id, rate);
701a7c5f873SElaine Zhang 		break;
702809e91fdSElaine Zhang #endif
703045029cbSKever Yang 	default:
704045029cbSKever Yang 		return -ENOENT;
705045029cbSKever Yang 	}
706045029cbSKever Yang 
707809e91fdSElaine Zhang 	return ret;
708045029cbSKever Yang }
709045029cbSKever Yang 
710809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
rk322x_gmac_set_parent(struct clk * clk,struct clk * parent)71158996dfcSDavid Wu static int rk322x_gmac_set_parent(struct clk *clk, struct clk *parent)
71258996dfcSDavid Wu {
71358996dfcSDavid Wu 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
71458996dfcSDavid Wu 	struct rk322x_cru *cru = priv->cru;
71558996dfcSDavid Wu 
71658996dfcSDavid Wu 	/*
71758996dfcSDavid Wu 	 * If the requested parent is in the same clock-controller and the id
71858996dfcSDavid Wu 	 * is SCLK_MAC_SRC ("sclk_gmac_src"), switch to the internal clock.
71958996dfcSDavid Wu 	 */
72058996dfcSDavid Wu 	if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_SRC)) {
72158996dfcSDavid Wu 		debug("%s: switching RGMII to SCLK_MAC_SRC\n", __func__);
72258996dfcSDavid Wu 		rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), 0);
72358996dfcSDavid Wu 		return 0;
72458996dfcSDavid Wu 	}
72558996dfcSDavid Wu 
72658996dfcSDavid Wu 	/*
72758996dfcSDavid Wu 	 * If the requested parent is in the same clock-controller and the id
72858996dfcSDavid Wu 	 * is SCLK_MAC_EXTCLK (sclk_mac_extclk), switch to the external clock.
72958996dfcSDavid Wu 	 */
73058996dfcSDavid Wu 	if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC_EXTCLK)) {
73158996dfcSDavid Wu 		debug("%s: switching RGMII to SCLK_MAC_EXTCLK\n", __func__);
73258996dfcSDavid Wu 		rk_clrsetreg(&cru->cru_clksel_con[5], BIT(5), BIT(5));
73358996dfcSDavid Wu 		return 0;
73458996dfcSDavid Wu 	}
73558996dfcSDavid Wu 
73658996dfcSDavid Wu 	return -EINVAL;
73758996dfcSDavid Wu }
73858996dfcSDavid Wu 
rk322x_gmac_extclk_set_parent(struct clk * clk,struct clk * parent)73958996dfcSDavid Wu static int rk322x_gmac_extclk_set_parent(struct clk *clk, struct clk *parent)
74058996dfcSDavid Wu {
74158996dfcSDavid Wu 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
74258996dfcSDavid Wu 	const char *clock_output_name;
74358996dfcSDavid Wu 	struct rk322x_cru *cru = priv->cru;
74458996dfcSDavid Wu 	int ret;
74558996dfcSDavid Wu 
74658996dfcSDavid Wu 	ret = dev_read_string_index(parent->dev, "clock-output-names",
74758996dfcSDavid Wu 				    parent->id, &clock_output_name);
74858996dfcSDavid Wu 	if (ret < 0)
74958996dfcSDavid Wu 		return -ENODATA;
75058996dfcSDavid Wu 
75158996dfcSDavid Wu 	if (!strcmp(clock_output_name, "ext_gmac")) {
75258996dfcSDavid Wu 		debug("%s: switching gmac extclk to ext_gmac\n", __func__);
75358996dfcSDavid Wu 		rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), 0);
75458996dfcSDavid Wu 		return 0;
75558996dfcSDavid Wu 	} else if (!strcmp(clock_output_name, "phy_50m_out")) {
75658996dfcSDavid Wu 		debug("%s: switching gmac extclk to phy_50m_out\n", __func__);
75758996dfcSDavid Wu 		rk_clrsetreg(&cru->cru_clksel_con[29], BIT(10), BIT(10));
75858996dfcSDavid Wu 		return 0;
75958996dfcSDavid Wu 	}
76058996dfcSDavid Wu 
76158996dfcSDavid Wu 	return -EINVAL;
76258996dfcSDavid Wu }
76358996dfcSDavid Wu 
rk322x_lcdc_set_parent(struct clk * clk,struct clk * parent)764809e91fdSElaine Zhang static int rk322x_lcdc_set_parent(struct clk *clk, struct clk *parent)
765809e91fdSElaine Zhang {
766809e91fdSElaine Zhang 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
767809e91fdSElaine Zhang 
768809e91fdSElaine Zhang 	if (parent->id == HDMIPHY)
769809e91fdSElaine Zhang 		rk_clrsetreg(&priv->cru->cru_clksel_con[27],
770809e91fdSElaine Zhang 			     DCLK_LCDC_SEL_MASK,
771809e91fdSElaine Zhang 			     DCLK_LCDC_SEL_HDMIPHY << DCLK_LCDC_SEL_SHIFT);
772809e91fdSElaine Zhang 	else if (parent->id == PLL_CPLL)
773809e91fdSElaine Zhang 		rk_clrsetreg(&priv->cru->cru_clksel_con[27],
774809e91fdSElaine Zhang 			     DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK,
775809e91fdSElaine Zhang 			     (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) |
776809e91fdSElaine Zhang 			     (DCLK_LCDC_PLL_SEL_CPLL <<
777809e91fdSElaine Zhang 			     DCLK_LCDC_PLL_SEL_SHIFT));
778809e91fdSElaine Zhang 	else
779809e91fdSElaine Zhang 		rk_clrsetreg(&priv->cru->cru_clksel_con[27],
780809e91fdSElaine Zhang 			     DCLK_LCDC_SEL_MASK | DCLK_LCDC_PLL_SEL_MASK,
781809e91fdSElaine Zhang 			     (DCLK_LCDC_SEL_PLL << DCLK_LCDC_SEL_SHIFT) |
782809e91fdSElaine Zhang 			     (DCLK_LCDC_PLL_SEL_GPLL <<
783809e91fdSElaine Zhang 			     DCLK_LCDC_PLL_SEL_SHIFT));
784809e91fdSElaine Zhang 
785809e91fdSElaine Zhang 	return 0;
786809e91fdSElaine Zhang }
787809e91fdSElaine Zhang #endif
788809e91fdSElaine Zhang 
rk322x_clk_set_parent(struct clk * clk,struct clk * parent)78958996dfcSDavid Wu static int rk322x_clk_set_parent(struct clk *clk, struct clk *parent)
79058996dfcSDavid Wu {
79158996dfcSDavid Wu 	switch (clk->id) {
792809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
79358996dfcSDavid Wu 	case SCLK_MAC:
79458996dfcSDavid Wu 		return rk322x_gmac_set_parent(clk, parent);
79558996dfcSDavid Wu 	case SCLK_MAC_EXTCLK:
79658996dfcSDavid Wu 		return rk322x_gmac_extclk_set_parent(clk, parent);
797809e91fdSElaine Zhang 	case DCLK_VOP:
798809e91fdSElaine Zhang 		return rk322x_lcdc_set_parent(clk, parent);
799809e91fdSElaine Zhang #endif
80058996dfcSDavid Wu 	}
80158996dfcSDavid Wu 
80258996dfcSDavid Wu 	debug("%s: unsupported clk %ld\n", __func__, clk->id);
80358996dfcSDavid Wu 	return -ENOENT;
80458996dfcSDavid Wu }
80558996dfcSDavid Wu 
806809e91fdSElaine Zhang #define ROCKCHIP_MMC_DELAY_SEL		BIT(10)
807809e91fdSElaine Zhang #define ROCKCHIP_MMC_DEGREE_MASK	0x3
808809e91fdSElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_OFFSET	2
809809e91fdSElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
810809e91fdSElaine Zhang 
811809e91fdSElaine Zhang #define PSECS_PER_SEC 1000000000000LL
812809e91fdSElaine Zhang /*
813809e91fdSElaine Zhang  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
814809e91fdSElaine Zhang  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
815809e91fdSElaine Zhang  */
816809e91fdSElaine Zhang #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
817809e91fdSElaine Zhang 
rk322x_mmc_get_phase(struct clk * clk)818809e91fdSElaine Zhang int rk322x_mmc_get_phase(struct clk *clk)
819809e91fdSElaine Zhang {
820809e91fdSElaine Zhang 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
821809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
822809e91fdSElaine Zhang 	u32 raw_value, delay_num;
823809e91fdSElaine Zhang 	u16 degrees = 0;
824809e91fdSElaine Zhang 	ulong rate;
825809e91fdSElaine Zhang 
826809e91fdSElaine Zhang 	rate = rk322x_clk_get_rate(clk);
827809e91fdSElaine Zhang 
828809e91fdSElaine Zhang 	if (rate < 0)
829809e91fdSElaine Zhang 		return rate;
830809e91fdSElaine Zhang 
831809e91fdSElaine Zhang 	if (clk->id == SCLK_EMMC_SAMPLE)
832809e91fdSElaine Zhang 		raw_value = readl(&cru->cru_emmc_con[1]);
833809e91fdSElaine Zhang 	else if (clk->id == SCLK_SDMMC_SAMPLE)
834809e91fdSElaine Zhang 		raw_value = readl(&cru->cru_sdmmc_con[1]);
835809e91fdSElaine Zhang 	else
836809e91fdSElaine Zhang 		raw_value = readl(&cru->cru_sdio_con[1]);
837809e91fdSElaine Zhang 
838809e91fdSElaine Zhang 	raw_value >>= 1;
839809e91fdSElaine Zhang 	degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
840809e91fdSElaine Zhang 
841809e91fdSElaine Zhang 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
842809e91fdSElaine Zhang 		/* degrees/delaynum * 10000 */
843809e91fdSElaine Zhang 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
844809e91fdSElaine Zhang 					36 * (rate / 1000000);
845809e91fdSElaine Zhang 
846809e91fdSElaine Zhang 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
847809e91fdSElaine Zhang 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
848809e91fdSElaine Zhang 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
849809e91fdSElaine Zhang 	}
850809e91fdSElaine Zhang 
851809e91fdSElaine Zhang 	return degrees % 360;
852809e91fdSElaine Zhang }
853809e91fdSElaine Zhang 
rk322x_mmc_set_phase(struct clk * clk,u32 degrees)854809e91fdSElaine Zhang int rk322x_mmc_set_phase(struct clk *clk, u32 degrees)
855809e91fdSElaine Zhang {
856809e91fdSElaine Zhang 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
857809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
858809e91fdSElaine Zhang 	u8 nineties, remainder, delay_num;
859809e91fdSElaine Zhang 	u32 raw_value, delay;
860809e91fdSElaine Zhang 	ulong rate;
861809e91fdSElaine Zhang 
862809e91fdSElaine Zhang 	rate = rk322x_clk_get_rate(clk);
863809e91fdSElaine Zhang 
864809e91fdSElaine Zhang 	if (rate < 0)
865809e91fdSElaine Zhang 		return rate;
866809e91fdSElaine Zhang 
867809e91fdSElaine Zhang 	nineties = degrees / 90;
868809e91fdSElaine Zhang 	remainder = (degrees % 90);
869809e91fdSElaine Zhang 
870809e91fdSElaine Zhang 	/*
871809e91fdSElaine Zhang 	 * Convert to delay; do a little extra work to make sure we
872809e91fdSElaine Zhang 	 * don't overflow 32-bit / 64-bit numbers.
873809e91fdSElaine Zhang 	 */
874809e91fdSElaine Zhang 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
875809e91fdSElaine Zhang 	delay *= remainder;
876809e91fdSElaine Zhang 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
877809e91fdSElaine Zhang 				(ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
878809e91fdSElaine Zhang 
879809e91fdSElaine Zhang 	delay_num = (u8)min_t(u32, delay, 255);
880809e91fdSElaine Zhang 
881809e91fdSElaine Zhang 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
882809e91fdSElaine Zhang 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
883809e91fdSElaine Zhang 	raw_value |= nineties;
884809e91fdSElaine Zhang 
885809e91fdSElaine Zhang 	raw_value <<= 1;
886809e91fdSElaine Zhang 	if (clk->id == SCLK_EMMC_SAMPLE)
887809e91fdSElaine Zhang 		writel(raw_value | 0xffff0000, &cru->cru_emmc_con[1]);
888809e91fdSElaine Zhang 	else if (clk->id == SCLK_SDMMC_SAMPLE)
889809e91fdSElaine Zhang 		writel(raw_value | 0xffff0000, &cru->cru_sdmmc_con[1]);
890809e91fdSElaine Zhang 	else
891809e91fdSElaine Zhang 		writel(raw_value | 0xffff0000, &cru->cru_sdio_con[1]);
892809e91fdSElaine Zhang 
893809e91fdSElaine Zhang 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
894809e91fdSElaine Zhang 	      degrees, delay_num, raw_value, rk322x_mmc_get_phase(clk));
895809e91fdSElaine Zhang 
896809e91fdSElaine Zhang 	return 0;
897809e91fdSElaine Zhang }
898809e91fdSElaine Zhang 
rk322x_clk_get_phase(struct clk * clk)899809e91fdSElaine Zhang static int rk322x_clk_get_phase(struct clk *clk)
900809e91fdSElaine Zhang {
901809e91fdSElaine Zhang 	int ret;
902809e91fdSElaine Zhang 
903809e91fdSElaine Zhang 	debug("%s %ld\n", __func__, clk->id);
904809e91fdSElaine Zhang 	switch (clk->id) {
905809e91fdSElaine Zhang 	case SCLK_EMMC_SAMPLE:
906809e91fdSElaine Zhang 	case SCLK_SDMMC_SAMPLE:
907809e91fdSElaine Zhang 	case SCLK_SDIO_SAMPLE:
908809e91fdSElaine Zhang 		ret = rk322x_mmc_get_phase(clk);
909809e91fdSElaine Zhang 		break;
910809e91fdSElaine Zhang 	default:
911809e91fdSElaine Zhang 		return -ENOENT;
912809e91fdSElaine Zhang 	}
913809e91fdSElaine Zhang 
914809e91fdSElaine Zhang 	return ret;
915809e91fdSElaine Zhang }
916809e91fdSElaine Zhang 
rk322x_clk_set_phase(struct clk * clk,int degrees)917809e91fdSElaine Zhang static int rk322x_clk_set_phase(struct clk *clk, int degrees)
918809e91fdSElaine Zhang {
919809e91fdSElaine Zhang 	int ret;
920809e91fdSElaine Zhang 
921809e91fdSElaine Zhang 	debug("%s %ld\n", __func__, clk->id);
922809e91fdSElaine Zhang 	switch (clk->id) {
923809e91fdSElaine Zhang 	case SCLK_EMMC_SAMPLE:
924809e91fdSElaine Zhang 	case SCLK_SDMMC_SAMPLE:
925809e91fdSElaine Zhang 	case SCLK_SDIO_SAMPLE:
926809e91fdSElaine Zhang 		ret = rk322x_mmc_set_phase(clk, degrees);
927809e91fdSElaine Zhang 		break;
928809e91fdSElaine Zhang 	default:
929809e91fdSElaine Zhang 		return -ENOENT;
930809e91fdSElaine Zhang 	}
931809e91fdSElaine Zhang 
932809e91fdSElaine Zhang 	return ret;
933809e91fdSElaine Zhang }
934809e91fdSElaine Zhang 
935045029cbSKever Yang static struct clk_ops rk322x_clk_ops = {
936045029cbSKever Yang 	.get_rate	= rk322x_clk_get_rate,
937045029cbSKever Yang 	.set_rate	= rk322x_clk_set_rate,
93858996dfcSDavid Wu 	.set_parent	= rk322x_clk_set_parent,
939809e91fdSElaine Zhang 	.get_phase	= rk322x_clk_get_phase,
940809e91fdSElaine Zhang 	.set_phase	= rk322x_clk_set_phase,
941045029cbSKever Yang };
942045029cbSKever Yang 
rk322x_clk_ofdata_to_platdata(struct udevice * dev)943045029cbSKever Yang static int rk322x_clk_ofdata_to_platdata(struct udevice *dev)
944045029cbSKever Yang {
945045029cbSKever Yang 	struct rk322x_clk_priv *priv = dev_get_priv(dev);
946045029cbSKever Yang 
947cd47f9d7SKever Yang 	priv->cru = dev_read_addr_ptr(dev);
948045029cbSKever Yang 
949045029cbSKever Yang 	return 0;
950045029cbSKever Yang }
951045029cbSKever Yang 
952c93db2f3SKever Yang #ifndef CONFIG_TPL_BUILD
rkclk_init(struct rk322x_clk_priv * priv)953809e91fdSElaine Zhang static void rkclk_init(struct rk322x_clk_priv *priv)
954809e91fdSElaine Zhang {
955809e91fdSElaine Zhang 	struct rk322x_cru *cru = priv->cru;
956809e91fdSElaine Zhang 
957809e91fdSElaine Zhang 	if (rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
958809e91fdSElaine Zhang 				  priv->cru, APLL) != APLL_HZ)
959809e91fdSElaine Zhang 		rk322x_armclk_set_clk(priv, APLL_HZ);
960809e91fdSElaine Zhang 
961809e91fdSElaine Zhang 	priv->gpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[GPLL],
962809e91fdSElaine Zhang 					      priv->cru, GPLL);
963809e91fdSElaine Zhang 	priv->cpll_hz = rockchip_pll_get_rate(&rk322x_pll_clks[CPLL],
964809e91fdSElaine Zhang 					      priv->cru, CPLL);
965809e91fdSElaine Zhang 
966809e91fdSElaine Zhang 	/* before set pll set child div first */
967809e91fdSElaine Zhang 	rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ / 4);
968809e91fdSElaine Zhang 	rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ / 4);
969809e91fdSElaine Zhang 	rk322x_mmc_set_clk(priv, SCLK_EMMC, 50000000);
970809e91fdSElaine Zhang 	rk322x_mmc_set_clk(priv, SCLK_SDMMC, 50000000);
971809e91fdSElaine Zhang 	rk322x_mmc_set_clk(priv, SCLK_SDIO, 50000000);
972809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[2], (0x1 << 14) |
973809e91fdSElaine Zhang 		     (0x1f << 8), (1 << 14) | (0xb << 8));
974809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[23], (0x1f << 0) | (0x1f << 8),
975809e91fdSElaine Zhang 		     (0x1f << 0) | (5 << 8));
976809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[33],
977809e91fdSElaine Zhang 		     ACLK_VOP_PLL_SEL_MASK | ACLK_VOP_DIV_CON_MASK,
978809e91fdSElaine Zhang 		     ACLK_VOP_PLL_SEL_GPLL << ACLK_VOP_PLL_SEL_SHIFT |
979809e91fdSElaine Zhang 		     3 << ACLK_VOP_DIV_CON_SHIFT);
980809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[22], 0x1f << 0, 5 << 0);
981809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[24], 0x1f << 0, 0xb << 0);
982809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[28], (0x1f << 8) | (0x1f << 0),
983809e91fdSElaine Zhang 		     (5 << 8) | (5 << 0));
984809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[31], (0x1f << 8) | (0x1f << 0),
985809e91fdSElaine Zhang 		     (5 << 8) | (5 << 0));
986809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[32], 0x1f << 0, 5 << 0);
987809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[33], (0x1f << 8) | (0x1f << 0),
988809e91fdSElaine Zhang 		     (5 << 8) | (5 << 0));
989809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_clksel_con[34], (0x1f << 8) | (0x1f << 0),
990809e91fdSElaine Zhang 		     (5 << 8) | (3 << 0));
991809e91fdSElaine Zhang 
992809e91fdSElaine Zhang 	rockchip_pll_set_rate(&rk322x_pll_clks[GPLL],
993809e91fdSElaine Zhang 			      priv->cru, GPLL, GPLL_HZ);
994809e91fdSElaine Zhang 	priv->gpll_hz = GPLL_HZ;
995809e91fdSElaine Zhang 
996809e91fdSElaine Zhang 	rockchip_pll_set_rate(&rk322x_pll_clks[CPLL],
997809e91fdSElaine Zhang 			      priv->cru, CPLL, CPLL_HZ);
998809e91fdSElaine Zhang 	priv->cpll_hz = CPLL_HZ;
999809e91fdSElaine Zhang 
1000809e91fdSElaine Zhang 	rk322x_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ);
1001809e91fdSElaine Zhang 	rk322x_bus_set_clk(priv, HCLK_CPU, ACLK_BUS_HZ / 2);
1002809e91fdSElaine Zhang 	rk322x_bus_set_clk(priv, PCLK_CPU, ACLK_BUS_HZ / 2);
1003809e91fdSElaine Zhang 	rk322x_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ);
1004809e91fdSElaine Zhang 	rk322x_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2);
1005809e91fdSElaine Zhang 	rk322x_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2);
1006809e91fdSElaine Zhang 	/*rk322x_mmc_set_clk(priv, SCLK_EMMC, rate);*/
1007809e91fdSElaine Zhang 
1008809e91fdSElaine Zhang 	/* set usbphy and hdmiphy from phy */
1009809e91fdSElaine Zhang 	rk_clrsetreg(&cru->cru_misc_con, (0x1 << 13) |
1010809e91fdSElaine Zhang 		     (0x1 << 15), (0 << 15) | (0 << 13));
1011809e91fdSElaine Zhang }
1012c93db2f3SKever Yang #endif
1013809e91fdSElaine Zhang 
rk322x_clk_probe(struct udevice * dev)1014045029cbSKever Yang static int rk322x_clk_probe(struct udevice *dev)
1015045029cbSKever Yang {
1016c93db2f3SKever Yang #ifndef CONFIG_TPL_BUILD
1017045029cbSKever Yang 	struct rk322x_clk_priv *priv = dev_get_priv(dev);
1018e9dcade2SElaine Zhang 	int ret = 0;
1019e9dcade2SElaine Zhang 
10202401c256SElaine Zhang 	priv->sync_kernel = false;
10212401c256SElaine Zhang 	if (!priv->armclk_enter_hz)
10222401c256SElaine Zhang 		priv->armclk_enter_hz =
10232401c256SElaine Zhang 		rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
10242401c256SElaine Zhang 				      priv->cru, APLL);
1025809e91fdSElaine Zhang 	rkclk_init(priv);
10262401c256SElaine Zhang 	if (!priv->armclk_init_hz)
10272401c256SElaine Zhang 		priv->armclk_init_hz =
10282401c256SElaine Zhang 		rockchip_pll_get_rate(&rk322x_pll_clks[APLL],
10292401c256SElaine Zhang 				      priv->cru, APLL);
1030e9dcade2SElaine Zhang 	ret = clk_set_defaults(dev);
1031e9dcade2SElaine Zhang 	if (ret)
1032e9dcade2SElaine Zhang 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
10332401c256SElaine Zhang 	else
10342401c256SElaine Zhang 		priv->sync_kernel = true;
1035c93db2f3SKever Yang #endif
1036045029cbSKever Yang 	return 0;
1037045029cbSKever Yang }
1038045029cbSKever Yang 
rk322x_clk_bind(struct udevice * dev)1039045029cbSKever Yang static int rk322x_clk_bind(struct udevice *dev)
1040045029cbSKever Yang {
1041045029cbSKever Yang 	int ret;
10423d555d75SElaine Zhang 	struct udevice *sys_child, *sf_child;
1043fbdd1558SKever Yang 	struct sysreset_reg *priv;
10443d555d75SElaine Zhang 	struct softreset_reg *sf_priv;
1045045029cbSKever Yang 
1046045029cbSKever Yang 	/* The reset driver does not have a device node, so bind it here */
1047fbdd1558SKever Yang 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1048fbdd1558SKever Yang 				 &sys_child);
1049fbdd1558SKever Yang 	if (ret) {
1050fbdd1558SKever Yang 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1051fbdd1558SKever Yang 	} else {
1052fbdd1558SKever Yang 		priv = malloc(sizeof(struct sysreset_reg));
1053fbdd1558SKever Yang 		priv->glb_srst_fst_value = offsetof(struct rk322x_cru,
1054fbdd1558SKever Yang 						    cru_glb_srst_fst_value);
1055fbdd1558SKever Yang 		priv->glb_srst_snd_value = offsetof(struct rk322x_cru,
1056fbdd1558SKever Yang 						    cru_glb_srst_snd_value);
1057fbdd1558SKever Yang 		sys_child->priv = priv;
1058fbdd1558SKever Yang 	}
1059045029cbSKever Yang 
10603d555d75SElaine Zhang 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
10613d555d75SElaine Zhang 					 dev_ofnode(dev), &sf_child);
10623d555d75SElaine Zhang 	if (ret) {
10633d555d75SElaine Zhang 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
10643d555d75SElaine Zhang 	} else {
10653d555d75SElaine Zhang 		sf_priv = malloc(sizeof(struct softreset_reg));
10663d555d75SElaine Zhang 		sf_priv->sf_reset_offset = offsetof(struct rk322x_cru,
10673d555d75SElaine Zhang 						    cru_softrst_con[0]);
10683d555d75SElaine Zhang 		sf_priv->sf_reset_num = 9;
10693d555d75SElaine Zhang 		sf_child->priv = sf_priv;
10703d555d75SElaine Zhang 	}
10713d555d75SElaine Zhang 
1072045029cbSKever Yang 	return 0;
1073045029cbSKever Yang }
1074045029cbSKever Yang 
1075045029cbSKever Yang static const struct udevice_id rk322x_clk_ids[] = {
1076045029cbSKever Yang 	{ .compatible = "rockchip,rk3228-cru" },
1077045029cbSKever Yang 	{ }
1078045029cbSKever Yang };
1079045029cbSKever Yang 
1080045029cbSKever Yang U_BOOT_DRIVER(rockchip_rk322x_cru) = {
1081045029cbSKever Yang 	.name		= "clk_rk322x",
1082045029cbSKever Yang 	.id		= UCLASS_CLK,
1083045029cbSKever Yang 	.of_match	= rk322x_clk_ids,
1084045029cbSKever Yang 	.priv_auto_alloc_size = sizeof(struct rk322x_clk_priv),
1085045029cbSKever Yang 	.ofdata_to_platdata = rk322x_clk_ofdata_to_platdata,
1086045029cbSKever Yang 	.ops		= &rk322x_clk_ops,
1087045029cbSKever Yang 	.bind		= rk322x_clk_bind,
1088045029cbSKever Yang 	.probe		= rk322x_clk_probe,
1089045029cbSKever Yang };
1090809e91fdSElaine Zhang 
1091809e91fdSElaine Zhang #ifndef CONFIG_SPL_BUILD
1092809e91fdSElaine Zhang /**
1093809e91fdSElaine Zhang  * soc_clk_dump() - Print clock frequencies
1094809e91fdSElaine Zhang  * Returns zero on success
1095809e91fdSElaine Zhang  *
1096809e91fdSElaine Zhang  * Implementation for the clk dump command.
1097809e91fdSElaine Zhang  */
soc_clk_dump(void)1098809e91fdSElaine Zhang int soc_clk_dump(void)
1099809e91fdSElaine Zhang {
1100809e91fdSElaine Zhang 	struct udevice *cru_dev;
11012401c256SElaine Zhang 	struct rk322x_clk_priv *priv;
1102809e91fdSElaine Zhang 	const struct rk322x_clk_info *clk_dump;
1103809e91fdSElaine Zhang 	struct clk clk;
1104809e91fdSElaine Zhang 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
1105809e91fdSElaine Zhang 	unsigned long rate;
1106809e91fdSElaine Zhang 	int i, ret;
1107809e91fdSElaine Zhang 
1108809e91fdSElaine Zhang 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1109809e91fdSElaine Zhang 					  DM_GET_DRIVER(rockchip_rk322x_cru),
1110809e91fdSElaine Zhang 					  &cru_dev);
1111809e91fdSElaine Zhang 	if (ret) {
1112809e91fdSElaine Zhang 		printf("%s failed to get cru device\n", __func__);
1113809e91fdSElaine Zhang 		return ret;
1114809e91fdSElaine Zhang 	}
1115809e91fdSElaine Zhang 
11162401c256SElaine Zhang 	priv = dev_get_priv(cru_dev);
11172401c256SElaine Zhang 	printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
11182401c256SElaine Zhang 	       priv->sync_kernel ? "sync kernel" : "uboot",
11192401c256SElaine Zhang 	       priv->armclk_enter_hz / 1000,
11202401c256SElaine Zhang 	       priv->armclk_init_hz / 1000,
11212401c256SElaine Zhang 	       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
11222401c256SElaine Zhang 	       priv->set_armclk_rate ? " KHz" : "N/A");
1123809e91fdSElaine Zhang 	for (i = 0; i < clk_count; i++) {
1124809e91fdSElaine Zhang 		clk_dump = &clks_dump[i];
1125809e91fdSElaine Zhang 		if (clk_dump->name) {
1126809e91fdSElaine Zhang 			clk.id = clk_dump->id;
1127809e91fdSElaine Zhang 			if (clk_dump->is_cru)
1128809e91fdSElaine Zhang 				ret = clk_request(cru_dev, &clk);
1129809e91fdSElaine Zhang 			if (ret < 0)
1130809e91fdSElaine Zhang 				return ret;
1131809e91fdSElaine Zhang 
1132809e91fdSElaine Zhang 			rate = clk_get_rate(&clk);
1133809e91fdSElaine Zhang 			clk_free(&clk);
1134809e91fdSElaine Zhang 			if (i == 0) {
1135809e91fdSElaine Zhang 				if (rate < 0)
11362401c256SElaine Zhang 					printf("  %s %s\n", clk_dump->name,
1137809e91fdSElaine Zhang 					       "unknown");
1138809e91fdSElaine Zhang 				else
11392401c256SElaine Zhang 					printf("  %s %lu KHz\n", clk_dump->name,
11402401c256SElaine Zhang 					       rate / 1000);
1141809e91fdSElaine Zhang 			} else {
1142809e91fdSElaine Zhang 				if (rate < 0)
11432401c256SElaine Zhang 					printf("  %s %s\n", clk_dump->name,
1144809e91fdSElaine Zhang 					       "unknown");
1145809e91fdSElaine Zhang 				else
11462401c256SElaine Zhang 					printf("  %s %lu KHz\n", clk_dump->name,
11472401c256SElaine Zhang 					       rate / 1000);
1148809e91fdSElaine Zhang 			}
1149809e91fdSElaine Zhang 		}
1150809e91fdSElaine Zhang 	}
1151809e91fdSElaine Zhang 
1152809e91fdSElaine Zhang 	return 0;
1153809e91fdSElaine Zhang }
1154809e91fdSElaine Zhang #endif
1155809e91fdSElaine Zhang 
1156