xref: /OK3568_Linux_fs/u-boot/drivers/clk/rockchip/clk_rk3066.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2015 Google, Inc
3*4882a593Smuzhiyun  * (C) Copyright 2016 Heiko Stuebner <heiko@sntech.de>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <clk-uclass.h>
10*4882a593Smuzhiyun #include <dm.h>
11*4882a593Smuzhiyun #include <dt-structs.h>
12*4882a593Smuzhiyun #include <errno.h>
13*4882a593Smuzhiyun #include <mapmem.h>
14*4882a593Smuzhiyun #include <syscon.h>
15*4882a593Smuzhiyun #include <asm/io.h>
16*4882a593Smuzhiyun #include <asm/arch/clock.h>
17*4882a593Smuzhiyun #include <asm/arch/cru_rk3066.h>
18*4882a593Smuzhiyun #include <asm/arch/grf_rk3066.h>
19*4882a593Smuzhiyun #include <asm/arch/hardware.h>
20*4882a593Smuzhiyun #include <dt-bindings/clock/rk3066a-cru.h>
21*4882a593Smuzhiyun #include <dm/device-internal.h>
22*4882a593Smuzhiyun #include <dm/lists.h>
23*4882a593Smuzhiyun #include <dm/uclass-internal.h>
24*4882a593Smuzhiyun #include <linux/log2.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun enum rk3066_clk_type {
29*4882a593Smuzhiyun 	RK3066_CRU,
30*4882a593Smuzhiyun 	RK3066A_CRU,
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun struct rk3066_clk_plat {
34*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_PLATDATA)
35*4882a593Smuzhiyun 	struct dtd_rockchip_rk3066a_cru dtd;
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #ifndef CONFIG_SPL_BUILD
40*4882a593Smuzhiyun #define RK3066_CLK_DUMP(_id, _name, _iscru)	\
41*4882a593Smuzhiyun {						\
42*4882a593Smuzhiyun 	.id = _id,				\
43*4882a593Smuzhiyun 	.name = _name,				\
44*4882a593Smuzhiyun 	.is_cru = _iscru,			\
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun static const struct rk3066_clk_info clks_dump[] = {
48*4882a593Smuzhiyun 	RK3066_CLK_DUMP(PLL_APLL, "apll", true),
49*4882a593Smuzhiyun 	RK3066_CLK_DUMP(PLL_DPLL, "dpll", true),
50*4882a593Smuzhiyun 	RK3066_CLK_DUMP(PLL_GPLL, "gpll", true),
51*4882a593Smuzhiyun 	RK3066_CLK_DUMP(PLL_CPLL, "cpll", true),
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun #endif
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun struct pll_div {
56*4882a593Smuzhiyun 	u32 nr;
57*4882a593Smuzhiyun 	u32 nf;
58*4882a593Smuzhiyun 	u32 no;
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun enum {
62*4882a593Smuzhiyun 	VCO_MAX_HZ	= 1416U * 1000000,
63*4882a593Smuzhiyun 	VCO_MIN_HZ	= 300 * 1000000,
64*4882a593Smuzhiyun 	OUTPUT_MAX_HZ	= 1416U * 1000000,
65*4882a593Smuzhiyun 	OUTPUT_MIN_HZ	= 30 * 1000000,
66*4882a593Smuzhiyun 	FREF_MAX_HZ	= 1416U * 1000000,
67*4882a593Smuzhiyun 	FREF_MIN_HZ	= 30 * 1000,
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun enum {
71*4882a593Smuzhiyun 	/* PLL CON0 */
72*4882a593Smuzhiyun 	PLL_OD_MASK		= 0x0f,
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	/* PLL CON1 */
75*4882a593Smuzhiyun 	PLL_NF_MASK		= 0x1fff,
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	/* PLL CON2 */
78*4882a593Smuzhiyun 	PLL_BWADJ_MASK		= 0x0fff,
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	/* PLL CON3 */
81*4882a593Smuzhiyun 	PLL_RESET_SHIFT		= 5,
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	/* GRF_SOC_STATUS0 */
84*4882a593Smuzhiyun 	SOCSTS_DPLL_LOCK	= 1 << 4,
85*4882a593Smuzhiyun 	SOCSTS_APLL_LOCK	= 1 << 5,
86*4882a593Smuzhiyun 	SOCSTS_CPLL_LOCK	= 1 << 6,
87*4882a593Smuzhiyun 	SOCSTS_GPLL_LOCK	= 1 << 7,
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #define RATE_TO_DIV(input_rate, output_rate) \
91*4882a593Smuzhiyun 	((input_rate) / (output_rate) - 1);
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun #define DIV_TO_RATE(input_rate, div)	((input_rate) / ((div) + 1))
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun #define PLL_DIVISORS(hz, _nr, _no) {\
96*4882a593Smuzhiyun 	.nr = _nr, .nf = (u32)((u64)hz * _nr * _no / OSC_HZ), .no = _no};\
97*4882a593Smuzhiyun 	_Static_assert(((u64)hz * _nr * _no / OSC_HZ) * OSC_HZ /\
98*4882a593Smuzhiyun 		       (_nr * _no) == hz, #hz "Hz cannot be hit with PLL "\
99*4882a593Smuzhiyun 		       "divisors on line " __stringify(__LINE__));
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /* Keep divisors as low as possible to reduce jitter and power usage */
102*4882a593Smuzhiyun #ifdef CONFIG_TPL_BUILD
103*4882a593Smuzhiyun static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2);
104*4882a593Smuzhiyun static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2);
105*4882a593Smuzhiyun #endif
106*4882a593Smuzhiyun 
rkclk_set_pll(struct rk3066_cru * cru,enum rk_clk_id clk_id,const struct pll_div * div,bool has_bwadj)107*4882a593Smuzhiyun static int rkclk_set_pll(struct rk3066_cru *cru, enum rk_clk_id clk_id,
108*4882a593Smuzhiyun 			 const struct pll_div *div, bool has_bwadj)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	int pll_id = rk_pll_id(clk_id);
111*4882a593Smuzhiyun 	struct rk3066_pll *pll = &cru->pll[pll_id];
112*4882a593Smuzhiyun 	/* All PLLs have same VCO and output frequency range restrictions. */
113*4882a593Smuzhiyun 	uint vco_hz = OSC_HZ / 1000 * div->nf / div->nr * 1000;
114*4882a593Smuzhiyun 	uint output_hz = vco_hz / div->no;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	debug("PLL at %x: nf=%d, nr=%d, no=%d, vco=%u Hz, output=%u Hz\n",
117*4882a593Smuzhiyun 	      (uint)pll, div->nf, div->nr, div->no, vco_hz, output_hz);
118*4882a593Smuzhiyun 	assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
119*4882a593Smuzhiyun 	       output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ &&
120*4882a593Smuzhiyun 	       (div->no == 1 || !(div->no % 2)));
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	/* enter reset */
123*4882a593Smuzhiyun 	rk_setreg(&pll->con3, 1 << PLL_RESET_SHIFT);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	rk_clrsetreg(&pll->con0,
126*4882a593Smuzhiyun 		     CLKR_MASK | PLL_OD_MASK,
127*4882a593Smuzhiyun 		     ((div->nr - 1) << CLKR_SHIFT) | (div->no - 1));
128*4882a593Smuzhiyun 	rk_clrsetreg(&pll->con1, CLKF_MASK, div->nf - 1);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (has_bwadj)
131*4882a593Smuzhiyun 		rk_clrsetreg(&pll->con2, PLL_BWADJ_MASK, (div->nf >> 1) - 1);
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	udelay(10);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/* return from reset */
136*4882a593Smuzhiyun 	rk_clrreg(&pll->con3, 1 << PLL_RESET_SHIFT);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	return 0;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
rkclk_configure_ddr(struct rk3066_cru * cru,struct rk3066_grf * grf,unsigned int hz,bool has_bwadj)141*4882a593Smuzhiyun static int rkclk_configure_ddr(struct rk3066_cru *cru, struct rk3066_grf *grf,
142*4882a593Smuzhiyun 			       unsigned int hz, bool has_bwadj)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	static const struct pll_div dpll_cfg[] = {
145*4882a593Smuzhiyun 		{.nf = 25, .nr = 2, .no = 1},
146*4882a593Smuzhiyun 		{.nf = 400, .nr = 9, .no = 2},
147*4882a593Smuzhiyun 		{.nf = 500, .nr = 9, .no = 2},
148*4882a593Smuzhiyun 		{.nf = 100, .nr = 3, .no = 1},
149*4882a593Smuzhiyun 	};
150*4882a593Smuzhiyun 	int cfg;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	switch (hz) {
153*4882a593Smuzhiyun 	case 300000000:
154*4882a593Smuzhiyun 		cfg = 0;
155*4882a593Smuzhiyun 		break;
156*4882a593Smuzhiyun 	case 533000000:	/* actually 533.3P MHz */
157*4882a593Smuzhiyun 		cfg = 1;
158*4882a593Smuzhiyun 		break;
159*4882a593Smuzhiyun 	case 666000000:	/* actually 666.6P MHz */
160*4882a593Smuzhiyun 		cfg = 2;
161*4882a593Smuzhiyun 		break;
162*4882a593Smuzhiyun 	case 800000000:
163*4882a593Smuzhiyun 		cfg = 3;
164*4882a593Smuzhiyun 		break;
165*4882a593Smuzhiyun 	default:
166*4882a593Smuzhiyun 		debug("Unsupported SDRAM frequency");
167*4882a593Smuzhiyun 		return -EINVAL;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	/* pll enter slow-mode */
171*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
172*4882a593Smuzhiyun 		     DPLL_MODE_SLOW << DPLL_MODE_SHIFT);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	rkclk_set_pll(cru, CLK_DDR, &dpll_cfg[cfg], has_bwadj);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/* wait for pll lock */
177*4882a593Smuzhiyun 	while (!(readl(&grf->soc_status0) & SOCSTS_DPLL_LOCK))
178*4882a593Smuzhiyun 		udelay(1);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	/* PLL enter normal-mode */
181*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_mode_con, DPLL_MODE_MASK,
182*4882a593Smuzhiyun 		     DPLL_MODE_NORMAL << DPLL_MODE_SHIFT);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	return 0;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
rkclk_configure_cpu(struct rk3066_cru * cru,struct rk3066_grf * grf,unsigned int hz,bool has_bwadj)187*4882a593Smuzhiyun static int rkclk_configure_cpu(struct rk3066_cru *cru, struct rk3066_grf *grf,
188*4882a593Smuzhiyun 			      unsigned int hz, bool has_bwadj)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	static const struct pll_div apll_cfg[] = {
191*4882a593Smuzhiyun 		{.nf = 50, .nr = 1, .no = 2},
192*4882a593Smuzhiyun 		{.nf = 59, .nr = 1, .no = 1},
193*4882a593Smuzhiyun 	};
194*4882a593Smuzhiyun 	int div_core_peri, div_aclk_core, cfg;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	/*
197*4882a593Smuzhiyun 	 * We support two possible frequencies, the safe 600MHz
198*4882a593Smuzhiyun 	 * which will work with default pmic settings and will
199*4882a593Smuzhiyun 	 * be set to get away from the 24MHz default and
200*4882a593Smuzhiyun 	 * the maximum of 1.416Ghz, which boards can set if they
201*4882a593Smuzhiyun 	 * were able to get pmic support for it.
202*4882a593Smuzhiyun 	 */
203*4882a593Smuzhiyun 	switch (hz) {
204*4882a593Smuzhiyun 	case APLL_SAFE_HZ:
205*4882a593Smuzhiyun 		cfg = 0;
206*4882a593Smuzhiyun 		div_core_peri = 1;
207*4882a593Smuzhiyun 		div_aclk_core = 3;
208*4882a593Smuzhiyun 		break;
209*4882a593Smuzhiyun 	case APLL_HZ:
210*4882a593Smuzhiyun 		cfg = 1;
211*4882a593Smuzhiyun 		div_core_peri = 2;
212*4882a593Smuzhiyun 		div_aclk_core = 3;
213*4882a593Smuzhiyun 		break;
214*4882a593Smuzhiyun 	default:
215*4882a593Smuzhiyun 		debug("Unsupported ARMCLK frequency");
216*4882a593Smuzhiyun 		return -EINVAL;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	/* pll enter slow-mode */
220*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
221*4882a593Smuzhiyun 		     APLL_MODE_SLOW << APLL_MODE_SHIFT);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	rkclk_set_pll(cru, CLK_ARM, &apll_cfg[cfg], has_bwadj);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/* waiting for pll lock */
226*4882a593Smuzhiyun 	while (!(readl(&grf->soc_status0) & SOCSTS_APLL_LOCK))
227*4882a593Smuzhiyun 		udelay(1);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	/* Set divider for peripherals attached to the cpu core. */
230*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_clksel_con[0],
231*4882a593Smuzhiyun 		CORE_PERI_DIV_MASK,
232*4882a593Smuzhiyun 		div_core_peri << CORE_PERI_DIV_SHIFT);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	/* set up dependent divisor for aclk_core */
235*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_clksel_con[1],
236*4882a593Smuzhiyun 		CORE_ACLK_DIV_MASK,
237*4882a593Smuzhiyun 		div_aclk_core << CORE_ACLK_DIV_SHIFT);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	/* PLL enter normal-mode */
240*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_mode_con, APLL_MODE_MASK,
241*4882a593Smuzhiyun 		     APLL_MODE_NORMAL << APLL_MODE_SHIFT);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	return hz;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun /* Get pll rate by id */
rkclk_pll_get_rate(struct rk3066_cru * cru,enum rk_clk_id clk_id)247*4882a593Smuzhiyun static uint32_t rkclk_pll_get_rate(struct rk3066_cru *cru,
248*4882a593Smuzhiyun 				   enum rk_clk_id clk_id)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	uint32_t nr, no, nf;
251*4882a593Smuzhiyun 	uint32_t con;
252*4882a593Smuzhiyun 	int pll_id = rk_pll_id(clk_id);
253*4882a593Smuzhiyun 	struct rk3066_pll *pll = &cru->pll[pll_id];
254*4882a593Smuzhiyun 	static u8 clk_shift[CLK_COUNT] = {
255*4882a593Smuzhiyun 		0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, CPLL_MODE_SHIFT,
256*4882a593Smuzhiyun 		GPLL_MODE_SHIFT
257*4882a593Smuzhiyun 	};
258*4882a593Smuzhiyun 	uint shift;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	con = readl(&cru->cru_mode_con);
261*4882a593Smuzhiyun 	shift = clk_shift[clk_id];
262*4882a593Smuzhiyun 	switch ((con >> shift) & APLL_MODE_MASK >> APLL_MODE_SHIFT) {
263*4882a593Smuzhiyun 	case APLL_MODE_SLOW:
264*4882a593Smuzhiyun 		return OSC_HZ;
265*4882a593Smuzhiyun 	case APLL_MODE_NORMAL:
266*4882a593Smuzhiyun 		/* normal mode */
267*4882a593Smuzhiyun 		con = readl(&pll->con0);
268*4882a593Smuzhiyun 		no = ((con >> CLKOD_SHIFT) & (CLKOD_MASK >> CLKOD_SHIFT)) + 1;
269*4882a593Smuzhiyun 		nr = ((con >> CLKR_SHIFT) & (CLKR_MASK >> CLKR_SHIFT)) + 1;
270*4882a593Smuzhiyun 		con = readl(&pll->con1);
271*4882a593Smuzhiyun 		nf = ((con >> CLKF_SHIFT) & (CLKF_MASK >> CLKF_SHIFT)) + 1;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 		return (24 * nf / (nr * no)) * 1000000;
274*4882a593Smuzhiyun 	case APLL_MODE_DEEP:
275*4882a593Smuzhiyun 	default:
276*4882a593Smuzhiyun 		return 32768;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun 
rockchip_mmc_get_clk(struct rk3066_cru * cru,uint gclk_rate,int periph)280*4882a593Smuzhiyun static ulong rockchip_mmc_get_clk(struct rk3066_cru *cru, uint gclk_rate,
281*4882a593Smuzhiyun 				  int periph)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	uint div;
284*4882a593Smuzhiyun 	u32 con;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	switch (periph) {
287*4882a593Smuzhiyun 	case HCLK_EMMC:
288*4882a593Smuzhiyun 		con = readl(&cru->cru_clksel_con[12]);
289*4882a593Smuzhiyun 		div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK >> EMMC_DIV_SHIFT;
290*4882a593Smuzhiyun 		break;
291*4882a593Smuzhiyun 	case HCLK_SDMMC:
292*4882a593Smuzhiyun 		con = readl(&cru->cru_clksel_con[11]);
293*4882a593Smuzhiyun 		div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK >> MMC0_DIV_SHIFT;
294*4882a593Smuzhiyun 		break;
295*4882a593Smuzhiyun 	case HCLK_SDIO:
296*4882a593Smuzhiyun 		con = readl(&cru->cru_clksel_con[12]);
297*4882a593Smuzhiyun 		div = (con >> SDIO_DIV_SHIFT) & SDIO_DIV_MASK >> SDIO_DIV_SHIFT;
298*4882a593Smuzhiyun 		break;
299*4882a593Smuzhiyun 	default:
300*4882a593Smuzhiyun 		return -EINVAL;
301*4882a593Smuzhiyun 	}
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	return DIV_TO_RATE(gclk_rate, div);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
rockchip_mmc_set_clk(struct rk3066_cru * cru,uint gclk_rate,int periph,uint freq)306*4882a593Smuzhiyun static ulong rockchip_mmc_set_clk(struct rk3066_cru *cru, uint gclk_rate,
307*4882a593Smuzhiyun 				  int  periph, uint freq)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun 	int src_clk_div;
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	debug("%s: gclk_rate=%u\n", __func__, gclk_rate);
312*4882a593Smuzhiyun 	src_clk_div = RATE_TO_DIV(gclk_rate, freq);
313*4882a593Smuzhiyun 	if (src_clk_div > 0x3f)
314*4882a593Smuzhiyun 		src_clk_div = 0x3f;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	switch (periph) {
317*4882a593Smuzhiyun 	case HCLK_EMMC:
318*4882a593Smuzhiyun 		rk_clrsetreg(&cru->cru_clksel_con[12],
319*4882a593Smuzhiyun 			     EMMC_DIV_MASK,
320*4882a593Smuzhiyun 			     src_clk_div << EMMC_DIV_SHIFT);
321*4882a593Smuzhiyun 		break;
322*4882a593Smuzhiyun 	case HCLK_SDMMC:
323*4882a593Smuzhiyun 		rk_clrsetreg(&cru->cru_clksel_con[11],
324*4882a593Smuzhiyun 			     MMC0_DIV_MASK,
325*4882a593Smuzhiyun 			     src_clk_div << MMC0_DIV_SHIFT);
326*4882a593Smuzhiyun 		break;
327*4882a593Smuzhiyun 	case HCLK_SDIO:
328*4882a593Smuzhiyun 		rk_clrsetreg(&cru->cru_clksel_con[12],
329*4882a593Smuzhiyun 			     SDIO_DIV_MASK,
330*4882a593Smuzhiyun 			     src_clk_div << SDIO_DIV_SHIFT);
331*4882a593Smuzhiyun 		break;
332*4882a593Smuzhiyun 	default:
333*4882a593Smuzhiyun 		return -EINVAL;
334*4882a593Smuzhiyun 	}
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	return rockchip_mmc_get_clk(cru, gclk_rate, periph);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun 
rockchip_spi_get_clk(struct rk3066_cru * cru,uint gclk_rate,int periph)339*4882a593Smuzhiyun static ulong rockchip_spi_get_clk(struct rk3066_cru *cru, uint gclk_rate,
340*4882a593Smuzhiyun 				  int periph)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	uint div;
343*4882a593Smuzhiyun 	u32 con;
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	switch (periph) {
346*4882a593Smuzhiyun 	case SCLK_SPI0:
347*4882a593Smuzhiyun 		con = readl(&cru->cru_clksel_con[25]);
348*4882a593Smuzhiyun 		div = (con >> SPI0_DIV_SHIFT) & SPI0_DIV_MASK >> SPI0_DIV_SHIFT;
349*4882a593Smuzhiyun 		break;
350*4882a593Smuzhiyun 	case SCLK_SPI1:
351*4882a593Smuzhiyun 		con = readl(&cru->cru_clksel_con[25]);
352*4882a593Smuzhiyun 		div = (con >> SPI1_DIV_SHIFT) & SPI1_DIV_MASK >> SPI1_DIV_SHIFT;
353*4882a593Smuzhiyun 		break;
354*4882a593Smuzhiyun 	default:
355*4882a593Smuzhiyun 		return -EINVAL;
356*4882a593Smuzhiyun 	}
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	return DIV_TO_RATE(gclk_rate, div);
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
rockchip_spi_set_clk(struct rk3066_cru * cru,uint gclk_rate,int periph,uint freq)361*4882a593Smuzhiyun static ulong rockchip_spi_set_clk(struct rk3066_cru *cru, uint gclk_rate,
362*4882a593Smuzhiyun 				  int periph, uint freq)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	int src_clk_div = RATE_TO_DIV(gclk_rate, freq);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	switch (periph) {
367*4882a593Smuzhiyun 	case SCLK_SPI0:
368*4882a593Smuzhiyun 		assert(src_clk_div <= SPI0_DIV_MASK >> SPI0_DIV_SHIFT);
369*4882a593Smuzhiyun 		rk_clrsetreg(&cru->cru_clksel_con[25],
370*4882a593Smuzhiyun 			     SPI0_DIV_MASK,
371*4882a593Smuzhiyun 			     src_clk_div << SPI0_DIV_SHIFT);
372*4882a593Smuzhiyun 		break;
373*4882a593Smuzhiyun 	case SCLK_SPI1:
374*4882a593Smuzhiyun 		assert(src_clk_div <= SPI1_DIV_MASK >> SPI1_DIV_SHIFT);
375*4882a593Smuzhiyun 		rk_clrsetreg(&cru->cru_clksel_con[25],
376*4882a593Smuzhiyun 			     SPI1_DIV_MASK,
377*4882a593Smuzhiyun 			     src_clk_div << SPI1_DIV_SHIFT);
378*4882a593Smuzhiyun 		break;
379*4882a593Smuzhiyun 	default:
380*4882a593Smuzhiyun 		return -EINVAL;
381*4882a593Smuzhiyun 	}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	return rockchip_spi_get_clk(cru, gclk_rate, periph);
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun #ifdef CONFIG_TPL_BUILD
rkclk_init(struct rk3066_cru * cru,struct rk3066_grf * grf,bool has_bwadj)386*4882a593Smuzhiyun static void rkclk_init(struct rk3066_cru *cru, struct rk3066_grf *grf,
387*4882a593Smuzhiyun 		       bool has_bwadj)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun 	u32 aclk_div, hclk_div, pclk_div, h2p_div;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	/* pll enter slow-mode */
392*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_mode_con,
393*4882a593Smuzhiyun 		     GPLL_MODE_MASK |
394*4882a593Smuzhiyun 		     CPLL_MODE_MASK,
395*4882a593Smuzhiyun 		     GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
396*4882a593Smuzhiyun 		     CPLL_MODE_SLOW << CPLL_MODE_SHIFT);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	/* init pll */
399*4882a593Smuzhiyun 	rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg, has_bwadj);
400*4882a593Smuzhiyun 	rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg, has_bwadj);
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	/* waiting for pll lock */
403*4882a593Smuzhiyun 	while ((readl(&grf->soc_status0) &
404*4882a593Smuzhiyun 			(SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK)) !=
405*4882a593Smuzhiyun 			(SOCSTS_CPLL_LOCK | SOCSTS_GPLL_LOCK))
406*4882a593Smuzhiyun 		udelay(1);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	/*
409*4882a593Smuzhiyun 	 * cpu clock pll source selection and
410*4882a593Smuzhiyun 	 * reparent aclk_cpu_pre from apll to gpll
411*4882a593Smuzhiyun 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
412*4882a593Smuzhiyun 	 */
413*4882a593Smuzhiyun 	aclk_div = RATE_TO_DIV(GPLL_HZ, CPU_ACLK_HZ);
414*4882a593Smuzhiyun 	assert((aclk_div + 1) * CPU_ACLK_HZ <= GPLL_HZ && aclk_div < 0x1f);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_clksel_con[0],
417*4882a593Smuzhiyun 		     CPU_ACLK_PLL_MASK |
418*4882a593Smuzhiyun 		     A9_CPU_DIV_MASK,
419*4882a593Smuzhiyun 		     CPU_ACLK_PLL_SELECT_GPLL << CPU_ACLK_PLL_SHIFT |
420*4882a593Smuzhiyun 		     aclk_div << A9_CPU_DIV_SHIFT);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	hclk_div = ilog2(CPU_ACLK_HZ / CPU_HCLK_HZ);
423*4882a593Smuzhiyun 	assert((1 << hclk_div) * CPU_HCLK_HZ <= CPU_ACLK_HZ && hclk_div < 0x3);
424*4882a593Smuzhiyun 	pclk_div = ilog2(CPU_ACLK_HZ / CPU_PCLK_HZ);
425*4882a593Smuzhiyun 	assert((1 << pclk_div) * CPU_PCLK_HZ <= CPU_ACLK_HZ && pclk_div < 0x4);
426*4882a593Smuzhiyun 	h2p_div = ilog2(CPU_HCLK_HZ / CPU_H2P_HZ);
427*4882a593Smuzhiyun 	assert((1 << h2p_div) * CPU_H2P_HZ <= CPU_HCLK_HZ && pclk_div < 0x3);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_clksel_con[1],
430*4882a593Smuzhiyun 		     AHB2APB_DIV_MASK |
431*4882a593Smuzhiyun 		     CPU_PCLK_DIV_MASK |
432*4882a593Smuzhiyun 		     CPU_HCLK_DIV_MASK,
433*4882a593Smuzhiyun 		     h2p_div << AHB2APB_DIV_SHIFT |
434*4882a593Smuzhiyun 		     pclk_div << CPU_PCLK_DIV_SHIFT |
435*4882a593Smuzhiyun 		     hclk_div << CPU_HCLK_DIV_SHIFT);
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	/*
438*4882a593Smuzhiyun 	 * peri clock pll source selection and
439*4882a593Smuzhiyun 	 * set up dependent divisors for PCLK/HCLK and ACLK clocks.
440*4882a593Smuzhiyun 	 */
441*4882a593Smuzhiyun 	aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
442*4882a593Smuzhiyun 	assert((aclk_div + 1) * PERI_ACLK_HZ <= GPLL_HZ && aclk_div < 0x1f);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ);
445*4882a593Smuzhiyun 	assert((1 << hclk_div) * PERI_HCLK_HZ <=
446*4882a593Smuzhiyun 		PERI_ACLK_HZ && (hclk_div < 0x4));
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ);
449*4882a593Smuzhiyun 	assert((1 << pclk_div) * PERI_PCLK_HZ <=
450*4882a593Smuzhiyun 		PERI_ACLK_HZ && (pclk_div < 0x4));
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_clksel_con[10],
453*4882a593Smuzhiyun 		     PERI_PCLK_DIV_MASK |
454*4882a593Smuzhiyun 		     PERI_HCLK_DIV_MASK |
455*4882a593Smuzhiyun 		     PERI_ACLK_DIV_MASK,
456*4882a593Smuzhiyun 		     PERI_SEL_GPLL << PERI_SEL_PLL_SHIFT |
457*4882a593Smuzhiyun 		     pclk_div << PERI_PCLK_DIV_SHIFT |
458*4882a593Smuzhiyun 		     hclk_div << PERI_HCLK_DIV_SHIFT |
459*4882a593Smuzhiyun 		     aclk_div << PERI_ACLK_DIV_SHIFT);
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	/* PLL enter normal-mode */
462*4882a593Smuzhiyun 	rk_clrsetreg(&cru->cru_mode_con,
463*4882a593Smuzhiyun 		     GPLL_MODE_MASK |
464*4882a593Smuzhiyun 		     CPLL_MODE_MASK,
465*4882a593Smuzhiyun 		     GPLL_MODE_NORMAL << GPLL_MODE_SHIFT |
466*4882a593Smuzhiyun 		     CPLL_MODE_NORMAL << CPLL_MODE_SHIFT);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	rockchip_mmc_set_clk(cru, PERI_HCLK_HZ, HCLK_SDMMC, 16000000);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun #endif
471*4882a593Smuzhiyun 
rk3066_clk_get_rate(struct clk * clk)472*4882a593Smuzhiyun static ulong rk3066_clk_get_rate(struct clk *clk)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun 	struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
475*4882a593Smuzhiyun 	ulong new_rate, gclk_rate;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
478*4882a593Smuzhiyun 	switch (clk->id) {
479*4882a593Smuzhiyun 	case 1 ... 4:
480*4882a593Smuzhiyun 		new_rate = rkclk_pll_get_rate(priv->cru, clk->id);
481*4882a593Smuzhiyun 		break;
482*4882a593Smuzhiyun 	case HCLK_EMMC:
483*4882a593Smuzhiyun 	case HCLK_SDMMC:
484*4882a593Smuzhiyun 	case HCLK_SDIO:
485*4882a593Smuzhiyun 		new_rate = rockchip_mmc_get_clk(priv->cru, PERI_HCLK_HZ,
486*4882a593Smuzhiyun 						clk->id);
487*4882a593Smuzhiyun 		break;
488*4882a593Smuzhiyun 	case SCLK_SPI0:
489*4882a593Smuzhiyun 	case SCLK_SPI1:
490*4882a593Smuzhiyun 		new_rate = rockchip_spi_get_clk(priv->cru, PERI_PCLK_HZ,
491*4882a593Smuzhiyun 						clk->id);
492*4882a593Smuzhiyun 		break;
493*4882a593Smuzhiyun 	case PCLK_I2C0:
494*4882a593Smuzhiyun 	case PCLK_I2C1:
495*4882a593Smuzhiyun 	case PCLK_I2C2:
496*4882a593Smuzhiyun 	case PCLK_I2C3:
497*4882a593Smuzhiyun 	case PCLK_I2C4:
498*4882a593Smuzhiyun 		return gclk_rate;
499*4882a593Smuzhiyun 	default:
500*4882a593Smuzhiyun 		return -ENOENT;
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 	return new_rate;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
rk3066_clk_set_rate(struct clk * clk,ulong rate)506*4882a593Smuzhiyun static ulong rk3066_clk_set_rate(struct clk *clk, ulong rate)
507*4882a593Smuzhiyun {
508*4882a593Smuzhiyun 	struct rk3066_clk_priv *priv = dev_get_priv(clk->dev);
509*4882a593Smuzhiyun 	struct rk3066_cru *cru = priv->cru;
510*4882a593Smuzhiyun 	ulong new_rate;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	switch (clk->id) {
513*4882a593Smuzhiyun 	case PLL_APLL:
514*4882a593Smuzhiyun 		new_rate = rkclk_configure_cpu(priv->cru, priv->grf, rate,
515*4882a593Smuzhiyun 					       priv->has_bwadj);
516*4882a593Smuzhiyun 		break;
517*4882a593Smuzhiyun 	case CLK_DDR:
518*4882a593Smuzhiyun 		new_rate = rkclk_configure_ddr(priv->cru, priv->grf, rate,
519*4882a593Smuzhiyun 					       priv->has_bwadj);
520*4882a593Smuzhiyun 		break;
521*4882a593Smuzhiyun 	case HCLK_EMMC:
522*4882a593Smuzhiyun 	case HCLK_SDMMC:
523*4882a593Smuzhiyun 	case HCLK_SDIO:
524*4882a593Smuzhiyun 		new_rate = rockchip_mmc_set_clk(cru, PERI_HCLK_HZ,
525*4882a593Smuzhiyun 						clk->id, rate);
526*4882a593Smuzhiyun 		break;
527*4882a593Smuzhiyun 	case SCLK_SPI0:
528*4882a593Smuzhiyun 	case SCLK_SPI1:
529*4882a593Smuzhiyun 		new_rate = rockchip_spi_set_clk(cru, PERI_PCLK_HZ,
530*4882a593Smuzhiyun 						clk->id, rate);
531*4882a593Smuzhiyun 		break;
532*4882a593Smuzhiyun 	default:
533*4882a593Smuzhiyun 		return -ENOENT;
534*4882a593Smuzhiyun 	}
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun 	return new_rate;
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun static struct clk_ops rk3066_clk_ops = {
540*4882a593Smuzhiyun 	.get_rate	= rk3066_clk_get_rate,
541*4882a593Smuzhiyun 	.set_rate	= rk3066_clk_set_rate,
542*4882a593Smuzhiyun };
543*4882a593Smuzhiyun 
rk3066_clk_ofdata_to_platdata(struct udevice * dev)544*4882a593Smuzhiyun static int rk3066_clk_ofdata_to_platdata(struct udevice *dev)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun #if !CONFIG_IS_ENABLED(OF_PLATDATA)
547*4882a593Smuzhiyun 	struct rk3066_clk_priv *priv = dev_get_priv(dev);
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	priv->cru = dev_read_addr_ptr(dev);
550*4882a593Smuzhiyun #endif
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	return 0;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
rk3066_clk_probe(struct udevice * dev)555*4882a593Smuzhiyun static int rk3066_clk_probe(struct udevice *dev)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun 	struct rk3066_clk_priv *priv = dev_get_priv(dev);
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
560*4882a593Smuzhiyun 	if (IS_ERR(priv->grf))
561*4882a593Smuzhiyun 		return PTR_ERR(priv->grf);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun #ifdef CONFIG_TPL_BUILD
564*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(OF_PLATDATA)
565*4882a593Smuzhiyun 	struct rk3066_clk_plat *plat = dev_get_platdata(dev);
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	priv->cru = map_sysmem(plat->dtd.reg[0], plat->dtd.reg[1]);
568*4882a593Smuzhiyun #endif
569*4882a593Smuzhiyun 	priv->sync_kernel = false;
570*4882a593Smuzhiyun 	if (!priv->armclk_enter_hz)
571*4882a593Smuzhiyun 		priv->armclk_enter_hz = rkclk_pll_get_rate(priv->cru,
572*4882a593Smuzhiyun 							   CLK_ARM);
573*4882a593Smuzhiyun 	rkclk_init(priv->cru, priv->grf, 1);
574*4882a593Smuzhiyun 	if (!priv->armclk_init_hz)
575*4882a593Smuzhiyun 		priv->armclk_init_hz = rkclk_pll_get_rate(priv->cru,
576*4882a593Smuzhiyun 							  CLK_ARM);
577*4882a593Smuzhiyun #endif
578*4882a593Smuzhiyun 	return 0;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun 
rk3066_clk_bind(struct udevice * dev)581*4882a593Smuzhiyun static int rk3066_clk_bind(struct udevice *dev)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	int ret;
584*4882a593Smuzhiyun 	struct udevice *sys_child, *sf_child;
585*4882a593Smuzhiyun 	struct sysreset_reg *priv;
586*4882a593Smuzhiyun 	struct softreset_reg *sf_priv;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	/* The reset driver does not have a device node, so bind it here */
589*4882a593Smuzhiyun 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
590*4882a593Smuzhiyun 				 &sys_child);
591*4882a593Smuzhiyun 	if (ret) {
592*4882a593Smuzhiyun 		debug("Warning: No sysreset driver: ret=%d\n", ret);
593*4882a593Smuzhiyun 	} else {
594*4882a593Smuzhiyun 		priv = malloc(sizeof(struct sysreset_reg));
595*4882a593Smuzhiyun 		priv->glb_srst_fst_value = offsetof(struct rk3066_cru,
596*4882a593Smuzhiyun 						    cru_glb_srst_fst_value);
597*4882a593Smuzhiyun 		priv->glb_srst_snd_value = offsetof(struct rk3066_cru,
598*4882a593Smuzhiyun 						    cru_glb_srst_snd_value);
599*4882a593Smuzhiyun 		sys_child->priv = priv;
600*4882a593Smuzhiyun 	}
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
603*4882a593Smuzhiyun 					 dev_ofnode(dev), &sf_child);
604*4882a593Smuzhiyun 	if (ret) {
605*4882a593Smuzhiyun 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
606*4882a593Smuzhiyun 	} else {
607*4882a593Smuzhiyun 		sf_priv = malloc(sizeof(struct softreset_reg));
608*4882a593Smuzhiyun 		sf_priv->sf_reset_offset = offsetof(struct rk3066_cru,
609*4882a593Smuzhiyun 						    cru_softrst_con[0]);
610*4882a593Smuzhiyun 		sf_priv->sf_reset_num = 9;
611*4882a593Smuzhiyun 		sf_child->priv = sf_priv;
612*4882a593Smuzhiyun 	}
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	return 0;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun static const struct udevice_id rk3066_clk_ids[] = {
618*4882a593Smuzhiyun 	{ .compatible = "rockchip,rk3066a-cru" },
619*4882a593Smuzhiyun 	{ }
620*4882a593Smuzhiyun };
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun U_BOOT_DRIVER(rockchip_rk3066a_cru) = {
623*4882a593Smuzhiyun 	.name			= "rockchip_rk3066a_cru",
624*4882a593Smuzhiyun 	.id			= UCLASS_CLK,
625*4882a593Smuzhiyun 	.of_match		= rk3066_clk_ids,
626*4882a593Smuzhiyun 	.priv_auto_alloc_size	= sizeof(struct rk3066_clk_priv),
627*4882a593Smuzhiyun 	.platdata_auto_alloc_size = sizeof(struct rk3066_clk_plat),
628*4882a593Smuzhiyun 	.ops			= &rk3066_clk_ops,
629*4882a593Smuzhiyun 	.bind			= rk3066_clk_bind,
630*4882a593Smuzhiyun 	.ofdata_to_platdata	= rk3066_clk_ofdata_to_platdata,
631*4882a593Smuzhiyun 	.probe			= rk3066_clk_probe,
632*4882a593Smuzhiyun };
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun #ifndef CONFIG_SPL_BUILD
635*4882a593Smuzhiyun /**
636*4882a593Smuzhiyun  * soc_clk_dump() - Print clock frequencies
637*4882a593Smuzhiyun  * Returns zero on success
638*4882a593Smuzhiyun  *
639*4882a593Smuzhiyun  * Implementation for the clk dump command.
640*4882a593Smuzhiyun  */
soc_clk_dump(void)641*4882a593Smuzhiyun int soc_clk_dump(void)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	struct udevice *cru_dev;
644*4882a593Smuzhiyun 	struct rk3066_clk_priv *priv;
645*4882a593Smuzhiyun 	const struct rk3066_clk_info *clk_dump;
646*4882a593Smuzhiyun 	struct clk clk;
647*4882a593Smuzhiyun 	unsigned long clk_count = ARRAY_SIZE(clks_dump);
648*4882a593Smuzhiyun 	unsigned long rate;
649*4882a593Smuzhiyun 	int i, ret;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	ret = uclass_get_device_by_driver(UCLASS_CLK,
652*4882a593Smuzhiyun 					  DM_GET_DRIVER(rockchip_rk3066a_cru),
653*4882a593Smuzhiyun 					  &cru_dev);
654*4882a593Smuzhiyun 	if (ret) {
655*4882a593Smuzhiyun 		printf("%s failed to get cru device\n", __func__);
656*4882a593Smuzhiyun 		return ret;
657*4882a593Smuzhiyun 	}
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	priv = dev_get_priv(cru_dev);
660*4882a593Smuzhiyun 	printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
661*4882a593Smuzhiyun 	       priv->sync_kernel ? "sync kernel" : "uboot",
662*4882a593Smuzhiyun 	       priv->armclk_enter_hz / 1000,
663*4882a593Smuzhiyun 	       priv->armclk_init_hz / 1000,
664*4882a593Smuzhiyun 	       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
665*4882a593Smuzhiyun 	       priv->set_armclk_rate ? " KHz" : "N/A");
666*4882a593Smuzhiyun 	for (i = 0; i < clk_count; i++) {
667*4882a593Smuzhiyun 		clk_dump = &clks_dump[i];
668*4882a593Smuzhiyun 		if (clk_dump->name) {
669*4882a593Smuzhiyun 			clk.id = clk_dump->id;
670*4882a593Smuzhiyun 			if (clk_dump->is_cru)
671*4882a593Smuzhiyun 				ret = clk_request(cru_dev, &clk);
672*4882a593Smuzhiyun 			if (ret < 0)
673*4882a593Smuzhiyun 				return ret;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 			rate = clk_get_rate(&clk);
676*4882a593Smuzhiyun 			clk_free(&clk);
677*4882a593Smuzhiyun 			if (i == 0) {
678*4882a593Smuzhiyun 				if (rate < 0)
679*4882a593Smuzhiyun 					printf("  %s %s\n", clk_dump->name,
680*4882a593Smuzhiyun 					       "unknown");
681*4882a593Smuzhiyun 				else
682*4882a593Smuzhiyun 					printf("  %s %lu KHz\n", clk_dump->name,
683*4882a593Smuzhiyun 					       rate / 1000);
684*4882a593Smuzhiyun 			} else {
685*4882a593Smuzhiyun 				if (rate < 0)
686*4882a593Smuzhiyun 					printf("  %s %s\n", clk_dump->name,
687*4882a593Smuzhiyun 					       "unknown");
688*4882a593Smuzhiyun 				else
689*4882a593Smuzhiyun 					printf("  %s %lu KHz\n", clk_dump->name,
690*4882a593Smuzhiyun 					       rate / 1000);
691*4882a593Smuzhiyun 			}
692*4882a593Smuzhiyun 		}
693*4882a593Smuzhiyun 	}
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	return 0;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun #endif
698*4882a593Smuzhiyun 
699