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