xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3528.c (revision 9d012e6487fb00738fed3fce5e5e28c6155de00a)
1c6f7c1a3SJoseph Chen // SPDX-License-Identifier: GPL-2.0
2c6f7c1a3SJoseph Chen /*
3c6f7c1a3SJoseph Chen  * Copyright (c) 2022 Fuzhou Rockchip Electronics Co., Ltd
4c6f7c1a3SJoseph Chen  * Author: Joseph Chen <chenjh@rock-chips.com>
5c6f7c1a3SJoseph Chen  */
6c6f7c1a3SJoseph Chen 
7c6f7c1a3SJoseph Chen #include <common.h>
8c6f7c1a3SJoseph Chen #include <clk-uclass.h>
9c6f7c1a3SJoseph Chen #include <dm.h>
10c6f7c1a3SJoseph Chen #include <syscon.h>
11c6f7c1a3SJoseph Chen #include <asm/arch/clock.h>
12c6f7c1a3SJoseph Chen #include <asm/arch/cru_rk3528.h>
13c6f7c1a3SJoseph Chen #include <asm/arch/grf_rk3528.h>
14c6f7c1a3SJoseph Chen #include <asm/arch/hardware.h>
15c6f7c1a3SJoseph Chen #include <asm/io.h>
16c6f7c1a3SJoseph Chen #include <dm/lists.h>
17c6f7c1a3SJoseph Chen #include <dt-bindings/clock/rk3528-cru.h>
18c6f7c1a3SJoseph Chen 
19c6f7c1a3SJoseph Chen DECLARE_GLOBAL_DATA_PTR;
20c6f7c1a3SJoseph Chen 
21c6f7c1a3SJoseph Chen #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
22c6f7c1a3SJoseph Chen 
23c6f7c1a3SJoseph Chen /*
24c6f7c1a3SJoseph Chen  *	PLL attention.
25c6f7c1a3SJoseph Chen  *
26c6f7c1a3SJoseph Chen  * [FRAC PLL]: GPLL, PPLL, DPLL
27c6f7c1a3SJoseph Chen  *   - frac mode: refdiv can be 1 or 2 only
28c6f7c1a3SJoseph Chen  *   - int mode:  refdiv has no special limit
29c6f7c1a3SJoseph Chen  *   - VCO range: [950, 3800] MHZ
30c6f7c1a3SJoseph Chen  *
31c6f7c1a3SJoseph Chen  * [INT PLL]:  CPLL, APLL
32c6f7c1a3SJoseph Chen  *   - int mode:  refdiv can be 1 or 2 only
33c6f7c1a3SJoseph Chen  *   - VCO range: [475, 1900] MHZ
34c6f7c1a3SJoseph Chen  *
35c6f7c1a3SJoseph Chen  * [PPLL]: normal mode only.
36c6f7c1a3SJoseph Chen  *
37c6f7c1a3SJoseph Chen  */
38c6f7c1a3SJoseph Chen static struct rockchip_pll_rate_table rk3528_pll_rates[] = {
39c6f7c1a3SJoseph Chen 	/* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
40c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
41c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
42c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
43c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
44c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
45c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
46c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
47c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
48c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),		/* GPLL */
49c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1092000000, 2, 91, 1, 1, 1, 0),
50c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1008000000, 1, 42, 1, 1, 1, 0),
51c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(1000000000, 1, 125, 3, 1, 1, 0), 	/* PPLL */
52c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(996000000, 2, 83, 1, 1, 1, 0),		/* CPLL */
53c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(960000000, 1, 40, 1, 1, 1, 0),
54c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
55c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
56c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0),
57c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
58c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
59c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0),
60c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
61c6f7c1a3SJoseph Chen 	RK3036_PLL_RATE(96000000, 1, 24, 3, 2, 1, 0),
62c6f7c1a3SJoseph Chen 	{ /* sentinel */ },
63c6f7c1a3SJoseph Chen };
64c6f7c1a3SJoseph Chen 
65c6f7c1a3SJoseph Chen static struct rockchip_pll_clock rk3528_pll_clks[] = {
66c6f7c1a3SJoseph Chen 	[APLL] = PLL(pll_rk3328, PLL_APLL, RK3528_PLL_CON(0),
67c6f7c1a3SJoseph Chen 		     RK3528_MODE_CON, 0, 10, 0, rk3528_pll_rates),
68c6f7c1a3SJoseph Chen 
69c6f7c1a3SJoseph Chen 	[CPLL] = PLL(pll_rk3328, PLL_CPLL, RK3528_PLL_CON(8),
70c6f7c1a3SJoseph Chen 		     RK3528_MODE_CON, 2, 10, 0, rk3528_pll_rates),
71c6f7c1a3SJoseph Chen 
72c6f7c1a3SJoseph Chen 	[GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3528_PLL_CON(24),
73c6f7c1a3SJoseph Chen 		     RK3528_MODE_CON, 4, 10, 0, rk3528_pll_rates),
74c6f7c1a3SJoseph Chen 
75c6f7c1a3SJoseph Chen 	[PPLL] = PLL(pll_rk3328, PLL_PPLL, RK3528_PCIE_PLL_CON(32),
76c6f7c1a3SJoseph Chen 		     RK3528_MODE_CON, 6, 10, ROCKCHIP_PLL_FIXED_MODE, rk3528_pll_rates),
77c6f7c1a3SJoseph Chen 
78c6f7c1a3SJoseph Chen 	[DPLL] = PLL(pll_rk3328, PLL_DPLL, RK3528_DDRPHY_PLL_CON(16),
79c6f7c1a3SJoseph Chen 		     RK3528_DDRPHY_MODE_CON, 0, 10, 0, rk3528_pll_rates),
80c6f7c1a3SJoseph Chen };
81c6f7c1a3SJoseph Chen 
82c6f7c1a3SJoseph Chen #define RK3528_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg)	\
83c6f7c1a3SJoseph Chen {								\
84c6f7c1a3SJoseph Chen 	.rate = _rate##U,					\
85c6f7c1a3SJoseph Chen 	.aclk_div = (_aclk_m_core),				\
86c6f7c1a3SJoseph Chen 	.pclk_div = (_pclk_dbg),				\
87c6f7c1a3SJoseph Chen }
88c6f7c1a3SJoseph Chen 
89c6f7c1a3SJoseph Chen /* sign-off: _aclk_m_core: 550M, _pclk_dbg: 137.5M, */
90c6f7c1a3SJoseph Chen static struct rockchip_cpu_rate_table rk3528_cpu_rates[] = {
91c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1896000000, 1, 13),
92c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1800000000, 1, 12),
93c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1704000000, 1, 11),
94c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1608000000, 1, 11),
95c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1512000000, 1, 11),
96c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1416000000, 1, 9),
97c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1296000000, 1, 8),
98c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1200000000, 1, 8),
99c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1188000000, 1, 8),
100c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1092000000, 1, 7),
101c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1008000000, 1, 6),
102c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(1000000000, 1, 6),
103c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(996000000, 1, 6),
104c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(960000000, 1, 6),
105c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(912000000, 1, 6),
106c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(816000000, 1, 5),
107c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(600000000, 1, 3),
108c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(594000000, 1, 3),
109c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(408000000, 1, 2),
110c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(312000000, 1, 2),
111c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(216000000, 1, 1),
112c6f7c1a3SJoseph Chen 	RK3528_CPUCLK_RATE(96000000, 1, 0),
113c6f7c1a3SJoseph Chen };
114c6f7c1a3SJoseph Chen 
115c6f7c1a3SJoseph Chen #ifndef CONFIG_SPL_BUILD
116c6f7c1a3SJoseph Chen #define RK3528_CLK_DUMP(_id, _name)		\
117c6f7c1a3SJoseph Chen {						\
118c6f7c1a3SJoseph Chen 	.id = _id,				\
119c6f7c1a3SJoseph Chen 	.name = _name,				\
120c6f7c1a3SJoseph Chen }
121c6f7c1a3SJoseph Chen 
122c6f7c1a3SJoseph Chen static const struct rk3528_clk_info clks_dump[] = {
123c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(PLL_APLL, "apll"),
124c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(PLL_GPLL, "gpll"),
125c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(PLL_CPLL, "cpll"),
126c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(PLL_DPLL, "dpll"),
127c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(PLL_PPLL, "ppll"),
128c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_50M_SRC,   "clk_50m"),
129c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_100M_SRC,  "clk_100m"),
130c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_150M_SRC,  "clk_150m"),
131c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_200M_SRC,  "clk_200m"),
132c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_250M_SRC,  "clk_250m"),
133c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_300M_SRC,  "clk_300m"),
134c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_339M_SRC,  "clk_339m"),
135c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_400M_SRC,  "clk_400m"),
136c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_500M_SRC,  "clk_600m"),
137c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_600M_SRC,  "clk_600m"),
138c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_PPLL_50M_MATRIX,  "clk_ppll_50m"),
139c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_PPLL_100M_MATRIX, "clk_ppll_100m"),
140c6f7c1a3SJoseph Chen 	RK3528_CLK_DUMP(CLK_PPLL_125M_MATRIX, "clk_ppll_125m"),
141c6f7c1a3SJoseph Chen };
142c6f7c1a3SJoseph Chen #endif
143c6f7c1a3SJoseph Chen 
144c6f7c1a3SJoseph Chen /*
145c6f7c1a3SJoseph Chen  *
146c6f7c1a3SJoseph Chen  * rational_best_approximation(31415, 10000,
147c6f7c1a3SJoseph Chen  *		(1 << 8) - 1, (1 << 5) - 1, &n, &d);
148c6f7c1a3SJoseph Chen  *
149c6f7c1a3SJoseph Chen  * you may look at given_numerator as a fixed point number,
150c6f7c1a3SJoseph Chen  * with the fractional part size described in given_denominator.
151c6f7c1a3SJoseph Chen  *
152c6f7c1a3SJoseph Chen  * for theoretical background, see:
153c6f7c1a3SJoseph Chen  * http://en.wikipedia.org/wiki/Continued_fraction
154c6f7c1a3SJoseph Chen  */
155c6f7c1a3SJoseph Chen static void rational_best_approximation(unsigned long given_numerator,
156c6f7c1a3SJoseph Chen 					unsigned long given_denominator,
157c6f7c1a3SJoseph Chen 					unsigned long max_numerator,
158c6f7c1a3SJoseph Chen 					unsigned long max_denominator,
159c6f7c1a3SJoseph Chen 					unsigned long *best_numerator,
160c6f7c1a3SJoseph Chen 					unsigned long *best_denominator)
161c6f7c1a3SJoseph Chen {
162c6f7c1a3SJoseph Chen 	unsigned long n, d, n0, d0, n1, d1;
163c6f7c1a3SJoseph Chen 
164c6f7c1a3SJoseph Chen 	n = given_numerator;
165c6f7c1a3SJoseph Chen 	d = given_denominator;
166c6f7c1a3SJoseph Chen 	n0 = 0;
167c6f7c1a3SJoseph Chen 	d1 = 0;
168c6f7c1a3SJoseph Chen 	n1 = 1;
169c6f7c1a3SJoseph Chen 	d0 = 1;
170c6f7c1a3SJoseph Chen 	for (;;) {
171c6f7c1a3SJoseph Chen 		unsigned long t, a;
172c6f7c1a3SJoseph Chen 
173c6f7c1a3SJoseph Chen 		if (n1 > max_numerator || d1 > max_denominator) {
174c6f7c1a3SJoseph Chen 			n1 = n0;
175c6f7c1a3SJoseph Chen 			d1 = d0;
176c6f7c1a3SJoseph Chen 			break;
177c6f7c1a3SJoseph Chen 		}
178c6f7c1a3SJoseph Chen 		if (d == 0)
179c6f7c1a3SJoseph Chen 			break;
180c6f7c1a3SJoseph Chen 		t = d;
181c6f7c1a3SJoseph Chen 		a = n / d;
182c6f7c1a3SJoseph Chen 		d = n % d;
183c6f7c1a3SJoseph Chen 		n = t;
184c6f7c1a3SJoseph Chen 		t = n0 + a * n1;
185c6f7c1a3SJoseph Chen 		n0 = n1;
186c6f7c1a3SJoseph Chen 		n1 = t;
187c6f7c1a3SJoseph Chen 		t = d0 + a * d1;
188c6f7c1a3SJoseph Chen 		d0 = d1;
189c6f7c1a3SJoseph Chen 		d1 = t;
190c6f7c1a3SJoseph Chen 	}
191c6f7c1a3SJoseph Chen 	*best_numerator = n1;
192c6f7c1a3SJoseph Chen 	*best_denominator = d1;
193c6f7c1a3SJoseph Chen }
194c6f7c1a3SJoseph Chen 
195c6f7c1a3SJoseph Chen static int rk3528_armclk_set_clk(struct rk3528_clk_priv *priv, ulong new_rate)
196c6f7c1a3SJoseph Chen {
197c6f7c1a3SJoseph Chen 	const struct rockchip_cpu_rate_table *rate;
198c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
199c6f7c1a3SJoseph Chen 	ulong old_rate;
200c6f7c1a3SJoseph Chen 
201c6f7c1a3SJoseph Chen 	rate = rockchip_get_cpu_settings(rk3528_cpu_rates, new_rate);
202c6f7c1a3SJoseph Chen 	if (!rate) {
203c6f7c1a3SJoseph Chen 		printf("%s unsupported rate\n", __func__);
204c6f7c1a3SJoseph Chen 		return -EINVAL;
205c6f7c1a3SJoseph Chen 	}
206c6f7c1a3SJoseph Chen 
207c6f7c1a3SJoseph Chen 	/*
208c6f7c1a3SJoseph Chen 	 * set up dependent divisors for DBG and ACLK clocks.
209c6f7c1a3SJoseph Chen 	 */
210c6f7c1a3SJoseph Chen 	old_rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru, APLL);
211c6f7c1a3SJoseph Chen 	if (old_rate > new_rate) {
212c6f7c1a3SJoseph Chen 		if (rockchip_pll_set_rate(&rk3528_pll_clks[APLL],
213c6f7c1a3SJoseph Chen 					  priv->cru, APLL, new_rate))
214c6f7c1a3SJoseph Chen 			return -EINVAL;
215c6f7c1a3SJoseph Chen 
216c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK,
217c6f7c1a3SJoseph Chen 			     rate->pclk_div << RK3528_DIV_PCLK_DBG_SHIFT);
218c6f7c1a3SJoseph Chen 
219c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[5], RK3528_DIV_ACLK_M_CORE_MASK,
220c6f7c1a3SJoseph Chen 			     rate->aclk_div << RK3528_DIV_ACLK_M_CORE_SHIFT);
221c6f7c1a3SJoseph Chen 	} else if (old_rate < new_rate) {
222c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK,
223c6f7c1a3SJoseph Chen 			     rate->pclk_div << RK3528_DIV_PCLK_DBG_SHIFT);
224c6f7c1a3SJoseph Chen 
225c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[5], RK3528_DIV_ACLK_M_CORE_MASK,
226c6f7c1a3SJoseph Chen 			     rate->aclk_div << RK3528_DIV_ACLK_M_CORE_SHIFT);
227c6f7c1a3SJoseph Chen 
228c6f7c1a3SJoseph Chen 		if (rockchip_pll_set_rate(&rk3528_pll_clks[APLL],
229c6f7c1a3SJoseph Chen 					  priv->cru, APLL, new_rate))
230c6f7c1a3SJoseph Chen 			return -EINVAL;
231c6f7c1a3SJoseph Chen 	}
232c6f7c1a3SJoseph Chen 
233c6f7c1a3SJoseph Chen 	return 0;
234c6f7c1a3SJoseph Chen }
235c6f7c1a3SJoseph Chen 
236c6f7c1a3SJoseph Chen static ulong rk3528_ppll_matrix_get_rate(struct rk3528_clk_priv *priv,
237c6f7c1a3SJoseph Chen 				      ulong clk_id)
238c6f7c1a3SJoseph Chen {
239c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
240c6f7c1a3SJoseph Chen 	u32 div, mask, shift;
241c6f7c1a3SJoseph Chen 	void *reg;
242c6f7c1a3SJoseph Chen 
243c6f7c1a3SJoseph Chen 	switch (clk_id) {
244c6f7c1a3SJoseph Chen 	case CLK_PPLL_50M_MATRIX:
245c6f7c1a3SJoseph Chen 	case CLK_GMAC1_RMII_VPU:
246c6f7c1a3SJoseph Chen 		mask = PCEICRU_CLKSEL_CON01_CLK_MATRIX_50M_SRC_DIV_MASK;
247c6f7c1a3SJoseph Chen 		shift = PCEICRU_CLKSEL_CON01_CLK_MATRIX_50M_SRC_DIV_SHIFT;
248c6f7c1a3SJoseph Chen 		reg = &cru->pcieclksel_con[1];
249c6f7c1a3SJoseph Chen 		break;
250c6f7c1a3SJoseph Chen 
251c6f7c1a3SJoseph Chen 	case CLK_PPLL_100M_MATRIX:
252c6f7c1a3SJoseph Chen 		mask = PCEICRU_CLKSEL_CON01_CLK_MATRIX_100M_SRC_DIV_MASK;
253c6f7c1a3SJoseph Chen 		shift = PCEICRU_CLKSEL_CON01_CLK_MATRIX_100M_SRC_DIV_SHIFT;
254c6f7c1a3SJoseph Chen 		reg = &cru->pcieclksel_con[1];
255c6f7c1a3SJoseph Chen 		break;
256c6f7c1a3SJoseph Chen 
257c6f7c1a3SJoseph Chen 	case CLK_PPLL_125M_MATRIX:
258c6f7c1a3SJoseph Chen 	case CLK_GMAC1_SRC_VPU:
259c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON60_CLK_MATRIX_125M_SRC_DIV_MASK;
260c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON60_CLK_MATRIX_125M_SRC_DIV_SHIFT;
261c6f7c1a3SJoseph Chen 		reg = &cru->clksel_con[60];
262c6f7c1a3SJoseph Chen 		break;
263c6f7c1a3SJoseph Chen 
264c6f7c1a3SJoseph Chen 	case CLK_GMAC1_VPU_25M:
265c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON60_CLK_MATRIX_25M_SRC_DIV_MASK;
266c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON60_CLK_MATRIX_25M_SRC_DIV_SHIFT;
267c6f7c1a3SJoseph Chen 		reg = &cru->clksel_con[60];
268c6f7c1a3SJoseph Chen 		break;
269c6f7c1a3SJoseph Chen 	default:
270c6f7c1a3SJoseph Chen 		return -ENOENT;
271c6f7c1a3SJoseph Chen 	}
272c6f7c1a3SJoseph Chen 
273c6f7c1a3SJoseph Chen 	div = (readl(reg) & mask) >> shift;
274c6f7c1a3SJoseph Chen 
275c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(priv->ppll_hz, div);
276c6f7c1a3SJoseph Chen }
277c6f7c1a3SJoseph Chen 
278c6f7c1a3SJoseph Chen static ulong rk3528_ppll_matrix_set_rate(struct rk3528_clk_priv *priv,
279c6f7c1a3SJoseph Chen 				      ulong clk_id, ulong rate)
280c6f7c1a3SJoseph Chen {
281c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
282c6f7c1a3SJoseph Chen 	u32 id, div, mask, shift;
283c6f7c1a3SJoseph Chen 	u8 is_pciecru = 0;
284c6f7c1a3SJoseph Chen 
285c6f7c1a3SJoseph Chen 	switch (clk_id) {
286c6f7c1a3SJoseph Chen 	case CLK_PPLL_50M_MATRIX:
287c6f7c1a3SJoseph Chen 		id = 1;
288c6f7c1a3SJoseph Chen 		mask = PCEICRU_CLKSEL_CON01_CLK_MATRIX_50M_SRC_DIV_MASK;
289c6f7c1a3SJoseph Chen 		shift = PCEICRU_CLKSEL_CON01_CLK_MATRIX_50M_SRC_DIV_SHIFT;
290c6f7c1a3SJoseph Chen 		is_pciecru = 1;
291c6f7c1a3SJoseph Chen 		break;
292c6f7c1a3SJoseph Chen 
293c6f7c1a3SJoseph Chen 	case CLK_PPLL_100M_MATRIX:
294c6f7c1a3SJoseph Chen 		id = 1;
295c6f7c1a3SJoseph Chen 		mask = PCEICRU_CLKSEL_CON01_CLK_MATRIX_100M_SRC_DIV_MASK;
296c6f7c1a3SJoseph Chen 		shift = PCEICRU_CLKSEL_CON01_CLK_MATRIX_100M_SRC_DIV_SHIFT;
297c6f7c1a3SJoseph Chen 		is_pciecru = 1;
298c6f7c1a3SJoseph Chen 		break;
299c6f7c1a3SJoseph Chen 
300c6f7c1a3SJoseph Chen 	case CLK_PPLL_125M_MATRIX:
301c6f7c1a3SJoseph Chen 		id = 60;
302c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON60_CLK_MATRIX_125M_SRC_DIV_MASK;
303c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON60_CLK_MATRIX_125M_SRC_DIV_SHIFT;
304c6f7c1a3SJoseph Chen 		break;
305c6f7c1a3SJoseph Chen 	case CLK_GMAC1_VPU_25M:
306c6f7c1a3SJoseph Chen 		id = 60;
307c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON60_CLK_MATRIX_25M_SRC_DIV_MASK;
308c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON60_CLK_MATRIX_25M_SRC_DIV_SHIFT;
309c6f7c1a3SJoseph Chen 		break;
310c6f7c1a3SJoseph Chen 	default:
311c6f7c1a3SJoseph Chen 		return -ENOENT;
312c6f7c1a3SJoseph Chen 	}
313c6f7c1a3SJoseph Chen 
314c6f7c1a3SJoseph Chen 	div = DIV_ROUND_UP(priv->ppll_hz, rate);
315c6f7c1a3SJoseph Chen 	if (is_pciecru)
316c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->pcieclksel_con[id], mask, (div - 1) << shift);
317c6f7c1a3SJoseph Chen 	else
318c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[id], mask, (div - 1) << shift);
319c6f7c1a3SJoseph Chen 
320c6f7c1a3SJoseph Chen 	return rk3528_ppll_matrix_get_rate(priv, clk_id);
321c6f7c1a3SJoseph Chen }
322c6f7c1a3SJoseph Chen 
323c6f7c1a3SJoseph Chen static ulong rk3528_cgpll_matrix_get_rate(struct rk3528_clk_priv *priv,
324c6f7c1a3SJoseph Chen 				      ulong clk_id)
325c6f7c1a3SJoseph Chen {
326c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
327c6f7c1a3SJoseph Chen 	u32 sel, div, mask, shift, con;
328c6f7c1a3SJoseph Chen 	u32 sel_mask = 0, sel_shift;
329c6f7c1a3SJoseph Chen 	u8 is_gpll_parent = 1;
330c6f7c1a3SJoseph Chen 	u8 is_halfdiv = 0;
331c6f7c1a3SJoseph Chen 	ulong prate;
332c6f7c1a3SJoseph Chen 
333c6f7c1a3SJoseph Chen 	switch (clk_id) {
334c6f7c1a3SJoseph Chen 	case CLK_MATRIX_50M_SRC:
335c6f7c1a3SJoseph Chen 		con = 0;
336c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON00_CLK_MATRIX_50M_SRC_DIV_MASK;
337c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON00_CLK_MATRIX_50M_SRC_DIV_SHIFT;
338c6f7c1a3SJoseph Chen 		is_gpll_parent = 0;
339c6f7c1a3SJoseph Chen 		break;
340c6f7c1a3SJoseph Chen 
341c6f7c1a3SJoseph Chen 	case CLK_MATRIX_100M_SRC:
342c6f7c1a3SJoseph Chen 		con = 0;
343c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON00_CLK_MATRIX_100M_SRC_DIV_MASK;
344c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON00_CLK_MATRIX_100M_SRC_DIV_SHIFT;
345c6f7c1a3SJoseph Chen 		is_gpll_parent = 0;
346c6f7c1a3SJoseph Chen 		break;
347c6f7c1a3SJoseph Chen 
348c6f7c1a3SJoseph Chen 	case CLK_MATRIX_150M_SRC:
349c6f7c1a3SJoseph Chen 		con = 1;
350c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON01_CLK_MATRIX_150M_SRC_DIV_MASK;
351c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON01_CLK_MATRIX_150M_SRC_DIV_SHIFT;
352c6f7c1a3SJoseph Chen 		break;
353c6f7c1a3SJoseph Chen 
354c6f7c1a3SJoseph Chen 	case CLK_MATRIX_200M_SRC:
355c6f7c1a3SJoseph Chen 		con = 1;
356c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON01_CLK_MATRIX_200M_SRC_DIV_MASK;
357c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON01_CLK_MATRIX_200M_SRC_DIV_SHIFT;
358c6f7c1a3SJoseph Chen 		break;
359c6f7c1a3SJoseph Chen 
360c6f7c1a3SJoseph Chen 	case CLK_MATRIX_250M_SRC:
361c6f7c1a3SJoseph Chen 		con = 1;
362c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_DIV_MASK;
363c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_DIV_SHIFT;
364c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_SEL_MASK;
365c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_SEL_SHIFT;
366c6f7c1a3SJoseph Chen 		break;
367c6f7c1a3SJoseph Chen 
368c6f7c1a3SJoseph Chen 	case CLK_MATRIX_300M_SRC:
369c6f7c1a3SJoseph Chen 		con = 2;
370c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON02_CLK_MATRIX_300M_SRC_DIV_MASK;
371c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON02_CLK_MATRIX_300M_SRC_DIV_SHIFT;
372c6f7c1a3SJoseph Chen 		break;
373c6f7c1a3SJoseph Chen 
374c6f7c1a3SJoseph Chen 	case CLK_MATRIX_339M_SRC:
375c6f7c1a3SJoseph Chen 		con = 2;
376c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON02_CLK_MATRIX_339M_SRC_DIV_MASK;
377c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON02_CLK_MATRIX_339M_SRC_DIV_SHIFT;
378c6f7c1a3SJoseph Chen 		is_halfdiv = 1;
379c6f7c1a3SJoseph Chen 		break;
380c6f7c1a3SJoseph Chen 
381c6f7c1a3SJoseph Chen 	case CLK_MATRIX_400M_SRC:
382c6f7c1a3SJoseph Chen 		con = 2;
383c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON02_CLK_MATRIX_400M_SRC_DIV_MASK;
384c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON02_CLK_MATRIX_400M_SRC_DIV_SHIFT;
385c6f7c1a3SJoseph Chen 		break;
386c6f7c1a3SJoseph Chen 
387c6f7c1a3SJoseph Chen 	case CLK_MATRIX_500M_SRC:
388c6f7c1a3SJoseph Chen 		con = 3;
389c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_DIV_MASK;
390c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_DIV_SHIFT;
391c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_SEL_MASK;
392c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_SEL_SHIFT;
393c6f7c1a3SJoseph Chen 		break;
394c6f7c1a3SJoseph Chen 
395c6f7c1a3SJoseph Chen 	case CLK_MATRIX_600M_SRC:
396c6f7c1a3SJoseph Chen 		con = 4;
397c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON04_CLK_MATRIX_600M_SRC_DIV_MASK;
398c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON04_CLK_MATRIX_600M_SRC_DIV_SHIFT;
399c6f7c1a3SJoseph Chen 		break;
400c6f7c1a3SJoseph Chen 
401c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_ROOT:
402c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_BIU:
403c6f7c1a3SJoseph Chen 		con = 43;
404c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON43_ACLK_BUS_VOPGL_ROOT_DIV_MASK;
405c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON43_ACLK_BUS_VOPGL_ROOT_DIV_SHIFT;
406c6f7c1a3SJoseph Chen 		break;
407c6f7c1a3SJoseph Chen 
408c6f7c1a3SJoseph Chen 	default:
409c6f7c1a3SJoseph Chen 		return -ENOENT;
410c6f7c1a3SJoseph Chen 	}
411c6f7c1a3SJoseph Chen 
412c6f7c1a3SJoseph Chen 	if (sel_mask) {
413c6f7c1a3SJoseph Chen 		sel = (readl(&cru->clksel_con[con]) & sel_mask) >> sel_shift;
414c6f7c1a3SJoseph Chen 		if (sel == CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX) // TODO
415c6f7c1a3SJoseph Chen 			prate = priv->gpll_hz;
416c6f7c1a3SJoseph Chen 		else
417c6f7c1a3SJoseph Chen 			prate = priv->cpll_hz;
418c6f7c1a3SJoseph Chen 	} else {
419c6f7c1a3SJoseph Chen 		if (is_gpll_parent)
420c6f7c1a3SJoseph Chen 			prate = priv->gpll_hz;
421c6f7c1a3SJoseph Chen 		else
422c6f7c1a3SJoseph Chen 			prate = priv->cpll_hz;
423c6f7c1a3SJoseph Chen 	}
424c6f7c1a3SJoseph Chen 
425c6f7c1a3SJoseph Chen 	div = (readl(&cru->clksel_con[con]) & mask) >> shift;
426c6f7c1a3SJoseph Chen 
427c6f7c1a3SJoseph Chen 	return is_halfdiv ? DIV_TO_RATE(prate * 2, (3 + 2 * div) + 1) : DIV_TO_RATE(prate, div);
428c6f7c1a3SJoseph Chen }
429c6f7c1a3SJoseph Chen 
430c6f7c1a3SJoseph Chen static ulong rk3528_cgpll_matrix_set_rate(struct rk3528_clk_priv *priv,
431c6f7c1a3SJoseph Chen 				      ulong clk_id, ulong rate)
432c6f7c1a3SJoseph Chen {
433c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
434c6f7c1a3SJoseph Chen 	u32 sel, div, mask, shift, con;
435c6f7c1a3SJoseph Chen 	u32 sel_mask = 0, sel_shift;
436c6f7c1a3SJoseph Chen 	u8 is_gpll_parent = 1;
437c6f7c1a3SJoseph Chen 	u8 is_halfdiv = 0;
438c6f7c1a3SJoseph Chen 	ulong prate = 0;
439c6f7c1a3SJoseph Chen 
440c6f7c1a3SJoseph Chen 	switch (clk_id) {
441c6f7c1a3SJoseph Chen 	case CLK_MATRIX_50M_SRC:
442c6f7c1a3SJoseph Chen 		con = 0;
443c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON00_CLK_MATRIX_50M_SRC_DIV_MASK;
444c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON00_CLK_MATRIX_50M_SRC_DIV_SHIFT;
445c6f7c1a3SJoseph Chen 		is_gpll_parent = 0;
446c6f7c1a3SJoseph Chen 		break;
447c6f7c1a3SJoseph Chen 
448c6f7c1a3SJoseph Chen 	case CLK_MATRIX_100M_SRC:
449c6f7c1a3SJoseph Chen 		con = 0;
450c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON00_CLK_MATRIX_100M_SRC_DIV_MASK;
451c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON00_CLK_MATRIX_100M_SRC_DIV_SHIFT;
452c6f7c1a3SJoseph Chen 		is_gpll_parent = 0;
453c6f7c1a3SJoseph Chen 		break;
454c6f7c1a3SJoseph Chen 
455c6f7c1a3SJoseph Chen 	case CLK_MATRIX_150M_SRC:
456c6f7c1a3SJoseph Chen 		con = 1;
457c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON01_CLK_MATRIX_150M_SRC_DIV_MASK;
458c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON01_CLK_MATRIX_150M_SRC_DIV_SHIFT;
459c6f7c1a3SJoseph Chen 		break;
460c6f7c1a3SJoseph Chen 
461c6f7c1a3SJoseph Chen 	case CLK_MATRIX_200M_SRC:
462c6f7c1a3SJoseph Chen 		con = 1;
463c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON01_CLK_MATRIX_200M_SRC_DIV_MASK;
464c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON01_CLK_MATRIX_200M_SRC_DIV_SHIFT;
465c6f7c1a3SJoseph Chen 		break;
466c6f7c1a3SJoseph Chen 
467c6f7c1a3SJoseph Chen 	case CLK_MATRIX_250M_SRC:
468c6f7c1a3SJoseph Chen 		con = 1;
469c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_DIV_MASK;
470c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_DIV_SHIFT;
471c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_SEL_MASK;
472c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON01_CLK_MATRIX_250M_SRC_SEL_SHIFT;
473c6f7c1a3SJoseph Chen 		break;
474c6f7c1a3SJoseph Chen 
475c6f7c1a3SJoseph Chen 	case CLK_MATRIX_300M_SRC:
476c6f7c1a3SJoseph Chen 		con = 2;
477c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON02_CLK_MATRIX_300M_SRC_DIV_MASK;
478c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON02_CLK_MATRIX_300M_SRC_DIV_SHIFT;
479c6f7c1a3SJoseph Chen 		break;
480c6f7c1a3SJoseph Chen 
481c6f7c1a3SJoseph Chen 	case CLK_MATRIX_339M_SRC:
482c6f7c1a3SJoseph Chen 		con = 2;
483c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON02_CLK_MATRIX_339M_SRC_DIV_MASK;
484c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON02_CLK_MATRIX_339M_SRC_DIV_SHIFT;
485c6f7c1a3SJoseph Chen 		is_halfdiv = 1;
486c6f7c1a3SJoseph Chen 		break;
487c6f7c1a3SJoseph Chen 
488c6f7c1a3SJoseph Chen 	case CLK_MATRIX_400M_SRC:
489c6f7c1a3SJoseph Chen 		con = 2;
490c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON02_CLK_MATRIX_400M_SRC_DIV_MASK;
491c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON02_CLK_MATRIX_400M_SRC_DIV_SHIFT;
492c6f7c1a3SJoseph Chen 		break;
493c6f7c1a3SJoseph Chen 
494c6f7c1a3SJoseph Chen 	case CLK_MATRIX_500M_SRC:
495c6f7c1a3SJoseph Chen 		con = 3;
496c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_DIV_MASK;
497c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_DIV_SHIFT;
498c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_SEL_MASK;
499c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON03_CLK_MATRIX_500M_SRC_SEL_SHIFT;
500c6f7c1a3SJoseph Chen 		break;
501c6f7c1a3SJoseph Chen 
502c6f7c1a3SJoseph Chen 	case CLK_MATRIX_600M_SRC:
503c6f7c1a3SJoseph Chen 		con = 4;
504c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON04_CLK_MATRIX_600M_SRC_DIV_MASK;
505c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON04_CLK_MATRIX_600M_SRC_DIV_SHIFT;
506c6f7c1a3SJoseph Chen 		break;
507c6f7c1a3SJoseph Chen 
508c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_ROOT:
509c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_BIU:
510c6f7c1a3SJoseph Chen 		con = 43;
511c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON43_ACLK_BUS_VOPGL_ROOT_DIV_MASK;
512c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON43_ACLK_BUS_VOPGL_ROOT_DIV_SHIFT;
513c6f7c1a3SJoseph Chen 		break;
514c6f7c1a3SJoseph Chen 
515c6f7c1a3SJoseph Chen 	default:
516c6f7c1a3SJoseph Chen 		return -ENOENT;
517c6f7c1a3SJoseph Chen 	}
518c6f7c1a3SJoseph Chen 
519c6f7c1a3SJoseph Chen 	if (sel_mask) {
520c6f7c1a3SJoseph Chen 		if (priv->gpll_hz % rate == 0) {
521c6f7c1a3SJoseph Chen 			sel = CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX; // TODO
522c6f7c1a3SJoseph Chen 			prate = priv->gpll_hz;
523c6f7c1a3SJoseph Chen 		} else {
524c6f7c1a3SJoseph Chen 			sel = CLK_MATRIX_250M_SRC_SEL_CLK_CPLL_MUX;
525c6f7c1a3SJoseph Chen 			prate = priv->cpll_hz;
526c6f7c1a3SJoseph Chen 		}
527c6f7c1a3SJoseph Chen 	} else {
528c6f7c1a3SJoseph Chen 		if (is_gpll_parent)
529c6f7c1a3SJoseph Chen 			prate = priv->gpll_hz;
530c6f7c1a3SJoseph Chen 		else
531c6f7c1a3SJoseph Chen 			prate = priv->cpll_hz;
532c6f7c1a3SJoseph Chen 	}
533c6f7c1a3SJoseph Chen 
534c6f7c1a3SJoseph Chen 	if (is_halfdiv)
535c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP((prate * 2) - (3 * rate), 2 * rate);
536c6f7c1a3SJoseph Chen 	else
537c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(prate, rate);
538c6f7c1a3SJoseph Chen 
539c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[con], mask, (div - 1) << shift);
540c6f7c1a3SJoseph Chen 	if (sel_mask)
541c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[con], sel_mask, sel << sel_shift);
542c6f7c1a3SJoseph Chen 
543c6f7c1a3SJoseph Chen 	return rk3528_cgpll_matrix_get_rate(priv, clk_id);
544c6f7c1a3SJoseph Chen }
545c6f7c1a3SJoseph Chen 
546c6f7c1a3SJoseph Chen static ulong rk3528_i2c_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
547c6f7c1a3SJoseph Chen {
548c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
549c6f7c1a3SJoseph Chen 	u32 id, sel, con, mask, shift;
550c6f7c1a3SJoseph Chen 	u8 is_pmucru = 0;
551c6f7c1a3SJoseph Chen 	ulong rate;
552c6f7c1a3SJoseph Chen 
553c6f7c1a3SJoseph Chen 	switch (clk_id) {
554c6f7c1a3SJoseph Chen 	case CLK_I2C0:
555c6f7c1a3SJoseph Chen 		id = 79;
556c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON79_CLK_I2C0_SEL_MASK;
557c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON79_CLK_I2C0_SEL_SHIFT;
558c6f7c1a3SJoseph Chen 		break;
559c6f7c1a3SJoseph Chen 
560c6f7c1a3SJoseph Chen 	case CLK_I2C1:
561c6f7c1a3SJoseph Chen 		id = 79;
562c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON79_CLK_I2C1_SEL_MASK;
563c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON79_CLK_I2C1_SEL_SHIFT;
564c6f7c1a3SJoseph Chen 		break;
565c6f7c1a3SJoseph Chen 
566c6f7c1a3SJoseph Chen 	case CLK_I2C2:
567c6f7c1a3SJoseph Chen 		id = 0;
568c6f7c1a3SJoseph Chen 		mask = PMUCRU_CLKSEL_CON0_CLK_I2C2_SEL_MASK;
569c6f7c1a3SJoseph Chen 		shift = PMUCRU_CLKSEL_CON0_CLK_I2C2_SEL_SHIFT;
570c6f7c1a3SJoseph Chen 		is_pmucru = 1;
571c6f7c1a3SJoseph Chen 		break;
572c6f7c1a3SJoseph Chen 
573c6f7c1a3SJoseph Chen 	case CLK_I2C3:
574c6f7c1a3SJoseph Chen 		id = 63;
575c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON63_CLK_I2C3_SEL_MASK;
576c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON63_CLK_I2C3_SEL_SHIFT;
577c6f7c1a3SJoseph Chen 		break;
578c6f7c1a3SJoseph Chen 
579c6f7c1a3SJoseph Chen 	case CLK_I2C4:
580c6f7c1a3SJoseph Chen 		id = 85;
581c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON85_CLK_I2C4_SEL_MASK;
582c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON85_CLK_I2C4_SEL_SHIFT;
583c6f7c1a3SJoseph Chen 		break;
584c6f7c1a3SJoseph Chen 
585c6f7c1a3SJoseph Chen 	case CLK_I2C5:
586c6f7c1a3SJoseph Chen 		id = 63;
587c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON63_CLK_I2C5_SEL_MASK;
588c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON63_CLK_I2C5_SEL_SHIFT;
589c6f7c1a3SJoseph Chen 		break;
590c6f7c1a3SJoseph Chen 
591c6f7c1a3SJoseph Chen 	case CLK_I2C6:
592c6f7c1a3SJoseph Chen 		id = 64;
593c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON64_CLK_I2C6_SEL_MASK;
594c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON64_CLK_I2C6_SEL_SHIFT;
595c6f7c1a3SJoseph Chen 		break;
596c6f7c1a3SJoseph Chen 
597c6f7c1a3SJoseph Chen 	case CLK_I2C7:
598c6f7c1a3SJoseph Chen 		id = 86;
599c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON86_CLK_I2C7_SEL_MASK;
600c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON86_CLK_I2C7_SEL_SHIFT;
601c6f7c1a3SJoseph Chen 		break;
602c6f7c1a3SJoseph Chen 
603c6f7c1a3SJoseph Chen 	default:
604c6f7c1a3SJoseph Chen 		return -ENOENT;
605c6f7c1a3SJoseph Chen 	}
606c6f7c1a3SJoseph Chen 
607c6f7c1a3SJoseph Chen 	if (is_pmucru)
608c6f7c1a3SJoseph Chen 		con = readl(&cru->pmuclksel_con[id]);
609c6f7c1a3SJoseph Chen 	else
610c6f7c1a3SJoseph Chen 		con = readl(&cru->clksel_con[id]);
611c6f7c1a3SJoseph Chen 	sel = (con & mask) >> shift;
612c6f7c1a3SJoseph Chen 	if (sel == CLK_I2C3_SEL_CLK_MATRIX_200M_SRC)
613c6f7c1a3SJoseph Chen 		rate = 200 * MHz;
614c6f7c1a3SJoseph Chen 	else if (sel == CLK_I2C3_SEL_CLK_MATRIX_100M_SRC)
615c6f7c1a3SJoseph Chen 		rate = 100 * MHz;
616c6f7c1a3SJoseph Chen 	else if (sel == CLK_I2C3_SEL_CLK_MATRIX_50M_SRC)
617c6f7c1a3SJoseph Chen 		rate = 50 * MHz;
618c6f7c1a3SJoseph Chen 	else
619c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
620c6f7c1a3SJoseph Chen 
621c6f7c1a3SJoseph Chen 	return rate;
622c6f7c1a3SJoseph Chen }
623c6f7c1a3SJoseph Chen 
624c6f7c1a3SJoseph Chen static ulong rk3528_i2c_set_clk(struct rk3528_clk_priv *priv, ulong clk_id,
625c6f7c1a3SJoseph Chen 				ulong rate)
626c6f7c1a3SJoseph Chen {
627c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
628c6f7c1a3SJoseph Chen 	u32 id, sel, mask, shift;
629c6f7c1a3SJoseph Chen 	u8 is_pmucru = 0;
630c6f7c1a3SJoseph Chen 
631c6f7c1a3SJoseph Chen 	if (rate == 200 * MHz)
632c6f7c1a3SJoseph Chen 		sel = CLK_I2C3_SEL_CLK_MATRIX_200M_SRC;
633c6f7c1a3SJoseph Chen 	else if (rate == 100 * MHz)
634c6f7c1a3SJoseph Chen 		sel = CLK_I2C3_SEL_CLK_MATRIX_100M_SRC;
635c6f7c1a3SJoseph Chen 	else if (rate == 50 * MHz)
636c6f7c1a3SJoseph Chen 		sel = CLK_I2C3_SEL_CLK_MATRIX_50M_SRC;
637c6f7c1a3SJoseph Chen 	else
638c6f7c1a3SJoseph Chen 		sel = CLK_I2C3_SEL_XIN_OSC0_FUNC;
639c6f7c1a3SJoseph Chen 
640c6f7c1a3SJoseph Chen 	switch (clk_id) {
641c6f7c1a3SJoseph Chen 	case CLK_I2C0:
642c6f7c1a3SJoseph Chen 		id = 79;
643c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON79_CLK_I2C0_SEL_MASK;
644c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON79_CLK_I2C0_SEL_SHIFT;
645c6f7c1a3SJoseph Chen 		break;
646c6f7c1a3SJoseph Chen 
647c6f7c1a3SJoseph Chen 	case CLK_I2C1:
648c6f7c1a3SJoseph Chen 		id = 79;
649c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON79_CLK_I2C1_SEL_MASK;
650c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON79_CLK_I2C1_SEL_SHIFT;
651c6f7c1a3SJoseph Chen 		break;
652c6f7c1a3SJoseph Chen 
653c6f7c1a3SJoseph Chen 	case CLK_I2C2:
654c6f7c1a3SJoseph Chen 		id = 0;
655c6f7c1a3SJoseph Chen 		mask = PMUCRU_CLKSEL_CON0_CLK_I2C2_SEL_MASK;
656c6f7c1a3SJoseph Chen 		shift = PMUCRU_CLKSEL_CON0_CLK_I2C2_SEL_SHIFT;
657c6f7c1a3SJoseph Chen 		is_pmucru = 1;
658c6f7c1a3SJoseph Chen 		break;
659c6f7c1a3SJoseph Chen 
660c6f7c1a3SJoseph Chen 	case CLK_I2C3:
661c6f7c1a3SJoseph Chen 		id = 63;
662c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON63_CLK_I2C3_SEL_MASK;
663c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON63_CLK_I2C3_SEL_SHIFT;
664c6f7c1a3SJoseph Chen 		break;
665c6f7c1a3SJoseph Chen 
666c6f7c1a3SJoseph Chen 	case CLK_I2C4:
667c6f7c1a3SJoseph Chen 		id = 85;
668c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON85_CLK_I2C4_SEL_MASK;
669c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON85_CLK_I2C4_SEL_SHIFT;
670c6f7c1a3SJoseph Chen 		break;
671c6f7c1a3SJoseph Chen 
672c6f7c1a3SJoseph Chen 	case CLK_I2C5:
673c6f7c1a3SJoseph Chen 		id = 63;
674c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON63_CLK_I2C5_SEL_MASK;
675c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON63_CLK_I2C5_SEL_SHIFT;
676c6f7c1a3SJoseph Chen 
677c6f7c1a3SJoseph Chen 	case CLK_I2C6:
678c6f7c1a3SJoseph Chen 		id = 64;
679c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON64_CLK_I2C6_SEL_MASK;
680c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON64_CLK_I2C6_SEL_SHIFT;
681c6f7c1a3SJoseph Chen 		break;
682c6f7c1a3SJoseph Chen 
683c6f7c1a3SJoseph Chen 	case CLK_I2C7:
684c6f7c1a3SJoseph Chen 		id = 86;
685c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON86_CLK_I2C7_SEL_MASK;
686c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON86_CLK_I2C7_SEL_SHIFT;
687c6f7c1a3SJoseph Chen 		break;
688c6f7c1a3SJoseph Chen 
689c6f7c1a3SJoseph Chen 	default:
690c6f7c1a3SJoseph Chen 		return -ENOENT;
691c6f7c1a3SJoseph Chen 	}
692c6f7c1a3SJoseph Chen 
693c6f7c1a3SJoseph Chen 	if (is_pmucru)
694c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->pmuclksel_con[id], mask, sel << shift);
695c6f7c1a3SJoseph Chen 	else
696c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift);
697c6f7c1a3SJoseph Chen 
698c6f7c1a3SJoseph Chen 	return rk3528_i2c_get_clk(priv, clk_id);
699c6f7c1a3SJoseph Chen }
700c6f7c1a3SJoseph Chen 
701c6f7c1a3SJoseph Chen static ulong rk3528_spi_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
702c6f7c1a3SJoseph Chen {
703c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
704c6f7c1a3SJoseph Chen 	u32 id, sel, con, mask, shift;
705c6f7c1a3SJoseph Chen 	ulong rate;
706c6f7c1a3SJoseph Chen 
707c6f7c1a3SJoseph Chen 	switch (clk_id) {
708c6f7c1a3SJoseph Chen 	case CLK_SPI0:
709c6f7c1a3SJoseph Chen 		id = 79;
710c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON79_CLK_SPI0_SEL_MASK;
711c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON79_CLK_SPI0_SEL_SHIFT;
712c6f7c1a3SJoseph Chen 		break;
713c6f7c1a3SJoseph Chen 
714c6f7c1a3SJoseph Chen 	case CLK_SPI1:
715c6f7c1a3SJoseph Chen 		id = 63;
716c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON63_CLK_SPI1_SEL_MASK;
717c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON63_CLK_SPI1_SEL_SHIFT;
718c6f7c1a3SJoseph Chen 		break;
719c6f7c1a3SJoseph Chen 	default:
720c6f7c1a3SJoseph Chen 		return -ENOENT;
721c6f7c1a3SJoseph Chen 	}
722c6f7c1a3SJoseph Chen 
723c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
724c6f7c1a3SJoseph Chen 	sel = (con & mask) >> shift;
725c6f7c1a3SJoseph Chen 	if (sel == CLK_SPI1_SEL_CLK_MATRIX_200M_SRC)
726c6f7c1a3SJoseph Chen 		rate = 200 * MHz;
727c6f7c1a3SJoseph Chen 	if (sel == CLK_SPI1_SEL_CLK_MATRIX_100M_SRC)
728c6f7c1a3SJoseph Chen 		rate = 100 * MHz;
729c6f7c1a3SJoseph Chen 	if (sel == CLK_SPI1_SEL_CLK_MATRIX_50M_SRC)
730c6f7c1a3SJoseph Chen 		rate = 50 * MHz;
731c6f7c1a3SJoseph Chen 	else
732c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
733c6f7c1a3SJoseph Chen 
734c6f7c1a3SJoseph Chen 	return rate;
735c6f7c1a3SJoseph Chen }
736c6f7c1a3SJoseph Chen 
737c6f7c1a3SJoseph Chen static ulong rk3528_spi_set_clk(struct rk3528_clk_priv *priv,
738c6f7c1a3SJoseph Chen 				ulong clk_id, ulong rate)
739c6f7c1a3SJoseph Chen {
740c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
741c6f7c1a3SJoseph Chen 	u32 id, sel, mask, shift;
742c6f7c1a3SJoseph Chen 
743c6f7c1a3SJoseph Chen 	if (rate == 200 * MHz)
744c6f7c1a3SJoseph Chen 		sel = CLK_SPI1_SEL_CLK_MATRIX_200M_SRC;
745c6f7c1a3SJoseph Chen 	else if (rate == 100 * MHz)
746c6f7c1a3SJoseph Chen 		sel = CLK_SPI1_SEL_CLK_MATRIX_100M_SRC;
747c6f7c1a3SJoseph Chen 	else if (rate == 50 * MHz)
748c6f7c1a3SJoseph Chen 		sel = CLK_SPI1_SEL_CLK_MATRIX_50M_SRC;
749c6f7c1a3SJoseph Chen 	else
750c6f7c1a3SJoseph Chen 		sel = CLK_SPI1_SEL_XIN_OSC0_FUNC;
751c6f7c1a3SJoseph Chen 
752c6f7c1a3SJoseph Chen 	switch (clk_id) {
753c6f7c1a3SJoseph Chen 	case CLK_SPI0:
754c6f7c1a3SJoseph Chen 		id = 79;
755c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON79_CLK_SPI0_SEL_MASK;
756c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON79_CLK_SPI0_SEL_SHIFT;
757c6f7c1a3SJoseph Chen 		break;
758c6f7c1a3SJoseph Chen 
759c6f7c1a3SJoseph Chen 	case CLK_SPI1:
760c6f7c1a3SJoseph Chen 		id = 63;
761c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON63_CLK_SPI1_SEL_MASK;
762c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON63_CLK_SPI1_SEL_SHIFT;
763c6f7c1a3SJoseph Chen 		break;
764c6f7c1a3SJoseph Chen 	default:
765c6f7c1a3SJoseph Chen 		return -ENOENT;
766c6f7c1a3SJoseph Chen 	}
767c6f7c1a3SJoseph Chen 
768c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift);
769c6f7c1a3SJoseph Chen 
770c6f7c1a3SJoseph Chen 	return rk3528_spi_get_clk(priv, clk_id);
771c6f7c1a3SJoseph Chen }
772c6f7c1a3SJoseph Chen 
773c6f7c1a3SJoseph Chen static ulong rk3528_pwm_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
774c6f7c1a3SJoseph Chen {
775c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
776c6f7c1a3SJoseph Chen 	u32 id, sel, con, mask, shift;
777c6f7c1a3SJoseph Chen 	ulong rate;
778c6f7c1a3SJoseph Chen 
779c6f7c1a3SJoseph Chen 	switch (clk_id) {
780c6f7c1a3SJoseph Chen 	case CLK_PWM0:
781c6f7c1a3SJoseph Chen 		id = 44;
782c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON44_CLK_PWM0_SEL_MASK;
783c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON44_CLK_PWM0_SEL_SHIFT;
784c6f7c1a3SJoseph Chen 		break;
785c6f7c1a3SJoseph Chen 
786c6f7c1a3SJoseph Chen 	case CLK_PWM1:
787c6f7c1a3SJoseph Chen 		id = 44;
788c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON44_CLK_PWM1_SEL_MASK;
789c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON44_CLK_PWM1_SEL_SHIFT;
790c6f7c1a3SJoseph Chen 		break;
791c6f7c1a3SJoseph Chen 
792c6f7c1a3SJoseph Chen 	default:
793c6f7c1a3SJoseph Chen 		return -ENOENT;
794c6f7c1a3SJoseph Chen 	}
795c6f7c1a3SJoseph Chen 
796c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
797c6f7c1a3SJoseph Chen 	sel = (con & mask) >> shift;
798c6f7c1a3SJoseph Chen 	if (sel == CLK_PWM0_SEL_CLK_MATRIX_100M_SRC)
799c6f7c1a3SJoseph Chen 		rate = 100 * MHz;
800c6f7c1a3SJoseph Chen 	if (sel == CLK_PWM0_SEL_CLK_MATRIX_50M_SRC)
801c6f7c1a3SJoseph Chen 		rate = 50 * MHz;
802c6f7c1a3SJoseph Chen 	else
803c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
804c6f7c1a3SJoseph Chen 
805c6f7c1a3SJoseph Chen 	return rate;
806c6f7c1a3SJoseph Chen }
807c6f7c1a3SJoseph Chen 
808c6f7c1a3SJoseph Chen static ulong rk3528_pwm_set_clk(struct rk3528_clk_priv *priv,
809c6f7c1a3SJoseph Chen 				ulong clk_id, ulong rate)
810c6f7c1a3SJoseph Chen {
811c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
812c6f7c1a3SJoseph Chen 	u32 id, sel, mask, shift;
813c6f7c1a3SJoseph Chen 
814c6f7c1a3SJoseph Chen 	if (rate == 100 * MHz)
815c6f7c1a3SJoseph Chen 		sel = CLK_PWM0_SEL_CLK_MATRIX_100M_SRC;
816c6f7c1a3SJoseph Chen 	else if (rate == 50 * MHz)
817c6f7c1a3SJoseph Chen 		sel = CLK_PWM0_SEL_CLK_MATRIX_50M_SRC;
818c6f7c1a3SJoseph Chen 	else
819c6f7c1a3SJoseph Chen 		sel = CLK_PWM0_SEL_XIN_OSC0_FUNC;
820c6f7c1a3SJoseph Chen 
821c6f7c1a3SJoseph Chen 	switch (clk_id) {
822c6f7c1a3SJoseph Chen 	case CLK_PWM0:
823c6f7c1a3SJoseph Chen 		id = 44;
824c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON44_CLK_PWM0_SEL_MASK;
825c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON44_CLK_PWM0_SEL_SHIFT;
826c6f7c1a3SJoseph Chen 		break;
827c6f7c1a3SJoseph Chen 
828c6f7c1a3SJoseph Chen 	case CLK_PWM1:
829c6f7c1a3SJoseph Chen 		id = 44;
830c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON44_CLK_PWM1_SEL_MASK;
831c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON44_CLK_PWM1_SEL_SHIFT;
832c6f7c1a3SJoseph Chen 		break;
833c6f7c1a3SJoseph Chen 
834c6f7c1a3SJoseph Chen 	default:
835c6f7c1a3SJoseph Chen 		return -ENOENT;
836c6f7c1a3SJoseph Chen 	}
837c6f7c1a3SJoseph Chen 
838c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift);
839c6f7c1a3SJoseph Chen 
840c6f7c1a3SJoseph Chen 	return rk3528_pwm_get_clk(priv, clk_id);
841c6f7c1a3SJoseph Chen }
842c6f7c1a3SJoseph Chen 
843c6f7c1a3SJoseph Chen static ulong rk3528_adc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
844c6f7c1a3SJoseph Chen {
845c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
846c6f7c1a3SJoseph Chen 	u32 div, con;
847c6f7c1a3SJoseph Chen 
848c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[74]);
849c6f7c1a3SJoseph Chen 	switch (clk_id) {
850c6f7c1a3SJoseph Chen 	case CLK_SARADC:
851c6f7c1a3SJoseph Chen 		div = (con & CRU_CLKSEL_CON74_CLK_SARADC_DIV_MASK) >>
852c6f7c1a3SJoseph Chen 			CRU_CLKSEL_CON74_CLK_SARADC_DIV_SHIFT;
853c6f7c1a3SJoseph Chen 		break;
854c6f7c1a3SJoseph Chen 
855c6f7c1a3SJoseph Chen 	case CLK_TSADC_TSEN:
856c6f7c1a3SJoseph Chen 		div = (con & CRU_CLKSEL_CON74_CLK_TSADC_TSEN_DIV_MASK) >>
857c6f7c1a3SJoseph Chen 			CRU_CLKSEL_CON74_CLK_TSADC_TSEN_DIV_SHIFT;
858c6f7c1a3SJoseph Chen 		break;
859c6f7c1a3SJoseph Chen 
860c6f7c1a3SJoseph Chen 	case CLK_TSADC:
861c6f7c1a3SJoseph Chen 		div = (con & CRU_CLKSEL_CON74_CLK_TSADC_DIV_MASK) >>
862c6f7c1a3SJoseph Chen 			CRU_CLKSEL_CON74_CLK_TSADC_DIV_SHIFT;
863c6f7c1a3SJoseph Chen 		break;
864c6f7c1a3SJoseph Chen 
865c6f7c1a3SJoseph Chen 	default:
866c6f7c1a3SJoseph Chen 		return -ENOENT;
867c6f7c1a3SJoseph Chen 	}
868c6f7c1a3SJoseph Chen 
869c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(OSC_HZ, div);
870c6f7c1a3SJoseph Chen }
871c6f7c1a3SJoseph Chen 
872c6f7c1a3SJoseph Chen static ulong rk3528_adc_set_clk(struct rk3528_clk_priv *priv,
873c6f7c1a3SJoseph Chen 				ulong clk_id, ulong rate)
874c6f7c1a3SJoseph Chen {
875c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
876c6f7c1a3SJoseph Chen 	u32 div, mask, shift;
877c6f7c1a3SJoseph Chen 
878c6f7c1a3SJoseph Chen 	switch (clk_id) {
879c6f7c1a3SJoseph Chen 	case CLK_SARADC:
880c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON74_CLK_SARADC_DIV_MASK;
881c6f7c1a3SJoseph Chen 		shift =	CRU_CLKSEL_CON74_CLK_SARADC_DIV_SHIFT;
882c6f7c1a3SJoseph Chen 		break;
883c6f7c1a3SJoseph Chen 
884c6f7c1a3SJoseph Chen 	case CLK_TSADC_TSEN:
885c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON74_CLK_TSADC_TSEN_DIV_MASK;
886c6f7c1a3SJoseph Chen 		shift =	CRU_CLKSEL_CON74_CLK_TSADC_TSEN_DIV_SHIFT;
887c6f7c1a3SJoseph Chen 		break;
888c6f7c1a3SJoseph Chen 
889c6f7c1a3SJoseph Chen 	case CLK_TSADC:
890c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON74_CLK_TSADC_DIV_MASK;
891c6f7c1a3SJoseph Chen 		shift =	CRU_CLKSEL_CON74_CLK_TSADC_DIV_SHIFT;
892c6f7c1a3SJoseph Chen 		break;
893c6f7c1a3SJoseph Chen 
894c6f7c1a3SJoseph Chen 	default:
895c6f7c1a3SJoseph Chen 		return -ENOENT;
896c6f7c1a3SJoseph Chen 	}
897c6f7c1a3SJoseph Chen 
898c6f7c1a3SJoseph Chen 	div = DIV_ROUND_UP(OSC_HZ, rate);
899c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[74], mask, (div - 1) << shift);
900c6f7c1a3SJoseph Chen 
901c6f7c1a3SJoseph Chen 	return rk3528_adc_get_clk(priv, clk_id);
902c6f7c1a3SJoseph Chen }
903c6f7c1a3SJoseph Chen 
904c6f7c1a3SJoseph Chen 
905c6f7c1a3SJoseph Chen static ulong rk3528_crypto_get_rate(struct rk3528_clk_priv *priv, ulong clk_id)
906c6f7c1a3SJoseph Chen {
907c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
908c6f7c1a3SJoseph Chen 	u32 id, sel, con, mask, shift;
909c6f7c1a3SJoseph Chen 	ulong rate;
910c6f7c1a3SJoseph Chen 
911c6f7c1a3SJoseph Chen 	switch (clk_id) {
912c6f7c1a3SJoseph Chen 	case CLK_CORE_CRYPTO:
913c6f7c1a3SJoseph Chen 		id = 43;
914c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON43_CLK_CORE_CRYPTO_SEL_MASK;
915c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON43_CLK_CORE_CRYPTO_SEL_SHIFT;
916c6f7c1a3SJoseph Chen 		break;
917c6f7c1a3SJoseph Chen 
918c6f7c1a3SJoseph Chen 	case CLK_PKA_CRYPTO:
919c6f7c1a3SJoseph Chen 		id = 44;
920c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON44_CLK_PKA_CRYPTO_SEL_MASK;
921c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON44_CLK_PKA_CRYPTO_SEL_SHIFT;
922c6f7c1a3SJoseph Chen 		break;
923c6f7c1a3SJoseph Chen 
924c6f7c1a3SJoseph Chen 	default:
925c6f7c1a3SJoseph Chen 		return -ENOENT;
926c6f7c1a3SJoseph Chen 	}
927c6f7c1a3SJoseph Chen 
928c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
929c6f7c1a3SJoseph Chen 	sel = (con & mask) >> shift;
930c6f7c1a3SJoseph Chen 	if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_300M_SRC)
931c6f7c1a3SJoseph Chen 		rate = 300 * MHz;
932c6f7c1a3SJoseph Chen 	else if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_200M_SRC)
933c6f7c1a3SJoseph Chen 		rate = 200 * MHz;
934c6f7c1a3SJoseph Chen 	else if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_100M_SRC)
935c6f7c1a3SJoseph Chen 		rate = 100 * MHz;
936c6f7c1a3SJoseph Chen 	else
937c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
938c6f7c1a3SJoseph Chen 
939c6f7c1a3SJoseph Chen 	return rate;
940c6f7c1a3SJoseph Chen }
941c6f7c1a3SJoseph Chen 
942c6f7c1a3SJoseph Chen static ulong rk3528_crypto_set_rate(struct rk3528_clk_priv *priv,
943c6f7c1a3SJoseph Chen 				    ulong clk_id, ulong rate)
944c6f7c1a3SJoseph Chen {
945c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
946c6f7c1a3SJoseph Chen 	u32 id, sel, mask, shift;
947c6f7c1a3SJoseph Chen 
948c6f7c1a3SJoseph Chen 	if (rate == 300 * MHz)
949c6f7c1a3SJoseph Chen 		sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_300M_SRC;
950c6f7c1a3SJoseph Chen 	else if (rate == 200 * MHz)
951c6f7c1a3SJoseph Chen 		sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_200M_SRC;
952c6f7c1a3SJoseph Chen 	else if (rate == 100 * MHz)
953c6f7c1a3SJoseph Chen 		sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_100M_SRC;
954c6f7c1a3SJoseph Chen 	else
955c6f7c1a3SJoseph Chen 		sel = CLK_CORE_CRYPTO_SEL_XIN_OSC0_FUNC;
956c6f7c1a3SJoseph Chen 
957c6f7c1a3SJoseph Chen 	switch (clk_id) {
958c6f7c1a3SJoseph Chen 	case CLK_CORE_CRYPTO:
959c6f7c1a3SJoseph Chen 		id = 43;
960c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON43_CLK_CORE_CRYPTO_SEL_MASK;
961c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON43_CLK_CORE_CRYPTO_SEL_SHIFT;
962c6f7c1a3SJoseph Chen 		break;
963c6f7c1a3SJoseph Chen 
964c6f7c1a3SJoseph Chen 	case CLK_PKA_CRYPTO:
965c6f7c1a3SJoseph Chen 		id = 44;
966c6f7c1a3SJoseph Chen 		mask = CRU_CLKSEL_CON44_CLK_PKA_CRYPTO_SEL_MASK;
967c6f7c1a3SJoseph Chen 		shift = CRU_CLKSEL_CON44_CLK_PKA_CRYPTO_SEL_SHIFT;
968c6f7c1a3SJoseph Chen 		break;
969c6f7c1a3SJoseph Chen 
970c6f7c1a3SJoseph Chen 	default:
971c6f7c1a3SJoseph Chen 		return -ENOENT;
972c6f7c1a3SJoseph Chen 	}
973c6f7c1a3SJoseph Chen 
974c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift);
975c6f7c1a3SJoseph Chen 
976c6f7c1a3SJoseph Chen 	return rk3528_crypto_get_rate(priv, clk_id);
977c6f7c1a3SJoseph Chen }
978c6f7c1a3SJoseph Chen 
979c6f7c1a3SJoseph Chen static ulong rk3528_sdmmc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
980c6f7c1a3SJoseph Chen {
981c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
982c6f7c1a3SJoseph Chen 	u32 div, sel, con;
983c6f7c1a3SJoseph Chen 	ulong prate;
984c6f7c1a3SJoseph Chen 
985c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[85]);
986c6f7c1a3SJoseph Chen 	div = (con & CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_DIV_MASK) >>
987c6f7c1a3SJoseph Chen 		CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_DIV_SHIFT;
988c6f7c1a3SJoseph Chen 	sel = (con & CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_SEL_MASK) >>
989c6f7c1a3SJoseph Chen 		CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_SEL_SHIFT;
990c6f7c1a3SJoseph Chen 
991c6f7c1a3SJoseph Chen 	if (sel == CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX)
992c6f7c1a3SJoseph Chen 		prate = priv->gpll_hz;
993c6f7c1a3SJoseph Chen 	else if (sel == CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX)
994c6f7c1a3SJoseph Chen 		prate = priv->cpll_hz;
995c6f7c1a3SJoseph Chen 	else
996c6f7c1a3SJoseph Chen 		prate = OSC_HZ;
997c6f7c1a3SJoseph Chen 
998c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(prate, div);
999c6f7c1a3SJoseph Chen }
1000c6f7c1a3SJoseph Chen 
1001c6f7c1a3SJoseph Chen static ulong rk3528_sdmmc_set_clk(struct rk3528_clk_priv *priv,
1002c6f7c1a3SJoseph Chen 				  ulong clk_id, ulong rate)
1003c6f7c1a3SJoseph Chen {
1004c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1005c6f7c1a3SJoseph Chen 	u32 div, sel;
1006c6f7c1a3SJoseph Chen 
1007c6f7c1a3SJoseph Chen 	if (OSC_HZ % rate == 0) {
1008c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(OSC_HZ, rate);
1009c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_SDMMC0_SEL_XIN_OSC0_FUNC;
1010c6f7c1a3SJoseph Chen 	} else if ((priv->cpll_hz % rate) == 0) {
1011c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->cpll_hz, rate);
1012c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX;
1013c6f7c1a3SJoseph Chen 	} else {
1014c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1015c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX;
1016c6f7c1a3SJoseph Chen 	}
1017c6f7c1a3SJoseph Chen 
1018c6f7c1a3SJoseph Chen 	assert(div - 1 <= 31);
1019c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[85],
1020c6f7c1a3SJoseph Chen 		     CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_SEL_MASK |
1021c6f7c1a3SJoseph Chen 		     CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_DIV_MASK,
1022c6f7c1a3SJoseph Chen 		     sel << CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_SEL_SHIFT |
1023c6f7c1a3SJoseph Chen 		     (div - 1) << CRU_CLKSEL_CON85_CCLK_SRC_SDMMC0_DIV_SHIFT);
1024c6f7c1a3SJoseph Chen 
1025c6f7c1a3SJoseph Chen 	return rk3528_sdmmc_get_clk(priv, clk_id);
1026c6f7c1a3SJoseph Chen }
1027c6f7c1a3SJoseph Chen 
1028c6f7c1a3SJoseph Chen static ulong rk3528_sfc_get_clk(struct rk3528_clk_priv *priv)
1029c6f7c1a3SJoseph Chen {
1030c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1031c6f7c1a3SJoseph Chen 	u32 div, sel, con, parent;
1032c6f7c1a3SJoseph Chen 
1033c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[61]);
1034c6f7c1a3SJoseph Chen 	div = (con & CRU_CLKSEL_CON61_SCLK_SFC_DIV_MASK) >>
1035c6f7c1a3SJoseph Chen 		CRU_CLKSEL_CON61_SCLK_SFC_DIV_SHIFT;
1036c6f7c1a3SJoseph Chen 	sel = (con & CRU_CLKSEL_CON61_SCLK_SFC_SEL_MASK) >>
1037c6f7c1a3SJoseph Chen 		CRU_CLKSEL_CON61_SCLK_SFC_SEL_SHIFT;
1038c6f7c1a3SJoseph Chen 	if (sel == SCLK_SFC_SEL_CLK_GPLL_MUX)
1039c6f7c1a3SJoseph Chen 		parent = priv->gpll_hz;
1040c6f7c1a3SJoseph Chen 	else if (sel == SCLK_SFC_SEL_CLK_CPLL_MUX)
1041c6f7c1a3SJoseph Chen 		parent = priv->cpll_hz;
1042c6f7c1a3SJoseph Chen 	else
1043c6f7c1a3SJoseph Chen 		parent = OSC_HZ;
1044c6f7c1a3SJoseph Chen 
1045c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(parent, div);
1046c6f7c1a3SJoseph Chen }
1047c6f7c1a3SJoseph Chen 
1048c6f7c1a3SJoseph Chen static ulong rk3528_sfc_set_clk(struct rk3528_clk_priv *priv, ulong rate)
1049c6f7c1a3SJoseph Chen {
1050c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1051c6f7c1a3SJoseph Chen 	int div, sel;
1052c6f7c1a3SJoseph Chen 
1053c6f7c1a3SJoseph Chen 	if (OSC_HZ % rate == 0) {
1054c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(OSC_HZ, rate);
1055c6f7c1a3SJoseph Chen 		sel = SCLK_SFC_SEL_XIN_OSC0_FUNC;
1056c6f7c1a3SJoseph Chen 	} else if ((priv->cpll_hz % rate) == 0) {
1057c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->cpll_hz, rate);
1058c6f7c1a3SJoseph Chen 		sel = SCLK_SFC_SEL_CLK_CPLL_MUX;
1059c6f7c1a3SJoseph Chen 	} else {
1060c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1061c6f7c1a3SJoseph Chen 		sel = SCLK_SFC_SEL_CLK_GPLL_MUX;
1062c6f7c1a3SJoseph Chen 	}
1063c6f7c1a3SJoseph Chen 
1064c6f7c1a3SJoseph Chen 	assert(div - 1 <= 63);
1065c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[61],
1066c6f7c1a3SJoseph Chen 		     CRU_CLKSEL_CON61_SCLK_SFC_SEL_MASK |
1067c6f7c1a3SJoseph Chen 		     CRU_CLKSEL_CON61_SCLK_SFC_DIV_MASK,
1068c6f7c1a3SJoseph Chen 		     sel << CRU_CLKSEL_CON61_SCLK_SFC_SEL_SHIFT |
1069c6f7c1a3SJoseph Chen 		     (div - 1) << CRU_CLKSEL_CON61_SCLK_SFC_DIV_SHIFT);
1070c6f7c1a3SJoseph Chen 
1071c6f7c1a3SJoseph Chen 	return rk3528_sfc_get_clk(priv);
1072c6f7c1a3SJoseph Chen }
1073c6f7c1a3SJoseph Chen 
1074c6f7c1a3SJoseph Chen static ulong rk3528_emmc_get_clk(struct rk3528_clk_priv *priv)
1075c6f7c1a3SJoseph Chen {
1076c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1077c6f7c1a3SJoseph Chen 	u32 div, sel, con, parent;
1078c6f7c1a3SJoseph Chen 
1079c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[62]);
1080c6f7c1a3SJoseph Chen 	div = (con & CRU_CLKSEL_CON62_CCLK_SRC_EMMC_DIV_MASK) >>
1081c6f7c1a3SJoseph Chen 		CRU_CLKSEL_CON62_CCLK_SRC_EMMC_DIV_SHIFT;
1082c6f7c1a3SJoseph Chen 	sel = (con & CRU_CLKSEL_CON62_CCLK_SRC_EMMC_SEL_MASK) >>
1083c6f7c1a3SJoseph Chen 		CRU_CLKSEL_CON62_CCLK_SRC_EMMC_SEL_SHIFT;
1084c6f7c1a3SJoseph Chen 
1085c6f7c1a3SJoseph Chen 	if (sel == CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX)
1086c6f7c1a3SJoseph Chen 		parent = priv->gpll_hz;
1087c6f7c1a3SJoseph Chen 	else if (sel == CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX)
1088c6f7c1a3SJoseph Chen 		parent = priv->cpll_hz;
1089c6f7c1a3SJoseph Chen 	else
1090c6f7c1a3SJoseph Chen 		parent = OSC_HZ;
1091c6f7c1a3SJoseph Chen 
1092c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(parent, div);
1093c6f7c1a3SJoseph Chen }
1094c6f7c1a3SJoseph Chen 
1095c6f7c1a3SJoseph Chen static ulong rk3528_emmc_set_clk(struct rk3528_clk_priv *priv, ulong rate)
1096c6f7c1a3SJoseph Chen {
1097c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1098c6f7c1a3SJoseph Chen 	u32 div, sel;
1099c6f7c1a3SJoseph Chen 
1100c6f7c1a3SJoseph Chen 	if (OSC_HZ % rate == 0) {
1101c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(OSC_HZ, rate);
1102c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_EMMC_SEL_XIN_OSC0_FUNC;
1103c6f7c1a3SJoseph Chen 	} else if ((priv->cpll_hz % rate) == 0) {
1104c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->cpll_hz, rate);
1105c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX;
1106c6f7c1a3SJoseph Chen 	} else {
1107c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1108c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX;
1109c6f7c1a3SJoseph Chen 	}
1110c6f7c1a3SJoseph Chen 
1111c6f7c1a3SJoseph Chen 	assert(div - 1 <= 31);
1112c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[62],
1113c6f7c1a3SJoseph Chen 		     CRU_CLKSEL_CON62_CCLK_SRC_EMMC_SEL_MASK |
1114c6f7c1a3SJoseph Chen 		     CRU_CLKSEL_CON62_CCLK_SRC_EMMC_DIV_MASK,
1115c6f7c1a3SJoseph Chen 		     sel << CRU_CLKSEL_CON62_CCLK_SRC_EMMC_SEL_SHIFT |
1116c6f7c1a3SJoseph Chen 		     (div - 1) << CRU_CLKSEL_CON62_CCLK_SRC_EMMC_DIV_SHIFT);
1117c6f7c1a3SJoseph Chen 
1118c6f7c1a3SJoseph Chen 	return rk3528_emmc_get_clk(priv);
1119c6f7c1a3SJoseph Chen }
1120c6f7c1a3SJoseph Chen 
1121c6f7c1a3SJoseph Chen static ulong rk3528_dclk_vop_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
1122c6f7c1a3SJoseph Chen {
1123c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1124c6f7c1a3SJoseph Chen 	u32 div_mask, div_shift;
1125c6f7c1a3SJoseph Chen 	u32 sel_mask, sel_shift;
1126c6f7c1a3SJoseph Chen 	u32 id, con, sel, div;
1127c6f7c1a3SJoseph Chen 	ulong prate;
1128c6f7c1a3SJoseph Chen 
1129c6f7c1a3SJoseph Chen 	switch (clk_id) {
1130c6f7c1a3SJoseph Chen 	case DCLK_VOP0:
1131c6f7c1a3SJoseph Chen 		id = 32;
1132c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_SEL_MASK;
1133c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_SEL_SHIFT;
1134c6f7c1a3SJoseph Chen 		/* FIXME if need src: clk_hdmiphy_pixel_io */
1135c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_DIV_MASK;
1136c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_DIV_SHIFT;
1137c6f7c1a3SJoseph Chen 		break;
1138c6f7c1a3SJoseph Chen 
1139c6f7c1a3SJoseph Chen 	case DCLK_VOP1:
1140c6f7c1a3SJoseph Chen 		id = 33;
1141c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_SEL_MASK;
1142c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_SEL_SHIFT;
1143c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_DIV_MASK;
1144c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_DIV_SHIFT;
1145c6f7c1a3SJoseph Chen 		break;
1146c6f7c1a3SJoseph Chen 
1147c6f7c1a3SJoseph Chen 	default:
1148c6f7c1a3SJoseph Chen 		return -ENOENT;
1149c6f7c1a3SJoseph Chen 	}
1150c6f7c1a3SJoseph Chen 
1151c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
1152c6f7c1a3SJoseph Chen 	div = (con & div_mask) >> div_shift;
1153c6f7c1a3SJoseph Chen 	sel = (con & sel_mask) >> sel_shift;
1154c6f7c1a3SJoseph Chen 	if (sel == DCLK_VOP_SRC_SEL_CLK_GPLL_MUX)
1155c6f7c1a3SJoseph Chen 		prate = priv->gpll_hz;
1156c6f7c1a3SJoseph Chen 	else
1157c6f7c1a3SJoseph Chen 		prate = priv->cpll_hz;
1158c6f7c1a3SJoseph Chen 
1159c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(prate, div);
1160c6f7c1a3SJoseph Chen }
1161c6f7c1a3SJoseph Chen 
1162c6f7c1a3SJoseph Chen static ulong rk3528_dclk_vop_set_clk(struct rk3528_clk_priv *priv,
1163c6f7c1a3SJoseph Chen 				     ulong clk_id, ulong rate)
1164c6f7c1a3SJoseph Chen {
1165c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1166c6f7c1a3SJoseph Chen 	u32 div_mask, div_shift;
1167c6f7c1a3SJoseph Chen 	u32 sel_mask, sel_shift;
1168c6f7c1a3SJoseph Chen 	u32 id, sel, div;
1169c6f7c1a3SJoseph Chen 	ulong prate;
1170c6f7c1a3SJoseph Chen 
1171c6f7c1a3SJoseph Chen 	switch (clk_id) {
1172c6f7c1a3SJoseph Chen 	case DCLK_VOP0:
1173c6f7c1a3SJoseph Chen 		id = 32;
1174c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_SEL_MASK;
1175c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_SEL_SHIFT;
1176c6f7c1a3SJoseph Chen 		/* FIXME if need src: clk_hdmiphy_pixel_io */
1177c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_DIV_MASK;
1178c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON32_DCLK_VOP_SRC0_DIV_SHIFT;
1179c6f7c1a3SJoseph Chen 		break;
1180c6f7c1a3SJoseph Chen 
1181c6f7c1a3SJoseph Chen 	case DCLK_VOP1:
1182c6f7c1a3SJoseph Chen 		id = 33;
1183c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_SEL_MASK;
1184c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_SEL_SHIFT;
1185c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_DIV_MASK;
1186c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON33_DCLK_VOP_SRC1_DIV_SHIFT;
1187c6f7c1a3SJoseph Chen 		break;
1188c6f7c1a3SJoseph Chen 
1189c6f7c1a3SJoseph Chen 	default:
1190c6f7c1a3SJoseph Chen 		return -ENOENT;
1191c6f7c1a3SJoseph Chen 	}
1192c6f7c1a3SJoseph Chen 
1193c6f7c1a3SJoseph Chen 	if ((priv->gpll_hz % rate) == 0) {
1194c6f7c1a3SJoseph Chen 		prate = priv->gpll_hz;
1195*9d012e64SJoseph Chen 		sel = (DCLK_VOP_SRC_SEL_CLK_GPLL_MUX << sel_shift) & sel_mask;
1196c6f7c1a3SJoseph Chen 	} else {
1197c6f7c1a3SJoseph Chen 		prate = priv->cpll_hz;
1198*9d012e64SJoseph Chen 		sel = (DCLK_VOP_SRC_SEL_CLK_CPLL_MUX << sel_shift) & sel_mask;
1199c6f7c1a3SJoseph Chen 	}
1200c6f7c1a3SJoseph Chen 
1201*9d012e64SJoseph Chen 	div = ((DIV_ROUND_UP(prate, rate) - 1) << div_shift) & div_mask;
1202c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], sel, div);
1203c6f7c1a3SJoseph Chen 
1204c6f7c1a3SJoseph Chen 	return rk3528_dclk_vop_get_clk(priv, clk_id);
1205c6f7c1a3SJoseph Chen }
1206c6f7c1a3SJoseph Chen 
1207c6f7c1a3SJoseph Chen static ulong rk3528_uart_get_rate(struct rk3528_clk_priv *priv, ulong clk_id)
1208c6f7c1a3SJoseph Chen {
1209c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1210c6f7c1a3SJoseph Chen 	u32 sel_shift, sel_mask, div_shift, div_mask;
1211c6f7c1a3SJoseph Chen 	u32 sel, id, con, frac_div, div;
1212c6f7c1a3SJoseph Chen 	ulong m, n, rate;
1213c6f7c1a3SJoseph Chen 
1214c6f7c1a3SJoseph Chen 	switch (clk_id) {
1215c6f7c1a3SJoseph Chen 	case SCLK_UART0:
1216c6f7c1a3SJoseph Chen 		id = 6;
1217c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON06_SCLK_UART0_SRC_SEL_SHIFT;
1218c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON06_SCLK_UART0_SRC_SEL_MASK;
1219c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON04_CLK_UART0_SRC_DIV_SHIFT;
1220c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON04_CLK_UART0_SRC_DIV_MASK;
1221c6f7c1a3SJoseph Chen 		break;
1222c6f7c1a3SJoseph Chen 
1223c6f7c1a3SJoseph Chen 	case SCLK_UART1:
1224c6f7c1a3SJoseph Chen 		id = 8;
1225c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON08_SCLK_UART1_SRC_SEL_SHIFT;
1226c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON08_SCLK_UART1_SRC_SEL_MASK;
1227c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON06_CLK_UART1_SRC_DIV_SHIFT;
1228c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON06_CLK_UART1_SRC_DIV_MASK;
1229c6f7c1a3SJoseph Chen 		break;
1230c6f7c1a3SJoseph Chen 
1231c6f7c1a3SJoseph Chen 	case SCLK_UART2:
1232c6f7c1a3SJoseph Chen 		id = 10;
1233c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON10_SCLK_UART2_SRC_SEL_SHIFT;
1234c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON10_SCLK_UART2_SRC_SEL_MASK;
1235c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON08_CLK_UART2_SRC_DIV_SHIFT;
1236c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON08_CLK_UART2_SRC_DIV_MASK;
1237c6f7c1a3SJoseph Chen 		break;
1238c6f7c1a3SJoseph Chen 
1239c6f7c1a3SJoseph Chen 	case SCLK_UART3:
1240c6f7c1a3SJoseph Chen 		id = 12;
1241c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON12_SCLK_UART3_SRC_SEL_SHIFT;
1242c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON12_SCLK_UART3_SRC_SEL_MASK;
1243c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON10_CLK_UART3_SRC_DIV_SHIFT;
1244c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON10_CLK_UART3_SRC_DIV_MASK;
1245c6f7c1a3SJoseph Chen 		break;
1246c6f7c1a3SJoseph Chen 
1247c6f7c1a3SJoseph Chen 	case SCLK_UART4:
1248c6f7c1a3SJoseph Chen 		id = 14;
1249c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON14_SCLK_UART4_SRC_SEL_SHIFT;
1250c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON14_SCLK_UART4_SRC_SEL_MASK;
1251c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON12_CLK_UART4_SRC_DIV_SHIFT;
1252c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON12_CLK_UART4_SRC_DIV_MASK;
1253c6f7c1a3SJoseph Chen 		break;
1254c6f7c1a3SJoseph Chen 
1255c6f7c1a3SJoseph Chen 	case SCLK_UART5:
1256c6f7c1a3SJoseph Chen 		id = 16;
1257c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON16_SCLK_UART5_SRC_SEL_SHIFT;
1258c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON16_SCLK_UART5_SRC_SEL_MASK;
1259c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON14_CLK_UART5_SRC_DIV_SHIFT;
1260c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON14_CLK_UART5_SRC_DIV_MASK;
1261c6f7c1a3SJoseph Chen 		break;
1262c6f7c1a3SJoseph Chen 
1263c6f7c1a3SJoseph Chen 	case SCLK_UART6:
1264c6f7c1a3SJoseph Chen 		id = 18;
1265c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON18_SCLK_UART6_SRC_SEL_SHIFT;
1266c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON18_SCLK_UART6_SRC_SEL_MASK;
1267c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON16_CLK_UART6_SRC_DIV_SHIFT;
1268c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON16_CLK_UART6_SRC_DIV_MASK;
1269c6f7c1a3SJoseph Chen 		break;
1270c6f7c1a3SJoseph Chen 
1271c6f7c1a3SJoseph Chen 	case SCLK_UART7:
1272c6f7c1a3SJoseph Chen 		id = 20;
1273c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON20_SCLK_UART7_SRC_SEL_SHIFT;
1274c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON20_SCLK_UART7_SRC_SEL_MASK;
1275c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON18_CLK_UART7_SRC_DIV_SHIFT;
1276c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON18_CLK_UART7_SRC_DIV_MASK;
1277c6f7c1a3SJoseph Chen 		break;
1278c6f7c1a3SJoseph Chen 
1279c6f7c1a3SJoseph Chen 	default:
1280c6f7c1a3SJoseph Chen 		return -ENOENT;
1281c6f7c1a3SJoseph Chen 	}
1282c6f7c1a3SJoseph Chen 
1283c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id - 2]);
1284c6f7c1a3SJoseph Chen 	div = (con & div_mask) >> div_shift;
1285c6f7c1a3SJoseph Chen 
1286c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
1287c6f7c1a3SJoseph Chen 	sel = (con & sel_mask) >> sel_shift;
1288c6f7c1a3SJoseph Chen 
1289c6f7c1a3SJoseph Chen 	if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_SRC) {
1290c6f7c1a3SJoseph Chen 		rate = DIV_TO_RATE(priv->gpll_hz, div);
1291c6f7c1a3SJoseph Chen 	} else if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_FRAC) {
1292c6f7c1a3SJoseph Chen 		frac_div = readl(&cru->clksel_con[id - 1]);
1293c6f7c1a3SJoseph Chen 		n = (frac_div & 0xffff0000) >> 16;
1294c6f7c1a3SJoseph Chen 		m = frac_div & 0x0000ffff;
1295c6f7c1a3SJoseph Chen 		rate = DIV_TO_RATE(priv->gpll_hz, div) * n / m;
1296c6f7c1a3SJoseph Chen 	} else {
1297c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
1298c6f7c1a3SJoseph Chen 	}
1299c6f7c1a3SJoseph Chen 
1300c6f7c1a3SJoseph Chen 	return rate;
1301c6f7c1a3SJoseph Chen }
1302c6f7c1a3SJoseph Chen 
1303c6f7c1a3SJoseph Chen static ulong rk3528_uart_set_rate(struct rk3528_clk_priv *priv,
1304c6f7c1a3SJoseph Chen 				  ulong clk_id, ulong rate)
1305c6f7c1a3SJoseph Chen {
1306c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1307c6f7c1a3SJoseph Chen 	u32 sel_shift, sel_mask, div_shift, div_mask;
1308c6f7c1a3SJoseph Chen 	u32 sel, id, div;
1309c6f7c1a3SJoseph Chen 	ulong m = 0, n = 0, val;
1310c6f7c1a3SJoseph Chen 
1311c6f7c1a3SJoseph Chen 	if (rate == OSC_HZ) {
1312c6f7c1a3SJoseph Chen 		sel = SCLK_UART0_SRC_SEL_XIN_OSC0_FUNC;
1313c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(OSC_HZ, rate);
1314c6f7c1a3SJoseph Chen 	} else if (priv->gpll_hz % rate == 0) {
1315c6f7c1a3SJoseph Chen 		sel = SCLK_UART0_SRC_SEL_CLK_UART0_SRC;
1316c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1317c6f7c1a3SJoseph Chen 	} else {
1318c6f7c1a3SJoseph Chen 		sel = SCLK_UART0_SRC_SEL_CLK_UART0_FRAC;
1319c6f7c1a3SJoseph Chen 		div = 2;
1320c6f7c1a3SJoseph Chen 		rational_best_approximation(rate, priv->gpll_hz / div,
1321c6f7c1a3SJoseph Chen 					    GENMASK(16 - 1, 0),
1322c6f7c1a3SJoseph Chen 					    GENMASK(16 - 1, 0),
1323c6f7c1a3SJoseph Chen 					    &n, &m);
1324c6f7c1a3SJoseph Chen 	}
1325c6f7c1a3SJoseph Chen 
1326c6f7c1a3SJoseph Chen 	switch (clk_id) {
1327c6f7c1a3SJoseph Chen 	case SCLK_UART0:
1328c6f7c1a3SJoseph Chen 		id = 6;
1329c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON06_SCLK_UART0_SRC_SEL_SHIFT;
1330c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON06_SCLK_UART0_SRC_SEL_MASK;
1331c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON04_CLK_UART0_SRC_DIV_SHIFT;
1332c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON04_CLK_UART0_SRC_DIV_MASK;
1333c6f7c1a3SJoseph Chen 		break;
1334c6f7c1a3SJoseph Chen 
1335c6f7c1a3SJoseph Chen 	case SCLK_UART1:
1336c6f7c1a3SJoseph Chen 		id = 8;
1337c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON08_SCLK_UART1_SRC_SEL_SHIFT;
1338c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON08_SCLK_UART1_SRC_SEL_MASK;
1339c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON06_CLK_UART1_SRC_DIV_SHIFT;
1340c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON06_CLK_UART1_SRC_DIV_MASK;
1341c6f7c1a3SJoseph Chen 		break;
1342c6f7c1a3SJoseph Chen 
1343c6f7c1a3SJoseph Chen 	case SCLK_UART2:
1344c6f7c1a3SJoseph Chen 		id = 10;
1345c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON10_SCLK_UART2_SRC_SEL_SHIFT;
1346c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON10_SCLK_UART2_SRC_SEL_MASK;
1347c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON08_CLK_UART2_SRC_DIV_SHIFT;
1348c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON08_CLK_UART2_SRC_DIV_MASK;
1349c6f7c1a3SJoseph Chen 		break;
1350c6f7c1a3SJoseph Chen 
1351c6f7c1a3SJoseph Chen 	case SCLK_UART3:
1352c6f7c1a3SJoseph Chen 		id = 12;
1353c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON12_SCLK_UART3_SRC_SEL_SHIFT;
1354c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON12_SCLK_UART3_SRC_SEL_MASK;
1355c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON10_CLK_UART3_SRC_DIV_SHIFT;
1356c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON10_CLK_UART3_SRC_DIV_MASK;
1357c6f7c1a3SJoseph Chen 		break;
1358c6f7c1a3SJoseph Chen 
1359c6f7c1a3SJoseph Chen 	case SCLK_UART4:
1360c6f7c1a3SJoseph Chen 		id = 14;
1361c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON14_SCLK_UART4_SRC_SEL_SHIFT;
1362c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON14_SCLK_UART4_SRC_SEL_MASK;
1363c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON12_CLK_UART4_SRC_DIV_SHIFT;
1364c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON12_CLK_UART4_SRC_DIV_MASK;
1365c6f7c1a3SJoseph Chen 		break;
1366c6f7c1a3SJoseph Chen 
1367c6f7c1a3SJoseph Chen 	case SCLK_UART5:
1368c6f7c1a3SJoseph Chen 		id = 16;
1369c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON16_SCLK_UART5_SRC_SEL_SHIFT;
1370c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON16_SCLK_UART5_SRC_SEL_MASK;
1371c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON14_CLK_UART5_SRC_DIV_SHIFT;
1372c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON14_CLK_UART5_SRC_DIV_MASK;
1373c6f7c1a3SJoseph Chen 		break;
1374c6f7c1a3SJoseph Chen 
1375c6f7c1a3SJoseph Chen 	case SCLK_UART6:
1376c6f7c1a3SJoseph Chen 		id = 18;
1377c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON18_SCLK_UART6_SRC_SEL_SHIFT;
1378c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON18_SCLK_UART6_SRC_SEL_MASK;
1379c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON16_CLK_UART6_SRC_DIV_SHIFT;
1380c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON16_CLK_UART6_SRC_DIV_MASK;
1381c6f7c1a3SJoseph Chen 		break;
1382c6f7c1a3SJoseph Chen 
1383c6f7c1a3SJoseph Chen 	case SCLK_UART7:
1384c6f7c1a3SJoseph Chen 		id = 20;
1385c6f7c1a3SJoseph Chen 		sel_shift = CRU_CLKSEL_CON20_SCLK_UART7_SRC_SEL_SHIFT;
1386c6f7c1a3SJoseph Chen 		sel_mask = CRU_CLKSEL_CON20_SCLK_UART7_SRC_SEL_MASK;
1387c6f7c1a3SJoseph Chen 		div_shift = CRU_CLKSEL_CON18_CLK_UART7_SRC_DIV_SHIFT;
1388c6f7c1a3SJoseph Chen 		div_mask = CRU_CLKSEL_CON18_CLK_UART7_SRC_DIV_MASK;
1389c6f7c1a3SJoseph Chen 		break;
1390c6f7c1a3SJoseph Chen 
1391c6f7c1a3SJoseph Chen 	default:
1392c6f7c1a3SJoseph Chen 		return -ENOENT;
1393c6f7c1a3SJoseph Chen 	}
1394c6f7c1a3SJoseph Chen 
1395c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id - 2], div_mask, (div - 1) << div_shift);
1396c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], sel_mask, sel << sel_shift);
1397c6f7c1a3SJoseph Chen 	if (m && n) {
1398c6f7c1a3SJoseph Chen 		val = n << 16 | m;
1399c6f7c1a3SJoseph Chen 		writel(val, &cru->clksel_con[id - 1]);
1400c6f7c1a3SJoseph Chen 	}
1401c6f7c1a3SJoseph Chen 
1402c6f7c1a3SJoseph Chen 	return rk3528_uart_get_rate(priv, clk_id);
1403c6f7c1a3SJoseph Chen }
1404c6f7c1a3SJoseph Chen 
1405c6f7c1a3SJoseph Chen static ulong rk3528_clk_get_rate(struct clk *clk)
1406c6f7c1a3SJoseph Chen {
1407c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(clk->dev);
1408c6f7c1a3SJoseph Chen 	ulong rate = 0;
1409c6f7c1a3SJoseph Chen 
1410c6f7c1a3SJoseph Chen 	if (!priv->gpll_hz || !priv->cpll_hz) {
1411c6f7c1a3SJoseph Chen 		printf("%s: gpll=%lu, cpll=%ld\n",
1412c6f7c1a3SJoseph Chen 		       __func__, priv->gpll_hz, priv->cpll_hz);
1413c6f7c1a3SJoseph Chen 		return -ENOENT;
1414c6f7c1a3SJoseph Chen 	}
1415c6f7c1a3SJoseph Chen 
1416c6f7c1a3SJoseph Chen 	switch (clk->id) {
1417c6f7c1a3SJoseph Chen 	case PLL_APLL:
1418c6f7c1a3SJoseph Chen 	case ARMCLK:
1419c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru,
1420c6f7c1a3SJoseph Chen 					     APLL);
1421c6f7c1a3SJoseph Chen 		break;
1422c6f7c1a3SJoseph Chen 	case PLL_CPLL:
1423c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL], priv->cru,
1424c6f7c1a3SJoseph Chen 					     CPLL);
1425c6f7c1a3SJoseph Chen 		break;
1426c6f7c1a3SJoseph Chen 	case PLL_GPLL:
1427c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL], priv->cru,
1428c6f7c1a3SJoseph Chen 					     GPLL);
1429c6f7c1a3SJoseph Chen 		break;
1430c6f7c1a3SJoseph Chen 
1431c6f7c1a3SJoseph Chen 	case PLL_PPLL:
1432c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], priv->cru,
1433c6f7c1a3SJoseph Chen 					     PPLL);
1434c6f7c1a3SJoseph Chen 		break;
1435c6f7c1a3SJoseph Chen 	case PLL_DPLL:
1436c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[DPLL], priv->cru,
1437c6f7c1a3SJoseph Chen 					     DPLL);
1438c6f7c1a3SJoseph Chen 		break;
1439c6f7c1a3SJoseph Chen 
1440c6f7c1a3SJoseph Chen 	case TCLK_WDT_NS:
1441c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
1442c6f7c1a3SJoseph Chen 		break;
1443c6f7c1a3SJoseph Chen 	case CLK_I2C0:
1444c6f7c1a3SJoseph Chen 	case CLK_I2C1:
1445c6f7c1a3SJoseph Chen 	case CLK_I2C2:
1446c6f7c1a3SJoseph Chen 	case CLK_I2C3:
1447c6f7c1a3SJoseph Chen 	case CLK_I2C4:
1448c6f7c1a3SJoseph Chen 	case CLK_I2C5:
1449c6f7c1a3SJoseph Chen 	case CLK_I2C6:
1450c6f7c1a3SJoseph Chen 	case CLK_I2C7:
1451c6f7c1a3SJoseph Chen 		rate = rk3528_i2c_get_clk(priv, clk->id);
1452c6f7c1a3SJoseph Chen 		break;
1453c6f7c1a3SJoseph Chen 	case CLK_SPI0:
1454c6f7c1a3SJoseph Chen 	case CLK_SPI1:
1455c6f7c1a3SJoseph Chen 		rate = rk3528_spi_get_clk(priv, clk->id);
1456c6f7c1a3SJoseph Chen 		break;
1457c6f7c1a3SJoseph Chen 	case CLK_PWM0:
1458c6f7c1a3SJoseph Chen 	case CLK_PWM1:
1459c6f7c1a3SJoseph Chen 		rate = rk3528_pwm_get_clk(priv, clk->id);
1460c6f7c1a3SJoseph Chen 		break;
1461c6f7c1a3SJoseph Chen 	case CLK_SARADC:
1462c6f7c1a3SJoseph Chen 	case CLK_TSADC:
1463c6f7c1a3SJoseph Chen 	case CLK_TSADC_TSEN:
1464c6f7c1a3SJoseph Chen 		rate = rk3528_adc_get_clk(priv, clk->id);
1465c6f7c1a3SJoseph Chen 		break;
1466c6f7c1a3SJoseph Chen 	case CCLK_SRC_EMMC:
1467c6f7c1a3SJoseph Chen 		rate = rk3528_emmc_get_clk(priv);
1468c6f7c1a3SJoseph Chen 		break;
1469c6f7c1a3SJoseph Chen 	case HCLK_SDMMC0:
1470c6f7c1a3SJoseph Chen 	case CCLK_SRC_SDMMC0:
1471c6f7c1a3SJoseph Chen 		rate = rk3528_sdmmc_get_clk(priv, clk->id);
1472c6f7c1a3SJoseph Chen 		break;
1473c6f7c1a3SJoseph Chen 	case SCLK_SFC:
1474c6f7c1a3SJoseph Chen 		rate = rk3528_sfc_get_clk(priv);
1475c6f7c1a3SJoseph Chen 		break;
1476c6f7c1a3SJoseph Chen 	case DCLK_VOP0:
1477c6f7c1a3SJoseph Chen 	case DCLK_VOP1:
1478c6f7c1a3SJoseph Chen 		rate = rk3528_dclk_vop_get_clk(priv, clk->id);
1479c6f7c1a3SJoseph Chen 		break;
1480c6f7c1a3SJoseph Chen 	case DCLK_CVBS:
1481c6f7c1a3SJoseph Chen 		rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1) / 4;
1482c6f7c1a3SJoseph Chen 		break;
1483c6f7c1a3SJoseph Chen 	case DCLK_4X_CVBS:
1484c6f7c1a3SJoseph Chen 		rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1);
1485c6f7c1a3SJoseph Chen 		break;
1486c6f7c1a3SJoseph Chen 	case SCLK_UART0:
1487c6f7c1a3SJoseph Chen 	case SCLK_UART1:
1488c6f7c1a3SJoseph Chen 	case SCLK_UART2:
1489c6f7c1a3SJoseph Chen 	case SCLK_UART3:
1490c6f7c1a3SJoseph Chen 	case SCLK_UART4:
1491c6f7c1a3SJoseph Chen 	case SCLK_UART5:
1492c6f7c1a3SJoseph Chen 	case SCLK_UART6:
1493c6f7c1a3SJoseph Chen 	case SCLK_UART7:
1494c6f7c1a3SJoseph Chen 		rate = rk3528_uart_get_rate(priv, clk->id);
1495c6f7c1a3SJoseph Chen 		break;
1496c6f7c1a3SJoseph Chen 	case CLK_CORE_CRYPTO:
1497c6f7c1a3SJoseph Chen 	case CLK_PKA_CRYPTO:
1498c6f7c1a3SJoseph Chen 		rate = rk3528_crypto_get_rate(priv, clk->id);
1499c6f7c1a3SJoseph Chen 		break;
1500c6f7c1a3SJoseph Chen 	case CLK_MATRIX_50M_SRC:
1501c6f7c1a3SJoseph Chen 	case CLK_MATRIX_100M_SRC:
1502c6f7c1a3SJoseph Chen 	case CLK_MATRIX_150M_SRC:
1503c6f7c1a3SJoseph Chen 	case CLK_MATRIX_200M_SRC:
1504c6f7c1a3SJoseph Chen 	case CLK_MATRIX_250M_SRC:
1505c6f7c1a3SJoseph Chen 	case CLK_MATRIX_300M_SRC:
1506c6f7c1a3SJoseph Chen 	case CLK_MATRIX_339M_SRC:
1507c6f7c1a3SJoseph Chen 	case CLK_MATRIX_400M_SRC:
1508c6f7c1a3SJoseph Chen 	case CLK_MATRIX_500M_SRC:
1509c6f7c1a3SJoseph Chen 	case CLK_MATRIX_600M_SRC:
1510c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_BIU:
1511c6f7c1a3SJoseph Chen 		rate = rk3528_cgpll_matrix_get_rate(priv, clk->id);
1512c6f7c1a3SJoseph Chen 		break;
1513c6f7c1a3SJoseph Chen 	case CLK_PPLL_50M_MATRIX:
1514c6f7c1a3SJoseph Chen 	case CLK_PPLL_100M_MATRIX:
1515c6f7c1a3SJoseph Chen 	case CLK_PPLL_125M_MATRIX:
1516c6f7c1a3SJoseph Chen 	case CLK_GMAC1_VPU_25M:
1517c6f7c1a3SJoseph Chen 	case CLK_GMAC1_RMII_VPU:
1518c6f7c1a3SJoseph Chen 	case CLK_GMAC1_SRC_VPU:
1519c6f7c1a3SJoseph Chen 		rate = rk3528_ppll_matrix_get_rate(priv, clk->id);
1520c6f7c1a3SJoseph Chen 		break;
1521c6f7c1a3SJoseph Chen 	default:
1522c6f7c1a3SJoseph Chen 		return -ENOENT;
1523c6f7c1a3SJoseph Chen 	}
1524c6f7c1a3SJoseph Chen 
1525c6f7c1a3SJoseph Chen 	return rate;
1526c6f7c1a3SJoseph Chen };
1527c6f7c1a3SJoseph Chen 
1528c6f7c1a3SJoseph Chen static ulong rk3528_clk_set_rate(struct clk *clk, ulong rate)
1529c6f7c1a3SJoseph Chen {
1530c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(clk->dev);
1531c6f7c1a3SJoseph Chen 	ulong ret = 0;
1532c6f7c1a3SJoseph Chen 
1533c6f7c1a3SJoseph Chen 	if (!priv->gpll_hz) {
1534c6f7c1a3SJoseph Chen 		printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1535c6f7c1a3SJoseph Chen 		return -ENOENT;
1536c6f7c1a3SJoseph Chen 	}
1537c6f7c1a3SJoseph Chen 
1538c6f7c1a3SJoseph Chen 	switch (clk->id) {
1539c6f7c1a3SJoseph Chen 	case PLL_APLL:
1540c6f7c1a3SJoseph Chen 	case ARMCLK:
1541c6f7c1a3SJoseph Chen 		if (priv->armclk_hz)
1542c6f7c1a3SJoseph Chen 			rk3528_armclk_set_clk(priv, rate);
1543c6f7c1a3SJoseph Chen 		priv->armclk_hz = rate;
1544c6f7c1a3SJoseph Chen 		break;
1545c6f7c1a3SJoseph Chen 	case PLL_CPLL:
1546c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru,
1547c6f7c1a3SJoseph Chen 					    CPLL, rate);
1548c6f7c1a3SJoseph Chen 		priv->cpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL],
1549c6f7c1a3SJoseph Chen 						      priv->cru, CPLL);
1550c6f7c1a3SJoseph Chen 		break;
1551c6f7c1a3SJoseph Chen 	case PLL_GPLL:
1552c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru,
1553c6f7c1a3SJoseph Chen 					    GPLL, rate);
1554c6f7c1a3SJoseph Chen 		priv->gpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL],
1555c6f7c1a3SJoseph Chen 						      priv->cru, GPLL);
1556c6f7c1a3SJoseph Chen 		break;
1557c6f7c1a3SJoseph Chen 	case PLL_PPLL:
1558c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru,
1559c6f7c1a3SJoseph Chen 					    PPLL, rate);
1560c6f7c1a3SJoseph Chen 		priv->ppll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL],
1561c6f7c1a3SJoseph Chen 						      priv->cru, PPLL);
1562c6f7c1a3SJoseph Chen 		break;
1563c6f7c1a3SJoseph Chen 	case TCLK_WDT_NS:
1564c6f7c1a3SJoseph Chen 		return (rate == OSC_HZ) ? 0 : -EINVAL;
1565c6f7c1a3SJoseph Chen 	case CLK_I2C0:
1566c6f7c1a3SJoseph Chen 	case CLK_I2C1:
1567c6f7c1a3SJoseph Chen 	case CLK_I2C2:
1568c6f7c1a3SJoseph Chen 	case CLK_I2C3:
1569c6f7c1a3SJoseph Chen 	case CLK_I2C4:
1570c6f7c1a3SJoseph Chen 	case CLK_I2C5:
1571c6f7c1a3SJoseph Chen 	case CLK_I2C6:
1572c6f7c1a3SJoseph Chen 	case CLK_I2C7:
1573c6f7c1a3SJoseph Chen 		ret = rk3528_i2c_set_clk(priv, clk->id, rate);
1574c6f7c1a3SJoseph Chen 		break;
1575c6f7c1a3SJoseph Chen 	case CLK_SPI0:
1576c6f7c1a3SJoseph Chen 	case CLK_SPI1:
1577c6f7c1a3SJoseph Chen 		ret = rk3528_spi_set_clk(priv, clk->id, rate);
1578c6f7c1a3SJoseph Chen 		break;
1579c6f7c1a3SJoseph Chen 	case CLK_PWM0:
1580c6f7c1a3SJoseph Chen 	case CLK_PWM1:
1581c6f7c1a3SJoseph Chen 		ret = rk3528_pwm_set_clk(priv, clk->id, rate);
1582c6f7c1a3SJoseph Chen 		break;
1583c6f7c1a3SJoseph Chen 	case CLK_SARADC:
1584c6f7c1a3SJoseph Chen 	case CLK_TSADC:
1585c6f7c1a3SJoseph Chen 	case CLK_TSADC_TSEN:
1586c6f7c1a3SJoseph Chen 		ret = rk3528_adc_set_clk(priv, clk->id, rate);
1587c6f7c1a3SJoseph Chen 		break;
1588c6f7c1a3SJoseph Chen 	case HCLK_SDMMC0:
1589c6f7c1a3SJoseph Chen 	case CCLK_SRC_SDMMC0:
1590c6f7c1a3SJoseph Chen 		ret = rk3528_sdmmc_set_clk(priv, clk->id, rate);
1591c6f7c1a3SJoseph Chen 		break;
1592c6f7c1a3SJoseph Chen 	case SCLK_SFC:
1593c6f7c1a3SJoseph Chen 		ret = rk3528_sfc_set_clk(priv, rate);
1594c6f7c1a3SJoseph Chen 		break;
1595c6f7c1a3SJoseph Chen 	case CCLK_SRC_EMMC:
1596c6f7c1a3SJoseph Chen 		ret = rk3528_emmc_set_clk(priv, rate);
1597c6f7c1a3SJoseph Chen 		break;
1598c6f7c1a3SJoseph Chen 	case DCLK_VOP0:
1599c6f7c1a3SJoseph Chen 	case DCLK_VOP1:
1600c6f7c1a3SJoseph Chen 		ret = rk3528_dclk_vop_set_clk(priv, clk->id, rate);
1601c6f7c1a3SJoseph Chen 		break;
1602c6f7c1a3SJoseph Chen 	case SCLK_UART0:
1603c6f7c1a3SJoseph Chen 	case SCLK_UART1:
1604c6f7c1a3SJoseph Chen 	case SCLK_UART2:
1605c6f7c1a3SJoseph Chen 	case SCLK_UART3:
1606c6f7c1a3SJoseph Chen 	case SCLK_UART4:
1607c6f7c1a3SJoseph Chen 	case SCLK_UART5:
1608c6f7c1a3SJoseph Chen 	case SCLK_UART6:
1609c6f7c1a3SJoseph Chen 	case SCLK_UART7:
1610c6f7c1a3SJoseph Chen 		ret = rk3528_uart_set_rate(priv, clk->id, rate);
1611c6f7c1a3SJoseph Chen 		break;
1612c6f7c1a3SJoseph Chen 	case CLK_CORE_CRYPTO:
1613c6f7c1a3SJoseph Chen 	case CLK_PKA_CRYPTO:
1614c6f7c1a3SJoseph Chen 		ret = rk3528_crypto_set_rate(priv, clk->id, rate);
1615c6f7c1a3SJoseph Chen 		break;
1616c6f7c1a3SJoseph Chen 	case CLK_MATRIX_50M_SRC:
1617c6f7c1a3SJoseph Chen 	case CLK_MATRIX_100M_SRC:
1618c6f7c1a3SJoseph Chen 	case CLK_MATRIX_150M_SRC:
1619c6f7c1a3SJoseph Chen 	case CLK_MATRIX_200M_SRC:
1620c6f7c1a3SJoseph Chen 	case CLK_MATRIX_250M_SRC:
1621c6f7c1a3SJoseph Chen 	case CLK_MATRIX_300M_SRC:
1622c6f7c1a3SJoseph Chen 	case CLK_MATRIX_339M_SRC:
1623c6f7c1a3SJoseph Chen 	case CLK_MATRIX_400M_SRC:
1624c6f7c1a3SJoseph Chen 	case CLK_MATRIX_500M_SRC:
1625c6f7c1a3SJoseph Chen 	case CLK_MATRIX_600M_SRC:
1626c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_BIU:
1627c6f7c1a3SJoseph Chen 		ret = rk3528_cgpll_matrix_set_rate(priv, clk->id, rate);
1628c6f7c1a3SJoseph Chen 		break;
1629c6f7c1a3SJoseph Chen 	case CLK_PPLL_50M_MATRIX:
1630c6f7c1a3SJoseph Chen 	case CLK_PPLL_100M_MATRIX:
1631c6f7c1a3SJoseph Chen 	case CLK_PPLL_125M_MATRIX:
1632c6f7c1a3SJoseph Chen 	case CLK_GMAC1_VPU_25M:
1633c6f7c1a3SJoseph Chen 		ret = rk3528_ppll_matrix_set_rate(priv, clk->id, rate);
1634c6f7c1a3SJoseph Chen 		break;
1635a9533156SJoseph Chen 	case CLK_GMAC1_RMII_VPU:
1636a9533156SJoseph Chen 	case CLK_GMAC1_SRC_VPU:
1637a9533156SJoseph Chen 		/* dummy set */
1638a9533156SJoseph Chen 		ret = rk3528_ppll_matrix_get_rate(priv, clk->id);
1639a9533156SJoseph Chen 		break;
1640c6f7c1a3SJoseph Chen 	default:
1641c6f7c1a3SJoseph Chen 		return -ENOENT;
1642c6f7c1a3SJoseph Chen 	}
1643c6f7c1a3SJoseph Chen 
1644c6f7c1a3SJoseph Chen 	return ret;
1645c6f7c1a3SJoseph Chen };
1646c6f7c1a3SJoseph Chen 
1647c6f7c1a3SJoseph Chen 
1648c6f7c1a3SJoseph Chen static struct clk_ops rk3528_clk_ops = {
1649c6f7c1a3SJoseph Chen 	.get_rate = rk3528_clk_get_rate,
1650c6f7c1a3SJoseph Chen 	.set_rate = rk3528_clk_set_rate,
1651c6f7c1a3SJoseph Chen };
1652c6f7c1a3SJoseph Chen 
1653c6f7c1a3SJoseph Chen static ulong rk3528_grfclk_get_rate(struct clk *clk)
1654c6f7c1a3SJoseph Chen {
1655c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv;
1656c6f7c1a3SJoseph Chen 	struct udevice *cru_dev;
1657c6f7c1a3SJoseph Chen 	ulong rate = 0;
1658c6f7c1a3SJoseph Chen 	int ret;
1659c6f7c1a3SJoseph Chen 
1660c6f7c1a3SJoseph Chen 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1661c6f7c1a3SJoseph Chen 					  DM_GET_DRIVER(rockchip_rk3528_cru),
1662c6f7c1a3SJoseph Chen 					  &cru_dev);
1663c6f7c1a3SJoseph Chen 	if (ret) {
1664c6f7c1a3SJoseph Chen 		printf("%s: could not find cru device\n", __func__);
1665c6f7c1a3SJoseph Chen 		return ret;
1666c6f7c1a3SJoseph Chen 	}
1667c6f7c1a3SJoseph Chen 	priv = dev_get_priv(cru_dev);
1668c6f7c1a3SJoseph Chen 
1669c6f7c1a3SJoseph Chen 	switch (clk->id) {
1670c6f7c1a3SJoseph Chen 	case SCLK_SDMMC_SAMPLE:
1671c6f7c1a3SJoseph Chen 		rate = rk3528_sdmmc_get_clk(priv, CCLK_SRC_SDMMC0) / 2;
1672c6f7c1a3SJoseph Chen 		break;
1673c6f7c1a3SJoseph Chen 	default:
1674c6f7c1a3SJoseph Chen 		return -ENOENT;
1675c6f7c1a3SJoseph Chen 	}
1676c6f7c1a3SJoseph Chen 
1677c6f7c1a3SJoseph Chen 	return rate;
1678c6f7c1a3SJoseph Chen };
1679c6f7c1a3SJoseph Chen 
1680c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAY_SEL		BIT(11)
1681c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DEGREE_MASK	0x3
1682c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAYNUM_OFFSET	3
1683c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
1684c6f7c1a3SJoseph Chen #define PSECS_PER_SEC 1000000000000LL
1685c6f7c1a3SJoseph Chen /*
1686c6f7c1a3SJoseph Chen  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
1687c6f7c1a3SJoseph Chen  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
1688c6f7c1a3SJoseph Chen  */
1689c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
1690c6f7c1a3SJoseph Chen 
1691c6f7c1a3SJoseph Chen int rk3528_mmc_get_phase(struct clk *clk)
1692c6f7c1a3SJoseph Chen {
1693c6f7c1a3SJoseph Chen 	struct rk3528_grf_clk_priv *priv = dev_get_priv(clk->dev);
1694c6f7c1a3SJoseph Chen 	u32 raw_value = 0, delay_num;
1695c6f7c1a3SJoseph Chen 	u16 degrees = 0;
1696c6f7c1a3SJoseph Chen 	ulong rate;
1697c6f7c1a3SJoseph Chen 
1698c6f7c1a3SJoseph Chen 	rate = rk3528_grfclk_get_rate(clk);
1699c6f7c1a3SJoseph Chen 	if (rate < 0)
1700c6f7c1a3SJoseph Chen 		return rate;
1701c6f7c1a3SJoseph Chen 
1702c6f7c1a3SJoseph Chen 	if (clk->id == SCLK_SDMMC_SAMPLE)
1703c6f7c1a3SJoseph Chen 		raw_value = readl(&priv->grf->sdmmc_con1);
1704c6f7c1a3SJoseph Chen 	else
1705c6f7c1a3SJoseph Chen 		return -ENONET;
1706c6f7c1a3SJoseph Chen 
1707c6f7c1a3SJoseph Chen 	raw_value >>= 1;
1708c6f7c1a3SJoseph Chen 	degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
1709c6f7c1a3SJoseph Chen 
1710c6f7c1a3SJoseph Chen 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
1711c6f7c1a3SJoseph Chen 		/* degrees/delaynum * 10000 */
1712c6f7c1a3SJoseph Chen 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
1713c6f7c1a3SJoseph Chen 					36 * (rate / 1000000);
1714c6f7c1a3SJoseph Chen 
1715c6f7c1a3SJoseph Chen 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
1716c6f7c1a3SJoseph Chen 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
1717c6f7c1a3SJoseph Chen 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
1718c6f7c1a3SJoseph Chen 	}
1719c6f7c1a3SJoseph Chen 
1720c6f7c1a3SJoseph Chen 	return degrees % 360;
1721c6f7c1a3SJoseph Chen }
1722c6f7c1a3SJoseph Chen 
1723c6f7c1a3SJoseph Chen int rk3528_mmc_set_phase(struct clk *clk, u32 degrees)
1724c6f7c1a3SJoseph Chen {
1725c6f7c1a3SJoseph Chen 	struct rk3528_grf_clk_priv *priv = dev_get_priv(clk->dev);
1726c6f7c1a3SJoseph Chen 	u8 nineties, remainder, delay_num;
1727c6f7c1a3SJoseph Chen 	u32 raw_value, delay;
1728c6f7c1a3SJoseph Chen 	ulong rate;
1729c6f7c1a3SJoseph Chen 
1730c6f7c1a3SJoseph Chen 	rate = rk3528_grfclk_get_rate(clk);
1731c6f7c1a3SJoseph Chen 	if (rate < 0)
1732c6f7c1a3SJoseph Chen 		return rate;
1733c6f7c1a3SJoseph Chen 
1734c6f7c1a3SJoseph Chen 	nineties = degrees / 90;
1735c6f7c1a3SJoseph Chen 	remainder = (degrees % 90);
1736c6f7c1a3SJoseph Chen 
1737c6f7c1a3SJoseph Chen 	/*
1738c6f7c1a3SJoseph Chen 	 * Convert to delay; do a little extra work to make sure we
1739c6f7c1a3SJoseph Chen 	 * don't overflow 32-bit / 64-bit numbers.
1740c6f7c1a3SJoseph Chen 	 */
1741c6f7c1a3SJoseph Chen 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
1742c6f7c1a3SJoseph Chen 	delay *= remainder;
1743c6f7c1a3SJoseph Chen 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
1744c6f7c1a3SJoseph Chen 				  (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
1745c6f7c1a3SJoseph Chen 
1746c6f7c1a3SJoseph Chen 	delay_num = (u8)min_t(u32, delay, 255);
1747c6f7c1a3SJoseph Chen 
1748c6f7c1a3SJoseph Chen 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
1749c6f7c1a3SJoseph Chen 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
1750c6f7c1a3SJoseph Chen 	raw_value |= nineties;
1751c6f7c1a3SJoseph Chen 
1752c6f7c1a3SJoseph Chen 	raw_value <<= 1;
1753c6f7c1a3SJoseph Chen 	if (clk->id == SCLK_SDMMC_SAMPLE)
1754c6f7c1a3SJoseph Chen 		writel(raw_value | 0xffff0000, &priv->grf->sdmmc_con1);
1755c6f7c1a3SJoseph Chen 	else
1756c6f7c1a3SJoseph Chen 		return -ENONET;
1757c6f7c1a3SJoseph Chen 
1758c6f7c1a3SJoseph Chen 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
1759c6f7c1a3SJoseph Chen 	      degrees, delay_num, raw_value, rk3528_mmc_get_phase(clk));
1760c6f7c1a3SJoseph Chen 
1761c6f7c1a3SJoseph Chen 	return 0;
1762c6f7c1a3SJoseph Chen }
1763c6f7c1a3SJoseph Chen 
1764c6f7c1a3SJoseph Chen static int rk3528_grfclk_get_phase(struct clk *clk)
1765c6f7c1a3SJoseph Chen {
1766c6f7c1a3SJoseph Chen 	int ret;
1767c6f7c1a3SJoseph Chen 
1768c6f7c1a3SJoseph Chen 	debug("%s %ld\n", __func__, clk->id);
1769c6f7c1a3SJoseph Chen 	switch (clk->id) {
1770c6f7c1a3SJoseph Chen 	case SCLK_SDMMC_SAMPLE:
1771c6f7c1a3SJoseph Chen 		ret = rk3528_mmc_get_phase(clk);
1772c6f7c1a3SJoseph Chen 		break;
1773c6f7c1a3SJoseph Chen 	default:
1774c6f7c1a3SJoseph Chen 		return -ENOENT;
1775c6f7c1a3SJoseph Chen 	}
1776c6f7c1a3SJoseph Chen 
1777c6f7c1a3SJoseph Chen 	return ret;
1778c6f7c1a3SJoseph Chen }
1779c6f7c1a3SJoseph Chen 
1780c6f7c1a3SJoseph Chen static int rk3528_grfclk_set_phase(struct clk *clk, int degrees)
1781c6f7c1a3SJoseph Chen {
1782c6f7c1a3SJoseph Chen 	int ret;
1783c6f7c1a3SJoseph Chen 
1784c6f7c1a3SJoseph Chen 	debug("%s %ld\n", __func__, clk->id);
1785c6f7c1a3SJoseph Chen 	switch (clk->id) {
1786c6f7c1a3SJoseph Chen 	case SCLK_SDMMC_SAMPLE:
1787c6f7c1a3SJoseph Chen 		ret = rk3528_mmc_set_phase(clk, degrees);
1788c6f7c1a3SJoseph Chen 		break;
1789c6f7c1a3SJoseph Chen 	default:
1790c6f7c1a3SJoseph Chen 		return -ENOENT;
1791c6f7c1a3SJoseph Chen 	}
1792c6f7c1a3SJoseph Chen 
1793c6f7c1a3SJoseph Chen 	return ret;
1794c6f7c1a3SJoseph Chen }
1795c6f7c1a3SJoseph Chen 
1796c6f7c1a3SJoseph Chen static struct clk_ops rk3528_grfclk_ops = {
1797c6f7c1a3SJoseph Chen 	.get_rate = rk3528_grfclk_get_rate,
1798c6f7c1a3SJoseph Chen 	.get_phase = rk3528_grfclk_get_phase,
1799c6f7c1a3SJoseph Chen 	.set_phase = rk3528_grfclk_set_phase,
1800c6f7c1a3SJoseph Chen };
1801c6f7c1a3SJoseph Chen 
1802c6f7c1a3SJoseph Chen #ifndef CONFIG_SPL_BUILD
1803c6f7c1a3SJoseph Chen /**
1804c6f7c1a3SJoseph Chen  * soc_clk_dump() - Print clock frequencies
1805c6f7c1a3SJoseph Chen  * Returns zero on success
1806c6f7c1a3SJoseph Chen  *
1807c6f7c1a3SJoseph Chen  * Implementation for the clk dump command.
1808c6f7c1a3SJoseph Chen  */
1809c6f7c1a3SJoseph Chen int soc_clk_dump(void)
1810c6f7c1a3SJoseph Chen {
1811c6f7c1a3SJoseph Chen 	const struct rk3528_clk_info *clk_dump;
1812c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv;
1813c6f7c1a3SJoseph Chen 	struct udevice *cru_dev;
1814c6f7c1a3SJoseph Chen 	struct clk clk;
1815c6f7c1a3SJoseph Chen 	ulong clk_count = ARRAY_SIZE(clks_dump);
1816c6f7c1a3SJoseph Chen 	ulong rate;
1817c6f7c1a3SJoseph Chen 	int i, ret;
1818c6f7c1a3SJoseph Chen 
1819c6f7c1a3SJoseph Chen 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1820c6f7c1a3SJoseph Chen 					  DM_GET_DRIVER(rockchip_rk3528_cru),
1821c6f7c1a3SJoseph Chen 					  &cru_dev);
1822c6f7c1a3SJoseph Chen 	if (ret) {
1823c6f7c1a3SJoseph Chen 		printf("%s failed to get cru device\n", __func__);
1824c6f7c1a3SJoseph Chen 		return ret;
1825c6f7c1a3SJoseph Chen 	}
1826c6f7c1a3SJoseph Chen 
1827c6f7c1a3SJoseph Chen 	priv = dev_get_priv(cru_dev);
1828c6f7c1a3SJoseph Chen 	printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1829c6f7c1a3SJoseph Chen 	       priv->sync_kernel ? "sync kernel" : "uboot",
1830c6f7c1a3SJoseph Chen 	       priv->armclk_enter_hz / 1000,
1831c6f7c1a3SJoseph Chen 	       priv->armclk_init_hz / 1000,
1832c6f7c1a3SJoseph Chen 	       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1833c6f7c1a3SJoseph Chen 	       priv->set_armclk_rate ? " KHz" : "N/A");
1834c6f7c1a3SJoseph Chen 	for (i = 0; i < clk_count; i++) {
1835c6f7c1a3SJoseph Chen 		clk_dump = &clks_dump[i];
1836c6f7c1a3SJoseph Chen 		if (clk_dump->name) {
1837c6f7c1a3SJoseph Chen 			clk.id = clk_dump->id;
1838c6f7c1a3SJoseph Chen 			ret = clk_request(cru_dev, &clk);
1839c6f7c1a3SJoseph Chen 			if (ret < 0)
1840c6f7c1a3SJoseph Chen 				return ret;
1841c6f7c1a3SJoseph Chen 
1842c6f7c1a3SJoseph Chen 			rate = clk_get_rate(&clk);
1843c6f7c1a3SJoseph Chen 			clk_free(&clk);
1844c6f7c1a3SJoseph Chen 			if (i == 0) {
1845c6f7c1a3SJoseph Chen 				if (rate < 0)
1846c6f7c1a3SJoseph Chen 					printf("  %s %s\n", clk_dump->name,
1847c6f7c1a3SJoseph Chen 					       "unknown");
1848c6f7c1a3SJoseph Chen 				else
1849c6f7c1a3SJoseph Chen 					printf("  %s %lu KHz\n", clk_dump->name,
1850c6f7c1a3SJoseph Chen 					       rate / 1000);
1851c6f7c1a3SJoseph Chen 			} else {
1852c6f7c1a3SJoseph Chen 				if (rate < 0)
1853c6f7c1a3SJoseph Chen 					printf("  %s %s\n", clk_dump->name,
1854c6f7c1a3SJoseph Chen 					       "unknown");
1855c6f7c1a3SJoseph Chen 				else
1856c6f7c1a3SJoseph Chen 					printf("  %s %lu KHz\n", clk_dump->name,
1857c6f7c1a3SJoseph Chen 					       rate / 1000);
1858c6f7c1a3SJoseph Chen 			}
1859c6f7c1a3SJoseph Chen 		}
1860c6f7c1a3SJoseph Chen 	}
1861c6f7c1a3SJoseph Chen 
1862c6f7c1a3SJoseph Chen 	return 0;
1863c6f7c1a3SJoseph Chen }
1864c6f7c1a3SJoseph Chen #endif
1865c6f7c1a3SJoseph Chen 
1866c6f7c1a3SJoseph Chen static int rk3528_grfclk_probe(struct udevice *dev)
1867c6f7c1a3SJoseph Chen {
1868c6f7c1a3SJoseph Chen 	struct rk3528_grf_clk_priv *priv = dev_get_priv(dev);
1869c6f7c1a3SJoseph Chen 
1870c6f7c1a3SJoseph Chen 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
1871c6f7c1a3SJoseph Chen 	if (IS_ERR(priv->grf))
1872c6f7c1a3SJoseph Chen 		return PTR_ERR(priv->grf);
1873c6f7c1a3SJoseph Chen 
1874c6f7c1a3SJoseph Chen 	return 0;
1875c6f7c1a3SJoseph Chen }
1876c6f7c1a3SJoseph Chen 
1877c6f7c1a3SJoseph Chen static const struct udevice_id rk3528_grf_cru_ids[] = {
1878c6f7c1a3SJoseph Chen 	{ .compatible = "rockchip,rk3528-grf-cru" },
1879c6f7c1a3SJoseph Chen 	{ }
1880c6f7c1a3SJoseph Chen };
1881c6f7c1a3SJoseph Chen 
1882c6f7c1a3SJoseph Chen U_BOOT_DRIVER(rockchip_rk3528_grf_cru) = {
1883c6f7c1a3SJoseph Chen 	.name		= "rockchip_rk3528_grf_cru",
1884c6f7c1a3SJoseph Chen 	.id		= UCLASS_CLK,
1885c6f7c1a3SJoseph Chen 	.of_match	= rk3528_grf_cru_ids,
1886c6f7c1a3SJoseph Chen 	.priv_auto_alloc_size = sizeof(struct rk3528_grf_clk_priv),
1887c6f7c1a3SJoseph Chen 	.ops		= &rk3528_grfclk_ops,
1888c6f7c1a3SJoseph Chen 	.probe		= rk3528_grfclk_probe,
1889c6f7c1a3SJoseph Chen };
1890c6f7c1a3SJoseph Chen 
1891c6f7c1a3SJoseph Chen static void rk3528_clk_init(struct rk3528_clk_priv *priv)
1892c6f7c1a3SJoseph Chen {
1893c6f7c1a3SJoseph Chen 	int ret;
1894c6f7c1a3SJoseph Chen 
1895c6f7c1a3SJoseph Chen 	priv->sync_kernel = false;
1896c6f7c1a3SJoseph Chen 	if (!priv->armclk_enter_hz) {
1897c6f7c1a3SJoseph Chen 		priv->armclk_enter_hz =
1898c6f7c1a3SJoseph Chen 			rockchip_pll_get_rate(&rk3528_pll_clks[APLL],
1899c6f7c1a3SJoseph Chen 					      priv->cru, APLL);
1900c6f7c1a3SJoseph Chen 		priv->armclk_init_hz = priv->armclk_enter_hz;
1901c6f7c1a3SJoseph Chen 	}
1902c6f7c1a3SJoseph Chen 
1903c6f7c1a3SJoseph Chen 	if (priv->armclk_init_hz != APLL_HZ) {
1904c6f7c1a3SJoseph Chen 		ret = rk3528_armclk_set_clk(priv, APLL_HZ);
1905c6f7c1a3SJoseph Chen 		if (!ret)
1906c6f7c1a3SJoseph Chen 			priv->armclk_init_hz = APLL_HZ;
1907c6f7c1a3SJoseph Chen 	}
1908c6f7c1a3SJoseph Chen 
1909c6f7c1a3SJoseph Chen 	if (priv->cpll_hz != CPLL_HZ) {
1910c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru,
1911c6f7c1a3SJoseph Chen 					    CPLL, CPLL_HZ);
1912c6f7c1a3SJoseph Chen 		if (!ret)
1913c6f7c1a3SJoseph Chen 			priv->cpll_hz = CPLL_HZ;
1914c6f7c1a3SJoseph Chen 	}
1915c6f7c1a3SJoseph Chen 
1916c6f7c1a3SJoseph Chen 	if (priv->gpll_hz != GPLL_HZ) {
1917c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru,
1918c6f7c1a3SJoseph Chen 					    GPLL, GPLL_HZ);
1919c6f7c1a3SJoseph Chen 		if (!ret)
1920c6f7c1a3SJoseph Chen 			priv->gpll_hz = GPLL_HZ;
1921c6f7c1a3SJoseph Chen 	}
1922c6f7c1a3SJoseph Chen #if 0
1923c6f7c1a3SJoseph Chen 	if (priv->ppll_hz != PPLL_HZ) {
1924c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru,
1925c6f7c1a3SJoseph Chen 					    PPLL, PPLL_HZ);
1926c6f7c1a3SJoseph Chen 		if (!ret)
1927c6f7c1a3SJoseph Chen 			priv->ppll_hz = PPLL_HZ;
1928c6f7c1a3SJoseph Chen 	}
1929c6f7c1a3SJoseph Chen #endif
1930c6f7c1a3SJoseph Chen 	/* The default rate is 100Mhz, it's not friendly for remote IR module */
1931c6f7c1a3SJoseph Chen 	rk3528_pwm_set_clk(priv, CLK_PWM0, 24000000);
1932c6f7c1a3SJoseph Chen 	rk3528_pwm_set_clk(priv, CLK_PWM1, 24000000);
1933c6f7c1a3SJoseph Chen }
1934c6f7c1a3SJoseph Chen 
1935c6f7c1a3SJoseph Chen static int rk3528_clk_probe(struct udevice *dev)
1936c6f7c1a3SJoseph Chen {
1937c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(dev);
1938c6f7c1a3SJoseph Chen 	int ret;
1939c6f7c1a3SJoseph Chen 
1940c6f7c1a3SJoseph Chen 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
1941c6f7c1a3SJoseph Chen 	if (IS_ERR(priv->grf))
1942c6f7c1a3SJoseph Chen 		return PTR_ERR(priv->grf);
1943c6f7c1a3SJoseph Chen 
1944c6f7c1a3SJoseph Chen 	rk3528_clk_init(priv);
1945c6f7c1a3SJoseph Chen 
1946c6f7c1a3SJoseph Chen 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1947c6f7c1a3SJoseph Chen 	ret = clk_set_defaults(dev);
1948c6f7c1a3SJoseph Chen 	if (ret)
1949c6f7c1a3SJoseph Chen 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
1950c6f7c1a3SJoseph Chen 	else
1951c6f7c1a3SJoseph Chen 		priv->sync_kernel = true;
1952c6f7c1a3SJoseph Chen 
1953c6f7c1a3SJoseph Chen 	return 0;
1954c6f7c1a3SJoseph Chen }
1955c6f7c1a3SJoseph Chen 
1956c6f7c1a3SJoseph Chen static int rk3528_clk_ofdata_to_platdata(struct udevice *dev)
1957c6f7c1a3SJoseph Chen {
1958c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(dev);
1959c6f7c1a3SJoseph Chen 
1960c6f7c1a3SJoseph Chen 	priv->cru = dev_read_addr_ptr(dev);
1961c6f7c1a3SJoseph Chen 
1962c6f7c1a3SJoseph Chen 	return 0;
1963c6f7c1a3SJoseph Chen }
1964c6f7c1a3SJoseph Chen 
1965c6f7c1a3SJoseph Chen static int rk3528_clk_bind(struct udevice *dev)
1966c6f7c1a3SJoseph Chen {
1967c6f7c1a3SJoseph Chen 	struct udevice *sys_child, *sf_child;
1968c6f7c1a3SJoseph Chen 	struct softreset_reg *sf_priv;
1969c6f7c1a3SJoseph Chen 	struct sysreset_reg *priv;
1970c6f7c1a3SJoseph Chen 	int ret;
1971c6f7c1a3SJoseph Chen 
1972c6f7c1a3SJoseph Chen 	/* The reset driver does not have a device node, so bind it here */
1973c6f7c1a3SJoseph Chen 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1974c6f7c1a3SJoseph Chen 				 &sys_child);
1975c6f7c1a3SJoseph Chen 	if (ret) {
1976c6f7c1a3SJoseph Chen 		debug("Warning: No sysreset driver: ret=%d\n", ret);
1977c6f7c1a3SJoseph Chen 	} else {
1978c6f7c1a3SJoseph Chen 		priv = malloc(sizeof(struct sysreset_reg));
1979c6f7c1a3SJoseph Chen 		priv->glb_srst_fst_value = offsetof(struct rk3528_cru,
1980c6f7c1a3SJoseph Chen 						    glb_srst_fst);
1981c6f7c1a3SJoseph Chen 		priv->glb_srst_snd_value = offsetof(struct rk3528_cru,
1982c6f7c1a3SJoseph Chen 						    glb_srst_snd);
1983c6f7c1a3SJoseph Chen 		sys_child->priv = priv;
1984c6f7c1a3SJoseph Chen 	}
1985c6f7c1a3SJoseph Chen 
1986c6f7c1a3SJoseph Chen 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1987c6f7c1a3SJoseph Chen 					 dev_ofnode(dev), &sf_child);
1988c6f7c1a3SJoseph Chen 	if (ret) {
1989c6f7c1a3SJoseph Chen 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1990c6f7c1a3SJoseph Chen 	} else {
1991c6f7c1a3SJoseph Chen 		sf_priv = malloc(sizeof(struct softreset_reg));
1992c6f7c1a3SJoseph Chen 		sf_priv->sf_reset_offset = offsetof(struct rk3528_cru,
1993c6f7c1a3SJoseph Chen 						    softrst_con[0]);
1994c6f7c1a3SJoseph Chen 		sf_priv->sf_reset_num = 47;
1995c6f7c1a3SJoseph Chen 		sf_child->priv = sf_priv;
1996c6f7c1a3SJoseph Chen 	}
1997c6f7c1a3SJoseph Chen 
1998c6f7c1a3SJoseph Chen 	return 0;
1999c6f7c1a3SJoseph Chen }
2000c6f7c1a3SJoseph Chen 
2001c6f7c1a3SJoseph Chen static const struct udevice_id rk3528_clk_ids[] = {
2002c6f7c1a3SJoseph Chen 	{ .compatible = "rockchip,rk3528-cru" },
2003c6f7c1a3SJoseph Chen 	{ }
2004c6f7c1a3SJoseph Chen };
2005c6f7c1a3SJoseph Chen 
2006c6f7c1a3SJoseph Chen U_BOOT_DRIVER(rockchip_rk3528_cru) = {
2007c6f7c1a3SJoseph Chen 	.name		= "rockchip_rk3528_cru",
2008c6f7c1a3SJoseph Chen 	.id		= UCLASS_CLK,
2009c6f7c1a3SJoseph Chen 	.of_match	= rk3528_clk_ids,
2010c6f7c1a3SJoseph Chen 	.priv_auto_alloc_size = sizeof(struct rk3528_clk_priv),
2011c6f7c1a3SJoseph Chen 	.ofdata_to_platdata = rk3528_clk_ofdata_to_platdata,
2012c6f7c1a3SJoseph Chen 	.ops		= &rk3528_clk_ops,
2013c6f7c1a3SJoseph Chen 	.bind		= rk3528_clk_bind,
2014c6f7c1a3SJoseph Chen 	.probe		= rk3528_clk_probe,
2015c6f7c1a3SJoseph Chen };
2016c6f7c1a3SJoseph Chen 
2017