xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk322x.c (revision eecd6f34aec4e117fe54976a792ac1aa20d32ad8)
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 enum {
23045029cbSKever Yang 	VCO_MAX_HZ	= 3200U * 1000000,
24045029cbSKever Yang 	VCO_MIN_HZ	= 800 * 1000000,
25045029cbSKever Yang 	OUTPUT_MAX_HZ	= 3200U * 1000000,
26045029cbSKever Yang 	OUTPUT_MIN_HZ	= 24 * 1000000,
27045029cbSKever Yang };
28045029cbSKever Yang 
29045029cbSKever Yang #define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
30045029cbSKever Yang 
31045029cbSKever Yang #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
32045029cbSKever Yang 	.refdiv = _refdiv,\
33045029cbSKever Yang 	.fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ), \
34045029cbSKever Yang 	.postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
35045029cbSKever Yang 	_Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) * \
36045029cbSKever Yang 			 OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz, \
37045029cbSKever Yang 			 #hz "Hz cannot be hit with PLL "\
38045029cbSKever Yang 			 "divisors on line " __stringify(__LINE__));
39045029cbSKever Yang 
40045029cbSKever Yang /* use integer mode*/
41045029cbSKever Yang static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1);
42045029cbSKever Yang static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1);
43045029cbSKever Yang 
44045029cbSKever Yang static int rkclk_set_pll(struct rk322x_cru *cru, enum rk_clk_id clk_id,
45045029cbSKever Yang 			 const struct pll_div *div)
46045029cbSKever Yang {
47045029cbSKever Yang 	int pll_id = rk_pll_id(clk_id);
48045029cbSKever Yang 	struct rk322x_pll *pll = &cru->pll[pll_id];
49045029cbSKever Yang 
50045029cbSKever Yang 	/* All PLLs have same VCO and output frequency range restrictions. */
51045029cbSKever Yang 	uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000;
52045029cbSKever Yang 	uint output_hz = vco_hz / div->postdiv1 / div->postdiv2;
53045029cbSKever Yang 
54045029cbSKever Yang 	debug("PLL at %p: fb=%d, ref=%d, pst1=%d, pst2=%d, vco=%u Hz, output=%u Hz\n",
55045029cbSKever Yang 	      pll, div->fbdiv, div->refdiv, div->postdiv1,
56045029cbSKever Yang 	      div->postdiv2, vco_hz, output_hz);
57045029cbSKever Yang 	assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
58045029cbSKever Yang 	       output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ);
59045029cbSKever Yang 
60045029cbSKever Yang 	/* use integer mode */
61045029cbSKever Yang 	rk_setreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
62045029cbSKever Yang 	/* Power down */
63045029cbSKever Yang 	rk_setreg(&pll->con1, 1 << PLL_PD_SHIFT);
64045029cbSKever Yang 
65045029cbSKever Yang 	rk_clrsetreg(&pll->con0,
66045029cbSKever Yang 		     PLL_POSTDIV1_MASK | PLL_FBDIV_MASK,
67045029cbSKever Yang 		     (div->postdiv1 << PLL_POSTDIV1_SHIFT) | div->fbdiv);
68045029cbSKever Yang 	rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK | PLL_REFDIV_MASK,
69045029cbSKever Yang 		     (div->postdiv2 << PLL_POSTDIV2_SHIFT |
70045029cbSKever Yang 		     div->refdiv << PLL_REFDIV_SHIFT));
71045029cbSKever Yang 
72045029cbSKever Yang 	/* Power Up */
73045029cbSKever Yang 	rk_clrreg(&pll->con1, 1 << PLL_PD_SHIFT);
74045029cbSKever Yang 
75045029cbSKever Yang 	/* waiting for pll lock */
76045029cbSKever Yang 	while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))
77045029cbSKever Yang 		udelay(1);
78045029cbSKever Yang 
79045029cbSKever Yang 	return 0;
80045029cbSKever Yang }
81045029cbSKever Yang 
82045029cbSKever Yang static void rkclk_init(struct rk322x_cru *cru)
83045029cbSKever Yang {
84045029cbSKever Yang 	u32 aclk_div;
85045029cbSKever Yang 	u32 hclk_div;
86045029cbSKever Yang 	u32 pclk_div;
87045029cbSKever Yang 
88045029cbSKever Yang 	/* pll enter slow-mode */
89045029cbSKever Yang 	rk_clrsetreg(&cru->cru_mode_con,
90045029cbSKever Yang 		     GPLL_MODE_MASK | APLL_MODE_MASK,
91045029cbSKever Yang 		     GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
92045029cbSKever Yang 		     APLL_MODE_SLOW << APLL_MODE_SHIFT);
93045029cbSKever Yang 
94045029cbSKever Yang 	/* init pll */
95045029cbSKever Yang 	rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg);
96045029cbSKever Yang 	rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
97045029cbSKever Yang 
98045029cbSKever Yang 	/*
99045029cbSKever Yang 	 * select apll as cpu/core clock pll source and
100045029cbSKever Yang 	 * set up dependent divisors for PERI and ACLK clocks.
101045029cbSKever Yang 	 * core hz : apll = 1:1
102045029cbSKever Yang 	 */
103045029cbSKever Yang 	aclk_div = APLL_HZ / CORE_ACLK_HZ - 1;
104045029cbSKever Yang 	assert((aclk_div + 1) * CORE_ACLK_HZ == APLL_HZ && aclk_div < 0x7);
105045029cbSKever Yang 
106045029cbSKever Yang 	pclk_div = APLL_HZ / CORE_PERI_HZ - 1;
107045029cbSKever Yang 	assert((pclk_div + 1) * CORE_PERI_HZ == APLL_HZ && pclk_div < 0xf);
108045029cbSKever Yang 
109045029cbSKever Yang 	rk_clrsetreg(&cru->cru_clksel_con[0],
110045029cbSKever Yang 		     CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
111045029cbSKever Yang 		     CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
112045029cbSKever Yang 		     0 << CORE_DIV_CON_SHIFT);
113045029cbSKever Yang 
114045029cbSKever Yang 	rk_clrsetreg(&cru->cru_clksel_con[1],
115045029cbSKever Yang 		     CORE_ACLK_DIV_MASK | CORE_PERI_DIV_MASK,
116045029cbSKever Yang 		     aclk_div << CORE_ACLK_DIV_SHIFT |
117045029cbSKever Yang 		     pclk_div << CORE_PERI_DIV_SHIFT);
118045029cbSKever Yang 
119045029cbSKever Yang 	/*
120f04b6e29SKever Yang 	 * select gpll as pd_bus bus clock source and
121045029cbSKever Yang 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
122045029cbSKever Yang 	 */
123045029cbSKever Yang 	aclk_div = GPLL_HZ / BUS_ACLK_HZ - 1;
124045029cbSKever Yang 	assert((aclk_div + 1) * BUS_ACLK_HZ == GPLL_HZ && aclk_div <= 0x1f);
125045029cbSKever Yang 
126f04b6e29SKever Yang 	pclk_div = BUS_ACLK_HZ / BUS_PCLK_HZ - 1;
127045029cbSKever Yang 	assert((pclk_div + 1) * BUS_PCLK_HZ == GPLL_HZ && pclk_div <= 0x7);
128045029cbSKever Yang 
129f04b6e29SKever Yang 	hclk_div = BUS_ACLK_HZ / BUS_HCLK_HZ - 1;
130045029cbSKever Yang 	assert((hclk_div + 1) * BUS_HCLK_HZ == GPLL_HZ && hclk_div <= 0x3);
131045029cbSKever Yang 
132045029cbSKever Yang 	rk_clrsetreg(&cru->cru_clksel_con[0],
133045029cbSKever Yang 		     BUS_ACLK_PLL_SEL_MASK | BUS_ACLK_DIV_MASK,
134045029cbSKever Yang 		     BUS_ACLK_PLL_SEL_GPLL << BUS_ACLK_PLL_SEL_SHIFT |
135045029cbSKever Yang 		     aclk_div << BUS_ACLK_DIV_SHIFT);
136045029cbSKever Yang 
137045029cbSKever Yang 	rk_clrsetreg(&cru->cru_clksel_con[1],
138045029cbSKever Yang 		     BUS_PCLK_DIV_MASK | BUS_HCLK_DIV_MASK,
139045029cbSKever Yang 		     pclk_div << BUS_PCLK_DIV_SHIFT |
140045029cbSKever Yang 		     hclk_div << BUS_HCLK_DIV_SHIFT);
141045029cbSKever Yang 
142045029cbSKever Yang 	/*
143045029cbSKever Yang 	 * select gpll as pd_peri bus clock source and
144045029cbSKever Yang 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
145045029cbSKever Yang 	 */
146045029cbSKever Yang 	aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
147045029cbSKever Yang 	assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
148045029cbSKever Yang 
149045029cbSKever Yang 	hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ);
150045029cbSKever Yang 	assert((1 << hclk_div) * PERI_HCLK_HZ ==
151045029cbSKever Yang 		PERI_ACLK_HZ && (hclk_div < 0x4));
152045029cbSKever Yang 
153045029cbSKever Yang 	pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ);
154045029cbSKever Yang 	assert((1 << pclk_div) * PERI_PCLK_HZ ==
155045029cbSKever Yang 		PERI_ACLK_HZ && pclk_div < 0x8);
156045029cbSKever Yang 
157045029cbSKever Yang 	rk_clrsetreg(&cru->cru_clksel_con[10],
158045029cbSKever Yang 		     PERI_PLL_SEL_MASK | PERI_PCLK_DIV_MASK |
159045029cbSKever Yang 		     PERI_HCLK_DIV_MASK | PERI_ACLK_DIV_MASK,
160045029cbSKever Yang 		     PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
161045029cbSKever Yang 		     pclk_div << PERI_PCLK_DIV_SHIFT |
162045029cbSKever Yang 		     hclk_div << PERI_HCLK_DIV_SHIFT |
163045029cbSKever Yang 		     aclk_div << PERI_ACLK_DIV_SHIFT);
164045029cbSKever Yang 
165045029cbSKever Yang 	/* PLL enter normal-mode */
166045029cbSKever Yang 	rk_clrsetreg(&cru->cru_mode_con,
167045029cbSKever Yang 		     GPLL_MODE_MASK | APLL_MODE_MASK,
168045029cbSKever Yang 		     GPLL_MODE_NORM << GPLL_MODE_SHIFT |
169045029cbSKever Yang 		     APLL_MODE_NORM << APLL_MODE_SHIFT);
170045029cbSKever Yang }
171045029cbSKever Yang 
172045029cbSKever Yang /* Get pll rate by id */
173045029cbSKever Yang static uint32_t rkclk_pll_get_rate(struct rk322x_cru *cru,
174045029cbSKever Yang 				   enum rk_clk_id clk_id)
175045029cbSKever Yang {
176045029cbSKever Yang 	uint32_t refdiv, fbdiv, postdiv1, postdiv2;
177045029cbSKever Yang 	uint32_t con;
178045029cbSKever Yang 	int pll_id = rk_pll_id(clk_id);
179045029cbSKever Yang 	struct rk322x_pll *pll = &cru->pll[pll_id];
180045029cbSKever Yang 	static u8 clk_shift[CLK_COUNT] = {
181045029cbSKever Yang 		0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, 0xff,
182045029cbSKever Yang 		GPLL_MODE_SHIFT, 0xff
183045029cbSKever Yang 	};
184045029cbSKever Yang 	static u32 clk_mask[CLK_COUNT] = {
185045029cbSKever Yang 		0xff, APLL_MODE_MASK, DPLL_MODE_MASK, 0xff,
186045029cbSKever Yang 		GPLL_MODE_MASK, 0xff
187045029cbSKever Yang 	};
188045029cbSKever Yang 	uint shift;
189045029cbSKever Yang 	uint mask;
190045029cbSKever Yang 
191045029cbSKever Yang 	con = readl(&cru->cru_mode_con);
192045029cbSKever Yang 	shift = clk_shift[clk_id];
193045029cbSKever Yang 	mask = clk_mask[clk_id];
194045029cbSKever Yang 
195045029cbSKever Yang 	switch ((con & mask) >> shift) {
196045029cbSKever Yang 	case GPLL_MODE_SLOW:
197045029cbSKever Yang 		return OSC_HZ;
198045029cbSKever Yang 	case GPLL_MODE_NORM:
199045029cbSKever Yang 
200045029cbSKever Yang 		/* normal mode */
201045029cbSKever Yang 		con = readl(&pll->con0);
202045029cbSKever Yang 		postdiv1 = (con & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
203045029cbSKever Yang 		fbdiv = (con & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
204045029cbSKever Yang 		con = readl(&pll->con1);
205045029cbSKever Yang 		postdiv2 = (con & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
206045029cbSKever Yang 		refdiv = (con & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
207045029cbSKever Yang 		return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
208045029cbSKever Yang 	default:
209045029cbSKever Yang 		return 32768;
210045029cbSKever Yang 	}
211045029cbSKever Yang }
212045029cbSKever Yang 
213045029cbSKever Yang static ulong rockchip_mmc_get_clk(struct rk322x_cru *cru, uint clk_general_rate,
214045029cbSKever Yang 				  int periph)
215045029cbSKever Yang {
216045029cbSKever Yang 	uint src_rate;
217045029cbSKever Yang 	uint div, mux;
218045029cbSKever Yang 	u32 con;
219045029cbSKever Yang 
220045029cbSKever Yang 	switch (periph) {
221045029cbSKever Yang 	case HCLK_EMMC:
222045029cbSKever Yang 	case SCLK_EMMC:
2236c639845SKever Yang 	case SCLK_EMMC_SAMPLE:
224045029cbSKever Yang 		con = readl(&cru->cru_clksel_con[11]);
225045029cbSKever Yang 		mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT;
226045029cbSKever Yang 		con = readl(&cru->cru_clksel_con[12]);
227045029cbSKever Yang 		div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
228045029cbSKever Yang 		break;
229045029cbSKever Yang 	case HCLK_SDMMC:
230045029cbSKever Yang 	case SCLK_SDMMC:
231045029cbSKever Yang 		con = readl(&cru->cru_clksel_con[11]);
232045029cbSKever Yang 		mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT;
233045029cbSKever Yang 		div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT;
234045029cbSKever Yang 		break;
235045029cbSKever Yang 	default:
236045029cbSKever Yang 		return -EINVAL;
237045029cbSKever Yang 	}
238045029cbSKever Yang 
239045029cbSKever Yang 	src_rate = mux == EMMC_SEL_24M ? OSC_HZ : clk_general_rate;
2403a94d75dSKever Yang 	return DIV_TO_RATE(src_rate, div) / 2;
241045029cbSKever Yang }
242045029cbSKever Yang 
243045029cbSKever Yang static ulong rockchip_mmc_set_clk(struct rk322x_cru *cru, uint clk_general_rate,
244045029cbSKever Yang 				  int periph, uint freq)
245045029cbSKever Yang {
246045029cbSKever Yang 	int src_clk_div;
247045029cbSKever Yang 	int mux;
248045029cbSKever Yang 
249045029cbSKever Yang 	debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate);
250045029cbSKever Yang 
2513a94d75dSKever Yang 	/* mmc clock defaulg div 2 internal, need provide double in cru */
2523a94d75dSKever Yang 	src_clk_div = DIV_ROUND_UP(clk_general_rate / 2, freq);
253045029cbSKever Yang 
254217273cdSKever Yang 	if (src_clk_div > 128) {
2553a94d75dSKever Yang 		src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq);
256217273cdSKever Yang 		assert(src_clk_div - 1 < 128);
257045029cbSKever Yang 		mux = EMMC_SEL_24M;
258045029cbSKever Yang 	} else {
259045029cbSKever Yang 		mux = EMMC_SEL_GPLL;
260045029cbSKever Yang 	}
261045029cbSKever Yang 
262045029cbSKever Yang 	switch (periph) {
263045029cbSKever Yang 	case HCLK_EMMC:
264045029cbSKever Yang 	case SCLK_EMMC:
2656c639845SKever Yang 	case SCLK_EMMC_SAMPLE:
266045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[11],
267045029cbSKever Yang 			     EMMC_PLL_MASK,
268045029cbSKever Yang 			     mux << EMMC_PLL_SHIFT);
269045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[12],
270045029cbSKever Yang 			     EMMC_DIV_MASK,
271045029cbSKever Yang 			     (src_clk_div - 1) << EMMC_DIV_SHIFT);
272045029cbSKever Yang 		break;
273045029cbSKever Yang 	case HCLK_SDMMC:
274045029cbSKever Yang 	case SCLK_SDMMC:
275045029cbSKever Yang 		rk_clrsetreg(&cru->cru_clksel_con[11],
276045029cbSKever Yang 			     MMC0_PLL_MASK | MMC0_DIV_MASK,
277045029cbSKever Yang 			     mux << MMC0_PLL_SHIFT |
278045029cbSKever Yang 			     (src_clk_div - 1) << MMC0_DIV_SHIFT);
279045029cbSKever Yang 		break;
280045029cbSKever Yang 	default:
281045029cbSKever Yang 		return -EINVAL;
282045029cbSKever Yang 	}
283045029cbSKever Yang 
284045029cbSKever Yang 	return rockchip_mmc_get_clk(cru, clk_general_rate, periph);
285045029cbSKever Yang }
286045029cbSKever Yang 
287045029cbSKever Yang static int rk322x_ddr_set_clk(struct rk322x_cru *cru, unsigned int set_rate)
288045029cbSKever Yang {
289045029cbSKever Yang 	struct pll_div dpll_cfg;
290045029cbSKever Yang 
291045029cbSKever Yang 	/*  clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
292045029cbSKever Yang 	switch (set_rate) {
293045029cbSKever Yang 	case 400*MHz:
294045029cbSKever Yang 		dpll_cfg = (struct pll_div)
295045029cbSKever Yang 		{.refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1};
296045029cbSKever Yang 		break;
297045029cbSKever Yang 	case 600*MHz:
298045029cbSKever Yang 		dpll_cfg = (struct pll_div)
299045029cbSKever Yang 		{.refdiv = 1, .fbdiv = 75, .postdiv1 = 3, .postdiv2 = 1};
300045029cbSKever Yang 		break;
301045029cbSKever Yang 	case 800*MHz:
302045029cbSKever Yang 		dpll_cfg = (struct pll_div)
303045029cbSKever Yang 		{.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1};
304045029cbSKever Yang 		break;
305045029cbSKever Yang 	}
306045029cbSKever Yang 
307045029cbSKever Yang 	/* pll enter slow-mode */
308045029cbSKever Yang 	rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
309045029cbSKever Yang 		     DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
310045029cbSKever Yang 	rkclk_set_pll(cru, CLK_DDR, &dpll_cfg);
311045029cbSKever Yang 	/* PLL enter normal-mode */
312045029cbSKever Yang 	rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
313045029cbSKever Yang 		     DPLL_MODE_NORM << DPLL_MODE_SHIFT);
314045029cbSKever Yang 
315045029cbSKever Yang 	return set_rate;
316045029cbSKever Yang }
317*eecd6f34SZhangbin Tong 
318*eecd6f34SZhangbin Tong static ulong rk322x_get_bus_aclk(struct rk322x_cru *cru, ulong gclk_rate)
319*eecd6f34SZhangbin Tong {
320*eecd6f34SZhangbin Tong 	u32 con;
321*eecd6f34SZhangbin Tong 	u32 aclk_div;
322*eecd6f34SZhangbin Tong 
323*eecd6f34SZhangbin Tong 	con = readl(&cru->cru_clksel_con[0]);
324*eecd6f34SZhangbin Tong 	aclk_div = ((con & BUS_ACLK_DIV_MASK) >> BUS_ACLK_DIV_SHIFT) + 1;
325*eecd6f34SZhangbin Tong 
326*eecd6f34SZhangbin Tong 	return gclk_rate / aclk_div;
327*eecd6f34SZhangbin Tong }
328*eecd6f34SZhangbin Tong 
329*eecd6f34SZhangbin Tong static ulong rk322x_get_bus_pclk(struct rk322x_cru *cru, ulong gclk_rate)
330*eecd6f34SZhangbin Tong {
331*eecd6f34SZhangbin Tong 	u32 con;
332*eecd6f34SZhangbin Tong 	u32 pclk_div;
333*eecd6f34SZhangbin Tong 
334*eecd6f34SZhangbin Tong 	con = readl(&cru->cru_clksel_con[1]);
335*eecd6f34SZhangbin Tong 	pclk_div = ((con & BUS_PCLK_DIV_MASK) >> BUS_PCLK_DIV_SHIFT) + 1;
336*eecd6f34SZhangbin Tong 
337*eecd6f34SZhangbin Tong 	return rk322x_get_bus_aclk(cru, gclk_rate) / pclk_div;
338*eecd6f34SZhangbin Tong }
339*eecd6f34SZhangbin Tong 
340045029cbSKever Yang static ulong rk322x_clk_get_rate(struct clk *clk)
341045029cbSKever Yang {
342045029cbSKever Yang 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
343045029cbSKever Yang 	ulong rate, gclk_rate;
344045029cbSKever Yang 
345045029cbSKever Yang 	gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
346045029cbSKever Yang 	switch (clk->id) {
347045029cbSKever Yang 	case 0 ... 63:
348045029cbSKever Yang 		rate = rkclk_pll_get_rate(priv->cru, clk->id);
349045029cbSKever Yang 		break;
350045029cbSKever Yang 	case HCLK_EMMC:
351045029cbSKever Yang 	case SCLK_EMMC:
352045029cbSKever Yang 	case HCLK_SDMMC:
353045029cbSKever Yang 	case SCLK_SDMMC:
354045029cbSKever Yang 		rate = rockchip_mmc_get_clk(priv->cru, gclk_rate, clk->id);
355045029cbSKever Yang 		break;
356*eecd6f34SZhangbin Tong 	case PCLK_GPIO0 ... PCLK_TIMER:
357*eecd6f34SZhangbin Tong 		rate = rk322x_get_bus_pclk(priv->cru, gclk_rate);
358*eecd6f34SZhangbin Tong 		break;
359045029cbSKever Yang 	default:
360045029cbSKever Yang 		return -ENOENT;
361045029cbSKever Yang 	}
362045029cbSKever Yang 
363045029cbSKever Yang 	return rate;
364045029cbSKever Yang }
365045029cbSKever Yang 
366045029cbSKever Yang static ulong rk322x_clk_set_rate(struct clk *clk, ulong rate)
367045029cbSKever Yang {
368045029cbSKever Yang 	struct rk322x_clk_priv *priv = dev_get_priv(clk->dev);
369045029cbSKever Yang 	ulong new_rate, gclk_rate;
370045029cbSKever Yang 
371045029cbSKever Yang 	gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
372045029cbSKever Yang 	switch (clk->id) {
373045029cbSKever Yang 	case HCLK_EMMC:
374045029cbSKever Yang 	case SCLK_EMMC:
375045029cbSKever Yang 	case HCLK_SDMMC:
376045029cbSKever Yang 	case SCLK_SDMMC:
377045029cbSKever Yang 		new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate,
378045029cbSKever Yang 						clk->id, rate);
379045029cbSKever Yang 		break;
380045029cbSKever Yang 	case CLK_DDR:
381045029cbSKever Yang 		new_rate = rk322x_ddr_set_clk(priv->cru, rate);
382045029cbSKever Yang 		break;
383045029cbSKever Yang 	default:
384045029cbSKever Yang 		return -ENOENT;
385045029cbSKever Yang 	}
386045029cbSKever Yang 
387045029cbSKever Yang 	return new_rate;
388045029cbSKever Yang }
389045029cbSKever Yang 
390045029cbSKever Yang static struct clk_ops rk322x_clk_ops = {
391045029cbSKever Yang 	.get_rate	= rk322x_clk_get_rate,
392045029cbSKever Yang 	.set_rate	= rk322x_clk_set_rate,
393045029cbSKever Yang };
394045029cbSKever Yang 
395045029cbSKever Yang static int rk322x_clk_ofdata_to_platdata(struct udevice *dev)
396045029cbSKever Yang {
397045029cbSKever Yang 	struct rk322x_clk_priv *priv = dev_get_priv(dev);
398045029cbSKever Yang 
399045029cbSKever Yang 	priv->cru = (struct rk322x_cru *)devfdt_get_addr(dev);
400045029cbSKever Yang 
401045029cbSKever Yang 	return 0;
402045029cbSKever Yang }
403045029cbSKever Yang 
404045029cbSKever Yang static int rk322x_clk_probe(struct udevice *dev)
405045029cbSKever Yang {
406045029cbSKever Yang 	struct rk322x_clk_priv *priv = dev_get_priv(dev);
407045029cbSKever Yang 
408045029cbSKever Yang 	rkclk_init(priv->cru);
409045029cbSKever Yang 
410045029cbSKever Yang 	return 0;
411045029cbSKever Yang }
412045029cbSKever Yang 
413045029cbSKever Yang static int rk322x_clk_bind(struct udevice *dev)
414045029cbSKever Yang {
415045029cbSKever Yang 	int ret;
416045029cbSKever Yang 
417045029cbSKever Yang 	/* The reset driver does not have a device node, so bind it here */
418045029cbSKever Yang 	ret = device_bind_driver(gd->dm_root, "rk322x_sysreset", "reset", &dev);
419045029cbSKever Yang 	if (ret)
4206c9bca3cSKever Yang 		debug("Warning: No RK322x reset driver: ret=%d\n", ret);
421045029cbSKever Yang 
422045029cbSKever Yang 	return 0;
423045029cbSKever Yang }
424045029cbSKever Yang 
425045029cbSKever Yang static const struct udevice_id rk322x_clk_ids[] = {
426045029cbSKever Yang 	{ .compatible = "rockchip,rk3228-cru" },
427045029cbSKever Yang 	{ }
428045029cbSKever Yang };
429045029cbSKever Yang 
430045029cbSKever Yang U_BOOT_DRIVER(rockchip_rk322x_cru) = {
431045029cbSKever Yang 	.name		= "clk_rk322x",
432045029cbSKever Yang 	.id		= UCLASS_CLK,
433045029cbSKever Yang 	.of_match	= rk322x_clk_ids,
434045029cbSKever Yang 	.priv_auto_alloc_size = sizeof(struct rk322x_clk_priv),
435045029cbSKever Yang 	.ofdata_to_platdata = rk322x_clk_ofdata_to_platdata,
436045029cbSKever Yang 	.ops		= &rk322x_clk_ops,
437045029cbSKever Yang 	.bind		= rk322x_clk_bind,
438045029cbSKever Yang 	.probe		= rk322x_clk_probe,
439045029cbSKever Yang };
440