xref: /rk3399_rockchip-uboot/drivers/clk/rockchip/clk_rk3528.c (revision 5e016f25dc72f297153fdf29d2b7f3b311d60df5)
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"),
136eee09e1fSJoseph Chen 	RK3528_CLK_DUMP(CLK_MATRIX_500M_SRC,  "clk_500m"),
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  */
rational_best_approximation(unsigned long given_numerator,unsigned long given_denominator,unsigned long max_numerator,unsigned long max_denominator,unsigned long * best_numerator,unsigned long * best_denominator)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 
rk3528_armclk_set_clk(struct rk3528_clk_priv * priv,ulong new_rate)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 
21908bd15b0SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[39], 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 
22508bd15b0SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[39], 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 
rk3528_ppll_matrix_get_rate(struct rk3528_clk_priv * priv,ulong clk_id)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:
246e855752aSJoseph Chen 		mask = PCIE_CLK_MATRIX_50M_SRC_DIV_MASK;
247e855752aSJoseph Chen 		shift = PCIE_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:
252e855752aSJoseph Chen 		mask = PCIE_CLK_MATRIX_100M_SRC_DIV_MASK;
253e855752aSJoseph Chen 		shift = PCIE_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:
259e855752aSJoseph Chen 		mask = CLK_MATRIX_125M_SRC_DIV_MASK;
260e855752aSJoseph Chen 		shift = 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:
265e855752aSJoseph Chen 		mask = CLK_MATRIX_25M_SRC_DIV_MASK;
266e855752aSJoseph Chen 		shift = 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 
rk3528_ppll_matrix_set_rate(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)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;
288e855752aSJoseph Chen 		mask = PCIE_CLK_MATRIX_50M_SRC_DIV_MASK;
289e855752aSJoseph Chen 		shift = PCIE_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;
295e855752aSJoseph Chen 		mask = PCIE_CLK_MATRIX_100M_SRC_DIV_MASK;
296e855752aSJoseph Chen 		shift = PCIE_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;
302e855752aSJoseph Chen 		mask = CLK_MATRIX_125M_SRC_DIV_MASK;
303e855752aSJoseph Chen 		shift = CLK_MATRIX_125M_SRC_DIV_SHIFT;
304c6f7c1a3SJoseph Chen 		break;
305c6f7c1a3SJoseph Chen 	case CLK_GMAC1_VPU_25M:
306c6f7c1a3SJoseph Chen 		id = 60;
307e855752aSJoseph Chen 		mask = CLK_MATRIX_25M_SRC_DIV_MASK;
308e855752aSJoseph Chen 		shift = 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 
rk3528_cgpll_matrix_get_rate(struct rk3528_clk_priv * priv,ulong clk_id)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;
336e855752aSJoseph Chen 		mask = CLK_MATRIX_50M_SRC_DIV_MASK;
337e855752aSJoseph Chen 		shift = 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;
343e855752aSJoseph Chen 		mask = CLK_MATRIX_100M_SRC_DIV_MASK;
344e855752aSJoseph Chen 		shift = 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;
350e855752aSJoseph Chen 		mask = CLK_MATRIX_150M_SRC_DIV_MASK;
351e855752aSJoseph Chen 		shift = CLK_MATRIX_150M_SRC_DIV_SHIFT;
352c6f7c1a3SJoseph Chen 		break;
353c6f7c1a3SJoseph Chen 
354c6f7c1a3SJoseph Chen 	case CLK_MATRIX_200M_SRC:
355c6f7c1a3SJoseph Chen 		con = 1;
356e855752aSJoseph Chen 		mask = CLK_MATRIX_200M_SRC_DIV_MASK;
357e855752aSJoseph Chen 		shift = CLK_MATRIX_200M_SRC_DIV_SHIFT;
358c6f7c1a3SJoseph Chen 		break;
359c6f7c1a3SJoseph Chen 
360c6f7c1a3SJoseph Chen 	case CLK_MATRIX_250M_SRC:
361c6f7c1a3SJoseph Chen 		con = 1;
362e855752aSJoseph Chen 		mask = CLK_MATRIX_250M_SRC_DIV_MASK;
363e855752aSJoseph Chen 		shift = CLK_MATRIX_250M_SRC_DIV_SHIFT;
364e855752aSJoseph Chen 		sel_mask = CLK_MATRIX_250M_SRC_SEL_MASK;
365e855752aSJoseph Chen 		sel_shift = CLK_MATRIX_250M_SRC_SEL_SHIFT;
366c6f7c1a3SJoseph Chen 		break;
367c6f7c1a3SJoseph Chen 
368c6f7c1a3SJoseph Chen 	case CLK_MATRIX_300M_SRC:
369c6f7c1a3SJoseph Chen 		con = 2;
370e855752aSJoseph Chen 		mask = CLK_MATRIX_300M_SRC_DIV_MASK;
371e855752aSJoseph Chen 		shift = CLK_MATRIX_300M_SRC_DIV_SHIFT;
372c6f7c1a3SJoseph Chen 		break;
373c6f7c1a3SJoseph Chen 
374c6f7c1a3SJoseph Chen 	case CLK_MATRIX_339M_SRC:
375c6f7c1a3SJoseph Chen 		con = 2;
376e855752aSJoseph Chen 		mask = CLK_MATRIX_339M_SRC_DIV_MASK;
377e855752aSJoseph Chen 		shift = 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;
383e855752aSJoseph Chen 		mask = CLK_MATRIX_400M_SRC_DIV_MASK;
384e855752aSJoseph Chen 		shift = CLK_MATRIX_400M_SRC_DIV_SHIFT;
385c6f7c1a3SJoseph Chen 		break;
386c6f7c1a3SJoseph Chen 
387c6f7c1a3SJoseph Chen 	case CLK_MATRIX_500M_SRC:
388c6f7c1a3SJoseph Chen 		con = 3;
389e855752aSJoseph Chen 		mask = CLK_MATRIX_500M_SRC_DIV_MASK;
390e855752aSJoseph Chen 		shift = CLK_MATRIX_500M_SRC_DIV_SHIFT;
391e855752aSJoseph Chen 		sel_mask = CLK_MATRIX_500M_SRC_SEL_MASK;
392e855752aSJoseph Chen 		sel_shift = CLK_MATRIX_500M_SRC_SEL_SHIFT;
393c6f7c1a3SJoseph Chen 		break;
394c6f7c1a3SJoseph Chen 
395c6f7c1a3SJoseph Chen 	case CLK_MATRIX_600M_SRC:
396c6f7c1a3SJoseph Chen 		con = 4;
397e855752aSJoseph Chen 		mask = CLK_MATRIX_600M_SRC_DIV_MASK;
398e855752aSJoseph Chen 		shift = 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;
404e855752aSJoseph Chen 		mask = ACLK_BUS_VOPGL_ROOT_DIV_MASK;
405e855752aSJoseph Chen 		shift = 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 
427af1a0c68SJoseph Chen 	/* NOTE: '-1' to balance the DIV_TO_RATE() 'div+1' */
428af1a0c68SJoseph Chen 	return is_halfdiv ? DIV_TO_RATE(prate * 2, (3 + 2 * div) - 1) : DIV_TO_RATE(prate, div);
429c6f7c1a3SJoseph Chen }
430c6f7c1a3SJoseph Chen 
rk3528_cgpll_matrix_set_rate(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)431c6f7c1a3SJoseph Chen static ulong rk3528_cgpll_matrix_set_rate(struct rk3528_clk_priv *priv,
432c6f7c1a3SJoseph Chen 				      ulong clk_id, ulong rate)
433c6f7c1a3SJoseph Chen {
434c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
435c6f7c1a3SJoseph Chen 	u32 sel, div, mask, shift, con;
436c6f7c1a3SJoseph Chen 	u32 sel_mask = 0, sel_shift;
437c6f7c1a3SJoseph Chen 	u8 is_gpll_parent = 1;
438c6f7c1a3SJoseph Chen 	u8 is_halfdiv = 0;
439c6f7c1a3SJoseph Chen 	ulong prate = 0;
440c6f7c1a3SJoseph Chen 
441c6f7c1a3SJoseph Chen 	switch (clk_id) {
442c6f7c1a3SJoseph Chen 	case CLK_MATRIX_50M_SRC:
443c6f7c1a3SJoseph Chen 		con = 0;
444e855752aSJoseph Chen 		mask = CLK_MATRIX_50M_SRC_DIV_MASK;
445e855752aSJoseph Chen 		shift = CLK_MATRIX_50M_SRC_DIV_SHIFT;
446c6f7c1a3SJoseph Chen 		is_gpll_parent = 0;
447c6f7c1a3SJoseph Chen 		break;
448c6f7c1a3SJoseph Chen 
449c6f7c1a3SJoseph Chen 	case CLK_MATRIX_100M_SRC:
450c6f7c1a3SJoseph Chen 		con = 0;
451e855752aSJoseph Chen 		mask = CLK_MATRIX_100M_SRC_DIV_MASK;
452e855752aSJoseph Chen 		shift = CLK_MATRIX_100M_SRC_DIV_SHIFT;
453c6f7c1a3SJoseph Chen 		is_gpll_parent = 0;
454c6f7c1a3SJoseph Chen 		break;
455c6f7c1a3SJoseph Chen 
456c6f7c1a3SJoseph Chen 	case CLK_MATRIX_150M_SRC:
457c6f7c1a3SJoseph Chen 		con = 1;
458e855752aSJoseph Chen 		mask = CLK_MATRIX_150M_SRC_DIV_MASK;
459e855752aSJoseph Chen 		shift = CLK_MATRIX_150M_SRC_DIV_SHIFT;
460c6f7c1a3SJoseph Chen 		break;
461c6f7c1a3SJoseph Chen 
462c6f7c1a3SJoseph Chen 	case CLK_MATRIX_200M_SRC:
463c6f7c1a3SJoseph Chen 		con = 1;
464e855752aSJoseph Chen 		mask = CLK_MATRIX_200M_SRC_DIV_MASK;
465e855752aSJoseph Chen 		shift = CLK_MATRIX_200M_SRC_DIV_SHIFT;
466c6f7c1a3SJoseph Chen 		break;
467c6f7c1a3SJoseph Chen 
468c6f7c1a3SJoseph Chen 	case CLK_MATRIX_250M_SRC:
469c6f7c1a3SJoseph Chen 		con = 1;
470e855752aSJoseph Chen 		mask = CLK_MATRIX_250M_SRC_DIV_MASK;
471e855752aSJoseph Chen 		shift = CLK_MATRIX_250M_SRC_DIV_SHIFT;
472e855752aSJoseph Chen 		sel_mask = CLK_MATRIX_250M_SRC_SEL_MASK;
473e855752aSJoseph Chen 		sel_shift = CLK_MATRIX_250M_SRC_SEL_SHIFT;
474c6f7c1a3SJoseph Chen 		break;
475c6f7c1a3SJoseph Chen 
476c6f7c1a3SJoseph Chen 	case CLK_MATRIX_300M_SRC:
477c6f7c1a3SJoseph Chen 		con = 2;
478e855752aSJoseph Chen 		mask = CLK_MATRIX_300M_SRC_DIV_MASK;
479e855752aSJoseph Chen 		shift = CLK_MATRIX_300M_SRC_DIV_SHIFT;
480c6f7c1a3SJoseph Chen 		break;
481c6f7c1a3SJoseph Chen 
482c6f7c1a3SJoseph Chen 	case CLK_MATRIX_339M_SRC:
483c6f7c1a3SJoseph Chen 		con = 2;
484e855752aSJoseph Chen 		mask = CLK_MATRIX_339M_SRC_DIV_MASK;
485e855752aSJoseph Chen 		shift = CLK_MATRIX_339M_SRC_DIV_SHIFT;
486c6f7c1a3SJoseph Chen 		is_halfdiv = 1;
487c6f7c1a3SJoseph Chen 		break;
488c6f7c1a3SJoseph Chen 
489c6f7c1a3SJoseph Chen 	case CLK_MATRIX_400M_SRC:
490c6f7c1a3SJoseph Chen 		con = 2;
491e855752aSJoseph Chen 		mask = CLK_MATRIX_400M_SRC_DIV_MASK;
492e855752aSJoseph Chen 		shift = CLK_MATRIX_400M_SRC_DIV_SHIFT;
493c6f7c1a3SJoseph Chen 		break;
494c6f7c1a3SJoseph Chen 
495c6f7c1a3SJoseph Chen 	case CLK_MATRIX_500M_SRC:
496c6f7c1a3SJoseph Chen 		con = 3;
497e855752aSJoseph Chen 		mask = CLK_MATRIX_500M_SRC_DIV_MASK;
498e855752aSJoseph Chen 		shift = CLK_MATRIX_500M_SRC_DIV_SHIFT;
499e855752aSJoseph Chen 		sel_mask = CLK_MATRIX_500M_SRC_SEL_MASK;
500e855752aSJoseph Chen 		sel_shift = CLK_MATRIX_500M_SRC_SEL_SHIFT;
501c6f7c1a3SJoseph Chen 		break;
502c6f7c1a3SJoseph Chen 
503c6f7c1a3SJoseph Chen 	case CLK_MATRIX_600M_SRC:
504c6f7c1a3SJoseph Chen 		con = 4;
505e855752aSJoseph Chen 		mask = CLK_MATRIX_600M_SRC_DIV_MASK;
506e855752aSJoseph Chen 		shift = CLK_MATRIX_600M_SRC_DIV_SHIFT;
507c6f7c1a3SJoseph Chen 		break;
508c6f7c1a3SJoseph Chen 
509c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_ROOT:
510c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_BIU:
511c6f7c1a3SJoseph Chen 		con = 43;
512e855752aSJoseph Chen 		mask = ACLK_BUS_VOPGL_ROOT_DIV_MASK;
513e855752aSJoseph Chen 		shift = ACLK_BUS_VOPGL_ROOT_DIV_SHIFT;
514c6f7c1a3SJoseph Chen 		break;
515c6f7c1a3SJoseph Chen 
516c6f7c1a3SJoseph Chen 	default:
517c6f7c1a3SJoseph Chen 		return -ENOENT;
518c6f7c1a3SJoseph Chen 	}
519c6f7c1a3SJoseph Chen 
520c6f7c1a3SJoseph Chen 	if (sel_mask) {
521c6f7c1a3SJoseph Chen 		if (priv->gpll_hz % rate == 0) {
522c6f7c1a3SJoseph Chen 			sel = CLK_MATRIX_250M_SRC_SEL_CLK_GPLL_MUX; // TODO
523c6f7c1a3SJoseph Chen 			prate = priv->gpll_hz;
524c6f7c1a3SJoseph Chen 		} else {
525c6f7c1a3SJoseph Chen 			sel = CLK_MATRIX_250M_SRC_SEL_CLK_CPLL_MUX;
526c6f7c1a3SJoseph Chen 			prate = priv->cpll_hz;
527c6f7c1a3SJoseph Chen 		}
528c6f7c1a3SJoseph Chen 	} else {
529c6f7c1a3SJoseph Chen 		if (is_gpll_parent)
530c6f7c1a3SJoseph Chen 			prate = priv->gpll_hz;
531c6f7c1a3SJoseph Chen 		else
532c6f7c1a3SJoseph Chen 			prate = priv->cpll_hz;
533c6f7c1a3SJoseph Chen 	}
534c6f7c1a3SJoseph Chen 
535c6f7c1a3SJoseph Chen 	if (is_halfdiv)
536af1a0c68SJoseph Chen 		/* NOTE: '+1' to balance the following rk_clrsetreg() 'div-1' */
537af1a0c68SJoseph Chen 		div = DIV_ROUND_UP((prate * 2) - (3 * rate), 2 * rate) + 1;
538c6f7c1a3SJoseph Chen 	else
539c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(prate, rate);
540c6f7c1a3SJoseph Chen 
541c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[con], mask, (div - 1) << shift);
542c6f7c1a3SJoseph Chen 	if (sel_mask)
543c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[con], sel_mask, sel << sel_shift);
544c6f7c1a3SJoseph Chen 
545c6f7c1a3SJoseph Chen 	return rk3528_cgpll_matrix_get_rate(priv, clk_id);
546c6f7c1a3SJoseph Chen }
547c6f7c1a3SJoseph Chen 
rk3528_i2c_get_clk(struct rk3528_clk_priv * priv,ulong clk_id)548c6f7c1a3SJoseph Chen static ulong rk3528_i2c_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
549c6f7c1a3SJoseph Chen {
550c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
551c6f7c1a3SJoseph Chen 	u32 id, sel, con, mask, shift;
552c6f7c1a3SJoseph Chen 	u8 is_pmucru = 0;
553c6f7c1a3SJoseph Chen 	ulong rate;
554c6f7c1a3SJoseph Chen 
555c6f7c1a3SJoseph Chen 	switch (clk_id) {
556c6f7c1a3SJoseph Chen 	case CLK_I2C0:
557c6f7c1a3SJoseph Chen 		id = 79;
558e855752aSJoseph Chen 		mask = CLK_I2C0_SEL_MASK;
559e855752aSJoseph Chen 		shift = CLK_I2C0_SEL_SHIFT;
560c6f7c1a3SJoseph Chen 		break;
561c6f7c1a3SJoseph Chen 
562c6f7c1a3SJoseph Chen 	case CLK_I2C1:
563c6f7c1a3SJoseph Chen 		id = 79;
564e855752aSJoseph Chen 		mask = CLK_I2C1_SEL_MASK;
565e855752aSJoseph Chen 		shift = CLK_I2C1_SEL_SHIFT;
566c6f7c1a3SJoseph Chen 		break;
567c6f7c1a3SJoseph Chen 
568c6f7c1a3SJoseph Chen 	case CLK_I2C2:
569c6f7c1a3SJoseph Chen 		id = 0;
570e855752aSJoseph Chen 		mask = CLK_I2C2_SEL_MASK;
571e855752aSJoseph Chen 		shift = CLK_I2C2_SEL_SHIFT;
572c6f7c1a3SJoseph Chen 		is_pmucru = 1;
573c6f7c1a3SJoseph Chen 		break;
574c6f7c1a3SJoseph Chen 
575c6f7c1a3SJoseph Chen 	case CLK_I2C3:
576c6f7c1a3SJoseph Chen 		id = 63;
577e855752aSJoseph Chen 		mask = CLK_I2C3_SEL_MASK;
578e855752aSJoseph Chen 		shift = CLK_I2C3_SEL_SHIFT;
579c6f7c1a3SJoseph Chen 		break;
580c6f7c1a3SJoseph Chen 
581c6f7c1a3SJoseph Chen 	case CLK_I2C4:
582c6f7c1a3SJoseph Chen 		id = 85;
583e855752aSJoseph Chen 		mask = CLK_I2C4_SEL_MASK;
584e855752aSJoseph Chen 		shift = CLK_I2C4_SEL_SHIFT;
585c6f7c1a3SJoseph Chen 		break;
586c6f7c1a3SJoseph Chen 
587c6f7c1a3SJoseph Chen 	case CLK_I2C5:
588c6f7c1a3SJoseph Chen 		id = 63;
589e855752aSJoseph Chen 		mask = CLK_I2C5_SEL_MASK;
590e855752aSJoseph Chen 		shift = CLK_I2C5_SEL_SHIFT;
591c6f7c1a3SJoseph Chen 		break;
592c6f7c1a3SJoseph Chen 
593c6f7c1a3SJoseph Chen 	case CLK_I2C6:
594c6f7c1a3SJoseph Chen 		id = 64;
595e855752aSJoseph Chen 		mask = CLK_I2C6_SEL_MASK;
596e855752aSJoseph Chen 		shift = CLK_I2C6_SEL_SHIFT;
597c6f7c1a3SJoseph Chen 		break;
598c6f7c1a3SJoseph Chen 
599c6f7c1a3SJoseph Chen 	case CLK_I2C7:
600c6f7c1a3SJoseph Chen 		id = 86;
601e855752aSJoseph Chen 		mask = CLK_I2C7_SEL_MASK;
602e855752aSJoseph Chen 		shift = CLK_I2C7_SEL_SHIFT;
603c6f7c1a3SJoseph Chen 		break;
604c6f7c1a3SJoseph Chen 
605c6f7c1a3SJoseph Chen 	default:
606c6f7c1a3SJoseph Chen 		return -ENOENT;
607c6f7c1a3SJoseph Chen 	}
608c6f7c1a3SJoseph Chen 
609c6f7c1a3SJoseph Chen 	if (is_pmucru)
610c6f7c1a3SJoseph Chen 		con = readl(&cru->pmuclksel_con[id]);
611c6f7c1a3SJoseph Chen 	else
612c6f7c1a3SJoseph Chen 		con = readl(&cru->clksel_con[id]);
613c6f7c1a3SJoseph Chen 	sel = (con & mask) >> shift;
614c6f7c1a3SJoseph Chen 	if (sel == CLK_I2C3_SEL_CLK_MATRIX_200M_SRC)
615c6f7c1a3SJoseph Chen 		rate = 200 * MHz;
616c6f7c1a3SJoseph Chen 	else if (sel == CLK_I2C3_SEL_CLK_MATRIX_100M_SRC)
617c6f7c1a3SJoseph Chen 		rate = 100 * MHz;
618c6f7c1a3SJoseph Chen 	else if (sel == CLK_I2C3_SEL_CLK_MATRIX_50M_SRC)
619c6f7c1a3SJoseph Chen 		rate = 50 * MHz;
620c6f7c1a3SJoseph Chen 	else
621c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
622c6f7c1a3SJoseph Chen 
623c6f7c1a3SJoseph Chen 	return rate;
624c6f7c1a3SJoseph Chen }
625c6f7c1a3SJoseph Chen 
rk3528_i2c_set_clk(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)626c6f7c1a3SJoseph Chen static ulong rk3528_i2c_set_clk(struct rk3528_clk_priv *priv, ulong clk_id,
627c6f7c1a3SJoseph Chen 				ulong rate)
628c6f7c1a3SJoseph Chen {
629c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
630c6f7c1a3SJoseph Chen 	u32 id, sel, mask, shift;
631c6f7c1a3SJoseph Chen 	u8 is_pmucru = 0;
632c6f7c1a3SJoseph Chen 
633c6f7c1a3SJoseph Chen 	if (rate == 200 * MHz)
634c6f7c1a3SJoseph Chen 		sel = CLK_I2C3_SEL_CLK_MATRIX_200M_SRC;
635c6f7c1a3SJoseph Chen 	else if (rate == 100 * MHz)
636c6f7c1a3SJoseph Chen 		sel = CLK_I2C3_SEL_CLK_MATRIX_100M_SRC;
637c6f7c1a3SJoseph Chen 	else if (rate == 50 * MHz)
638c6f7c1a3SJoseph Chen 		sel = CLK_I2C3_SEL_CLK_MATRIX_50M_SRC;
639c6f7c1a3SJoseph Chen 	else
640c6f7c1a3SJoseph Chen 		sel = CLK_I2C3_SEL_XIN_OSC0_FUNC;
641c6f7c1a3SJoseph Chen 
642c6f7c1a3SJoseph Chen 	switch (clk_id) {
643c6f7c1a3SJoseph Chen 	case CLK_I2C0:
644c6f7c1a3SJoseph Chen 		id = 79;
645e855752aSJoseph Chen 		mask = CLK_I2C0_SEL_MASK;
646e855752aSJoseph Chen 		shift = CLK_I2C0_SEL_SHIFT;
647c6f7c1a3SJoseph Chen 		break;
648c6f7c1a3SJoseph Chen 
649c6f7c1a3SJoseph Chen 	case CLK_I2C1:
650c6f7c1a3SJoseph Chen 		id = 79;
651e855752aSJoseph Chen 		mask = CLK_I2C1_SEL_MASK;
652e855752aSJoseph Chen 		shift = CLK_I2C1_SEL_SHIFT;
653c6f7c1a3SJoseph Chen 		break;
654c6f7c1a3SJoseph Chen 
655c6f7c1a3SJoseph Chen 	case CLK_I2C2:
656c6f7c1a3SJoseph Chen 		id = 0;
657e855752aSJoseph Chen 		mask = CLK_I2C2_SEL_MASK;
658e855752aSJoseph Chen 		shift = CLK_I2C2_SEL_SHIFT;
659c6f7c1a3SJoseph Chen 		is_pmucru = 1;
660c6f7c1a3SJoseph Chen 		break;
661c6f7c1a3SJoseph Chen 
662c6f7c1a3SJoseph Chen 	case CLK_I2C3:
663c6f7c1a3SJoseph Chen 		id = 63;
664e855752aSJoseph Chen 		mask = CLK_I2C3_SEL_MASK;
665e855752aSJoseph Chen 		shift = CLK_I2C3_SEL_SHIFT;
666c6f7c1a3SJoseph Chen 		break;
667c6f7c1a3SJoseph Chen 
668c6f7c1a3SJoseph Chen 	case CLK_I2C4:
669c6f7c1a3SJoseph Chen 		id = 85;
670e855752aSJoseph Chen 		mask = CLK_I2C4_SEL_MASK;
671e855752aSJoseph Chen 		shift = CLK_I2C4_SEL_SHIFT;
672c6f7c1a3SJoseph Chen 		break;
673c6f7c1a3SJoseph Chen 
674c6f7c1a3SJoseph Chen 	case CLK_I2C5:
675c6f7c1a3SJoseph Chen 		id = 63;
676e855752aSJoseph Chen 		mask = CLK_I2C5_SEL_MASK;
677e855752aSJoseph Chen 		shift = CLK_I2C5_SEL_SHIFT;
678c6f7c1a3SJoseph Chen 
679c6f7c1a3SJoseph Chen 	case CLK_I2C6:
680c6f7c1a3SJoseph Chen 		id = 64;
681e855752aSJoseph Chen 		mask = CLK_I2C6_SEL_MASK;
682e855752aSJoseph Chen 		shift = CLK_I2C6_SEL_SHIFT;
683c6f7c1a3SJoseph Chen 		break;
684c6f7c1a3SJoseph Chen 
685c6f7c1a3SJoseph Chen 	case CLK_I2C7:
686c6f7c1a3SJoseph Chen 		id = 86;
687e855752aSJoseph Chen 		mask = CLK_I2C7_SEL_MASK;
688e855752aSJoseph Chen 		shift = CLK_I2C7_SEL_SHIFT;
689c6f7c1a3SJoseph Chen 		break;
690c6f7c1a3SJoseph Chen 
691c6f7c1a3SJoseph Chen 	default:
692c6f7c1a3SJoseph Chen 		return -ENOENT;
693c6f7c1a3SJoseph Chen 	}
694c6f7c1a3SJoseph Chen 
695c6f7c1a3SJoseph Chen 	if (is_pmucru)
696c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->pmuclksel_con[id], mask, sel << shift);
697c6f7c1a3SJoseph Chen 	else
698c6f7c1a3SJoseph Chen 		rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift);
699c6f7c1a3SJoseph Chen 
700c6f7c1a3SJoseph Chen 	return rk3528_i2c_get_clk(priv, clk_id);
701c6f7c1a3SJoseph Chen }
702c6f7c1a3SJoseph Chen 
rk3528_spi_get_clk(struct rk3528_clk_priv * priv,ulong clk_id)703c6f7c1a3SJoseph Chen static ulong rk3528_spi_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
704c6f7c1a3SJoseph Chen {
705c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
706c6f7c1a3SJoseph Chen 	u32 id, sel, con, mask, shift;
707c6f7c1a3SJoseph Chen 	ulong rate;
708c6f7c1a3SJoseph Chen 
709c6f7c1a3SJoseph Chen 	switch (clk_id) {
710c6f7c1a3SJoseph Chen 	case CLK_SPI0:
711c6f7c1a3SJoseph Chen 		id = 79;
712e855752aSJoseph Chen 		mask = CLK_SPI0_SEL_MASK;
713e855752aSJoseph Chen 		shift = CLK_SPI0_SEL_SHIFT;
714c6f7c1a3SJoseph Chen 		break;
715c6f7c1a3SJoseph Chen 
716c6f7c1a3SJoseph Chen 	case CLK_SPI1:
717c6f7c1a3SJoseph Chen 		id = 63;
718e855752aSJoseph Chen 		mask = CLK_SPI1_SEL_MASK;
719e855752aSJoseph Chen 		shift = CLK_SPI1_SEL_SHIFT;
720c6f7c1a3SJoseph Chen 		break;
721c6f7c1a3SJoseph Chen 	default:
722c6f7c1a3SJoseph Chen 		return -ENOENT;
723c6f7c1a3SJoseph Chen 	}
724c6f7c1a3SJoseph Chen 
725c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
726c6f7c1a3SJoseph Chen 	sel = (con & mask) >> shift;
727c6f7c1a3SJoseph Chen 	if (sel == CLK_SPI1_SEL_CLK_MATRIX_200M_SRC)
728c6f7c1a3SJoseph Chen 		rate = 200 * MHz;
7293aaac136SJoseph Chen 	else if (sel == CLK_SPI1_SEL_CLK_MATRIX_100M_SRC)
730c6f7c1a3SJoseph Chen 		rate = 100 * MHz;
7313aaac136SJoseph Chen 	else if (sel == CLK_SPI1_SEL_CLK_MATRIX_50M_SRC)
732c6f7c1a3SJoseph Chen 		rate = 50 * MHz;
733c6f7c1a3SJoseph Chen 	else
734c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
735c6f7c1a3SJoseph Chen 
736c6f7c1a3SJoseph Chen 	return rate;
737c6f7c1a3SJoseph Chen }
738c6f7c1a3SJoseph Chen 
rk3528_spi_set_clk(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)739c6f7c1a3SJoseph Chen static ulong rk3528_spi_set_clk(struct rk3528_clk_priv *priv,
740c6f7c1a3SJoseph Chen 				ulong clk_id, ulong rate)
741c6f7c1a3SJoseph Chen {
742c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
743c6f7c1a3SJoseph Chen 	u32 id, sel, mask, shift;
744c6f7c1a3SJoseph Chen 
745c6f7c1a3SJoseph Chen 	if (rate == 200 * MHz)
746c6f7c1a3SJoseph Chen 		sel = CLK_SPI1_SEL_CLK_MATRIX_200M_SRC;
747c6f7c1a3SJoseph Chen 	else if (rate == 100 * MHz)
748c6f7c1a3SJoseph Chen 		sel = CLK_SPI1_SEL_CLK_MATRIX_100M_SRC;
749c6f7c1a3SJoseph Chen 	else if (rate == 50 * MHz)
750c6f7c1a3SJoseph Chen 		sel = CLK_SPI1_SEL_CLK_MATRIX_50M_SRC;
751c6f7c1a3SJoseph Chen 	else
752c6f7c1a3SJoseph Chen 		sel = CLK_SPI1_SEL_XIN_OSC0_FUNC;
753c6f7c1a3SJoseph Chen 
754c6f7c1a3SJoseph Chen 	switch (clk_id) {
755c6f7c1a3SJoseph Chen 	case CLK_SPI0:
756c6f7c1a3SJoseph Chen 		id = 79;
757e855752aSJoseph Chen 		mask = CLK_SPI0_SEL_MASK;
758e855752aSJoseph Chen 		shift = CLK_SPI0_SEL_SHIFT;
759c6f7c1a3SJoseph Chen 		break;
760c6f7c1a3SJoseph Chen 
761c6f7c1a3SJoseph Chen 	case CLK_SPI1:
762c6f7c1a3SJoseph Chen 		id = 63;
763e855752aSJoseph Chen 		mask = CLK_SPI1_SEL_MASK;
764e855752aSJoseph Chen 		shift = CLK_SPI1_SEL_SHIFT;
765c6f7c1a3SJoseph Chen 		break;
766c6f7c1a3SJoseph Chen 	default:
767c6f7c1a3SJoseph Chen 		return -ENOENT;
768c6f7c1a3SJoseph Chen 	}
769c6f7c1a3SJoseph Chen 
770c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift);
771c6f7c1a3SJoseph Chen 
772c6f7c1a3SJoseph Chen 	return rk3528_spi_get_clk(priv, clk_id);
773c6f7c1a3SJoseph Chen }
774c6f7c1a3SJoseph Chen 
rk3528_pwm_get_clk(struct rk3528_clk_priv * priv,ulong clk_id)775c6f7c1a3SJoseph Chen static ulong rk3528_pwm_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
776c6f7c1a3SJoseph Chen {
777c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
778c6f7c1a3SJoseph Chen 	u32 id, sel, con, mask, shift;
779c6f7c1a3SJoseph Chen 	ulong rate;
780c6f7c1a3SJoseph Chen 
781c6f7c1a3SJoseph Chen 	switch (clk_id) {
782c6f7c1a3SJoseph Chen 	case CLK_PWM0:
783c6f7c1a3SJoseph Chen 		id = 44;
784e855752aSJoseph Chen 		mask = CLK_PWM0_SEL_MASK;
785e855752aSJoseph Chen 		shift = CLK_PWM0_SEL_SHIFT;
786c6f7c1a3SJoseph Chen 		break;
787c6f7c1a3SJoseph Chen 
788c6f7c1a3SJoseph Chen 	case CLK_PWM1:
789c6f7c1a3SJoseph Chen 		id = 44;
790e855752aSJoseph Chen 		mask = CLK_PWM1_SEL_MASK;
791e855752aSJoseph Chen 		shift = CLK_PWM1_SEL_SHIFT;
792c6f7c1a3SJoseph Chen 		break;
793c6f7c1a3SJoseph Chen 
794c6f7c1a3SJoseph Chen 	default:
795c6f7c1a3SJoseph Chen 		return -ENOENT;
796c6f7c1a3SJoseph Chen 	}
797c6f7c1a3SJoseph Chen 
798c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
799c6f7c1a3SJoseph Chen 	sel = (con & mask) >> shift;
800c6f7c1a3SJoseph Chen 	if (sel == CLK_PWM0_SEL_CLK_MATRIX_100M_SRC)
801c6f7c1a3SJoseph Chen 		rate = 100 * MHz;
802c6f7c1a3SJoseph Chen 	if (sel == CLK_PWM0_SEL_CLK_MATRIX_50M_SRC)
803c6f7c1a3SJoseph Chen 		rate = 50 * MHz;
804c6f7c1a3SJoseph Chen 	else
805c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
806c6f7c1a3SJoseph Chen 
807c6f7c1a3SJoseph Chen 	return rate;
808c6f7c1a3SJoseph Chen }
809c6f7c1a3SJoseph Chen 
rk3528_pwm_set_clk(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)810c6f7c1a3SJoseph Chen static ulong rk3528_pwm_set_clk(struct rk3528_clk_priv *priv,
811c6f7c1a3SJoseph Chen 				ulong clk_id, ulong rate)
812c6f7c1a3SJoseph Chen {
813c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
814c6f7c1a3SJoseph Chen 	u32 id, sel, mask, shift;
815c6f7c1a3SJoseph Chen 
816c6f7c1a3SJoseph Chen 	if (rate == 100 * MHz)
817c6f7c1a3SJoseph Chen 		sel = CLK_PWM0_SEL_CLK_MATRIX_100M_SRC;
818c6f7c1a3SJoseph Chen 	else if (rate == 50 * MHz)
819c6f7c1a3SJoseph Chen 		sel = CLK_PWM0_SEL_CLK_MATRIX_50M_SRC;
820c6f7c1a3SJoseph Chen 	else
821c6f7c1a3SJoseph Chen 		sel = CLK_PWM0_SEL_XIN_OSC0_FUNC;
822c6f7c1a3SJoseph Chen 
823c6f7c1a3SJoseph Chen 	switch (clk_id) {
824c6f7c1a3SJoseph Chen 	case CLK_PWM0:
825c6f7c1a3SJoseph Chen 		id = 44;
826e855752aSJoseph Chen 		mask = CLK_PWM0_SEL_MASK;
827e855752aSJoseph Chen 		shift = CLK_PWM0_SEL_SHIFT;
828c6f7c1a3SJoseph Chen 		break;
829c6f7c1a3SJoseph Chen 
830c6f7c1a3SJoseph Chen 	case CLK_PWM1:
831c6f7c1a3SJoseph Chen 		id = 44;
832e855752aSJoseph Chen 		mask = CLK_PWM1_SEL_MASK;
833e855752aSJoseph Chen 		shift = CLK_PWM1_SEL_SHIFT;
834c6f7c1a3SJoseph Chen 		break;
835c6f7c1a3SJoseph Chen 
836c6f7c1a3SJoseph Chen 	default:
837c6f7c1a3SJoseph Chen 		return -ENOENT;
838c6f7c1a3SJoseph Chen 	}
839c6f7c1a3SJoseph Chen 
840c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift);
841c6f7c1a3SJoseph Chen 
842c6f7c1a3SJoseph Chen 	return rk3528_pwm_get_clk(priv, clk_id);
843c6f7c1a3SJoseph Chen }
844c6f7c1a3SJoseph Chen 
rk3528_adc_get_clk(struct rk3528_clk_priv * priv,ulong clk_id)845c6f7c1a3SJoseph Chen static ulong rk3528_adc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
846c6f7c1a3SJoseph Chen {
847c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
848c6f7c1a3SJoseph Chen 	u32 div, con;
849c6f7c1a3SJoseph Chen 
850c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[74]);
851c6f7c1a3SJoseph Chen 	switch (clk_id) {
852c6f7c1a3SJoseph Chen 	case CLK_SARADC:
853e855752aSJoseph Chen 		div = (con & CLK_SARADC_DIV_MASK) >>
854e855752aSJoseph Chen 			CLK_SARADC_DIV_SHIFT;
855c6f7c1a3SJoseph Chen 		break;
856c6f7c1a3SJoseph Chen 
857c6f7c1a3SJoseph Chen 	case CLK_TSADC_TSEN:
858e855752aSJoseph Chen 		div = (con & CLK_TSADC_TSEN_DIV_MASK) >>
859e855752aSJoseph Chen 			CLK_TSADC_TSEN_DIV_SHIFT;
860c6f7c1a3SJoseph Chen 		break;
861c6f7c1a3SJoseph Chen 
862c6f7c1a3SJoseph Chen 	case CLK_TSADC:
863e855752aSJoseph Chen 		div = (con & CLK_TSADC_DIV_MASK) >>
864e855752aSJoseph Chen 			CLK_TSADC_DIV_SHIFT;
865c6f7c1a3SJoseph Chen 		break;
866c6f7c1a3SJoseph Chen 
867c6f7c1a3SJoseph Chen 	default:
868c6f7c1a3SJoseph Chen 		return -ENOENT;
869c6f7c1a3SJoseph Chen 	}
870c6f7c1a3SJoseph Chen 
871c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(OSC_HZ, div);
872c6f7c1a3SJoseph Chen }
873c6f7c1a3SJoseph Chen 
rk3528_adc_set_clk(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)874c6f7c1a3SJoseph Chen static ulong rk3528_adc_set_clk(struct rk3528_clk_priv *priv,
875c6f7c1a3SJoseph Chen 				ulong clk_id, ulong rate)
876c6f7c1a3SJoseph Chen {
877c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
878c6f7c1a3SJoseph Chen 	u32 div, mask, shift;
879c6f7c1a3SJoseph Chen 
880c6f7c1a3SJoseph Chen 	switch (clk_id) {
881c6f7c1a3SJoseph Chen 	case CLK_SARADC:
882e855752aSJoseph Chen 		mask = CLK_SARADC_DIV_MASK;
883e855752aSJoseph Chen 		shift =	CLK_SARADC_DIV_SHIFT;
884c6f7c1a3SJoseph Chen 		break;
885c6f7c1a3SJoseph Chen 
886c6f7c1a3SJoseph Chen 	case CLK_TSADC_TSEN:
887e855752aSJoseph Chen 		mask = CLK_TSADC_TSEN_DIV_MASK;
888e855752aSJoseph Chen 		shift =	CLK_TSADC_TSEN_DIV_SHIFT;
889c6f7c1a3SJoseph Chen 		break;
890c6f7c1a3SJoseph Chen 
891c6f7c1a3SJoseph Chen 	case CLK_TSADC:
892e855752aSJoseph Chen 		mask = CLK_TSADC_DIV_MASK;
893e855752aSJoseph Chen 		shift =	CLK_TSADC_DIV_SHIFT;
894c6f7c1a3SJoseph Chen 		break;
895c6f7c1a3SJoseph Chen 
896c6f7c1a3SJoseph Chen 	default:
897c6f7c1a3SJoseph Chen 		return -ENOENT;
898c6f7c1a3SJoseph Chen 	}
899c6f7c1a3SJoseph Chen 
900c6f7c1a3SJoseph Chen 	div = DIV_ROUND_UP(OSC_HZ, rate);
901c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[74], mask, (div - 1) << shift);
902c6f7c1a3SJoseph Chen 
903c6f7c1a3SJoseph Chen 	return rk3528_adc_get_clk(priv, clk_id);
904c6f7c1a3SJoseph Chen }
905c6f7c1a3SJoseph Chen 
rk3528_sdmmc_get_clk(struct rk3528_clk_priv * priv,ulong clk_id)906c6f7c1a3SJoseph Chen static ulong rk3528_sdmmc_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
907c6f7c1a3SJoseph Chen {
908c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
909c6f7c1a3SJoseph Chen 	u32 div, sel, con;
910c6f7c1a3SJoseph Chen 	ulong prate;
911c6f7c1a3SJoseph Chen 
912c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[85]);
913e855752aSJoseph Chen 	div = (con & CCLK_SRC_SDMMC0_DIV_MASK) >>
914e855752aSJoseph Chen 		CCLK_SRC_SDMMC0_DIV_SHIFT;
915e855752aSJoseph Chen 	sel = (con & CCLK_SRC_SDMMC0_SEL_MASK) >>
916e855752aSJoseph Chen 		CCLK_SRC_SDMMC0_SEL_SHIFT;
917c6f7c1a3SJoseph Chen 
918c6f7c1a3SJoseph Chen 	if (sel == CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX)
919c6f7c1a3SJoseph Chen 		prate = priv->gpll_hz;
920c6f7c1a3SJoseph Chen 	else if (sel == CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX)
921c6f7c1a3SJoseph Chen 		prate = priv->cpll_hz;
922c6f7c1a3SJoseph Chen 	else
923c6f7c1a3SJoseph Chen 		prate = OSC_HZ;
924c6f7c1a3SJoseph Chen 
925c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(prate, div);
926c6f7c1a3SJoseph Chen }
927c6f7c1a3SJoseph Chen 
rk3528_sdmmc_set_clk(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)928c6f7c1a3SJoseph Chen static ulong rk3528_sdmmc_set_clk(struct rk3528_clk_priv *priv,
929c6f7c1a3SJoseph Chen 				  ulong clk_id, ulong rate)
930c6f7c1a3SJoseph Chen {
931c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
932c6f7c1a3SJoseph Chen 	u32 div, sel;
933c6f7c1a3SJoseph Chen 
934c6f7c1a3SJoseph Chen 	if (OSC_HZ % rate == 0) {
935c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(OSC_HZ, rate);
936c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_SDMMC0_SEL_XIN_OSC0_FUNC;
937c6f7c1a3SJoseph Chen 	} else if ((priv->cpll_hz % rate) == 0) {
938c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->cpll_hz, rate);
939c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_SDMMC0_SEL_CLK_CPLL_MUX;
940c6f7c1a3SJoseph Chen 	} else {
941c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
942c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_SDMMC0_SEL_CLK_GPLL_MUX;
943c6f7c1a3SJoseph Chen 	}
944c6f7c1a3SJoseph Chen 
945c6f7c1a3SJoseph Chen 	assert(div - 1 <= 31);
946c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[85],
947e855752aSJoseph Chen 		     CCLK_SRC_SDMMC0_SEL_MASK |
948e855752aSJoseph Chen 		     CCLK_SRC_SDMMC0_DIV_MASK,
949e855752aSJoseph Chen 		     sel << CCLK_SRC_SDMMC0_SEL_SHIFT |
950e855752aSJoseph Chen 		     (div - 1) << CCLK_SRC_SDMMC0_DIV_SHIFT);
951c6f7c1a3SJoseph Chen 
952c6f7c1a3SJoseph Chen 	return rk3528_sdmmc_get_clk(priv, clk_id);
953c6f7c1a3SJoseph Chen }
954c6f7c1a3SJoseph Chen 
rk3528_sfc_get_clk(struct rk3528_clk_priv * priv)955c6f7c1a3SJoseph Chen static ulong rk3528_sfc_get_clk(struct rk3528_clk_priv *priv)
956c6f7c1a3SJoseph Chen {
957c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
958c6f7c1a3SJoseph Chen 	u32 div, sel, con, parent;
959c6f7c1a3SJoseph Chen 
960c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[61]);
961e855752aSJoseph Chen 	div = (con & SCLK_SFC_DIV_MASK) >>
962e855752aSJoseph Chen 		SCLK_SFC_DIV_SHIFT;
963e855752aSJoseph Chen 	sel = (con & SCLK_SFC_SEL_MASK) >>
964e855752aSJoseph Chen 		SCLK_SFC_SEL_SHIFT;
965c6f7c1a3SJoseph Chen 	if (sel == SCLK_SFC_SEL_CLK_GPLL_MUX)
966c6f7c1a3SJoseph Chen 		parent = priv->gpll_hz;
967c6f7c1a3SJoseph Chen 	else if (sel == SCLK_SFC_SEL_CLK_CPLL_MUX)
968c6f7c1a3SJoseph Chen 		parent = priv->cpll_hz;
969c6f7c1a3SJoseph Chen 	else
970c6f7c1a3SJoseph Chen 		parent = OSC_HZ;
971c6f7c1a3SJoseph Chen 
972c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(parent, div);
973c6f7c1a3SJoseph Chen }
974c6f7c1a3SJoseph Chen 
rk3528_sfc_set_clk(struct rk3528_clk_priv * priv,ulong rate)975c6f7c1a3SJoseph Chen static ulong rk3528_sfc_set_clk(struct rk3528_clk_priv *priv, ulong rate)
976c6f7c1a3SJoseph Chen {
977c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
978c6f7c1a3SJoseph Chen 	int div, sel;
979c6f7c1a3SJoseph Chen 
980c6f7c1a3SJoseph Chen 	if (OSC_HZ % rate == 0) {
981c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(OSC_HZ, rate);
982c6f7c1a3SJoseph Chen 		sel = SCLK_SFC_SEL_XIN_OSC0_FUNC;
983c6f7c1a3SJoseph Chen 	} else if ((priv->cpll_hz % rate) == 0) {
984c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->cpll_hz, rate);
985c6f7c1a3SJoseph Chen 		sel = SCLK_SFC_SEL_CLK_CPLL_MUX;
986c6f7c1a3SJoseph Chen 	} else {
987c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
988c6f7c1a3SJoseph Chen 		sel = SCLK_SFC_SEL_CLK_GPLL_MUX;
989c6f7c1a3SJoseph Chen 	}
990c6f7c1a3SJoseph Chen 
991c6f7c1a3SJoseph Chen 	assert(div - 1 <= 63);
992c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[61],
993e855752aSJoseph Chen 		     SCLK_SFC_SEL_MASK |
994e855752aSJoseph Chen 		     SCLK_SFC_DIV_MASK,
995e855752aSJoseph Chen 		     sel << SCLK_SFC_SEL_SHIFT |
996e855752aSJoseph Chen 		     (div - 1) << SCLK_SFC_DIV_SHIFT);
997c6f7c1a3SJoseph Chen 
998c6f7c1a3SJoseph Chen 	return rk3528_sfc_get_clk(priv);
999c6f7c1a3SJoseph Chen }
1000c6f7c1a3SJoseph Chen 
rk3528_emmc_get_clk(struct rk3528_clk_priv * priv)1001c6f7c1a3SJoseph Chen static ulong rk3528_emmc_get_clk(struct rk3528_clk_priv *priv)
1002c6f7c1a3SJoseph Chen {
1003c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1004c6f7c1a3SJoseph Chen 	u32 div, sel, con, parent;
1005c6f7c1a3SJoseph Chen 
1006c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[62]);
1007e855752aSJoseph Chen 	div = (con & CCLK_SRC_EMMC_DIV_MASK) >>
1008e855752aSJoseph Chen 		CCLK_SRC_EMMC_DIV_SHIFT;
1009e855752aSJoseph Chen 	sel = (con & CCLK_SRC_EMMC_SEL_MASK) >>
1010e855752aSJoseph Chen 		CCLK_SRC_EMMC_SEL_SHIFT;
1011c6f7c1a3SJoseph Chen 
1012c6f7c1a3SJoseph Chen 	if (sel == CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX)
1013c6f7c1a3SJoseph Chen 		parent = priv->gpll_hz;
1014c6f7c1a3SJoseph Chen 	else if (sel == CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX)
1015c6f7c1a3SJoseph Chen 		parent = priv->cpll_hz;
1016c6f7c1a3SJoseph Chen 	else
1017c6f7c1a3SJoseph Chen 		parent = OSC_HZ;
1018c6f7c1a3SJoseph Chen 
1019c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(parent, div);
1020c6f7c1a3SJoseph Chen }
1021c6f7c1a3SJoseph Chen 
rk3528_emmc_set_clk(struct rk3528_clk_priv * priv,ulong rate)1022c6f7c1a3SJoseph Chen static ulong rk3528_emmc_set_clk(struct rk3528_clk_priv *priv, ulong rate)
1023c6f7c1a3SJoseph Chen {
1024c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1025c6f7c1a3SJoseph Chen 	u32 div, sel;
1026c6f7c1a3SJoseph Chen 
1027c6f7c1a3SJoseph Chen 	if (OSC_HZ % rate == 0) {
1028c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(OSC_HZ, rate);
1029c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_EMMC_SEL_XIN_OSC0_FUNC;
1030c6f7c1a3SJoseph Chen 	} else if ((priv->cpll_hz % rate) == 0) {
1031c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->cpll_hz, rate);
1032c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_EMMC_SEL_CLK_CPLL_MUX;
1033c6f7c1a3SJoseph Chen 	} else {
1034c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1035c6f7c1a3SJoseph Chen 		sel = CCLK_SRC_EMMC_SEL_CLK_GPLL_MUX;
1036c6f7c1a3SJoseph Chen 	}
1037c6f7c1a3SJoseph Chen 
1038c6f7c1a3SJoseph Chen 	assert(div - 1 <= 31);
1039c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[62],
1040e855752aSJoseph Chen 		     CCLK_SRC_EMMC_SEL_MASK |
1041e855752aSJoseph Chen 		     CCLK_SRC_EMMC_DIV_MASK,
1042e855752aSJoseph Chen 		     sel << CCLK_SRC_EMMC_SEL_SHIFT |
1043e855752aSJoseph Chen 		     (div - 1) << CCLK_SRC_EMMC_DIV_SHIFT);
1044c6f7c1a3SJoseph Chen 
1045c6f7c1a3SJoseph Chen 	return rk3528_emmc_get_clk(priv);
1046c6f7c1a3SJoseph Chen }
1047c6f7c1a3SJoseph Chen 
rk3528_dclk_vop_get_clk(struct rk3528_clk_priv * priv,ulong clk_id)1048c6f7c1a3SJoseph Chen static ulong rk3528_dclk_vop_get_clk(struct rk3528_clk_priv *priv, ulong clk_id)
1049c6f7c1a3SJoseph Chen {
1050c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1051c6f7c1a3SJoseph Chen 	u32 div_mask, div_shift;
1052c6f7c1a3SJoseph Chen 	u32 sel_mask, sel_shift;
1053c6f7c1a3SJoseph Chen 	u32 id, con, sel, div;
1054c6f7c1a3SJoseph Chen 	ulong prate;
1055c6f7c1a3SJoseph Chen 
1056c6f7c1a3SJoseph Chen 	switch (clk_id) {
1057c6f7c1a3SJoseph Chen 	case DCLK_VOP0:
1058c6f7c1a3SJoseph Chen 		id = 32;
1059e855752aSJoseph Chen 		sel_mask = DCLK_VOP_SRC0_SEL_MASK;
1060e855752aSJoseph Chen 		sel_shift = DCLK_VOP_SRC0_SEL_SHIFT;
1061c6f7c1a3SJoseph Chen 		/* FIXME if need src: clk_hdmiphy_pixel_io */
1062e855752aSJoseph Chen 		div_mask = DCLK_VOP_SRC0_DIV_MASK;
1063e855752aSJoseph Chen 		div_shift = DCLK_VOP_SRC0_DIV_SHIFT;
1064c6f7c1a3SJoseph Chen 		break;
1065c6f7c1a3SJoseph Chen 
1066c6f7c1a3SJoseph Chen 	case DCLK_VOP1:
1067c6f7c1a3SJoseph Chen 		id = 33;
1068e855752aSJoseph Chen 		sel_mask = DCLK_VOP_SRC1_SEL_MASK;
1069e855752aSJoseph Chen 		sel_shift = DCLK_VOP_SRC1_SEL_SHIFT;
1070e855752aSJoseph Chen 		div_mask = DCLK_VOP_SRC1_DIV_MASK;
1071e855752aSJoseph Chen 		div_shift = DCLK_VOP_SRC1_DIV_SHIFT;
1072c6f7c1a3SJoseph Chen 		break;
1073c6f7c1a3SJoseph Chen 
1074c6f7c1a3SJoseph Chen 	default:
1075c6f7c1a3SJoseph Chen 		return -ENOENT;
1076c6f7c1a3SJoseph Chen 	}
1077c6f7c1a3SJoseph Chen 
1078c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
1079c6f7c1a3SJoseph Chen 	div = (con & div_mask) >> div_shift;
1080c6f7c1a3SJoseph Chen 	sel = (con & sel_mask) >> sel_shift;
1081c6f7c1a3SJoseph Chen 	if (sel == DCLK_VOP_SRC_SEL_CLK_GPLL_MUX)
1082c6f7c1a3SJoseph Chen 		prate = priv->gpll_hz;
1083c6f7c1a3SJoseph Chen 	else
1084c6f7c1a3SJoseph Chen 		prate = priv->cpll_hz;
1085c6f7c1a3SJoseph Chen 
1086c6f7c1a3SJoseph Chen 	return DIV_TO_RATE(prate, div);
1087c6f7c1a3SJoseph Chen }
1088c6f7c1a3SJoseph Chen 
rk3528_dclk_vop_set_clk(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)1089c6f7c1a3SJoseph Chen static ulong rk3528_dclk_vop_set_clk(struct rk3528_clk_priv *priv,
1090c6f7c1a3SJoseph Chen 				     ulong clk_id, ulong rate)
1091c6f7c1a3SJoseph Chen {
1092c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1093c6f7c1a3SJoseph Chen 	u32 div_mask, div_shift;
1094c6f7c1a3SJoseph Chen 	u32 sel_mask, sel_shift;
1095c6f7c1a3SJoseph Chen 	u32 id, sel, div;
1096c6f7c1a3SJoseph Chen 	ulong prate;
1097c6f7c1a3SJoseph Chen 
1098c6f7c1a3SJoseph Chen 	switch (clk_id) {
1099c6f7c1a3SJoseph Chen 	case DCLK_VOP0:
1100c6f7c1a3SJoseph Chen 		id = 32;
1101e855752aSJoseph Chen 		sel_mask = DCLK_VOP_SRC0_SEL_MASK;
1102e855752aSJoseph Chen 		sel_shift = DCLK_VOP_SRC0_SEL_SHIFT;
1103c6f7c1a3SJoseph Chen 		/* FIXME if need src: clk_hdmiphy_pixel_io */
1104e855752aSJoseph Chen 		div_mask = DCLK_VOP_SRC0_DIV_MASK;
1105e855752aSJoseph Chen 		div_shift = DCLK_VOP_SRC0_DIV_SHIFT;
1106c6f7c1a3SJoseph Chen 		break;
1107c6f7c1a3SJoseph Chen 
1108c6f7c1a3SJoseph Chen 	case DCLK_VOP1:
1109c6f7c1a3SJoseph Chen 		id = 33;
1110e855752aSJoseph Chen 		sel_mask = DCLK_VOP_SRC1_SEL_MASK;
1111e855752aSJoseph Chen 		sel_shift = DCLK_VOP_SRC1_SEL_SHIFT;
1112e855752aSJoseph Chen 		div_mask = DCLK_VOP_SRC1_DIV_MASK;
1113e855752aSJoseph Chen 		div_shift = DCLK_VOP_SRC1_DIV_SHIFT;
1114c6f7c1a3SJoseph Chen 		break;
1115c6f7c1a3SJoseph Chen 
1116c6f7c1a3SJoseph Chen 	default:
1117c6f7c1a3SJoseph Chen 		return -ENOENT;
1118c6f7c1a3SJoseph Chen 	}
1119c6f7c1a3SJoseph Chen 
1120c6f7c1a3SJoseph Chen 	if ((priv->gpll_hz % rate) == 0) {
1121c6f7c1a3SJoseph Chen 		prate = priv->gpll_hz;
11229d012e64SJoseph Chen 		sel = (DCLK_VOP_SRC_SEL_CLK_GPLL_MUX << sel_shift) & sel_mask;
1123c6f7c1a3SJoseph Chen 	} else {
1124c6f7c1a3SJoseph Chen 		prate = priv->cpll_hz;
11259d012e64SJoseph Chen 		sel = (DCLK_VOP_SRC_SEL_CLK_CPLL_MUX << sel_shift) & sel_mask;
1126c6f7c1a3SJoseph Chen 	}
1127c6f7c1a3SJoseph Chen 
11289d012e64SJoseph Chen 	div = ((DIV_ROUND_UP(prate, rate) - 1) << div_shift) & div_mask;
1129c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], sel, div);
1130c6f7c1a3SJoseph Chen 
1131c6f7c1a3SJoseph Chen 	return rk3528_dclk_vop_get_clk(priv, clk_id);
1132c6f7c1a3SJoseph Chen }
1133c6f7c1a3SJoseph Chen 
rk3528_uart_get_rate(struct rk3528_clk_priv * priv,ulong clk_id)1134c6f7c1a3SJoseph Chen static ulong rk3528_uart_get_rate(struct rk3528_clk_priv *priv, ulong clk_id)
1135c6f7c1a3SJoseph Chen {
1136c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1137c6f7c1a3SJoseph Chen 	u32 sel_shift, sel_mask, div_shift, div_mask;
1138c6f7c1a3SJoseph Chen 	u32 sel, id, con, frac_div, div;
1139c6f7c1a3SJoseph Chen 	ulong m, n, rate;
1140c6f7c1a3SJoseph Chen 
1141c6f7c1a3SJoseph Chen 	switch (clk_id) {
1142c6f7c1a3SJoseph Chen 	case SCLK_UART0:
1143c6f7c1a3SJoseph Chen 		id = 6;
1144e855752aSJoseph Chen 		sel_shift = SCLK_UART0_SRC_SEL_SHIFT;
1145e855752aSJoseph Chen 		sel_mask = SCLK_UART0_SRC_SEL_MASK;
1146e855752aSJoseph Chen 		div_shift = CLK_UART0_SRC_DIV_SHIFT;
1147e855752aSJoseph Chen 		div_mask = CLK_UART0_SRC_DIV_MASK;
1148c6f7c1a3SJoseph Chen 		break;
1149c6f7c1a3SJoseph Chen 
1150c6f7c1a3SJoseph Chen 	case SCLK_UART1:
1151c6f7c1a3SJoseph Chen 		id = 8;
1152e855752aSJoseph Chen 		sel_shift = SCLK_UART1_SRC_SEL_SHIFT;
1153e855752aSJoseph Chen 		sel_mask = SCLK_UART1_SRC_SEL_MASK;
1154e855752aSJoseph Chen 		div_shift = CLK_UART1_SRC_DIV_SHIFT;
1155e855752aSJoseph Chen 		div_mask = CLK_UART1_SRC_DIV_MASK;
1156c6f7c1a3SJoseph Chen 		break;
1157c6f7c1a3SJoseph Chen 
1158c6f7c1a3SJoseph Chen 	case SCLK_UART2:
1159c6f7c1a3SJoseph Chen 		id = 10;
1160e855752aSJoseph Chen 		sel_shift = SCLK_UART2_SRC_SEL_SHIFT;
1161e855752aSJoseph Chen 		sel_mask = SCLK_UART2_SRC_SEL_MASK;
1162e855752aSJoseph Chen 		div_shift = CLK_UART2_SRC_DIV_SHIFT;
1163e855752aSJoseph Chen 		div_mask = CLK_UART2_SRC_DIV_MASK;
1164c6f7c1a3SJoseph Chen 		break;
1165c6f7c1a3SJoseph Chen 
1166c6f7c1a3SJoseph Chen 	case SCLK_UART3:
1167c6f7c1a3SJoseph Chen 		id = 12;
1168e855752aSJoseph Chen 		sel_shift = SCLK_UART3_SRC_SEL_SHIFT;
1169e855752aSJoseph Chen 		sel_mask = SCLK_UART3_SRC_SEL_MASK;
1170e855752aSJoseph Chen 		div_shift = CLK_UART3_SRC_DIV_SHIFT;
1171e855752aSJoseph Chen 		div_mask = CLK_UART3_SRC_DIV_MASK;
1172c6f7c1a3SJoseph Chen 		break;
1173c6f7c1a3SJoseph Chen 
1174c6f7c1a3SJoseph Chen 	case SCLK_UART4:
1175c6f7c1a3SJoseph Chen 		id = 14;
1176e855752aSJoseph Chen 		sel_shift = SCLK_UART4_SRC_SEL_SHIFT;
1177e855752aSJoseph Chen 		sel_mask = SCLK_UART4_SRC_SEL_MASK;
1178e855752aSJoseph Chen 		div_shift = CLK_UART4_SRC_DIV_SHIFT;
1179e855752aSJoseph Chen 		div_mask = CLK_UART4_SRC_DIV_MASK;
1180c6f7c1a3SJoseph Chen 		break;
1181c6f7c1a3SJoseph Chen 
1182c6f7c1a3SJoseph Chen 	case SCLK_UART5:
1183c6f7c1a3SJoseph Chen 		id = 16;
1184e855752aSJoseph Chen 		sel_shift = SCLK_UART5_SRC_SEL_SHIFT;
1185e855752aSJoseph Chen 		sel_mask = SCLK_UART5_SRC_SEL_MASK;
1186e855752aSJoseph Chen 		div_shift = CLK_UART5_SRC_DIV_SHIFT;
1187e855752aSJoseph Chen 		div_mask = CLK_UART5_SRC_DIV_MASK;
1188c6f7c1a3SJoseph Chen 		break;
1189c6f7c1a3SJoseph Chen 
1190c6f7c1a3SJoseph Chen 	case SCLK_UART6:
1191c6f7c1a3SJoseph Chen 		id = 18;
1192e855752aSJoseph Chen 		sel_shift = SCLK_UART6_SRC_SEL_SHIFT;
1193e855752aSJoseph Chen 		sel_mask = SCLK_UART6_SRC_SEL_MASK;
1194e855752aSJoseph Chen 		div_shift = CLK_UART6_SRC_DIV_SHIFT;
1195e855752aSJoseph Chen 		div_mask = CLK_UART6_SRC_DIV_MASK;
1196c6f7c1a3SJoseph Chen 		break;
1197c6f7c1a3SJoseph Chen 
1198c6f7c1a3SJoseph Chen 	case SCLK_UART7:
1199c6f7c1a3SJoseph Chen 		id = 20;
1200e855752aSJoseph Chen 		sel_shift = SCLK_UART7_SRC_SEL_SHIFT;
1201e855752aSJoseph Chen 		sel_mask = SCLK_UART7_SRC_SEL_MASK;
1202e855752aSJoseph Chen 		div_shift = CLK_UART7_SRC_DIV_SHIFT;
1203e855752aSJoseph Chen 		div_mask = CLK_UART7_SRC_DIV_MASK;
1204c6f7c1a3SJoseph Chen 		break;
1205c6f7c1a3SJoseph Chen 
1206c6f7c1a3SJoseph Chen 	default:
1207c6f7c1a3SJoseph Chen 		return -ENOENT;
1208c6f7c1a3SJoseph Chen 	}
1209c6f7c1a3SJoseph Chen 
1210c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id - 2]);
1211c6f7c1a3SJoseph Chen 	div = (con & div_mask) >> div_shift;
1212c6f7c1a3SJoseph Chen 
1213c6f7c1a3SJoseph Chen 	con = readl(&cru->clksel_con[id]);
1214c6f7c1a3SJoseph Chen 	sel = (con & sel_mask) >> sel_shift;
1215c6f7c1a3SJoseph Chen 
1216c6f7c1a3SJoseph Chen 	if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_SRC) {
1217c6f7c1a3SJoseph Chen 		rate = DIV_TO_RATE(priv->gpll_hz, div);
1218c6f7c1a3SJoseph Chen 	} else if (sel == SCLK_UART0_SRC_SEL_CLK_UART0_FRAC) {
1219c6f7c1a3SJoseph Chen 		frac_div = readl(&cru->clksel_con[id - 1]);
1220c6f7c1a3SJoseph Chen 		n = (frac_div & 0xffff0000) >> 16;
1221c6f7c1a3SJoseph Chen 		m = frac_div & 0x0000ffff;
1222c6f7c1a3SJoseph Chen 		rate = DIV_TO_RATE(priv->gpll_hz, div) * n / m;
1223c6f7c1a3SJoseph Chen 	} else {
1224c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
1225c6f7c1a3SJoseph Chen 	}
1226c6f7c1a3SJoseph Chen 
1227c6f7c1a3SJoseph Chen 	return rate;
1228c6f7c1a3SJoseph Chen }
1229c6f7c1a3SJoseph Chen 
rk3528_uart_set_rate(struct rk3528_clk_priv * priv,ulong clk_id,ulong rate)1230c6f7c1a3SJoseph Chen static ulong rk3528_uart_set_rate(struct rk3528_clk_priv *priv,
1231c6f7c1a3SJoseph Chen 				  ulong clk_id, ulong rate)
1232c6f7c1a3SJoseph Chen {
1233c6f7c1a3SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
1234c6f7c1a3SJoseph Chen 	u32 sel_shift, sel_mask, div_shift, div_mask;
1235c6f7c1a3SJoseph Chen 	u32 sel, id, div;
1236c6f7c1a3SJoseph Chen 	ulong m = 0, n = 0, val;
1237c6f7c1a3SJoseph Chen 
1238c6f7c1a3SJoseph Chen 	if (rate == OSC_HZ) {
1239c6f7c1a3SJoseph Chen 		sel = SCLK_UART0_SRC_SEL_XIN_OSC0_FUNC;
1240c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(OSC_HZ, rate);
1241c6f7c1a3SJoseph Chen 	} else if (priv->gpll_hz % rate == 0) {
1242c6f7c1a3SJoseph Chen 		sel = SCLK_UART0_SRC_SEL_CLK_UART0_SRC;
1243c6f7c1a3SJoseph Chen 		div = DIV_ROUND_UP(priv->gpll_hz, rate);
1244c6f7c1a3SJoseph Chen 	} else {
1245c6f7c1a3SJoseph Chen 		sel = SCLK_UART0_SRC_SEL_CLK_UART0_FRAC;
1246c6f7c1a3SJoseph Chen 		div = 2;
1247c6f7c1a3SJoseph Chen 		rational_best_approximation(rate, priv->gpll_hz / div,
1248c6f7c1a3SJoseph Chen 					    GENMASK(16 - 1, 0),
1249c6f7c1a3SJoseph Chen 					    GENMASK(16 - 1, 0),
1250c6f7c1a3SJoseph Chen 					    &n, &m);
1251c6f7c1a3SJoseph Chen 	}
1252c6f7c1a3SJoseph Chen 
1253c6f7c1a3SJoseph Chen 	switch (clk_id) {
1254c6f7c1a3SJoseph Chen 	case SCLK_UART0:
1255c6f7c1a3SJoseph Chen 		id = 6;
1256e855752aSJoseph Chen 		sel_shift = SCLK_UART0_SRC_SEL_SHIFT;
1257e855752aSJoseph Chen 		sel_mask = SCLK_UART0_SRC_SEL_MASK;
1258e855752aSJoseph Chen 		div_shift = CLK_UART0_SRC_DIV_SHIFT;
1259e855752aSJoseph Chen 		div_mask = CLK_UART0_SRC_DIV_MASK;
1260c6f7c1a3SJoseph Chen 		break;
1261c6f7c1a3SJoseph Chen 
1262c6f7c1a3SJoseph Chen 	case SCLK_UART1:
1263c6f7c1a3SJoseph Chen 		id = 8;
1264e855752aSJoseph Chen 		sel_shift = SCLK_UART1_SRC_SEL_SHIFT;
1265e855752aSJoseph Chen 		sel_mask = SCLK_UART1_SRC_SEL_MASK;
1266e855752aSJoseph Chen 		div_shift = CLK_UART1_SRC_DIV_SHIFT;
1267e855752aSJoseph Chen 		div_mask = CLK_UART1_SRC_DIV_MASK;
1268c6f7c1a3SJoseph Chen 		break;
1269c6f7c1a3SJoseph Chen 
1270c6f7c1a3SJoseph Chen 	case SCLK_UART2:
1271c6f7c1a3SJoseph Chen 		id = 10;
1272e855752aSJoseph Chen 		sel_shift = SCLK_UART2_SRC_SEL_SHIFT;
1273e855752aSJoseph Chen 		sel_mask = SCLK_UART2_SRC_SEL_MASK;
1274e855752aSJoseph Chen 		div_shift = CLK_UART2_SRC_DIV_SHIFT;
1275e855752aSJoseph Chen 		div_mask = CLK_UART2_SRC_DIV_MASK;
1276c6f7c1a3SJoseph Chen 		break;
1277c6f7c1a3SJoseph Chen 
1278c6f7c1a3SJoseph Chen 	case SCLK_UART3:
1279c6f7c1a3SJoseph Chen 		id = 12;
1280e855752aSJoseph Chen 		sel_shift = SCLK_UART3_SRC_SEL_SHIFT;
1281e855752aSJoseph Chen 		sel_mask = SCLK_UART3_SRC_SEL_MASK;
1282e855752aSJoseph Chen 		div_shift = CLK_UART3_SRC_DIV_SHIFT;
1283e855752aSJoseph Chen 		div_mask = CLK_UART3_SRC_DIV_MASK;
1284c6f7c1a3SJoseph Chen 		break;
1285c6f7c1a3SJoseph Chen 
1286c6f7c1a3SJoseph Chen 	case SCLK_UART4:
1287c6f7c1a3SJoseph Chen 		id = 14;
1288e855752aSJoseph Chen 		sel_shift = SCLK_UART4_SRC_SEL_SHIFT;
1289e855752aSJoseph Chen 		sel_mask = SCLK_UART4_SRC_SEL_MASK;
1290e855752aSJoseph Chen 		div_shift = CLK_UART4_SRC_DIV_SHIFT;
1291e855752aSJoseph Chen 		div_mask = CLK_UART4_SRC_DIV_MASK;
1292c6f7c1a3SJoseph Chen 		break;
1293c6f7c1a3SJoseph Chen 
1294c6f7c1a3SJoseph Chen 	case SCLK_UART5:
1295c6f7c1a3SJoseph Chen 		id = 16;
1296e855752aSJoseph Chen 		sel_shift = SCLK_UART5_SRC_SEL_SHIFT;
1297e855752aSJoseph Chen 		sel_mask = SCLK_UART5_SRC_SEL_MASK;
1298e855752aSJoseph Chen 		div_shift = CLK_UART5_SRC_DIV_SHIFT;
1299e855752aSJoseph Chen 		div_mask = CLK_UART5_SRC_DIV_MASK;
1300c6f7c1a3SJoseph Chen 		break;
1301c6f7c1a3SJoseph Chen 
1302c6f7c1a3SJoseph Chen 	case SCLK_UART6:
1303c6f7c1a3SJoseph Chen 		id = 18;
1304e855752aSJoseph Chen 		sel_shift = SCLK_UART6_SRC_SEL_SHIFT;
1305e855752aSJoseph Chen 		sel_mask = SCLK_UART6_SRC_SEL_MASK;
1306e855752aSJoseph Chen 		div_shift = CLK_UART6_SRC_DIV_SHIFT;
1307e855752aSJoseph Chen 		div_mask = CLK_UART6_SRC_DIV_MASK;
1308c6f7c1a3SJoseph Chen 		break;
1309c6f7c1a3SJoseph Chen 
1310c6f7c1a3SJoseph Chen 	case SCLK_UART7:
1311c6f7c1a3SJoseph Chen 		id = 20;
1312e855752aSJoseph Chen 		sel_shift = SCLK_UART7_SRC_SEL_SHIFT;
1313e855752aSJoseph Chen 		sel_mask = SCLK_UART7_SRC_SEL_MASK;
1314e855752aSJoseph Chen 		div_shift = CLK_UART7_SRC_DIV_SHIFT;
1315e855752aSJoseph Chen 		div_mask = CLK_UART7_SRC_DIV_MASK;
1316c6f7c1a3SJoseph Chen 		break;
1317c6f7c1a3SJoseph Chen 
1318c6f7c1a3SJoseph Chen 	default:
1319c6f7c1a3SJoseph Chen 		return -ENOENT;
1320c6f7c1a3SJoseph Chen 	}
1321c6f7c1a3SJoseph Chen 
1322c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id - 2], div_mask, (div - 1) << div_shift);
1323c6f7c1a3SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], sel_mask, sel << sel_shift);
1324c6f7c1a3SJoseph Chen 	if (m && n) {
1325c6f7c1a3SJoseph Chen 		val = n << 16 | m;
1326c6f7c1a3SJoseph Chen 		writel(val, &cru->clksel_con[id - 1]);
1327c6f7c1a3SJoseph Chen 	}
1328c6f7c1a3SJoseph Chen 
1329c6f7c1a3SJoseph Chen 	return rk3528_uart_get_rate(priv, clk_id);
1330c6f7c1a3SJoseph Chen }
1331c6f7c1a3SJoseph Chen 
rk3528_clk_get_rate(struct clk * clk)1332c6f7c1a3SJoseph Chen static ulong rk3528_clk_get_rate(struct clk *clk)
1333c6f7c1a3SJoseph Chen {
1334c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(clk->dev);
1335c6f7c1a3SJoseph Chen 	ulong rate = 0;
1336c6f7c1a3SJoseph Chen 
1337c6f7c1a3SJoseph Chen 	if (!priv->gpll_hz || !priv->cpll_hz) {
1338c6f7c1a3SJoseph Chen 		printf("%s: gpll=%lu, cpll=%ld\n",
1339c6f7c1a3SJoseph Chen 		       __func__, priv->gpll_hz, priv->cpll_hz);
1340c6f7c1a3SJoseph Chen 		return -ENOENT;
1341c6f7c1a3SJoseph Chen 	}
1342c6f7c1a3SJoseph Chen 
1343c6f7c1a3SJoseph Chen 	switch (clk->id) {
1344c6f7c1a3SJoseph Chen 	case PLL_APLL:
1345c6f7c1a3SJoseph Chen 	case ARMCLK:
1346c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[APLL], priv->cru,
1347c6f7c1a3SJoseph Chen 					     APLL);
1348c6f7c1a3SJoseph Chen 		break;
1349c6f7c1a3SJoseph Chen 	case PLL_CPLL:
1350c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL], priv->cru,
1351c6f7c1a3SJoseph Chen 					     CPLL);
1352c6f7c1a3SJoseph Chen 		break;
1353c6f7c1a3SJoseph Chen 	case PLL_GPLL:
1354c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL], priv->cru,
1355c6f7c1a3SJoseph Chen 					     GPLL);
1356c6f7c1a3SJoseph Chen 		break;
1357c6f7c1a3SJoseph Chen 
1358c6f7c1a3SJoseph Chen 	case PLL_PPLL:
1359c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL], priv->cru,
1360c6f7c1a3SJoseph Chen 					     PPLL);
1361c6f7c1a3SJoseph Chen 		break;
1362c6f7c1a3SJoseph Chen 	case PLL_DPLL:
1363c6f7c1a3SJoseph Chen 		rate = rockchip_pll_get_rate(&rk3528_pll_clks[DPLL], priv->cru,
1364c6f7c1a3SJoseph Chen 					     DPLL);
1365c6f7c1a3SJoseph Chen 		break;
1366c6f7c1a3SJoseph Chen 
1367c6f7c1a3SJoseph Chen 	case TCLK_WDT_NS:
1368c6f7c1a3SJoseph Chen 		rate = OSC_HZ;
1369c6f7c1a3SJoseph Chen 		break;
1370c6f7c1a3SJoseph Chen 	case CLK_I2C0:
1371c6f7c1a3SJoseph Chen 	case CLK_I2C1:
1372c6f7c1a3SJoseph Chen 	case CLK_I2C2:
1373c6f7c1a3SJoseph Chen 	case CLK_I2C3:
1374c6f7c1a3SJoseph Chen 	case CLK_I2C4:
1375c6f7c1a3SJoseph Chen 	case CLK_I2C5:
1376c6f7c1a3SJoseph Chen 	case CLK_I2C6:
1377c6f7c1a3SJoseph Chen 	case CLK_I2C7:
1378c6f7c1a3SJoseph Chen 		rate = rk3528_i2c_get_clk(priv, clk->id);
1379c6f7c1a3SJoseph Chen 		break;
1380c6f7c1a3SJoseph Chen 	case CLK_SPI0:
1381c6f7c1a3SJoseph Chen 	case CLK_SPI1:
1382c6f7c1a3SJoseph Chen 		rate = rk3528_spi_get_clk(priv, clk->id);
1383c6f7c1a3SJoseph Chen 		break;
1384c6f7c1a3SJoseph Chen 	case CLK_PWM0:
1385c6f7c1a3SJoseph Chen 	case CLK_PWM1:
1386c6f7c1a3SJoseph Chen 		rate = rk3528_pwm_get_clk(priv, clk->id);
1387c6f7c1a3SJoseph Chen 		break;
1388c6f7c1a3SJoseph Chen 	case CLK_SARADC:
1389c6f7c1a3SJoseph Chen 	case CLK_TSADC:
1390c6f7c1a3SJoseph Chen 	case CLK_TSADC_TSEN:
1391c6f7c1a3SJoseph Chen 		rate = rk3528_adc_get_clk(priv, clk->id);
1392c6f7c1a3SJoseph Chen 		break;
1393c6f7c1a3SJoseph Chen 	case CCLK_SRC_EMMC:
1394c6f7c1a3SJoseph Chen 		rate = rk3528_emmc_get_clk(priv);
1395c6f7c1a3SJoseph Chen 		break;
1396c6f7c1a3SJoseph Chen 	case HCLK_SDMMC0:
1397c6f7c1a3SJoseph Chen 	case CCLK_SRC_SDMMC0:
1398c6f7c1a3SJoseph Chen 		rate = rk3528_sdmmc_get_clk(priv, clk->id);
1399c6f7c1a3SJoseph Chen 		break;
1400c6f7c1a3SJoseph Chen 	case SCLK_SFC:
1401c6f7c1a3SJoseph Chen 		rate = rk3528_sfc_get_clk(priv);
1402c6f7c1a3SJoseph Chen 		break;
1403c6f7c1a3SJoseph Chen 	case DCLK_VOP0:
1404c6f7c1a3SJoseph Chen 	case DCLK_VOP1:
1405c6f7c1a3SJoseph Chen 		rate = rk3528_dclk_vop_get_clk(priv, clk->id);
1406c6f7c1a3SJoseph Chen 		break;
1407c6f7c1a3SJoseph Chen 	case DCLK_CVBS:
1408c6f7c1a3SJoseph Chen 		rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1) / 4;
1409c6f7c1a3SJoseph Chen 		break;
1410c6f7c1a3SJoseph Chen 	case DCLK_4X_CVBS:
1411c6f7c1a3SJoseph Chen 		rate = rk3528_dclk_vop_get_clk(priv, DCLK_VOP1);
1412c6f7c1a3SJoseph Chen 		break;
1413c6f7c1a3SJoseph Chen 	case SCLK_UART0:
1414c6f7c1a3SJoseph Chen 	case SCLK_UART1:
1415c6f7c1a3SJoseph Chen 	case SCLK_UART2:
1416c6f7c1a3SJoseph Chen 	case SCLK_UART3:
1417c6f7c1a3SJoseph Chen 	case SCLK_UART4:
1418c6f7c1a3SJoseph Chen 	case SCLK_UART5:
1419c6f7c1a3SJoseph Chen 	case SCLK_UART6:
1420c6f7c1a3SJoseph Chen 	case SCLK_UART7:
1421c6f7c1a3SJoseph Chen 		rate = rk3528_uart_get_rate(priv, clk->id);
1422c6f7c1a3SJoseph Chen 		break;
1423c6f7c1a3SJoseph Chen 	case CLK_MATRIX_50M_SRC:
1424c6f7c1a3SJoseph Chen 	case CLK_MATRIX_100M_SRC:
1425c6f7c1a3SJoseph Chen 	case CLK_MATRIX_150M_SRC:
1426c6f7c1a3SJoseph Chen 	case CLK_MATRIX_200M_SRC:
1427c6f7c1a3SJoseph Chen 	case CLK_MATRIX_250M_SRC:
1428c6f7c1a3SJoseph Chen 	case CLK_MATRIX_300M_SRC:
1429c6f7c1a3SJoseph Chen 	case CLK_MATRIX_339M_SRC:
1430c6f7c1a3SJoseph Chen 	case CLK_MATRIX_400M_SRC:
1431c6f7c1a3SJoseph Chen 	case CLK_MATRIX_500M_SRC:
1432c6f7c1a3SJoseph Chen 	case CLK_MATRIX_600M_SRC:
1433c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_BIU:
1434c6f7c1a3SJoseph Chen 		rate = rk3528_cgpll_matrix_get_rate(priv, clk->id);
1435c6f7c1a3SJoseph Chen 		break;
1436c6f7c1a3SJoseph Chen 	case CLK_PPLL_50M_MATRIX:
1437c6f7c1a3SJoseph Chen 	case CLK_PPLL_100M_MATRIX:
1438c6f7c1a3SJoseph Chen 	case CLK_PPLL_125M_MATRIX:
1439c6f7c1a3SJoseph Chen 	case CLK_GMAC1_VPU_25M:
1440c6f7c1a3SJoseph Chen 	case CLK_GMAC1_RMII_VPU:
1441c6f7c1a3SJoseph Chen 	case CLK_GMAC1_SRC_VPU:
1442c6f7c1a3SJoseph Chen 		rate = rk3528_ppll_matrix_get_rate(priv, clk->id);
1443c6f7c1a3SJoseph Chen 		break;
1444c6f7c1a3SJoseph Chen 	default:
1445c6f7c1a3SJoseph Chen 		return -ENOENT;
1446c6f7c1a3SJoseph Chen 	}
1447c6f7c1a3SJoseph Chen 
1448c6f7c1a3SJoseph Chen 	return rate;
1449c6f7c1a3SJoseph Chen };
1450c6f7c1a3SJoseph Chen 
rk3528_clk_set_rate(struct clk * clk,ulong rate)1451c6f7c1a3SJoseph Chen static ulong rk3528_clk_set_rate(struct clk *clk, ulong rate)
1452c6f7c1a3SJoseph Chen {
1453c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(clk->dev);
1454c6f7c1a3SJoseph Chen 	ulong ret = 0;
1455c6f7c1a3SJoseph Chen 
1456c6f7c1a3SJoseph Chen 	if (!priv->gpll_hz) {
1457c6f7c1a3SJoseph Chen 		printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1458c6f7c1a3SJoseph Chen 		return -ENOENT;
1459c6f7c1a3SJoseph Chen 	}
1460c6f7c1a3SJoseph Chen 
1461c6f7c1a3SJoseph Chen 	switch (clk->id) {
1462c6f7c1a3SJoseph Chen 	case PLL_APLL:
1463c6f7c1a3SJoseph Chen 	case ARMCLK:
1464c6f7c1a3SJoseph Chen 		if (priv->armclk_hz)
1465c6f7c1a3SJoseph Chen 			rk3528_armclk_set_clk(priv, rate);
1466c6f7c1a3SJoseph Chen 		priv->armclk_hz = rate;
1467c6f7c1a3SJoseph Chen 		break;
1468c6f7c1a3SJoseph Chen 	case PLL_CPLL:
1469c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru,
1470c6f7c1a3SJoseph Chen 					    CPLL, rate);
1471c6f7c1a3SJoseph Chen 		priv->cpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[CPLL],
1472c6f7c1a3SJoseph Chen 						      priv->cru, CPLL);
1473c6f7c1a3SJoseph Chen 		break;
1474c6f7c1a3SJoseph Chen 	case PLL_GPLL:
1475c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru,
1476c6f7c1a3SJoseph Chen 					    GPLL, rate);
1477c6f7c1a3SJoseph Chen 		priv->gpll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[GPLL],
1478c6f7c1a3SJoseph Chen 						      priv->cru, GPLL);
1479c6f7c1a3SJoseph Chen 		break;
1480c6f7c1a3SJoseph Chen 	case PLL_PPLL:
1481c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru,
1482c6f7c1a3SJoseph Chen 					    PPLL, rate);
1483c6f7c1a3SJoseph Chen 		priv->ppll_hz = rockchip_pll_get_rate(&rk3528_pll_clks[PPLL],
1484c6f7c1a3SJoseph Chen 						      priv->cru, PPLL);
1485c6f7c1a3SJoseph Chen 		break;
1486c6f7c1a3SJoseph Chen 	case TCLK_WDT_NS:
1487c6f7c1a3SJoseph Chen 		return (rate == OSC_HZ) ? 0 : -EINVAL;
1488c6f7c1a3SJoseph Chen 	case CLK_I2C0:
1489c6f7c1a3SJoseph Chen 	case CLK_I2C1:
1490c6f7c1a3SJoseph Chen 	case CLK_I2C2:
1491c6f7c1a3SJoseph Chen 	case CLK_I2C3:
1492c6f7c1a3SJoseph Chen 	case CLK_I2C4:
1493c6f7c1a3SJoseph Chen 	case CLK_I2C5:
1494c6f7c1a3SJoseph Chen 	case CLK_I2C6:
1495c6f7c1a3SJoseph Chen 	case CLK_I2C7:
1496c6f7c1a3SJoseph Chen 		ret = rk3528_i2c_set_clk(priv, clk->id, rate);
1497c6f7c1a3SJoseph Chen 		break;
1498c6f7c1a3SJoseph Chen 	case CLK_SPI0:
1499c6f7c1a3SJoseph Chen 	case CLK_SPI1:
1500c6f7c1a3SJoseph Chen 		ret = rk3528_spi_set_clk(priv, clk->id, rate);
1501c6f7c1a3SJoseph Chen 		break;
1502c6f7c1a3SJoseph Chen 	case CLK_PWM0:
1503c6f7c1a3SJoseph Chen 	case CLK_PWM1:
1504c6f7c1a3SJoseph Chen 		ret = rk3528_pwm_set_clk(priv, clk->id, rate);
1505c6f7c1a3SJoseph Chen 		break;
1506c6f7c1a3SJoseph Chen 	case CLK_SARADC:
1507c6f7c1a3SJoseph Chen 	case CLK_TSADC:
1508c6f7c1a3SJoseph Chen 	case CLK_TSADC_TSEN:
1509c6f7c1a3SJoseph Chen 		ret = rk3528_adc_set_clk(priv, clk->id, rate);
1510c6f7c1a3SJoseph Chen 		break;
1511c6f7c1a3SJoseph Chen 	case HCLK_SDMMC0:
1512c6f7c1a3SJoseph Chen 	case CCLK_SRC_SDMMC0:
1513c6f7c1a3SJoseph Chen 		ret = rk3528_sdmmc_set_clk(priv, clk->id, rate);
1514c6f7c1a3SJoseph Chen 		break;
1515c6f7c1a3SJoseph Chen 	case SCLK_SFC:
1516c6f7c1a3SJoseph Chen 		ret = rk3528_sfc_set_clk(priv, rate);
1517c6f7c1a3SJoseph Chen 		break;
1518c6f7c1a3SJoseph Chen 	case CCLK_SRC_EMMC:
1519c6f7c1a3SJoseph Chen 		ret = rk3528_emmc_set_clk(priv, rate);
1520c6f7c1a3SJoseph Chen 		break;
1521c6f7c1a3SJoseph Chen 	case DCLK_VOP0:
1522c6f7c1a3SJoseph Chen 	case DCLK_VOP1:
1523c6f7c1a3SJoseph Chen 		ret = rk3528_dclk_vop_set_clk(priv, clk->id, rate);
1524c6f7c1a3SJoseph Chen 		break;
1525c6f7c1a3SJoseph Chen 	case SCLK_UART0:
1526c6f7c1a3SJoseph Chen 	case SCLK_UART1:
1527c6f7c1a3SJoseph Chen 	case SCLK_UART2:
1528c6f7c1a3SJoseph Chen 	case SCLK_UART3:
1529c6f7c1a3SJoseph Chen 	case SCLK_UART4:
1530c6f7c1a3SJoseph Chen 	case SCLK_UART5:
1531c6f7c1a3SJoseph Chen 	case SCLK_UART6:
1532c6f7c1a3SJoseph Chen 	case SCLK_UART7:
1533c6f7c1a3SJoseph Chen 		ret = rk3528_uart_set_rate(priv, clk->id, rate);
1534c6f7c1a3SJoseph Chen 		break;
1535c6f7c1a3SJoseph Chen 	case CLK_MATRIX_50M_SRC:
1536c6f7c1a3SJoseph Chen 	case CLK_MATRIX_100M_SRC:
1537c6f7c1a3SJoseph Chen 	case CLK_MATRIX_150M_SRC:
1538c6f7c1a3SJoseph Chen 	case CLK_MATRIX_200M_SRC:
1539c6f7c1a3SJoseph Chen 	case CLK_MATRIX_250M_SRC:
1540c6f7c1a3SJoseph Chen 	case CLK_MATRIX_300M_SRC:
1541c6f7c1a3SJoseph Chen 	case CLK_MATRIX_339M_SRC:
1542c6f7c1a3SJoseph Chen 	case CLK_MATRIX_400M_SRC:
1543c6f7c1a3SJoseph Chen 	case CLK_MATRIX_500M_SRC:
1544c6f7c1a3SJoseph Chen 	case CLK_MATRIX_600M_SRC:
1545c6f7c1a3SJoseph Chen 	case ACLK_BUS_VOPGL_BIU:
1546c6f7c1a3SJoseph Chen 		ret = rk3528_cgpll_matrix_set_rate(priv, clk->id, rate);
1547c6f7c1a3SJoseph Chen 		break;
1548c6f7c1a3SJoseph Chen 	case CLK_PPLL_50M_MATRIX:
1549c6f7c1a3SJoseph Chen 	case CLK_PPLL_100M_MATRIX:
1550c6f7c1a3SJoseph Chen 	case CLK_PPLL_125M_MATRIX:
1551c6f7c1a3SJoseph Chen 	case CLK_GMAC1_VPU_25M:
1552c6f7c1a3SJoseph Chen 		ret = rk3528_ppll_matrix_set_rate(priv, clk->id, rate);
1553c6f7c1a3SJoseph Chen 		break;
1554a9533156SJoseph Chen 	case CLK_GMAC1_RMII_VPU:
1555a9533156SJoseph Chen 	case CLK_GMAC1_SRC_VPU:
1556a9533156SJoseph Chen 		/* dummy set */
1557a9533156SJoseph Chen 		ret = rk3528_ppll_matrix_get_rate(priv, clk->id);
1558a9533156SJoseph Chen 		break;
1559c6f7c1a3SJoseph Chen 	default:
1560c6f7c1a3SJoseph Chen 		return -ENOENT;
1561c6f7c1a3SJoseph Chen 	}
1562c6f7c1a3SJoseph Chen 
1563c6f7c1a3SJoseph Chen 	return ret;
1564c6f7c1a3SJoseph Chen };
1565c6f7c1a3SJoseph Chen 
1566333ce117SJoseph Chen #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
rk3528_clk_set_parent(struct clk * clk,struct clk * parent)1567333ce117SJoseph Chen static int rk3528_clk_set_parent(struct clk *clk, struct clk *parent)
1568333ce117SJoseph Chen {
1569333ce117SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(clk->dev);
1570333ce117SJoseph Chen 	const char *clock_dev_name = parent->dev->name;
1571333ce117SJoseph Chen 
1572333ce117SJoseph Chen 	switch (clk->id) {
1573333ce117SJoseph Chen 	case DCLK_VOP0:
1574333ce117SJoseph Chen 		if (!strcmp(clock_dev_name, "inno_hdmi_pll_clk"))
1575333ce117SJoseph Chen 			/* clk_hdmiphy_pixel_io */
1576333ce117SJoseph Chen 			rk_clrsetreg(&priv->cru->clksel_con[84], 0x1, 1);
1577333ce117SJoseph Chen 		else
1578333ce117SJoseph Chen 			rk_clrsetreg(&priv->cru->clksel_con[84], 0x1, 0);
1579333ce117SJoseph Chen 		break;
1580333ce117SJoseph Chen 
1581333ce117SJoseph Chen 	default:
1582333ce117SJoseph Chen 		return -ENOENT;
1583333ce117SJoseph Chen 	}
1584333ce117SJoseph Chen 
1585333ce117SJoseph Chen 	return 0;
1586333ce117SJoseph Chen }
1587333ce117SJoseph Chen #endif
1588c6f7c1a3SJoseph Chen 
1589c6f7c1a3SJoseph Chen static struct clk_ops rk3528_clk_ops = {
1590c6f7c1a3SJoseph Chen 	.get_rate = rk3528_clk_get_rate,
1591c6f7c1a3SJoseph Chen 	.set_rate = rk3528_clk_set_rate,
1592333ce117SJoseph Chen #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1593333ce117SJoseph Chen 	.set_parent = rk3528_clk_set_parent,
1594333ce117SJoseph Chen #endif
1595c6f7c1a3SJoseph Chen };
1596c6f7c1a3SJoseph Chen 
rk3528_grfclk_get_rate(struct clk * clk)1597c6f7c1a3SJoseph Chen static ulong rk3528_grfclk_get_rate(struct clk *clk)
1598c6f7c1a3SJoseph Chen {
1599c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv;
1600c6f7c1a3SJoseph Chen 	struct udevice *cru_dev;
1601c6f7c1a3SJoseph Chen 	ulong rate = 0;
1602c6f7c1a3SJoseph Chen 	int ret;
1603c6f7c1a3SJoseph Chen 
1604c6f7c1a3SJoseph Chen 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1605c6f7c1a3SJoseph Chen 					  DM_GET_DRIVER(rockchip_rk3528_cru),
1606c6f7c1a3SJoseph Chen 					  &cru_dev);
1607c6f7c1a3SJoseph Chen 	if (ret) {
1608c6f7c1a3SJoseph Chen 		printf("%s: could not find cru device\n", __func__);
1609c6f7c1a3SJoseph Chen 		return ret;
1610c6f7c1a3SJoseph Chen 	}
1611c6f7c1a3SJoseph Chen 	priv = dev_get_priv(cru_dev);
1612c6f7c1a3SJoseph Chen 
1613c6f7c1a3SJoseph Chen 	switch (clk->id) {
1614c6f7c1a3SJoseph Chen 	case SCLK_SDMMC_SAMPLE:
1615c6f7c1a3SJoseph Chen 		rate = rk3528_sdmmc_get_clk(priv, CCLK_SRC_SDMMC0) / 2;
1616c6f7c1a3SJoseph Chen 		break;
1617c6f7c1a3SJoseph Chen 	default:
1618c6f7c1a3SJoseph Chen 		return -ENOENT;
1619c6f7c1a3SJoseph Chen 	}
1620c6f7c1a3SJoseph Chen 
1621c6f7c1a3SJoseph Chen 	return rate;
1622c6f7c1a3SJoseph Chen };
1623c6f7c1a3SJoseph Chen 
1624c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAY_SEL		BIT(11)
1625c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DEGREE_MASK	0x3
1626c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAYNUM_OFFSET	3
1627c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAYNUM_MASK	(0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
1628c6f7c1a3SJoseph Chen #define PSECS_PER_SEC 1000000000000LL
1629c6f7c1a3SJoseph Chen /*
1630c6f7c1a3SJoseph Chen  * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
1631c6f7c1a3SJoseph Chen  * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
1632c6f7c1a3SJoseph Chen  */
1633c6f7c1a3SJoseph Chen #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
1634c6f7c1a3SJoseph Chen 
rk3528_mmc_get_phase(struct clk * clk)1635c6f7c1a3SJoseph Chen int rk3528_mmc_get_phase(struct clk *clk)
1636c6f7c1a3SJoseph Chen {
1637c6f7c1a3SJoseph Chen 	struct rk3528_grf_clk_priv *priv = dev_get_priv(clk->dev);
1638c6f7c1a3SJoseph Chen 	u32 raw_value = 0, delay_num;
1639c6f7c1a3SJoseph Chen 	u16 degrees = 0;
1640c6f7c1a3SJoseph Chen 	ulong rate;
1641c6f7c1a3SJoseph Chen 
1642c6f7c1a3SJoseph Chen 	rate = rk3528_grfclk_get_rate(clk);
1643c6f7c1a3SJoseph Chen 	if (rate < 0)
1644c6f7c1a3SJoseph Chen 		return rate;
1645c6f7c1a3SJoseph Chen 
1646c6f7c1a3SJoseph Chen 	if (clk->id == SCLK_SDMMC_SAMPLE)
1647c6f7c1a3SJoseph Chen 		raw_value = readl(&priv->grf->sdmmc_con1);
1648c6f7c1a3SJoseph Chen 	else
1649c6f7c1a3SJoseph Chen 		return -ENONET;
1650c6f7c1a3SJoseph Chen 
1651c6f7c1a3SJoseph Chen 	raw_value >>= 1;
1652c6f7c1a3SJoseph Chen 	degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
1653c6f7c1a3SJoseph Chen 
1654c6f7c1a3SJoseph Chen 	if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
1655c6f7c1a3SJoseph Chen 		/* degrees/delaynum * 10000 */
1656c6f7c1a3SJoseph Chen 		unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
1657c6f7c1a3SJoseph Chen 					36 * (rate / 1000000);
1658c6f7c1a3SJoseph Chen 
1659c6f7c1a3SJoseph Chen 		delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
1660c6f7c1a3SJoseph Chen 		delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
1661c6f7c1a3SJoseph Chen 		degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
1662c6f7c1a3SJoseph Chen 	}
1663c6f7c1a3SJoseph Chen 
1664c6f7c1a3SJoseph Chen 	return degrees % 360;
1665c6f7c1a3SJoseph Chen }
1666c6f7c1a3SJoseph Chen 
rk3528_mmc_set_phase(struct clk * clk,u32 degrees)1667c6f7c1a3SJoseph Chen int rk3528_mmc_set_phase(struct clk *clk, u32 degrees)
1668c6f7c1a3SJoseph Chen {
1669c6f7c1a3SJoseph Chen 	struct rk3528_grf_clk_priv *priv = dev_get_priv(clk->dev);
1670c6f7c1a3SJoseph Chen 	u8 nineties, remainder, delay_num;
1671c6f7c1a3SJoseph Chen 	u32 raw_value, delay;
1672c6f7c1a3SJoseph Chen 	ulong rate;
1673c6f7c1a3SJoseph Chen 
1674c6f7c1a3SJoseph Chen 	rate = rk3528_grfclk_get_rate(clk);
1675c6f7c1a3SJoseph Chen 	if (rate < 0)
1676c6f7c1a3SJoseph Chen 		return rate;
1677c6f7c1a3SJoseph Chen 
1678c6f7c1a3SJoseph Chen 	nineties = degrees / 90;
1679c6f7c1a3SJoseph Chen 	remainder = (degrees % 90);
1680c6f7c1a3SJoseph Chen 
1681c6f7c1a3SJoseph Chen 	/*
1682c6f7c1a3SJoseph Chen 	 * Convert to delay; do a little extra work to make sure we
1683c6f7c1a3SJoseph Chen 	 * don't overflow 32-bit / 64-bit numbers.
1684c6f7c1a3SJoseph Chen 	 */
1685c6f7c1a3SJoseph Chen 	delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
1686c6f7c1a3SJoseph Chen 	delay *= remainder;
1687c6f7c1a3SJoseph Chen 	delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
1688c6f7c1a3SJoseph Chen 				  (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
1689c6f7c1a3SJoseph Chen 
1690c6f7c1a3SJoseph Chen 	delay_num = (u8)min_t(u32, delay, 255);
1691c6f7c1a3SJoseph Chen 
1692c6f7c1a3SJoseph Chen 	raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
1693c6f7c1a3SJoseph Chen 	raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
1694c6f7c1a3SJoseph Chen 	raw_value |= nineties;
1695c6f7c1a3SJoseph Chen 
1696c6f7c1a3SJoseph Chen 	raw_value <<= 1;
1697c6f7c1a3SJoseph Chen 	if (clk->id == SCLK_SDMMC_SAMPLE)
1698c6f7c1a3SJoseph Chen 		writel(raw_value | 0xffff0000, &priv->grf->sdmmc_con1);
1699c6f7c1a3SJoseph Chen 	else
1700c6f7c1a3SJoseph Chen 		return -ENONET;
1701c6f7c1a3SJoseph Chen 
1702c6f7c1a3SJoseph Chen 	debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
1703c6f7c1a3SJoseph Chen 	      degrees, delay_num, raw_value, rk3528_mmc_get_phase(clk));
1704c6f7c1a3SJoseph Chen 
1705c6f7c1a3SJoseph Chen 	return 0;
1706c6f7c1a3SJoseph Chen }
1707c6f7c1a3SJoseph Chen 
rk3528_grfclk_get_phase(struct clk * clk)1708c6f7c1a3SJoseph Chen static int rk3528_grfclk_get_phase(struct clk *clk)
1709c6f7c1a3SJoseph Chen {
1710c6f7c1a3SJoseph Chen 	int ret;
1711c6f7c1a3SJoseph Chen 
1712c6f7c1a3SJoseph Chen 	debug("%s %ld\n", __func__, clk->id);
1713c6f7c1a3SJoseph Chen 	switch (clk->id) {
1714c6f7c1a3SJoseph Chen 	case SCLK_SDMMC_SAMPLE:
1715c6f7c1a3SJoseph Chen 		ret = rk3528_mmc_get_phase(clk);
1716c6f7c1a3SJoseph Chen 		break;
1717c6f7c1a3SJoseph Chen 	default:
1718c6f7c1a3SJoseph Chen 		return -ENOENT;
1719c6f7c1a3SJoseph Chen 	}
1720c6f7c1a3SJoseph Chen 
1721c6f7c1a3SJoseph Chen 	return ret;
1722c6f7c1a3SJoseph Chen }
1723c6f7c1a3SJoseph Chen 
rk3528_grfclk_set_phase(struct clk * clk,int degrees)1724c6f7c1a3SJoseph Chen static int rk3528_grfclk_set_phase(struct clk *clk, int degrees)
1725c6f7c1a3SJoseph Chen {
1726c6f7c1a3SJoseph Chen 	int ret;
1727c6f7c1a3SJoseph Chen 
1728c6f7c1a3SJoseph Chen 	debug("%s %ld\n", __func__, clk->id);
1729c6f7c1a3SJoseph Chen 	switch (clk->id) {
1730c6f7c1a3SJoseph Chen 	case SCLK_SDMMC_SAMPLE:
1731c6f7c1a3SJoseph Chen 		ret = rk3528_mmc_set_phase(clk, degrees);
1732c6f7c1a3SJoseph Chen 		break;
1733c6f7c1a3SJoseph Chen 	default:
1734c6f7c1a3SJoseph Chen 		return -ENOENT;
1735c6f7c1a3SJoseph Chen 	}
1736c6f7c1a3SJoseph Chen 
1737c6f7c1a3SJoseph Chen 	return ret;
1738c6f7c1a3SJoseph Chen }
1739c6f7c1a3SJoseph Chen 
1740c6f7c1a3SJoseph Chen static struct clk_ops rk3528_grfclk_ops = {
1741c6f7c1a3SJoseph Chen 	.get_rate = rk3528_grfclk_get_rate,
1742c6f7c1a3SJoseph Chen 	.get_phase = rk3528_grfclk_get_phase,
1743c6f7c1a3SJoseph Chen 	.set_phase = rk3528_grfclk_set_phase,
1744c6f7c1a3SJoseph Chen };
1745c6f7c1a3SJoseph Chen 
1746c6f7c1a3SJoseph Chen #ifndef CONFIG_SPL_BUILD
1747c6f7c1a3SJoseph Chen /**
1748c6f7c1a3SJoseph Chen  * soc_clk_dump() - Print clock frequencies
1749c6f7c1a3SJoseph Chen  * Returns zero on success
1750c6f7c1a3SJoseph Chen  *
1751c6f7c1a3SJoseph Chen  * Implementation for the clk dump command.
1752c6f7c1a3SJoseph Chen  */
soc_clk_dump(void)1753c6f7c1a3SJoseph Chen int soc_clk_dump(void)
1754c6f7c1a3SJoseph Chen {
1755c6f7c1a3SJoseph Chen 	const struct rk3528_clk_info *clk_dump;
1756c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv;
1757c6f7c1a3SJoseph Chen 	struct udevice *cru_dev;
1758c6f7c1a3SJoseph Chen 	struct clk clk;
1759c6f7c1a3SJoseph Chen 	ulong clk_count = ARRAY_SIZE(clks_dump);
1760c6f7c1a3SJoseph Chen 	ulong rate;
1761c6f7c1a3SJoseph Chen 	int i, ret;
1762c6f7c1a3SJoseph Chen 
1763c6f7c1a3SJoseph Chen 	ret = uclass_get_device_by_driver(UCLASS_CLK,
1764c6f7c1a3SJoseph Chen 					  DM_GET_DRIVER(rockchip_rk3528_cru),
1765c6f7c1a3SJoseph Chen 					  &cru_dev);
1766c6f7c1a3SJoseph Chen 	if (ret) {
1767c6f7c1a3SJoseph Chen 		printf("%s failed to get cru device\n", __func__);
1768c6f7c1a3SJoseph Chen 		return ret;
1769c6f7c1a3SJoseph Chen 	}
1770c6f7c1a3SJoseph Chen 
1771c6f7c1a3SJoseph Chen 	priv = dev_get_priv(cru_dev);
1772c6f7c1a3SJoseph Chen 	printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1773c6f7c1a3SJoseph Chen 	       priv->sync_kernel ? "sync kernel" : "uboot",
1774c6f7c1a3SJoseph Chen 	       priv->armclk_enter_hz / 1000,
1775c6f7c1a3SJoseph Chen 	       priv->armclk_init_hz / 1000,
1776c6f7c1a3SJoseph Chen 	       priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1777c6f7c1a3SJoseph Chen 	       priv->set_armclk_rate ? " KHz" : "N/A");
1778c6f7c1a3SJoseph Chen 	for (i = 0; i < clk_count; i++) {
1779c6f7c1a3SJoseph Chen 		clk_dump = &clks_dump[i];
1780c6f7c1a3SJoseph Chen 		if (clk_dump->name) {
1781c6f7c1a3SJoseph Chen 			clk.id = clk_dump->id;
1782c6f7c1a3SJoseph Chen 			ret = clk_request(cru_dev, &clk);
1783c6f7c1a3SJoseph Chen 			if (ret < 0)
1784c6f7c1a3SJoseph Chen 				return ret;
1785c6f7c1a3SJoseph Chen 
1786c6f7c1a3SJoseph Chen 			rate = clk_get_rate(&clk);
1787c6f7c1a3SJoseph Chen 			clk_free(&clk);
1788c6f7c1a3SJoseph Chen 			if (i == 0) {
1789c6f7c1a3SJoseph Chen 				if (rate < 0)
1790c6f7c1a3SJoseph Chen 					printf("  %s %s\n", clk_dump->name,
1791c6f7c1a3SJoseph Chen 					       "unknown");
1792c6f7c1a3SJoseph Chen 				else
1793c6f7c1a3SJoseph Chen 					printf("  %s %lu KHz\n", clk_dump->name,
1794c6f7c1a3SJoseph Chen 					       rate / 1000);
1795c6f7c1a3SJoseph Chen 			} else {
1796c6f7c1a3SJoseph Chen 				if (rate < 0)
1797c6f7c1a3SJoseph Chen 					printf("  %s %s\n", clk_dump->name,
1798c6f7c1a3SJoseph Chen 					       "unknown");
1799c6f7c1a3SJoseph Chen 				else
1800c6f7c1a3SJoseph Chen 					printf("  %s %lu KHz\n", clk_dump->name,
1801c6f7c1a3SJoseph Chen 					       rate / 1000);
1802c6f7c1a3SJoseph Chen 			}
1803c6f7c1a3SJoseph Chen 		}
1804c6f7c1a3SJoseph Chen 	}
1805c6f7c1a3SJoseph Chen 
1806c6f7c1a3SJoseph Chen 	return 0;
1807c6f7c1a3SJoseph Chen }
1808c6f7c1a3SJoseph Chen #endif
1809c6f7c1a3SJoseph Chen 
rk3528_grfclk_probe(struct udevice * dev)1810c6f7c1a3SJoseph Chen static int rk3528_grfclk_probe(struct udevice *dev)
1811c6f7c1a3SJoseph Chen {
1812c6f7c1a3SJoseph Chen 	struct rk3528_grf_clk_priv *priv = dev_get_priv(dev);
1813c6f7c1a3SJoseph Chen 
1814c6f7c1a3SJoseph Chen 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
1815c6f7c1a3SJoseph Chen 	if (IS_ERR(priv->grf))
1816c6f7c1a3SJoseph Chen 		return PTR_ERR(priv->grf);
1817c6f7c1a3SJoseph Chen 
1818c6f7c1a3SJoseph Chen 	return 0;
1819c6f7c1a3SJoseph Chen }
1820c6f7c1a3SJoseph Chen 
1821c6f7c1a3SJoseph Chen static const struct udevice_id rk3528_grf_cru_ids[] = {
1822c6f7c1a3SJoseph Chen 	{ .compatible = "rockchip,rk3528-grf-cru" },
1823c6f7c1a3SJoseph Chen 	{ }
1824c6f7c1a3SJoseph Chen };
1825c6f7c1a3SJoseph Chen 
1826c6f7c1a3SJoseph Chen U_BOOT_DRIVER(rockchip_rk3528_grf_cru) = {
1827c6f7c1a3SJoseph Chen 	.name		= "rockchip_rk3528_grf_cru",
1828c6f7c1a3SJoseph Chen 	.id		= UCLASS_CLK,
1829c6f7c1a3SJoseph Chen 	.of_match	= rk3528_grf_cru_ids,
1830c6f7c1a3SJoseph Chen 	.priv_auto_alloc_size = sizeof(struct rk3528_grf_clk_priv),
1831c6f7c1a3SJoseph Chen 	.ops		= &rk3528_grfclk_ops,
1832c6f7c1a3SJoseph Chen 	.probe		= rk3528_grfclk_probe,
1833c6f7c1a3SJoseph Chen };
1834c6f7c1a3SJoseph Chen 
1835*5e016f25SFinley Xiao #ifdef CONFIG_SPL_BUILD
1836*5e016f25SFinley Xiao 
1837*5e016f25SFinley Xiao #define COREGRF_BASE	0xff300000
1838*5e016f25SFinley Xiao #define PVTPLL_CON0_L	0x0
1839*5e016f25SFinley Xiao #define PVTPLL_CON0_H	0x4
1840*5e016f25SFinley Xiao 
rk3528_cpu_pvtpll_set_rate(struct rk3528_clk_priv * priv,ulong rate)1841*5e016f25SFinley Xiao static int rk3528_cpu_pvtpll_set_rate(struct rk3528_clk_priv *priv, ulong rate)
1842*5e016f25SFinley Xiao {
1843*5e016f25SFinley Xiao 	struct rk3528_cru *cru = priv->cru;
1844*5e016f25SFinley Xiao 	u32 length;
1845*5e016f25SFinley Xiao 
1846*5e016f25SFinley Xiao 	if (rate >= 1200000000)
1847*5e016f25SFinley Xiao 		length = 8;
1848*5e016f25SFinley Xiao 	else if (rate >= 1008000000)
1849*5e016f25SFinley Xiao 		length = 11;
1850*5e016f25SFinley Xiao 	else
1851*5e016f25SFinley Xiao 		length = 17;
1852*5e016f25SFinley Xiao 
1853*5e016f25SFinley Xiao 	/* set pclk dbg div to 9 */
1854*5e016f25SFinley Xiao 	rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK,
1855*5e016f25SFinley Xiao 		     9 << RK3528_DIV_PCLK_DBG_SHIFT);
1856*5e016f25SFinley Xiao 	/* set aclk_m_core div to 1 */
1857*5e016f25SFinley Xiao 	rk_clrsetreg(&cru->clksel_con[39], RK3528_DIV_ACLK_M_CORE_MASK,
1858*5e016f25SFinley Xiao 		     1 << RK3528_DIV_ACLK_M_CORE_SHIFT);
1859*5e016f25SFinley Xiao 
1860*5e016f25SFinley Xiao 	/* set ring sel = 1 */
1861*5e016f25SFinley Xiao 	writel(0x07000000 | (1 << 8), COREGRF_BASE + PVTPLL_CON0_L);
1862*5e016f25SFinley Xiao 	/* set length */
1863*5e016f25SFinley Xiao 	writel(0x007f0000 | length, COREGRF_BASE + PVTPLL_CON0_H);
1864*5e016f25SFinley Xiao 	/* enable pvtpll */
1865*5e016f25SFinley Xiao 	writel(0x00020002, COREGRF_BASE + PVTPLL_CON0_L);
1866*5e016f25SFinley Xiao 	/* start monitor */
1867*5e016f25SFinley Xiao 	writel(0x00010001, COREGRF_BASE + PVTPLL_CON0_L);
1868*5e016f25SFinley Xiao 
1869*5e016f25SFinley Xiao 	/* set core mux pvtpll */
1870*5e016f25SFinley Xiao 	writel(0x00010001, &cru->clksel_con[40]);
1871*5e016f25SFinley Xiao 	writel(0x00100010, &cru->clksel_con[39]);
1872*5e016f25SFinley Xiao 
1873*5e016f25SFinley Xiao 	/* set pclk dbg div to 8 */
1874*5e016f25SFinley Xiao 	rk_clrsetreg(&cru->clksel_con[40], RK3528_DIV_PCLK_DBG_MASK,
1875*5e016f25SFinley Xiao 		     8 << RK3528_DIV_PCLK_DBG_SHIFT);
1876*5e016f25SFinley Xiao 
1877*5e016f25SFinley Xiao 	return 0;
1878*5e016f25SFinley Xiao }
1879*5e016f25SFinley Xiao #endif
1880*5e016f25SFinley Xiao 
rk3528_clk_init(struct rk3528_clk_priv * priv)1881161d3423SJoseph Chen static int rk3528_clk_init(struct rk3528_clk_priv *priv)
1882c6f7c1a3SJoseph Chen {
1883c6f7c1a3SJoseph Chen 	int ret;
1884c6f7c1a3SJoseph Chen 
1885c6f7c1a3SJoseph Chen 	priv->sync_kernel = false;
1886161d3423SJoseph Chen 
1887161d3423SJoseph Chen #ifdef CONFIG_SPL_BUILD
18888da8d76aSFinley Xiao 	/*
18898da8d76aSFinley Xiao 	 * BOOTROM:
18908da8d76aSFinley Xiao 	 *	CPU 1902/2(postdiv1)=546M
18918da8d76aSFinley Xiao 	 *	CPLL 996/2(postdiv1)=498M
18928da8d76aSFinley Xiao 	 *	GPLL 1188/2(postdiv1)=594M
18938da8d76aSFinley Xiao 	 *	   |-- clk_matrix_200m_src_div=1 => rate: 300M
18948da8d76aSFinley Xiao 	 *	   |-- clk_matrix_300m_src_div=2 => rate: 200M
18958da8d76aSFinley Xiao 	 *
18968da8d76aSFinley Xiao 	 * Avoid overclocking when change GPLL rate:
18978da8d76aSFinley Xiao 	 *	Change clk_matrix_200m_src_div to 5.
18988da8d76aSFinley Xiao 	 *	Change clk_matrix_300m_src_div to 3.
18998da8d76aSFinley Xiao 	 */
19008da8d76aSFinley Xiao 	writel(0x01200120, &priv->cru->clksel_con[1]);
19018da8d76aSFinley Xiao 	writel(0x00030003, &priv->cru->clksel_con[2]);
19028da8d76aSFinley Xiao 
1903c6f7c1a3SJoseph Chen 	if (!priv->armclk_enter_hz) {
1904c6f7c1a3SJoseph Chen 		priv->armclk_enter_hz =
1905c6f7c1a3SJoseph Chen 			rockchip_pll_get_rate(&rk3528_pll_clks[APLL],
1906c6f7c1a3SJoseph Chen 					      priv->cru, APLL);
1907c6f7c1a3SJoseph Chen 		priv->armclk_init_hz = priv->armclk_enter_hz;
1908c6f7c1a3SJoseph Chen 	}
1909c6f7c1a3SJoseph Chen 
1910c6f7c1a3SJoseph Chen 	if (priv->armclk_init_hz != APLL_HZ) {
1911c6f7c1a3SJoseph Chen 		ret = rk3528_armclk_set_clk(priv, APLL_HZ);
1912c6f7c1a3SJoseph Chen 		if (!ret)
1913c6f7c1a3SJoseph Chen 			priv->armclk_init_hz = APLL_HZ;
1914c6f7c1a3SJoseph Chen 	}
1915*5e016f25SFinley Xiao 
1916*5e016f25SFinley Xiao 	if (!rk3528_cpu_pvtpll_set_rate(priv, CPU_PVTPLL_HZ)) {
1917*5e016f25SFinley Xiao 		printf("cpu pvtpll %d KHz\n", CPU_PVTPLL_HZ / 1000);
1918*5e016f25SFinley Xiao 		priv->armclk_init_hz = CPU_PVTPLL_HZ;
1919*5e016f25SFinley Xiao 	}
1920*5e016f25SFinley Xiao 
1921ffe7a059SYifeng Zhao #elif CONFIG_IS_ENABLED(CLK_SCMI)
1922161d3423SJoseph Chen 	if (!priv->armclk_enter_hz) {
1923161d3423SJoseph Chen 		struct clk clk;
1924c6f7c1a3SJoseph Chen 
1925161d3423SJoseph Chen 		ret = rockchip_get_scmi_clk(&clk.dev);
1926161d3423SJoseph Chen 		if (ret) {
1927161d3423SJoseph Chen 			printf("Failed to get scmi clk dev\n");
1928161d3423SJoseph Chen 			return ret;
1929161d3423SJoseph Chen 		}
1930161d3423SJoseph Chen 
1931161d3423SJoseph Chen 		clk.id = SCMI_CLK_CPU;
1932161d3423SJoseph Chen 		ret = clk_set_rate(&clk, CPU_PVTPLL_HZ);
1933161d3423SJoseph Chen 		if (ret < 0) {
1934161d3423SJoseph Chen 			printf("Failed to set scmi cpu %dhz\n", CPU_PVTPLL_HZ);
1935161d3423SJoseph Chen 			return ret;
1936161d3423SJoseph Chen 		} else {
1937*5e016f25SFinley Xiao 			priv->armclk_enter_hz = CPU_PVTPLL_HZ;
1938161d3423SJoseph Chen 			priv->armclk_init_hz = CPU_PVTPLL_HZ;
1939161d3423SJoseph Chen 		}
1940161d3423SJoseph Chen 	}
1941161d3423SJoseph Chen #endif
1942c6f7c1a3SJoseph Chen 	if (priv->cpll_hz != CPLL_HZ) {
1943c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[CPLL], priv->cru,
1944c6f7c1a3SJoseph Chen 					    CPLL, CPLL_HZ);
1945c6f7c1a3SJoseph Chen 		if (!ret)
1946c6f7c1a3SJoseph Chen 			priv->cpll_hz = CPLL_HZ;
1947c6f7c1a3SJoseph Chen 	}
1948c6f7c1a3SJoseph Chen 
1949c6f7c1a3SJoseph Chen 	if (priv->gpll_hz != GPLL_HZ) {
1950c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[GPLL], priv->cru,
1951c6f7c1a3SJoseph Chen 					    GPLL, GPLL_HZ);
1952c6f7c1a3SJoseph Chen 		if (!ret)
1953c6f7c1a3SJoseph Chen 			priv->gpll_hz = GPLL_HZ;
1954c6f7c1a3SJoseph Chen 	}
19551a259ed3SJoseph Chen 
1956c6f7c1a3SJoseph Chen 	if (priv->ppll_hz != PPLL_HZ) {
1957c6f7c1a3SJoseph Chen 		ret = rockchip_pll_set_rate(&rk3528_pll_clks[PPLL], priv->cru,
1958c6f7c1a3SJoseph Chen 					    PPLL, PPLL_HZ);
1959c6f7c1a3SJoseph Chen 		if (!ret)
1960c6f7c1a3SJoseph Chen 			priv->ppll_hz = PPLL_HZ;
1961c6f7c1a3SJoseph Chen 	}
19621a259ed3SJoseph Chen 
1963eee09e1fSJoseph Chen #ifdef CONFIG_SPL_BUILD
1964eee09e1fSJoseph Chen 	/* Init to override bootrom config */
1965eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_50M_SRC,   50000000);
1966eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_100M_SRC, 100000000);
1967eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_150M_SRC, 150000000);
1968eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_200M_SRC, 200000000);
1969eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_250M_SRC, 250000000);
1970eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_300M_SRC, 300000000);
1971eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_339M_SRC, 340000000);
1972eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_400M_SRC, 400000000);
1973eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_500M_SRC, 500000000);
1974eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, CLK_MATRIX_600M_SRC, 600000000);
1975eee09e1fSJoseph Chen 	rk3528_cgpll_matrix_set_rate(priv, ACLK_BUS_VOPGL_BIU,  500000000);
1976eee09e1fSJoseph Chen 
1977c6f7c1a3SJoseph Chen 	/* The default rate is 100Mhz, it's not friendly for remote IR module */
1978c6f7c1a3SJoseph Chen 	rk3528_pwm_set_clk(priv, CLK_PWM0, 24000000);
1979c6f7c1a3SJoseph Chen 	rk3528_pwm_set_clk(priv, CLK_PWM1, 24000000);
1980eee09e1fSJoseph Chen #endif
1981161d3423SJoseph Chen 	return 0;
1982c6f7c1a3SJoseph Chen }
1983c6f7c1a3SJoseph Chen 
rk3528_clk_probe(struct udevice * dev)1984c6f7c1a3SJoseph Chen static int rk3528_clk_probe(struct udevice *dev)
1985c6f7c1a3SJoseph Chen {
1986c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(dev);
1987c6f7c1a3SJoseph Chen 	int ret;
1988c6f7c1a3SJoseph Chen 
1989c6f7c1a3SJoseph Chen 	priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
1990c6f7c1a3SJoseph Chen 	if (IS_ERR(priv->grf))
1991c6f7c1a3SJoseph Chen 		return PTR_ERR(priv->grf);
1992c6f7c1a3SJoseph Chen 
1993161d3423SJoseph Chen 	ret = rk3528_clk_init(priv);
1994161d3423SJoseph Chen 	if (ret)
1995161d3423SJoseph Chen 		return ret;
1996c6f7c1a3SJoseph Chen 
1997c6f7c1a3SJoseph Chen 	/* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1998c6f7c1a3SJoseph Chen 	ret = clk_set_defaults(dev);
1999c6f7c1a3SJoseph Chen 	if (ret)
2000c6f7c1a3SJoseph Chen 		debug("%s clk_set_defaults failed %d\n", __func__, ret);
2001c6f7c1a3SJoseph Chen 	else
2002c6f7c1a3SJoseph Chen 		priv->sync_kernel = true;
2003c6f7c1a3SJoseph Chen 
2004c6f7c1a3SJoseph Chen 	return 0;
2005c6f7c1a3SJoseph Chen }
2006c6f7c1a3SJoseph Chen 
rk3528_clk_ofdata_to_platdata(struct udevice * dev)2007c6f7c1a3SJoseph Chen static int rk3528_clk_ofdata_to_platdata(struct udevice *dev)
2008c6f7c1a3SJoseph Chen {
2009c6f7c1a3SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(dev);
2010c6f7c1a3SJoseph Chen 
2011c6f7c1a3SJoseph Chen 	priv->cru = dev_read_addr_ptr(dev);
2012c6f7c1a3SJoseph Chen 
2013c6f7c1a3SJoseph Chen 	return 0;
2014c6f7c1a3SJoseph Chen }
2015c6f7c1a3SJoseph Chen 
rk3528_clk_bind(struct udevice * dev)2016c6f7c1a3SJoseph Chen static int rk3528_clk_bind(struct udevice *dev)
2017c6f7c1a3SJoseph Chen {
2018c6f7c1a3SJoseph Chen 	struct udevice *sys_child, *sf_child;
2019c6f7c1a3SJoseph Chen 	struct softreset_reg *sf_priv;
2020c6f7c1a3SJoseph Chen 	struct sysreset_reg *priv;
2021c6f7c1a3SJoseph Chen 	int ret;
2022c6f7c1a3SJoseph Chen 
2023c6f7c1a3SJoseph Chen 	/* The reset driver does not have a device node, so bind it here */
2024c6f7c1a3SJoseph Chen 	ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
2025c6f7c1a3SJoseph Chen 				 &sys_child);
2026c6f7c1a3SJoseph Chen 	if (ret) {
2027c6f7c1a3SJoseph Chen 		debug("Warning: No sysreset driver: ret=%d\n", ret);
2028c6f7c1a3SJoseph Chen 	} else {
2029c6f7c1a3SJoseph Chen 		priv = malloc(sizeof(struct sysreset_reg));
2030c6f7c1a3SJoseph Chen 		priv->glb_srst_fst_value = offsetof(struct rk3528_cru,
2031c6f7c1a3SJoseph Chen 						    glb_srst_fst);
2032c6f7c1a3SJoseph Chen 		priv->glb_srst_snd_value = offsetof(struct rk3528_cru,
2033c6f7c1a3SJoseph Chen 						    glb_srst_snd);
2034c6f7c1a3SJoseph Chen 		sys_child->priv = priv;
2035c6f7c1a3SJoseph Chen 	}
2036c6f7c1a3SJoseph Chen 
2037c6f7c1a3SJoseph Chen 	ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
2038c6f7c1a3SJoseph Chen 					 dev_ofnode(dev), &sf_child);
2039c6f7c1a3SJoseph Chen 	if (ret) {
2040c6f7c1a3SJoseph Chen 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
2041c6f7c1a3SJoseph Chen 	} else {
2042c6f7c1a3SJoseph Chen 		sf_priv = malloc(sizeof(struct softreset_reg));
2043c6f7c1a3SJoseph Chen 		sf_priv->sf_reset_offset = offsetof(struct rk3528_cru,
2044c6f7c1a3SJoseph Chen 						    softrst_con[0]);
2045c6f7c1a3SJoseph Chen 		sf_priv->sf_reset_num = 47;
2046c6f7c1a3SJoseph Chen 		sf_child->priv = sf_priv;
2047c6f7c1a3SJoseph Chen 	}
2048c6f7c1a3SJoseph Chen 
2049c6f7c1a3SJoseph Chen 	return 0;
2050c6f7c1a3SJoseph Chen }
2051c6f7c1a3SJoseph Chen 
2052c6f7c1a3SJoseph Chen static const struct udevice_id rk3528_clk_ids[] = {
2053c6f7c1a3SJoseph Chen 	{ .compatible = "rockchip,rk3528-cru" },
2054c6f7c1a3SJoseph Chen 	{ }
2055c6f7c1a3SJoseph Chen };
2056c6f7c1a3SJoseph Chen 
2057c6f7c1a3SJoseph Chen U_BOOT_DRIVER(rockchip_rk3528_cru) = {
2058c6f7c1a3SJoseph Chen 	.name		= "rockchip_rk3528_cru",
2059c6f7c1a3SJoseph Chen 	.id		= UCLASS_CLK,
2060c6f7c1a3SJoseph Chen 	.of_match	= rk3528_clk_ids,
2061c6f7c1a3SJoseph Chen 	.priv_auto_alloc_size = sizeof(struct rk3528_clk_priv),
2062c6f7c1a3SJoseph Chen 	.ofdata_to_platdata = rk3528_clk_ofdata_to_platdata,
2063c6f7c1a3SJoseph Chen 	.ops		= &rk3528_clk_ops,
2064c6f7c1a3SJoseph Chen 	.bind		= rk3528_clk_bind,
2065c6f7c1a3SJoseph Chen 	.probe		= rk3528_clk_probe,
2066c6f7c1a3SJoseph Chen };
2067c6f7c1a3SJoseph Chen 
206868ba0295SJoseph Chen /* spl scmi clk */
206968ba0295SJoseph Chen #ifdef CONFIG_SPL_BUILD
207068ba0295SJoseph Chen 
rk3528_crypto_get_rate(struct rk3528_clk_priv * priv,struct clk * clk)207168ba0295SJoseph Chen static ulong rk3528_crypto_get_rate(struct rk3528_clk_priv *priv, struct clk *clk)
207268ba0295SJoseph Chen {
207368ba0295SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
207468ba0295SJoseph Chen 	u32 id, sel, con, mask, shift;
207568ba0295SJoseph Chen 	ulong rate;
207668ba0295SJoseph Chen 
207768ba0295SJoseph Chen 	switch (clk->id) {
207868ba0295SJoseph Chen 	case SCMI_CORE_CRYPTO:
207968ba0295SJoseph Chen 		id = 43;
208068ba0295SJoseph Chen 		mask = CLK_CORE_CRYPTO_SEL_MASK;
208168ba0295SJoseph Chen 		shift = CLK_CORE_CRYPTO_SEL_SHIFT;
208268ba0295SJoseph Chen 		break;
208368ba0295SJoseph Chen 
208468ba0295SJoseph Chen 	case SCMI_PKA_CRYPTO:
208568ba0295SJoseph Chen 		id = 44;
208668ba0295SJoseph Chen 		mask = CLK_PKA_CRYPTO_SEL_MASK;
208768ba0295SJoseph Chen 		shift = CLK_PKA_CRYPTO_SEL_SHIFT;
208868ba0295SJoseph Chen 		break;
208968ba0295SJoseph Chen 
209068ba0295SJoseph Chen 	default:
209168ba0295SJoseph Chen 		return -ENOENT;
209268ba0295SJoseph Chen 	}
209368ba0295SJoseph Chen 
209468ba0295SJoseph Chen 	con = readl(&cru->clksel_con[id]);
209568ba0295SJoseph Chen 	sel = (con & mask) >> shift;
209668ba0295SJoseph Chen 	if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_300M_SRC)
209768ba0295SJoseph Chen 		rate = 300 * MHz;
209868ba0295SJoseph Chen 	else if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_200M_SRC)
209968ba0295SJoseph Chen 		rate = 200 * MHz;
210068ba0295SJoseph Chen 	else if (sel == CLK_CORE_CRYPTO_SEL_CLK_MATRIX_100M_SRC)
210168ba0295SJoseph Chen 		rate = 100 * MHz;
210268ba0295SJoseph Chen 	else
210368ba0295SJoseph Chen 		rate = OSC_HZ;
210468ba0295SJoseph Chen 
210568ba0295SJoseph Chen 	return rate;
210668ba0295SJoseph Chen }
210768ba0295SJoseph Chen 
rk3528_crypto_set_rate(struct rk3528_clk_priv * priv,struct clk * clk,ulong rate)210868ba0295SJoseph Chen static ulong rk3528_crypto_set_rate(struct rk3528_clk_priv *priv,
210968ba0295SJoseph Chen 				    struct clk *clk, ulong rate)
211068ba0295SJoseph Chen {
211168ba0295SJoseph Chen 	struct rk3528_cru *cru = priv->cru;
211268ba0295SJoseph Chen 	u32 id, sel, mask, shift;
211368ba0295SJoseph Chen 
211468ba0295SJoseph Chen 	if (rate == 300 * MHz)
211568ba0295SJoseph Chen 		sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_300M_SRC;
211668ba0295SJoseph Chen 	else if (rate == 200 * MHz)
211768ba0295SJoseph Chen 		sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_200M_SRC;
211868ba0295SJoseph Chen 	else if (rate == 100 * MHz)
211968ba0295SJoseph Chen 		sel = CLK_CORE_CRYPTO_SEL_CLK_MATRIX_100M_SRC;
212068ba0295SJoseph Chen 	else
212168ba0295SJoseph Chen 		sel = CLK_CORE_CRYPTO_SEL_XIN_OSC0_FUNC;
212268ba0295SJoseph Chen 
212368ba0295SJoseph Chen 	switch (clk->id) {
212468ba0295SJoseph Chen 	case SCMI_CORE_CRYPTO:
212568ba0295SJoseph Chen 		id = 43;
212668ba0295SJoseph Chen 		mask = CLK_CORE_CRYPTO_SEL_MASK;
212768ba0295SJoseph Chen 		shift = CLK_CORE_CRYPTO_SEL_SHIFT;
212868ba0295SJoseph Chen 		break;
212968ba0295SJoseph Chen 
213068ba0295SJoseph Chen 	case SCMI_PKA_CRYPTO:
213168ba0295SJoseph Chen 		id = 44;
213268ba0295SJoseph Chen 		mask = CLK_PKA_CRYPTO_SEL_MASK;
213368ba0295SJoseph Chen 		shift = CLK_PKA_CRYPTO_SEL_SHIFT;
213468ba0295SJoseph Chen 		break;
213568ba0295SJoseph Chen 
213668ba0295SJoseph Chen 	default:
213768ba0295SJoseph Chen 		return -ENOENT;
213868ba0295SJoseph Chen 	}
213968ba0295SJoseph Chen 
214068ba0295SJoseph Chen 	rk_clrsetreg(&cru->clksel_con[id], mask, sel << shift);
214168ba0295SJoseph Chen 
214268ba0295SJoseph Chen 	return rk3528_crypto_get_rate(priv, clk);
214368ba0295SJoseph Chen }
214468ba0295SJoseph Chen 
rk3528_clk_scmi_get_rate(struct clk * clk)214568ba0295SJoseph Chen static ulong rk3528_clk_scmi_get_rate(struct clk *clk)
214668ba0295SJoseph Chen {
214768ba0295SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(clk->dev);
214868ba0295SJoseph Chen 
214968ba0295SJoseph Chen 	switch (clk->id) {
215068ba0295SJoseph Chen 	case SCMI_CORE_CRYPTO:
215168ba0295SJoseph Chen 	case SCMI_PKA_CRYPTO:
215268ba0295SJoseph Chen 		return rk3528_crypto_get_rate(priv, clk);
215368ba0295SJoseph Chen 	default:
215468ba0295SJoseph Chen 		return -ENOENT;
215568ba0295SJoseph Chen 	}
215668ba0295SJoseph Chen };
215768ba0295SJoseph Chen 
rk3528_clk_scmi_set_rate(struct clk * clk,ulong rate)215868ba0295SJoseph Chen static ulong rk3528_clk_scmi_set_rate(struct clk *clk, ulong rate)
215968ba0295SJoseph Chen {
216068ba0295SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(clk->dev);
216168ba0295SJoseph Chen 
216268ba0295SJoseph Chen 	switch (clk->id) {
216368ba0295SJoseph Chen 	case SCMI_CORE_CRYPTO:
216468ba0295SJoseph Chen 	case SCMI_PKA_CRYPTO:
216568ba0295SJoseph Chen 		return rk3528_crypto_set_rate(priv, clk, rate);
216668ba0295SJoseph Chen 	default:
216768ba0295SJoseph Chen 		return -ENOENT;
216868ba0295SJoseph Chen 	}
216968ba0295SJoseph Chen 
217068ba0295SJoseph Chen 	return 0;
217168ba0295SJoseph Chen };
217268ba0295SJoseph Chen 
rk3528_scmi_clk_ofdata_to_platdata(struct udevice * dev)217368ba0295SJoseph Chen static int rk3528_scmi_clk_ofdata_to_platdata(struct udevice *dev)
217468ba0295SJoseph Chen {
217568ba0295SJoseph Chen 	struct rk3528_clk_priv *priv = dev_get_priv(dev);
217668ba0295SJoseph Chen 
217768ba0295SJoseph Chen 	priv->cru = (struct rk3528_cru *)0xff4a0000;
217868ba0295SJoseph Chen 
217968ba0295SJoseph Chen 	return 0;
218068ba0295SJoseph Chen }
218168ba0295SJoseph Chen 
218268ba0295SJoseph Chen /* A fake scmi driver for SPL/TPL where smccc agent is not available. */
218368ba0295SJoseph Chen static const struct clk_ops scmi_clk_ops = {
218468ba0295SJoseph Chen 	.get_rate = rk3528_clk_scmi_get_rate,
218568ba0295SJoseph Chen 	.set_rate = rk3528_clk_scmi_set_rate,
218668ba0295SJoseph Chen };
218768ba0295SJoseph Chen 
218868ba0295SJoseph Chen U_BOOT_DRIVER(scmi_clock) = {
218968ba0295SJoseph Chen 	.name = "scmi_clk",
219068ba0295SJoseph Chen 	.id = UCLASS_CLK,
219168ba0295SJoseph Chen 	.ops = &scmi_clk_ops,
219268ba0295SJoseph Chen 	.priv_auto_alloc_size = sizeof(struct rk3528_clk_priv),
219368ba0295SJoseph Chen 	.ofdata_to_platdata = rk3528_scmi_clk_ofdata_to_platdata,
219468ba0295SJoseph Chen };
219568ba0295SJoseph Chen #endif
2196