1f95775d6SJoseph Chen // SPDX-License-Identifier: GPL-2.0
2f95775d6SJoseph Chen /*
3f95775d6SJoseph Chen * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4f95775d6SJoseph Chen * Author: Finley Xiao <finley.xiao@rock-chips.com>
5f95775d6SJoseph Chen */
6f95775d6SJoseph Chen
7f95775d6SJoseph Chen #include <common.h>
8f95775d6SJoseph Chen #include <bitfield.h>
9f95775d6SJoseph Chen #include <clk-uclass.h>
10f95775d6SJoseph Chen #include <dm.h>
11f95775d6SJoseph Chen #include <errno.h>
12f95775d6SJoseph Chen #include <syscon.h>
13f95775d6SJoseph Chen #include <asm/arch/clock.h>
14f95775d6SJoseph Chen #include <asm/arch/cru_rv1126.h>
15f95775d6SJoseph Chen #include <asm/arch/grf_rv1126.h>
16f95775d6SJoseph Chen #include <asm/arch/hardware.h>
17f95775d6SJoseph Chen #include <asm/io.h>
18f95775d6SJoseph Chen #include <dm/lists.h>
19f95775d6SJoseph Chen #include <dt-bindings/clock/rv1126-cru.h>
20f95775d6SJoseph Chen
21f95775d6SJoseph Chen DECLARE_GLOBAL_DATA_PTR;
22f95775d6SJoseph Chen
23f95775d6SJoseph Chen #define RV1126_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
24f95775d6SJoseph Chen { \
25f95775d6SJoseph Chen .rate = _rate##U, \
26f95775d6SJoseph Chen .aclk_div = _aclk_div, \
27f95775d6SJoseph Chen .pclk_div = _pclk_div, \
28f95775d6SJoseph Chen }
29f95775d6SJoseph Chen
30f95775d6SJoseph Chen #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
31f95775d6SJoseph Chen
32f95775d6SJoseph Chen static struct rockchip_cpu_rate_table rv1126_cpu_rates[] = {
33f95775d6SJoseph Chen RV1126_CPUCLK_RATE(1200000000, 1, 5),
34f95775d6SJoseph Chen RV1126_CPUCLK_RATE(1008000000, 1, 5),
35f95775d6SJoseph Chen RV1126_CPUCLK_RATE(816000000, 1, 3),
36f95775d6SJoseph Chen RV1126_CPUCLK_RATE(600000000, 1, 3),
37f95775d6SJoseph Chen RV1126_CPUCLK_RATE(408000000, 1, 1),
38f95775d6SJoseph Chen };
39f95775d6SJoseph Chen
40f95775d6SJoseph Chen static struct rockchip_pll_rate_table rv1126_pll_rates[] = {
41f95775d6SJoseph Chen /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
42f95775d6SJoseph Chen RK3036_PLL_RATE(1600000000, 3, 200, 1, 1, 1, 0),
4385967b20SFinley Xiao RK3036_PLL_RATE(1400000000, 3, 350, 2, 1, 1, 0),
4482c18007SFinley Xiao RK3036_PLL_RATE(1200000000, 1, 100, 2, 1, 1, 0),
4582c18007SFinley Xiao RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
4682c18007SFinley Xiao RK3036_PLL_RATE(1100000000, 3, 275, 2, 1, 1, 0),
47f95775d6SJoseph Chen RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
4882c18007SFinley Xiao RK3036_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0),
49f95775d6SJoseph Chen RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
5082c18007SFinley Xiao RK3036_PLL_RATE(800000000, 3, 200, 2, 1, 1, 0),
5182c18007SFinley Xiao RK3036_PLL_RATE(600000000, 1, 100, 4, 1, 1, 0),
5282c18007SFinley Xiao RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
5382c18007SFinley Xiao RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
5482c18007SFinley Xiao RK3036_PLL_RATE(200000000, 1, 100, 6, 2, 1, 0),
5582c18007SFinley Xiao RK3036_PLL_RATE(100000000, 1, 100, 6, 4, 1, 0),
56f95775d6SJoseph Chen { /* sentinel */ },
57f95775d6SJoseph Chen };
58f95775d6SJoseph Chen
59f95775d6SJoseph Chen static struct rockchip_pll_clock rv1126_pll_clks[] = {
60f95775d6SJoseph Chen [APLL] = PLL(pll_rk3328, PLL_APLL, RV1126_PLL_CON(0),
61f95775d6SJoseph Chen RV1126_MODE_CON, 0, 10, 0, rv1126_pll_rates),
62f95775d6SJoseph Chen [DPLL] = PLL(pll_rk3328, PLL_DPLL, RV1126_PLL_CON(8),
63f95775d6SJoseph Chen RV1126_MODE_CON, 2, 10, 0, NULL),
64f95775d6SJoseph Chen [CPLL] = PLL(pll_rk3328, PLL_CPLL, RV1126_PLL_CON(16),
65f95775d6SJoseph Chen RV1126_MODE_CON, 4, 10, 0, rv1126_pll_rates),
66f95775d6SJoseph Chen [HPLL] = PLL(pll_rk3328, PLL_HPLL, RV1126_PLL_CON(24),
67f95775d6SJoseph Chen RV1126_MODE_CON, 6, 10, 0, rv1126_pll_rates),
68f95775d6SJoseph Chen [GPLL] = PLL(pll_rk3328, PLL_GPLL, RV1126_PMU_PLL_CON(0),
69f95775d6SJoseph Chen RV1126_PMU_MODE, 0, 10, 0, rv1126_pll_rates),
70f95775d6SJoseph Chen };
71f95775d6SJoseph Chen
72f95775d6SJoseph Chen #ifndef CONFIG_SPL_BUILD
73f95775d6SJoseph Chen #define RV1126_CLK_DUMP(_id, _name, _iscru) \
74f95775d6SJoseph Chen { \
75f95775d6SJoseph Chen .id = _id, \
76f95775d6SJoseph Chen .name = _name, \
77f95775d6SJoseph Chen .is_cru = _iscru, \
78f95775d6SJoseph Chen }
79f95775d6SJoseph Chen
80f95775d6SJoseph Chen static const struct rv1126_clk_info clks_dump[] = {
81f95775d6SJoseph Chen RV1126_CLK_DUMP(PLL_APLL, "apll", true),
82f95775d6SJoseph Chen RV1126_CLK_DUMP(PLL_DPLL, "dpll", true),
83f95775d6SJoseph Chen RV1126_CLK_DUMP(PLL_GPLL, "gpll", false),
84f95775d6SJoseph Chen RV1126_CLK_DUMP(PLL_CPLL, "cpll", true),
85f95775d6SJoseph Chen RV1126_CLK_DUMP(PLL_HPLL, "hpll", true),
86f95775d6SJoseph Chen RV1126_CLK_DUMP(ACLK_PDBUS, "aclk_pdbus", true),
87f95775d6SJoseph Chen RV1126_CLK_DUMP(HCLK_PDBUS, "hclk_pdbus", true),
88f95775d6SJoseph Chen RV1126_CLK_DUMP(PCLK_PDBUS, "pclk_pdbus", true),
89f95775d6SJoseph Chen RV1126_CLK_DUMP(ACLK_PDPHP, "aclk_pdphp", true),
90f95775d6SJoseph Chen RV1126_CLK_DUMP(HCLK_PDPHP, "hclk_pdphp", true),
91f95775d6SJoseph Chen RV1126_CLK_DUMP(HCLK_PDAUDIO, "hclk_pdaudio", true),
92f95775d6SJoseph Chen RV1126_CLK_DUMP(HCLK_PDCORE_NIU, "hclk_pdcore", true),
93f95775d6SJoseph Chen RV1126_CLK_DUMP(PCLK_PDPMU, "pclk_pdpmu", false),
94f95775d6SJoseph Chen };
95f95775d6SJoseph Chen #endif
96f95775d6SJoseph Chen
97f96f0122SFinley Xiao static ulong rv1126_gpll_set_rate(struct rv1126_clk_priv *priv,
98f96f0122SFinley Xiao struct rv1126_pmuclk_priv *pmu_priv,
99f96f0122SFinley Xiao ulong rate);
100f95775d6SJoseph Chen /*
101f95775d6SJoseph Chen *
102f95775d6SJoseph Chen * rational_best_approximation(31415, 10000,
103f95775d6SJoseph Chen * (1 << 8) - 1, (1 << 5) - 1, &n, &d);
104f95775d6SJoseph Chen *
105f95775d6SJoseph Chen * you may look at given_numerator as a fixed point number,
106f95775d6SJoseph Chen * with the fractional part size described in given_denominator.
107f95775d6SJoseph Chen *
108f95775d6SJoseph Chen * for theoretical background, see:
109f95775d6SJoseph Chen * http://en.wikipedia.org/wiki/Continued_fraction
110f95775d6SJoseph 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)111f95775d6SJoseph Chen static void rational_best_approximation(unsigned long given_numerator,
112f95775d6SJoseph Chen unsigned long given_denominator,
113f95775d6SJoseph Chen unsigned long max_numerator,
114f95775d6SJoseph Chen unsigned long max_denominator,
115f95775d6SJoseph Chen unsigned long *best_numerator,
116f95775d6SJoseph Chen unsigned long *best_denominator)
117f95775d6SJoseph Chen {
118f95775d6SJoseph Chen unsigned long n, d, n0, d0, n1, d1;
119f95775d6SJoseph Chen
120f95775d6SJoseph Chen n = given_numerator;
121f95775d6SJoseph Chen d = given_denominator;
122f95775d6SJoseph Chen n0 = 0;
123f95775d6SJoseph Chen d1 = 0;
124f95775d6SJoseph Chen n1 = 1;
125f95775d6SJoseph Chen d0 = 1;
126f95775d6SJoseph Chen for (;;) {
127f95775d6SJoseph Chen unsigned long t, a;
128f95775d6SJoseph Chen
129f95775d6SJoseph Chen if (n1 > max_numerator || d1 > max_denominator) {
130f95775d6SJoseph Chen n1 = n0;
131f95775d6SJoseph Chen d1 = d0;
132f95775d6SJoseph Chen break;
133f95775d6SJoseph Chen }
134f95775d6SJoseph Chen if (d == 0)
135f95775d6SJoseph Chen break;
136f95775d6SJoseph Chen t = d;
137f95775d6SJoseph Chen a = n / d;
138f95775d6SJoseph Chen d = n % d;
139f95775d6SJoseph Chen n = t;
140f95775d6SJoseph Chen t = n0 + a * n1;
141f95775d6SJoseph Chen n0 = n1;
142f95775d6SJoseph Chen n1 = t;
143f95775d6SJoseph Chen t = d0 + a * d1;
144f95775d6SJoseph Chen d0 = d1;
145f95775d6SJoseph Chen d1 = t;
146f95775d6SJoseph Chen }
147f95775d6SJoseph Chen *best_numerator = n1;
148f95775d6SJoseph Chen *best_denominator = d1;
149f95775d6SJoseph Chen }
150f95775d6SJoseph Chen
rv1126_gpll_get_pmuclk(struct rv1126_pmuclk_priv * priv)151f95775d6SJoseph Chen static ulong rv1126_gpll_get_pmuclk(struct rv1126_pmuclk_priv *priv)
152f95775d6SJoseph Chen {
153f95775d6SJoseph Chen return rockchip_pll_get_rate(&rv1126_pll_clks[GPLL],
154f95775d6SJoseph Chen priv->pmucru, GPLL);
155f95775d6SJoseph Chen }
156f95775d6SJoseph Chen
rv1126_gpll_set_pmuclk(struct rv1126_pmuclk_priv * pmu_priv,ulong rate)157f96f0122SFinley Xiao static ulong rv1126_gpll_set_pmuclk(struct rv1126_pmuclk_priv *pmu_priv, ulong rate)
158f95775d6SJoseph Chen {
159f96f0122SFinley Xiao struct udevice *cru_dev;
160f96f0122SFinley Xiao struct rv1126_clk_priv *priv;
161f95775d6SJoseph Chen int ret;
162f95775d6SJoseph Chen
163f96f0122SFinley Xiao ret = uclass_get_device_by_driver(UCLASS_CLK,
164f96f0122SFinley Xiao DM_GET_DRIVER(rockchip_rv1126_cru),
165f96f0122SFinley Xiao &cru_dev);
166f96f0122SFinley Xiao if (ret) {
167f96f0122SFinley Xiao printf("%s: could not find cru device\n", __func__);
168f95775d6SJoseph Chen return ret;
169f95775d6SJoseph Chen }
170f96f0122SFinley Xiao priv = dev_get_priv(cru_dev);
171f96f0122SFinley Xiao
172f96f0122SFinley Xiao if (rv1126_gpll_set_rate(priv, pmu_priv, rate)) {
173f96f0122SFinley Xiao printf("%s: failed to set gpll rate %lu\n", __func__, rate);
174f96f0122SFinley Xiao return -EINVAL;
175f96f0122SFinley Xiao }
176f96f0122SFinley Xiao return 0;
177f96f0122SFinley Xiao }
178f95775d6SJoseph Chen
rv1126_rtc32k_get_pmuclk(struct rv1126_pmuclk_priv * priv)179f95775d6SJoseph Chen static ulong rv1126_rtc32k_get_pmuclk(struct rv1126_pmuclk_priv *priv)
180f95775d6SJoseph Chen {
181f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
182f95775d6SJoseph Chen unsigned long m, n;
183f95775d6SJoseph Chen u32 fracdiv;
184f95775d6SJoseph Chen
185f95775d6SJoseph Chen fracdiv = readl(&pmucru->pmu_clksel_con[13]);
186f95775d6SJoseph Chen m = fracdiv & CLK_RTC32K_FRAC_NUMERATOR_MASK;
187f95775d6SJoseph Chen m >>= CLK_RTC32K_FRAC_NUMERATOR_SHIFT;
188f95775d6SJoseph Chen n = fracdiv & CLK_RTC32K_FRAC_DENOMINATOR_MASK;
189f95775d6SJoseph Chen n >>= CLK_RTC32K_FRAC_DENOMINATOR_SHIFT;
190f95775d6SJoseph Chen
191f95775d6SJoseph Chen return OSC_HZ * m / n;
192f95775d6SJoseph Chen }
193f95775d6SJoseph Chen
rv1126_rtc32k_set_pmuclk(struct rv1126_pmuclk_priv * priv,ulong rate)194f95775d6SJoseph Chen static ulong rv1126_rtc32k_set_pmuclk(struct rv1126_pmuclk_priv *priv,
195f95775d6SJoseph Chen ulong rate)
196f95775d6SJoseph Chen {
197f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
198f95775d6SJoseph Chen unsigned long m, n, val;
199f95775d6SJoseph Chen
20056a06ac8SFinley Xiao rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK,
20156a06ac8SFinley Xiao RTC32K_SEL_OSC0_DIV32K << RTC32K_SEL_SHIFT);
20256a06ac8SFinley Xiao
203f95775d6SJoseph Chen rational_best_approximation(rate, OSC_HZ,
204f95775d6SJoseph Chen GENMASK(16 - 1, 0),
205f95775d6SJoseph Chen GENMASK(16 - 1, 0),
206f95775d6SJoseph Chen &m, &n);
207f95775d6SJoseph Chen val = m << CLK_RTC32K_FRAC_NUMERATOR_SHIFT | n;
208f95775d6SJoseph Chen writel(val, &pmucru->pmu_clksel_con[13]);
209f95775d6SJoseph Chen
210f95775d6SJoseph Chen return rv1126_rtc32k_get_pmuclk(priv);
211f95775d6SJoseph Chen }
212f95775d6SJoseph Chen
rv1126_i2c_get_pmuclk(struct rv1126_pmuclk_priv * priv,ulong clk_id)213f95775d6SJoseph Chen static ulong rv1126_i2c_get_pmuclk(struct rv1126_pmuclk_priv *priv,
214f95775d6SJoseph Chen ulong clk_id)
215f95775d6SJoseph Chen {
216f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
217f95775d6SJoseph Chen u32 div, con;
218f95775d6SJoseph Chen
219f95775d6SJoseph Chen switch (clk_id) {
220f95775d6SJoseph Chen case CLK_I2C0:
221f95775d6SJoseph Chen con = readl(&pmucru->pmu_clksel_con[2]);
222f95775d6SJoseph Chen div = (con & CLK_I2C0_DIV_MASK) >> CLK_I2C0_DIV_SHIFT;
223f95775d6SJoseph Chen break;
224f95775d6SJoseph Chen case CLK_I2C2:
225f95775d6SJoseph Chen con = readl(&pmucru->pmu_clksel_con[3]);
226f95775d6SJoseph Chen div = (con & CLK_I2C1_DIV_MASK) >> CLK_I2C1_DIV_SHIFT;
227f95775d6SJoseph Chen break;
228f95775d6SJoseph Chen default:
229f95775d6SJoseph Chen return -ENOENT;
230f95775d6SJoseph Chen }
231f95775d6SJoseph Chen
232f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
233f95775d6SJoseph Chen }
234f95775d6SJoseph Chen
rv1126_i2c_set_pmuclk(struct rv1126_pmuclk_priv * priv,ulong clk_id,ulong rate)235f95775d6SJoseph Chen static ulong rv1126_i2c_set_pmuclk(struct rv1126_pmuclk_priv *priv,
236f95775d6SJoseph Chen ulong clk_id, ulong rate)
237f95775d6SJoseph Chen {
238f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
239f95775d6SJoseph Chen int src_clk_div;
240f95775d6SJoseph Chen
241f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
242f95775d6SJoseph Chen assert(src_clk_div - 1 <= 127);
243f95775d6SJoseph Chen
244f95775d6SJoseph Chen switch (clk_id) {
245f95775d6SJoseph Chen case CLK_I2C0:
246f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[2], CLK_I2C0_DIV_MASK,
247f95775d6SJoseph Chen (src_clk_div - 1) << CLK_I2C0_DIV_SHIFT);
248f95775d6SJoseph Chen break;
249f95775d6SJoseph Chen case CLK_I2C2:
250f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[3], CLK_I2C2_DIV_MASK,
251f95775d6SJoseph Chen (src_clk_div - 1) << CLK_I2C2_DIV_SHIFT);
252f95775d6SJoseph Chen break;
253f95775d6SJoseph Chen default:
254f95775d6SJoseph Chen return -ENOENT;
255f95775d6SJoseph Chen }
256f95775d6SJoseph Chen
257f95775d6SJoseph Chen return rv1126_i2c_get_pmuclk(priv, clk_id);
258f95775d6SJoseph Chen }
259f95775d6SJoseph Chen
rv1126_pwm_get_pmuclk(struct rv1126_pmuclk_priv * priv,ulong clk_id)260f95775d6SJoseph Chen static ulong rv1126_pwm_get_pmuclk(struct rv1126_pmuclk_priv *priv,
261f95775d6SJoseph Chen ulong clk_id)
262f95775d6SJoseph Chen {
263f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
264f95775d6SJoseph Chen u32 div, sel, con;
265f95775d6SJoseph Chen
266f95775d6SJoseph Chen switch (clk_id) {
267f95775d6SJoseph Chen case CLK_PWM0:
268f95775d6SJoseph Chen con = readl(&pmucru->pmu_clksel_con[6]);
269f95775d6SJoseph Chen sel = (con & CLK_PWM0_SEL_MASK) >> CLK_PWM0_SEL_SHIFT;
270f95775d6SJoseph Chen div = (con & CLK_PWM0_DIV_MASK) >> CLK_PWM0_DIV_SHIFT;
271f95775d6SJoseph Chen if (sel == CLK_PWM0_SEL_XIN24M)
272f95775d6SJoseph Chen return OSC_HZ;
273f95775d6SJoseph Chen break;
274f95775d6SJoseph Chen case CLK_PWM1:
275f95775d6SJoseph Chen con = readl(&pmucru->pmu_clksel_con[6]);
276f95775d6SJoseph Chen sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
277f95775d6SJoseph Chen div = (con & CLK_PWM1_DIV_MASK) >> CLK_PWM1_DIV_SHIFT;
278f95775d6SJoseph Chen if (sel == CLK_PWM1_SEL_XIN24M)
279f95775d6SJoseph Chen return OSC_HZ;
280f95775d6SJoseph Chen break;
281f95775d6SJoseph Chen default:
282f95775d6SJoseph Chen return -ENOENT;
283f95775d6SJoseph Chen }
284f95775d6SJoseph Chen
285f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
286f95775d6SJoseph Chen }
287f95775d6SJoseph Chen
rv1126_pwm_set_pmuclk(struct rv1126_pmuclk_priv * priv,ulong clk_id,ulong rate)288f95775d6SJoseph Chen static ulong rv1126_pwm_set_pmuclk(struct rv1126_pmuclk_priv *priv,
289f95775d6SJoseph Chen ulong clk_id, ulong rate)
290f95775d6SJoseph Chen {
291f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
292f95775d6SJoseph Chen int src_clk_div;
293f95775d6SJoseph Chen
294f95775d6SJoseph Chen switch (clk_id) {
295f95775d6SJoseph Chen case CLK_PWM0:
296f95775d6SJoseph Chen if (rate == OSC_HZ) {
297f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[6],
298f95775d6SJoseph Chen CLK_PWM0_SEL_MASK,
299f95775d6SJoseph Chen CLK_PWM0_SEL_XIN24M << CLK_PWM0_SEL_SHIFT);
300f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[6],
301f95775d6SJoseph Chen CLK_PWM0_DIV_MASK, 0);
302f95775d6SJoseph Chen } else {
303f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
304f95775d6SJoseph Chen assert(src_clk_div - 1 <= 127);
305f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[6],
306f95775d6SJoseph Chen CLK_PWM0_DIV_MASK,
307f95775d6SJoseph Chen (src_clk_div - 1) << CLK_PWM0_DIV_SHIFT);
308f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[6],
309f95775d6SJoseph Chen CLK_PWM0_SEL_MASK,
310f95775d6SJoseph Chen CLK_PWM0_SEL_GPLL << CLK_PWM0_SEL_SHIFT);
311f95775d6SJoseph Chen }
312f95775d6SJoseph Chen break;
313f95775d6SJoseph Chen case CLK_PWM1:
314f95775d6SJoseph Chen if (rate == OSC_HZ) {
315f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[6],
316f95775d6SJoseph Chen CLK_PWM1_SEL_MASK,
317f95775d6SJoseph Chen CLK_PWM1_SEL_XIN24M << CLK_PWM1_SEL_SHIFT);
318f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[6],
319f95775d6SJoseph Chen CLK_PWM1_DIV_MASK, 0);
320f95775d6SJoseph Chen } else {
321f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
322f95775d6SJoseph Chen assert(src_clk_div - 1 <= 127);
323f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[6],
324f95775d6SJoseph Chen CLK_PWM1_DIV_MASK,
325f95775d6SJoseph Chen (src_clk_div - 1) << CLK_PWM1_DIV_SHIFT);
326f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[6],
327f95775d6SJoseph Chen CLK_PWM1_SEL_MASK,
328f95775d6SJoseph Chen CLK_PWM1_SEL_GPLL << CLK_PWM1_SEL_SHIFT);
329f95775d6SJoseph Chen }
330f95775d6SJoseph Chen break;
331f95775d6SJoseph Chen default:
332f95775d6SJoseph Chen return -ENOENT;
333f95775d6SJoseph Chen }
334f95775d6SJoseph Chen
335f95775d6SJoseph Chen return rv1126_pwm_get_pmuclk(priv, clk_id);
336f95775d6SJoseph Chen }
337f95775d6SJoseph Chen
rv1126_spi_get_pmuclk(struct rv1126_pmuclk_priv * priv)338f95775d6SJoseph Chen static ulong rv1126_spi_get_pmuclk(struct rv1126_pmuclk_priv *priv)
339f95775d6SJoseph Chen {
340f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
341f95775d6SJoseph Chen u32 div, con;
342f95775d6SJoseph Chen
343f95775d6SJoseph Chen con = readl(&pmucru->pmu_clksel_con[9]);
344f95775d6SJoseph Chen div = (con & CLK_SPI0_DIV_MASK) >> CLK_SPI0_DIV_SHIFT;
345f95775d6SJoseph Chen
346f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
347f95775d6SJoseph Chen }
348f95775d6SJoseph Chen
rv1126_spi_set_pmuclk(struct rv1126_pmuclk_priv * priv,ulong rate)349f95775d6SJoseph Chen static ulong rv1126_spi_set_pmuclk(struct rv1126_pmuclk_priv *priv,
350f95775d6SJoseph Chen ulong rate)
351f95775d6SJoseph Chen {
352f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
353f95775d6SJoseph Chen int src_clk_div;
354f95775d6SJoseph Chen
355f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
356f95775d6SJoseph Chen assert(src_clk_div - 1 <= 127);
357f95775d6SJoseph Chen
358f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[9],
359f95775d6SJoseph Chen CLK_SPI0_SEL_MASK | CLK_SPI0_DIV_MASK,
360f95775d6SJoseph Chen CLK_SPI0_SEL_GPLL << CLK_SPI0_SEL_SHIFT |
361f95775d6SJoseph Chen (src_clk_div - 1) << CLK_SPI0_DIV_SHIFT);
362f95775d6SJoseph Chen
363f95775d6SJoseph Chen return rv1126_spi_get_pmuclk(priv);
364f95775d6SJoseph Chen }
365f95775d6SJoseph Chen
rv1126_pdpmu_get_pmuclk(struct rv1126_pmuclk_priv * priv)366f95775d6SJoseph Chen static ulong rv1126_pdpmu_get_pmuclk(struct rv1126_pmuclk_priv *priv)
367f95775d6SJoseph Chen {
368f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
369f95775d6SJoseph Chen u32 div, con;
370f95775d6SJoseph Chen
371f95775d6SJoseph Chen con = readl(&pmucru->pmu_clksel_con[1]);
372f95775d6SJoseph Chen div = (con & PCLK_PDPMU_DIV_MASK) >> PCLK_PDPMU_DIV_SHIFT;
373f95775d6SJoseph Chen
374f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
375f95775d6SJoseph Chen }
376f95775d6SJoseph Chen
rv1126_pdpmu_set_pmuclk(struct rv1126_pmuclk_priv * priv,ulong rate)377f95775d6SJoseph Chen static ulong rv1126_pdpmu_set_pmuclk(struct rv1126_pmuclk_priv *priv,
378f95775d6SJoseph Chen ulong rate)
379f95775d6SJoseph Chen {
380f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
381f95775d6SJoseph Chen int src_clk_div;
382f95775d6SJoseph Chen
383f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
384f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
385f95775d6SJoseph Chen
386f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[1],
387f95775d6SJoseph Chen PCLK_PDPMU_DIV_MASK,
388f95775d6SJoseph Chen (src_clk_div - 1) << PCLK_PDPMU_DIV_SHIFT);
389f95775d6SJoseph Chen
390f95775d6SJoseph Chen return rv1126_pdpmu_get_pmuclk(priv);
391f95775d6SJoseph Chen }
392f95775d6SJoseph Chen
rv1126_pmuclk_get_rate(struct clk * clk)393f95775d6SJoseph Chen static ulong rv1126_pmuclk_get_rate(struct clk *clk)
394f95775d6SJoseph Chen {
395f95775d6SJoseph Chen struct rv1126_pmuclk_priv *priv = dev_get_priv(clk->dev);
396f95775d6SJoseph Chen ulong rate = 0;
397f95775d6SJoseph Chen
398f95775d6SJoseph Chen if (!priv->gpll_hz) {
399f95775d6SJoseph Chen printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
400f95775d6SJoseph Chen return -ENOENT;
401f95775d6SJoseph Chen }
402f95775d6SJoseph Chen
403f95775d6SJoseph Chen debug("%s %ld\n", __func__, clk->id);
404f95775d6SJoseph Chen switch (clk->id) {
405f95775d6SJoseph Chen case PLL_GPLL:
406f95775d6SJoseph Chen rate = rv1126_gpll_get_pmuclk(priv);
407f95775d6SJoseph Chen break;
408f95775d6SJoseph Chen case CLK_RTC32K:
409f95775d6SJoseph Chen rate = rv1126_rtc32k_get_pmuclk(priv);
410f95775d6SJoseph Chen break;
411f95775d6SJoseph Chen case CLK_I2C0:
412f95775d6SJoseph Chen case CLK_I2C2:
413f95775d6SJoseph Chen rate = rv1126_i2c_get_pmuclk(priv, clk->id);
414f95775d6SJoseph Chen break;
415f95775d6SJoseph Chen case CLK_PWM0:
416f95775d6SJoseph Chen case CLK_PWM1:
417f95775d6SJoseph Chen rate = rv1126_pwm_get_pmuclk(priv, clk->id);
418f95775d6SJoseph Chen break;
419f95775d6SJoseph Chen case CLK_SPI0:
420f95775d6SJoseph Chen rate = rv1126_spi_get_pmuclk(priv);
421f95775d6SJoseph Chen break;
422f95775d6SJoseph Chen case PCLK_PDPMU:
423f95775d6SJoseph Chen rate = rv1126_pdpmu_get_pmuclk(priv);
424f95775d6SJoseph Chen break;
425f95775d6SJoseph Chen default:
426f95775d6SJoseph Chen return -ENOENT;
427f95775d6SJoseph Chen }
428f95775d6SJoseph Chen
429f95775d6SJoseph Chen return rate;
430f95775d6SJoseph Chen }
431f95775d6SJoseph Chen
rv1126_pmuclk_set_rate(struct clk * clk,ulong rate)432f95775d6SJoseph Chen static ulong rv1126_pmuclk_set_rate(struct clk *clk, ulong rate)
433f95775d6SJoseph Chen {
434f95775d6SJoseph Chen struct rv1126_pmuclk_priv *priv = dev_get_priv(clk->dev);
435f95775d6SJoseph Chen ulong ret = 0;
436f95775d6SJoseph Chen
437f95775d6SJoseph Chen if (!priv->gpll_hz) {
438f95775d6SJoseph Chen printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
439f95775d6SJoseph Chen return -ENOENT;
440f95775d6SJoseph Chen }
441f95775d6SJoseph Chen
442f95775d6SJoseph Chen debug("%s %ld %ld\n", __func__, clk->id, rate);
443f95775d6SJoseph Chen switch (clk->id) {
444f95775d6SJoseph Chen case PLL_GPLL:
445f95775d6SJoseph Chen ret = rv1126_gpll_set_pmuclk(priv, rate);
446f95775d6SJoseph Chen break;
447f95775d6SJoseph Chen case CLK_RTC32K:
448f95775d6SJoseph Chen ret = rv1126_rtc32k_set_pmuclk(priv, rate);
449f95775d6SJoseph Chen break;
450f95775d6SJoseph Chen case CLK_I2C0:
451f95775d6SJoseph Chen case CLK_I2C2:
452f95775d6SJoseph Chen ret = rv1126_i2c_set_pmuclk(priv, clk->id, rate);
453f95775d6SJoseph Chen break;
454f95775d6SJoseph Chen case CLK_PWM0:
455f95775d6SJoseph Chen case CLK_PWM1:
456f95775d6SJoseph Chen ret = rv1126_pwm_set_pmuclk(priv, clk->id, rate);
457f95775d6SJoseph Chen break;
458f95775d6SJoseph Chen case CLK_SPI0:
459f95775d6SJoseph Chen ret = rv1126_spi_set_pmuclk(priv, rate);
460f95775d6SJoseph Chen break;
461f95775d6SJoseph Chen case PCLK_PDPMU:
462f95775d6SJoseph Chen ret = rv1126_pdpmu_set_pmuclk(priv, rate);
463f95775d6SJoseph Chen break;
464f95775d6SJoseph Chen default:
465f95775d6SJoseph Chen return -ENOENT;
466f95775d6SJoseph Chen }
467f95775d6SJoseph Chen
468f95775d6SJoseph Chen return ret;
469f95775d6SJoseph Chen }
470f95775d6SJoseph Chen
rv1126_rtc32k_set_parent(struct clk * clk,struct clk * parent)471f95775d6SJoseph Chen static int rv1126_rtc32k_set_parent(struct clk *clk, struct clk *parent)
472f95775d6SJoseph Chen {
473f95775d6SJoseph Chen struct rv1126_pmuclk_priv *priv = dev_get_priv(clk->dev);
474f95775d6SJoseph Chen struct rv1126_pmucru *pmucru = priv->pmucru;
475f95775d6SJoseph Chen
476f95775d6SJoseph Chen if (parent->id == CLK_OSC0_DIV32K)
477f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK,
478f95775d6SJoseph Chen RTC32K_SEL_OSC0_DIV32K << RTC32K_SEL_SHIFT);
479f95775d6SJoseph Chen else
480f95775d6SJoseph Chen rk_clrsetreg(&pmucru->pmu_clksel_con[0], RTC32K_SEL_MASK,
481f95775d6SJoseph Chen RTC32K_SEL_OSC1_32K << RTC32K_SEL_SHIFT);
482f95775d6SJoseph Chen
483f95775d6SJoseph Chen return 0;
484f95775d6SJoseph Chen }
485f95775d6SJoseph Chen
rv1126_pmuclk_set_parent(struct clk * clk,struct clk * parent)486f95775d6SJoseph Chen static int rv1126_pmuclk_set_parent(struct clk *clk, struct clk *parent)
487f95775d6SJoseph Chen {
488f95775d6SJoseph Chen switch (clk->id) {
489f95775d6SJoseph Chen case CLK_RTC32K:
490f95775d6SJoseph Chen return rv1126_rtc32k_set_parent(clk, parent);
491f95775d6SJoseph Chen default:
492f95775d6SJoseph Chen return -ENOENT;
493f95775d6SJoseph Chen }
494f95775d6SJoseph Chen }
495f95775d6SJoseph Chen static struct clk_ops rv1126_pmuclk_ops = {
496f95775d6SJoseph Chen .get_rate = rv1126_pmuclk_get_rate,
497f95775d6SJoseph Chen .set_rate = rv1126_pmuclk_set_rate,
498f95775d6SJoseph Chen .set_parent = rv1126_pmuclk_set_parent,
499f95775d6SJoseph Chen };
500f95775d6SJoseph Chen
rv1126_pmuclk_probe(struct udevice * dev)501f95775d6SJoseph Chen static int rv1126_pmuclk_probe(struct udevice *dev)
502f95775d6SJoseph Chen {
503f95775d6SJoseph Chen struct rv1126_pmuclk_priv *priv = dev_get_priv(dev);
504f95775d6SJoseph Chen
505f95775d6SJoseph Chen priv->gpll_hz = rv1126_gpll_get_pmuclk(priv);
506f95775d6SJoseph Chen
507f95775d6SJoseph Chen return 0;
508f95775d6SJoseph Chen }
509f95775d6SJoseph Chen
rv1126_pmuclk_ofdata_to_platdata(struct udevice * dev)510f95775d6SJoseph Chen static int rv1126_pmuclk_ofdata_to_platdata(struct udevice *dev)
511f95775d6SJoseph Chen {
512f95775d6SJoseph Chen struct rv1126_pmuclk_priv *priv = dev_get_priv(dev);
513f95775d6SJoseph Chen
514f95775d6SJoseph Chen priv->pmucru = dev_read_addr_ptr(dev);
515f95775d6SJoseph Chen
516f95775d6SJoseph Chen return 0;
517f95775d6SJoseph Chen }
518f95775d6SJoseph Chen
rv1126_pmuclk_bind(struct udevice * dev)519f95775d6SJoseph Chen static int rv1126_pmuclk_bind(struct udevice *dev)
520f95775d6SJoseph Chen {
521f95775d6SJoseph Chen int ret = 0;
522f95775d6SJoseph Chen struct udevice *sf_child;
523f95775d6SJoseph Chen struct softreset_reg *sf_priv;
524f95775d6SJoseph Chen
525f95775d6SJoseph Chen ret = device_bind_driver_to_node(dev, "rockchip_reset",
526f95775d6SJoseph Chen "reset", dev_ofnode(dev),
527f95775d6SJoseph Chen &sf_child);
528f95775d6SJoseph Chen if (ret) {
529f95775d6SJoseph Chen debug("Warning: No rockchip reset driver: ret=%d\n", ret);
530f95775d6SJoseph Chen } else {
531f95775d6SJoseph Chen sf_priv = malloc(sizeof(struct softreset_reg));
532f95775d6SJoseph Chen sf_priv->sf_reset_offset = offsetof(struct rv1126_pmucru,
533f95775d6SJoseph Chen pmu_softrst_con[0]);
534f95775d6SJoseph Chen sf_priv->sf_reset_num = 2;
535f95775d6SJoseph Chen sf_child->priv = sf_priv;
536f95775d6SJoseph Chen }
537f95775d6SJoseph Chen
538f95775d6SJoseph Chen return 0;
539f95775d6SJoseph Chen }
540f95775d6SJoseph Chen
541f95775d6SJoseph Chen static const struct udevice_id rv1126_pmuclk_ids[] = {
542f95775d6SJoseph Chen { .compatible = "rockchip,rv1126-pmucru" },
543f95775d6SJoseph Chen { }
544f95775d6SJoseph Chen };
545f95775d6SJoseph Chen
546f95775d6SJoseph Chen U_BOOT_DRIVER(rockchip_rv1126_pmucru) = {
547f95775d6SJoseph Chen .name = "rockchip_rv1126_pmucru",
548f95775d6SJoseph Chen .id = UCLASS_CLK,
549f95775d6SJoseph Chen .of_match = rv1126_pmuclk_ids,
550f95775d6SJoseph Chen .priv_auto_alloc_size = sizeof(struct rv1126_pmuclk_priv),
551f95775d6SJoseph Chen .ofdata_to_platdata = rv1126_pmuclk_ofdata_to_platdata,
552f95775d6SJoseph Chen .ops = &rv1126_pmuclk_ops,
553f95775d6SJoseph Chen .bind = rv1126_pmuclk_bind,
554f95775d6SJoseph Chen .probe = rv1126_pmuclk_probe,
555f95775d6SJoseph Chen };
556f95775d6SJoseph Chen
557f95775d6SJoseph Chen
rv1126_armclk_set_clk(struct rv1126_clk_priv * priv,ulong hz)558f95775d6SJoseph Chen static int rv1126_armclk_set_clk(struct rv1126_clk_priv *priv, ulong hz)
559f95775d6SJoseph Chen {
560f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
561f95775d6SJoseph Chen const struct rockchip_cpu_rate_table *rate;
562f95775d6SJoseph Chen ulong old_rate;
563f95775d6SJoseph Chen
564f95775d6SJoseph Chen rate = rockchip_get_cpu_settings(rv1126_cpu_rates, hz);
565f95775d6SJoseph Chen if (!rate) {
566f95775d6SJoseph Chen printf("%s unsupported rate\n", __func__);
567f95775d6SJoseph Chen return -EINVAL;
568f95775d6SJoseph Chen }
569f95775d6SJoseph Chen
570f95775d6SJoseph Chen /*
571f95775d6SJoseph Chen * set up dependent divisors for DBG and ACLK clocks.
572f95775d6SJoseph Chen */
573f95775d6SJoseph Chen old_rate = rockchip_pll_get_rate(&rv1126_pll_clks[APLL],
574f95775d6SJoseph Chen priv->cru, APLL);
575f95775d6SJoseph Chen if (old_rate > hz) {
576f95775d6SJoseph Chen if (rockchip_pll_set_rate(&rv1126_pll_clks[APLL],
577f95775d6SJoseph Chen priv->cru, APLL, hz))
578f95775d6SJoseph Chen return -EINVAL;
579f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[1],
580f95775d6SJoseph Chen CORE_DBG_DIV_MASK | CORE_ACLK_DIV_MASK,
581f95775d6SJoseph Chen rate->pclk_div << CORE_DBG_DIV_SHIFT |
582f95775d6SJoseph Chen rate->aclk_div << CORE_ACLK_DIV_SHIFT);
583f95775d6SJoseph Chen } else if (old_rate < hz) {
584f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[1],
585f95775d6SJoseph Chen CORE_DBG_DIV_MASK | CORE_ACLK_DIV_MASK,
586f95775d6SJoseph Chen rate->pclk_div << CORE_DBG_DIV_SHIFT |
587f95775d6SJoseph Chen rate->aclk_div << CORE_ACLK_DIV_SHIFT);
588f95775d6SJoseph Chen if (rockchip_pll_set_rate(&rv1126_pll_clks[APLL],
589f95775d6SJoseph Chen priv->cru, APLL, hz))
590f95775d6SJoseph Chen return -EINVAL;
591f95775d6SJoseph Chen }
592f95775d6SJoseph Chen
593f95775d6SJoseph Chen return 0;
594f95775d6SJoseph Chen }
595f95775d6SJoseph Chen
rv1126_pdcore_get_clk(struct rv1126_clk_priv * priv)596f95775d6SJoseph Chen static ulong rv1126_pdcore_get_clk(struct rv1126_clk_priv *priv)
597f95775d6SJoseph Chen {
598f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
599f95775d6SJoseph Chen u32 con, div;
600f95775d6SJoseph Chen
601f95775d6SJoseph Chen con = readl(&cru->clksel_con[0]);
602f95775d6SJoseph Chen div = (con & CORE_HCLK_DIV_MASK) >> CORE_HCLK_DIV_SHIFT;
603f95775d6SJoseph Chen
604f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
605f95775d6SJoseph Chen }
606f95775d6SJoseph Chen
rv1126_pdcore_set_clk(struct rv1126_clk_priv * priv,ulong rate)607f95775d6SJoseph Chen static ulong rv1126_pdcore_set_clk(struct rv1126_clk_priv *priv, ulong rate)
608f95775d6SJoseph Chen {
609f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
610f95775d6SJoseph Chen int src_clk_div;
611b8650936SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
612f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
613f95775d6SJoseph Chen
614f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[0], CORE_HCLK_DIV_MASK,
615f95775d6SJoseph Chen (src_clk_div - 1) << CORE_HCLK_DIV_SHIFT);
616f95775d6SJoseph Chen
617f95775d6SJoseph Chen return rv1126_pdcore_get_clk(priv);
618f95775d6SJoseph Chen }
619f95775d6SJoseph Chen
rv1126_pdbus_get_clk(struct rv1126_clk_priv * priv,ulong clk_id)620f95775d6SJoseph Chen static ulong rv1126_pdbus_get_clk(struct rv1126_clk_priv *priv, ulong clk_id)
621f95775d6SJoseph Chen {
622f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
623f95775d6SJoseph Chen u32 con, div, sel, parent;
624f95775d6SJoseph Chen
625f95775d6SJoseph Chen switch (clk_id) {
626f95775d6SJoseph Chen case ACLK_PDBUS:
627f95775d6SJoseph Chen con = readl(&cru->clksel_con[2]);
628f95775d6SJoseph Chen div = (con & ACLK_PDBUS_DIV_MASK) >> ACLK_PDBUS_DIV_SHIFT;
629f95775d6SJoseph Chen sel = (con & ACLK_PDBUS_SEL_MASK) >> ACLK_PDBUS_SEL_SHIFT;
630f95775d6SJoseph Chen if (sel == ACLK_PDBUS_SEL_GPLL)
631f95775d6SJoseph Chen parent = priv->gpll_hz;
632f95775d6SJoseph Chen else if (sel == ACLK_PDBUS_SEL_CPLL)
633f95775d6SJoseph Chen parent = priv->cpll_hz;
634f95775d6SJoseph Chen else
635f95775d6SJoseph Chen return -ENOENT;
636f95775d6SJoseph Chen break;
637f95775d6SJoseph Chen case HCLK_PDBUS:
638f95775d6SJoseph Chen con = readl(&cru->clksel_con[2]);
639f95775d6SJoseph Chen div = (con & HCLK_PDBUS_DIV_MASK) >> HCLK_PDBUS_DIV_SHIFT;
640b8650936SFinley Xiao sel = (con & HCLK_PDBUS_SEL_MASK) >> HCLK_PDBUS_SEL_SHIFT;
641b8650936SFinley Xiao if (sel == HCLK_PDBUS_SEL_GPLL)
642f95775d6SJoseph Chen parent = priv->gpll_hz;
643b8650936SFinley Xiao else if (sel == HCLK_PDBUS_SEL_CPLL)
644b8650936SFinley Xiao parent = priv->cpll_hz;
645b8650936SFinley Xiao else
646b8650936SFinley Xiao return -ENOENT;
647f95775d6SJoseph Chen break;
648f95775d6SJoseph Chen case PCLK_PDBUS:
6491abad17aSElaine Zhang case PCLK_WDT:
650f95775d6SJoseph Chen con = readl(&cru->clksel_con[3]);
651f95775d6SJoseph Chen div = (con & PCLK_PDBUS_DIV_MASK) >> PCLK_PDBUS_DIV_SHIFT;
652b8650936SFinley Xiao sel = (con & PCLK_PDBUS_SEL_MASK) >> PCLK_PDBUS_SEL_SHIFT;
653b8650936SFinley Xiao if (sel == PCLK_PDBUS_SEL_GPLL)
654f95775d6SJoseph Chen parent = priv->gpll_hz;
655b8650936SFinley Xiao else if (sel == PCLK_PDBUS_SEL_CPLL)
656b8650936SFinley Xiao parent = priv->cpll_hz;
657b8650936SFinley Xiao else
658b8650936SFinley Xiao return -ENOENT;
659f95775d6SJoseph Chen break;
660f95775d6SJoseph Chen default:
661f95775d6SJoseph Chen return -ENOENT;
662f95775d6SJoseph Chen }
663f95775d6SJoseph Chen
664f95775d6SJoseph Chen return DIV_TO_RATE(parent, div);
665f95775d6SJoseph Chen }
666f95775d6SJoseph Chen
rv1126_pdbus_set_clk(struct rv1126_clk_priv * priv,ulong clk_id,ulong rate)667f95775d6SJoseph Chen static ulong rv1126_pdbus_set_clk(struct rv1126_clk_priv *priv, ulong clk_id,
668f95775d6SJoseph Chen ulong rate)
669f95775d6SJoseph Chen {
670f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
671658285c1SZiyuan Xu int src_clk_div, clk_sel;
672f95775d6SJoseph Chen
673f95775d6SJoseph Chen switch (clk_id) {
674f95775d6SJoseph Chen case ACLK_PDBUS:
675658285c1SZiyuan Xu if (CPLL_HZ % rate) {
676658285c1SZiyuan Xu src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
677658285c1SZiyuan Xu clk_sel = ACLK_PDBUS_SEL_GPLL;
678658285c1SZiyuan Xu } else {
679f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate);
680658285c1SZiyuan Xu clk_sel = ACLK_PDBUS_SEL_CPLL;
681658285c1SZiyuan Xu }
682f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
683f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[2],
684f95775d6SJoseph Chen ACLK_PDBUS_SEL_MASK | ACLK_PDBUS_DIV_MASK,
685658285c1SZiyuan Xu clk_sel << ACLK_PDBUS_SEL_SHIFT |
686f95775d6SJoseph Chen (src_clk_div - 1) << ACLK_PDBUS_DIV_SHIFT);
687f95775d6SJoseph Chen break;
688f95775d6SJoseph Chen case HCLK_PDBUS:
6894d22530eSFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
690f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
691f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[2],
692f95775d6SJoseph Chen HCLK_PDBUS_SEL_MASK | HCLK_PDBUS_DIV_MASK,
6934d22530eSFinley Xiao HCLK_PDBUS_SEL_GPLL << HCLK_PDBUS_SEL_SHIFT |
694f95775d6SJoseph Chen (src_clk_div - 1) << HCLK_PDBUS_DIV_SHIFT);
695f95775d6SJoseph Chen break;
696f95775d6SJoseph Chen case PCLK_PDBUS:
6971abad17aSElaine Zhang case PCLK_WDT:
69824f48ac9SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
699f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
700f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[3],
701f95775d6SJoseph Chen PCLK_PDBUS_SEL_MASK | PCLK_PDBUS_DIV_MASK,
70224f48ac9SFinley Xiao PCLK_PDBUS_SEL_GPLL << PCLK_PDBUS_SEL_SHIFT |
703f95775d6SJoseph Chen (src_clk_div - 1) << PCLK_PDBUS_DIV_SHIFT);
704f95775d6SJoseph Chen break;
705f95775d6SJoseph Chen
706f95775d6SJoseph Chen default:
707f95775d6SJoseph Chen printf("do not support this pdbus freq\n");
708f95775d6SJoseph Chen return -EINVAL;
709f95775d6SJoseph Chen }
710f95775d6SJoseph Chen
711f95775d6SJoseph Chen return rv1126_pdbus_get_clk(priv, clk_id);
712f95775d6SJoseph Chen }
713f95775d6SJoseph Chen
rv1126_pdphp_get_clk(struct rv1126_clk_priv * priv,ulong clk_id)714f95775d6SJoseph Chen static ulong rv1126_pdphp_get_clk(struct rv1126_clk_priv *priv, ulong clk_id)
715f95775d6SJoseph Chen {
716f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
717f95775d6SJoseph Chen u32 con, div, parent;
718f95775d6SJoseph Chen
719f95775d6SJoseph Chen switch (clk_id) {
720f95775d6SJoseph Chen case ACLK_PDPHP:
721f95775d6SJoseph Chen con = readl(&cru->clksel_con[53]);
722f95775d6SJoseph Chen div = (con & ACLK_PDPHP_DIV_MASK) >> ACLK_PDPHP_DIV_SHIFT;
723f95775d6SJoseph Chen parent = priv->gpll_hz;
724f95775d6SJoseph Chen break;
725f95775d6SJoseph Chen case HCLK_PDPHP:
726f95775d6SJoseph Chen con = readl(&cru->clksel_con[53]);
727f95775d6SJoseph Chen div = (con & HCLK_PDPHP_DIV_MASK) >> HCLK_PDPHP_DIV_SHIFT;
728f95775d6SJoseph Chen parent = priv->gpll_hz;
729f95775d6SJoseph Chen break;
730f95775d6SJoseph Chen default:
731f95775d6SJoseph Chen return -ENOENT;
732f95775d6SJoseph Chen }
733f95775d6SJoseph Chen
734f95775d6SJoseph Chen return DIV_TO_RATE(parent, div);
735f95775d6SJoseph Chen }
736f95775d6SJoseph Chen
rv1126_pdphp_set_clk(struct rv1126_clk_priv * priv,ulong clk_id,ulong rate)737f95775d6SJoseph Chen static ulong rv1126_pdphp_set_clk(struct rv1126_clk_priv *priv, ulong clk_id,
738f95775d6SJoseph Chen ulong rate)
739f95775d6SJoseph Chen {
740f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
741f95775d6SJoseph Chen int src_clk_div;
742f95775d6SJoseph Chen
743b8650936SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
744f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
745f95775d6SJoseph Chen
746f95775d6SJoseph Chen switch (clk_id) {
747f95775d6SJoseph Chen case ACLK_PDPHP:
748f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[53],
749f95775d6SJoseph Chen ACLK_PDPHP_SEL_MASK | ACLK_PDPHP_DIV_MASK,
750f95775d6SJoseph Chen ACLK_PDPHP_SEL_GPLL << ACLK_PDPHP_SEL_SHIFT |
751f95775d6SJoseph Chen (src_clk_div - 1) << ACLK_PDPHP_DIV_SHIFT);
752f95775d6SJoseph Chen break;
753f95775d6SJoseph Chen case HCLK_PDPHP:
754f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[53],
755f95775d6SJoseph Chen HCLK_PDPHP_DIV_MASK,
7566224aca8SFinley Xiao (src_clk_div - 1) << HCLK_PDPHP_DIV_SHIFT);
757f95775d6SJoseph Chen break;
758f95775d6SJoseph Chen default:
759f95775d6SJoseph Chen printf("do not support this pdphp freq\n");
760f95775d6SJoseph Chen return -EINVAL;
761f95775d6SJoseph Chen }
762f95775d6SJoseph Chen
763f95775d6SJoseph Chen return rv1126_pdphp_get_clk(priv, clk_id);
764f95775d6SJoseph Chen }
765f95775d6SJoseph Chen
rv1126_pdaudio_get_clk(struct rv1126_clk_priv * priv)766f95775d6SJoseph Chen static ulong rv1126_pdaudio_get_clk(struct rv1126_clk_priv *priv)
767f95775d6SJoseph Chen {
768f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
769f95775d6SJoseph Chen u32 con, div;
770f95775d6SJoseph Chen
771f95775d6SJoseph Chen con = readl(&cru->clksel_con[26]);
772f95775d6SJoseph Chen div = (con & HCLK_PDAUDIO_DIV_MASK) >> HCLK_PDAUDIO_DIV_SHIFT;
773f95775d6SJoseph Chen
774f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
775f95775d6SJoseph Chen }
776f95775d6SJoseph Chen
rv1126_pdaudio_set_clk(struct rv1126_clk_priv * priv,ulong rate)777f95775d6SJoseph Chen static ulong rv1126_pdaudio_set_clk(struct rv1126_clk_priv *priv, ulong rate)
778f95775d6SJoseph Chen {
779f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
780f95775d6SJoseph Chen int src_clk_div;
781f95775d6SJoseph Chen
782b8650936SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
783f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
784f95775d6SJoseph Chen
785f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[26], HCLK_PDAUDIO_DIV_MASK,
786f95775d6SJoseph Chen (src_clk_div - 1) << HCLK_PDAUDIO_DIV_SHIFT);
787f95775d6SJoseph Chen
788f95775d6SJoseph Chen return rv1126_pdaudio_get_clk(priv);
789f95775d6SJoseph Chen }
790f95775d6SJoseph Chen
rv1126_i2c_get_clk(struct rv1126_clk_priv * priv,ulong clk_id)791f95775d6SJoseph Chen static ulong rv1126_i2c_get_clk(struct rv1126_clk_priv *priv, ulong clk_id)
792f95775d6SJoseph Chen {
793f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
794f95775d6SJoseph Chen u32 div, con;
795f95775d6SJoseph Chen
796f95775d6SJoseph Chen switch (clk_id) {
797f95775d6SJoseph Chen case CLK_I2C1:
798f95775d6SJoseph Chen con = readl(&cru->clksel_con[5]);
799f95775d6SJoseph Chen div = (con & CLK_I2C1_DIV_MASK) >> CLK_I2C1_DIV_SHIFT;
800f95775d6SJoseph Chen break;
801f95775d6SJoseph Chen case CLK_I2C3:
802f95775d6SJoseph Chen con = readl(&cru->clksel_con[5]);
803f95775d6SJoseph Chen div = (con & CLK_I2C3_DIV_MASK) >> CLK_I2C3_DIV_SHIFT;
804f95775d6SJoseph Chen break;
805f95775d6SJoseph Chen case CLK_I2C4:
806f95775d6SJoseph Chen con = readl(&cru->clksel_con[6]);
807f95775d6SJoseph Chen div = (con & CLK_I2C4_DIV_MASK) >> CLK_I2C4_DIV_SHIFT;
808f95775d6SJoseph Chen break;
809f95775d6SJoseph Chen case CLK_I2C5:
810f95775d6SJoseph Chen con = readl(&cru->clksel_con[6]);
811f95775d6SJoseph Chen div = (con & CLK_I2C5_DIV_MASK) >> CLK_I2C5_DIV_SHIFT;
812f95775d6SJoseph Chen break;
813f95775d6SJoseph Chen default:
814f95775d6SJoseph Chen return -ENOENT;
815f95775d6SJoseph Chen }
816f95775d6SJoseph Chen
817f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
818f95775d6SJoseph Chen }
819f95775d6SJoseph Chen
rv1126_i2c_set_clk(struct rv1126_clk_priv * priv,ulong clk_id,ulong rate)820f95775d6SJoseph Chen static ulong rv1126_i2c_set_clk(struct rv1126_clk_priv *priv, ulong clk_id,
821f95775d6SJoseph Chen ulong rate)
822f95775d6SJoseph Chen {
823f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
824f95775d6SJoseph Chen int src_clk_div;
825f95775d6SJoseph Chen
826f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
827f95775d6SJoseph Chen assert(src_clk_div - 1 <= 127);
828f95775d6SJoseph Chen
829f95775d6SJoseph Chen switch (clk_id) {
830f95775d6SJoseph Chen case CLK_I2C1:
831f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[5], CLK_I2C1_DIV_MASK,
832f95775d6SJoseph Chen (src_clk_div - 1) << CLK_I2C1_DIV_SHIFT);
833f95775d6SJoseph Chen break;
834f95775d6SJoseph Chen case CLK_I2C3:
835f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[5], CLK_I2C3_DIV_MASK,
836f95775d6SJoseph Chen (src_clk_div - 1) << CLK_I2C3_DIV_SHIFT);
837f95775d6SJoseph Chen break;
838f95775d6SJoseph Chen case CLK_I2C4:
839f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[6], CLK_I2C4_DIV_MASK,
840f95775d6SJoseph Chen (src_clk_div - 1) << CLK_I2C4_DIV_SHIFT);
841f95775d6SJoseph Chen break;
842f95775d6SJoseph Chen case CLK_I2C5:
843f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[6], CLK_I2C5_DIV_MASK,
844f95775d6SJoseph Chen (src_clk_div - 1) << CLK_I2C5_DIV_SHIFT);
845f95775d6SJoseph Chen break;
846f95775d6SJoseph Chen default:
847f95775d6SJoseph Chen return -ENOENT;
848f95775d6SJoseph Chen }
849f95775d6SJoseph Chen
850f95775d6SJoseph Chen return rv1126_i2c_get_clk(priv, clk_id);
851f95775d6SJoseph Chen }
852f95775d6SJoseph Chen
rv1126_spi_get_clk(struct rv1126_clk_priv * priv)853f95775d6SJoseph Chen static ulong rv1126_spi_get_clk(struct rv1126_clk_priv *priv)
854f95775d6SJoseph Chen {
855f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
856f95775d6SJoseph Chen u32 div, con;
857f95775d6SJoseph Chen
858f95775d6SJoseph Chen con = readl(&cru->clksel_con[8]);
859f95775d6SJoseph Chen div = (con & CLK_SPI1_DIV_MASK) >> CLK_SPI1_DIV_SHIFT;
860f95775d6SJoseph Chen
861f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
862f95775d6SJoseph Chen }
863f95775d6SJoseph Chen
rv1126_spi_set_clk(struct rv1126_clk_priv * priv,ulong rate)864f95775d6SJoseph Chen static ulong rv1126_spi_set_clk(struct rv1126_clk_priv *priv, ulong rate)
865f95775d6SJoseph Chen {
866f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
867f95775d6SJoseph Chen int src_clk_div;
868f95775d6SJoseph Chen
869f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
870f95775d6SJoseph Chen assert(src_clk_div - 1 <= 127);
871f95775d6SJoseph Chen
872f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[8],
873f95775d6SJoseph Chen CLK_SPI1_SEL_MASK | CLK_SPI1_DIV_MASK,
874f95775d6SJoseph Chen CLK_SPI1_SEL_GPLL << CLK_SPI1_SEL_SHIFT |
875f95775d6SJoseph Chen (src_clk_div - 1) << CLK_SPI1_DIV_SHIFT);
876f95775d6SJoseph Chen
877f95775d6SJoseph Chen return rv1126_spi_get_clk(priv);
878f95775d6SJoseph Chen }
879f95775d6SJoseph Chen
rv1126_pwm_get_clk(struct rv1126_clk_priv * priv)880f95775d6SJoseph Chen static ulong rv1126_pwm_get_clk(struct rv1126_clk_priv *priv)
881f95775d6SJoseph Chen {
882f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
883f95775d6SJoseph Chen u32 div, sel, con;
884f95775d6SJoseph Chen
885f95775d6SJoseph Chen con = readl(&cru->clksel_con[9]);
886f95775d6SJoseph Chen sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT;
887f95775d6SJoseph Chen div = (con & CLK_PWM2_DIV_MASK) >> CLK_PWM2_DIV_SHIFT;
888f95775d6SJoseph Chen if (sel == CLK_PWM2_SEL_XIN24M)
889f95775d6SJoseph Chen return OSC_HZ;
890f95775d6SJoseph Chen
891f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div);
892f95775d6SJoseph Chen }
893f95775d6SJoseph Chen
rv1126_pwm_set_clk(struct rv1126_clk_priv * priv,ulong rate)894f95775d6SJoseph Chen static ulong rv1126_pwm_set_clk(struct rv1126_clk_priv *priv, ulong rate)
895f95775d6SJoseph Chen {
896f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
897f95775d6SJoseph Chen int src_clk_div;
898f95775d6SJoseph Chen
899f95775d6SJoseph Chen if (rate == OSC_HZ) {
900f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[9], CLK_PWM2_SEL_MASK,
901f95775d6SJoseph Chen CLK_PWM2_SEL_XIN24M << CLK_PWM2_SEL_SHIFT);
902f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[9], CLK_PWM2_DIV_MASK, 0);
903f95775d6SJoseph Chen } else {
904f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
905f95775d6SJoseph Chen assert(src_clk_div - 1 <= 127);
906f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[9], CLK_PWM2_DIV_MASK,
907f95775d6SJoseph Chen (src_clk_div - 1) << CLK_PWM2_DIV_SHIFT);
908f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[9], CLK_PWM2_SEL_MASK,
909f95775d6SJoseph Chen CLK_PWM2_SEL_GPLL << CLK_PWM2_SEL_SHIFT);
910f95775d6SJoseph Chen }
911f95775d6SJoseph Chen
912f95775d6SJoseph Chen return rv1126_pwm_get_clk(priv);
913f95775d6SJoseph Chen }
914f95775d6SJoseph Chen
rv1126_saradc_get_clk(struct rv1126_clk_priv * priv)915f95775d6SJoseph Chen static ulong rv1126_saradc_get_clk(struct rv1126_clk_priv *priv)
916f95775d6SJoseph Chen {
917f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
918f95775d6SJoseph Chen u32 div, con;
919f95775d6SJoseph Chen
920f95775d6SJoseph Chen con = readl(&cru->clksel_con[20]);
921f95775d6SJoseph Chen div = (con & CLK_SARADC_DIV_MASK) >> CLK_SARADC_DIV_SHIFT;
922f95775d6SJoseph Chen
923f95775d6SJoseph Chen return DIV_TO_RATE(OSC_HZ, div);
924f95775d6SJoseph Chen }
925f95775d6SJoseph Chen
rv1126_saradc_set_clk(struct rv1126_clk_priv * priv,ulong rate)926f95775d6SJoseph Chen static ulong rv1126_saradc_set_clk(struct rv1126_clk_priv *priv, ulong rate)
927f95775d6SJoseph Chen {
928f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
929f95775d6SJoseph Chen int src_clk_div;
930f95775d6SJoseph Chen
931f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(OSC_HZ, rate);
932f95775d6SJoseph Chen assert(src_clk_div - 1 <= 2047);
933f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[20], CLK_SARADC_DIV_MASK,
934f95775d6SJoseph Chen (src_clk_div - 1) << CLK_SARADC_DIV_SHIFT);
935f95775d6SJoseph Chen
936f95775d6SJoseph Chen return rv1126_saradc_get_clk(priv);
937f95775d6SJoseph Chen }
938f95775d6SJoseph Chen
rv1126_crypto_get_clk(struct rv1126_clk_priv * priv,ulong clk_id)939f95775d6SJoseph Chen static ulong rv1126_crypto_get_clk(struct rv1126_clk_priv *priv, ulong clk_id)
940f95775d6SJoseph Chen {
941f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
942f95775d6SJoseph Chen u32 div, sel, con, parent;
943f95775d6SJoseph Chen
944f95775d6SJoseph Chen switch (clk_id) {
945f95775d6SJoseph Chen case CLK_CRYPTO_CORE:
946f95775d6SJoseph Chen con = readl(&cru->clksel_con[7]);
947f95775d6SJoseph Chen div = (con & CLK_CRYPTO_CORE_DIV_MASK) >> CLK_CRYPTO_CORE_DIV_SHIFT;
948f95775d6SJoseph Chen sel = (con & CLK_CRYPTO_CORE_SEL_MASK) >> CLK_CRYPTO_CORE_SEL_SHIFT;
949f95775d6SJoseph Chen if (sel == CLK_CRYPTO_CORE_SEL_GPLL)
950f95775d6SJoseph Chen parent = priv->gpll_hz;
951f95775d6SJoseph Chen else if (sel == CLK_CRYPTO_CORE_SEL_CPLL)
952f95775d6SJoseph Chen parent = priv->cpll_hz;
953f95775d6SJoseph Chen else
954f95775d6SJoseph Chen return -ENOENT;
955f95775d6SJoseph Chen break;
956f95775d6SJoseph Chen case CLK_CRYPTO_PKA:
957f95775d6SJoseph Chen con = readl(&cru->clksel_con[7]);
958f95775d6SJoseph Chen div = (con & CLK_CRYPTO_PKA_DIV_MASK) >> CLK_CRYPTO_PKA_DIV_SHIFT;
959f95775d6SJoseph Chen sel = (con & CLK_CRYPTO_PKA_SEL_MASK) >> CLK_CRYPTO_PKA_SEL_SHIFT;
960f95775d6SJoseph Chen if (sel == CLK_CRYPTO_PKA_SEL_GPLL)
961f95775d6SJoseph Chen parent = priv->gpll_hz;
962f95775d6SJoseph Chen else if (sel == CLK_CRYPTO_PKA_SEL_CPLL)
963f95775d6SJoseph Chen parent = priv->cpll_hz;
964f95775d6SJoseph Chen else
965f95775d6SJoseph Chen return -ENOENT;
966f95775d6SJoseph Chen break;
967f95775d6SJoseph Chen case ACLK_CRYPTO:
968f95775d6SJoseph Chen con = readl(&cru->clksel_con[4]);
969f95775d6SJoseph Chen div = (con & ACLK_CRYPTO_DIV_MASK) >> ACLK_CRYPTO_DIV_SHIFT;
970f95775d6SJoseph Chen sel = (con & ACLK_CRYPTO_SEL_MASK) >> ACLK_CRYPTO_SEL_SHIFT;
971f95775d6SJoseph Chen if (sel == ACLK_CRYPTO_SEL_GPLL)
972f95775d6SJoseph Chen parent = priv->gpll_hz;
973f95775d6SJoseph Chen else if (sel == ACLK_CRYPTO_SEL_CPLL)
974f95775d6SJoseph Chen parent = priv->cpll_hz;
975f95775d6SJoseph Chen else
976f95775d6SJoseph Chen return -ENOENT;
977f95775d6SJoseph Chen break;
978f95775d6SJoseph Chen default:
979f95775d6SJoseph Chen return -ENOENT;
980f95775d6SJoseph Chen }
981f95775d6SJoseph Chen
982f95775d6SJoseph Chen return DIV_TO_RATE(parent, div);
983f95775d6SJoseph Chen }
984f95775d6SJoseph Chen
rv1126_crypto_set_clk(struct rv1126_clk_priv * priv,ulong clk_id,ulong rate)985f95775d6SJoseph Chen static ulong rv1126_crypto_set_clk(struct rv1126_clk_priv *priv, ulong clk_id,
986f95775d6SJoseph Chen ulong rate)
987f95775d6SJoseph Chen {
988f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
989f95775d6SJoseph Chen int src_clk_div;
990f95775d6SJoseph Chen
991f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
992f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
993f95775d6SJoseph Chen
994f95775d6SJoseph Chen switch (clk_id) {
995f95775d6SJoseph Chen case CLK_CRYPTO_CORE:
996f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[7],
997f95775d6SJoseph Chen CLK_CRYPTO_CORE_SEL_MASK |
998f95775d6SJoseph Chen CLK_CRYPTO_CORE_DIV_MASK,
999f95775d6SJoseph Chen CLK_CRYPTO_CORE_SEL_GPLL <<
1000f95775d6SJoseph Chen CLK_CRYPTO_CORE_SEL_SHIFT |
1001f95775d6SJoseph Chen (src_clk_div - 1) << CLK_CRYPTO_CORE_DIV_SHIFT);
1002f95775d6SJoseph Chen break;
1003f95775d6SJoseph Chen case CLK_CRYPTO_PKA:
1004f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[7],
1005f95775d6SJoseph Chen CLK_CRYPTO_PKA_SEL_MASK |
1006f95775d6SJoseph Chen CLK_CRYPTO_PKA_DIV_MASK,
1007f95775d6SJoseph Chen CLK_CRYPTO_PKA_SEL_GPLL <<
1008f95775d6SJoseph Chen CLK_CRYPTO_PKA_SEL_SHIFT |
1009f95775d6SJoseph Chen (src_clk_div - 1) << CLK_CRYPTO_PKA_DIV_SHIFT);
1010f95775d6SJoseph Chen break;
1011f95775d6SJoseph Chen case ACLK_CRYPTO:
1012f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[4],
1013f95775d6SJoseph Chen ACLK_CRYPTO_SEL_MASK | ACLK_CRYPTO_DIV_MASK,
1014f95775d6SJoseph Chen ACLK_CRYPTO_SEL_GPLL << ACLK_CRYPTO_SEL_SHIFT |
1015f95775d6SJoseph Chen (src_clk_div - 1) << ACLK_CRYPTO_DIV_SHIFT);
1016f95775d6SJoseph Chen break;
1017f95775d6SJoseph Chen default:
1018f95775d6SJoseph Chen return -ENOENT;
1019f95775d6SJoseph Chen }
1020f95775d6SJoseph Chen
1021f95775d6SJoseph Chen return rv1126_crypto_get_clk(priv, clk_id);
1022f95775d6SJoseph Chen }
1023f95775d6SJoseph Chen
rv1126_mmc_get_clk(struct rv1126_clk_priv * priv,ulong clk_id)1024f95775d6SJoseph Chen static ulong rv1126_mmc_get_clk(struct rv1126_clk_priv *priv, ulong clk_id)
1025f95775d6SJoseph Chen {
1026f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1027f95775d6SJoseph Chen u32 div, sel, con, con_id;
1028f95775d6SJoseph Chen
1029f95775d6SJoseph Chen switch (clk_id) {
1030f95775d6SJoseph Chen case HCLK_SDMMC:
1031f95775d6SJoseph Chen case CLK_SDMMC:
1032f95775d6SJoseph Chen con_id = 55;
1033f95775d6SJoseph Chen break;
1034f95775d6SJoseph Chen case HCLK_SDIO:
1035f95775d6SJoseph Chen case CLK_SDIO:
1036f95775d6SJoseph Chen con_id = 56;
1037f95775d6SJoseph Chen break;
1038f95775d6SJoseph Chen case HCLK_EMMC:
1039f95775d6SJoseph Chen case CLK_EMMC:
1040f95775d6SJoseph Chen case SCLK_EMMC_SAMPLE:
1041f95775d6SJoseph Chen con_id = 57;
1042f95775d6SJoseph Chen break;
1043f95775d6SJoseph Chen default:
1044f95775d6SJoseph Chen return -ENOENT;
1045f95775d6SJoseph Chen }
1046f95775d6SJoseph Chen
1047f95775d6SJoseph Chen con = readl(&cru->clksel_con[con_id]);
1048f95775d6SJoseph Chen div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
1049f95775d6SJoseph Chen sel = (con & EMMC_SEL_MASK) >> EMMC_SEL_SHIFT;
1050f95775d6SJoseph Chen if (sel == EMMC_SEL_GPLL)
1051f95775d6SJoseph Chen return DIV_TO_RATE(priv->gpll_hz, div) / 2;
1052f95775d6SJoseph Chen else if (sel == EMMC_SEL_CPLL)
1053f95775d6SJoseph Chen return DIV_TO_RATE(priv->cpll_hz, div) / 2;
1054f95775d6SJoseph Chen else if (sel == EMMC_SEL_XIN24M)
1055f95775d6SJoseph Chen return DIV_TO_RATE(OSC_HZ, div) / 2;
1056f95775d6SJoseph Chen
1057f95775d6SJoseph Chen return -ENOENT;
1058f95775d6SJoseph Chen }
1059f95775d6SJoseph Chen
rv1126_mmc_set_clk(struct rv1126_clk_priv * priv,ulong clk_id,ulong rate)1060f96f0122SFinley Xiao static ulong rv1126_mmc_set_clk(struct rv1126_clk_priv *priv, ulong clk_id,
1061f95775d6SJoseph Chen ulong rate)
1062f95775d6SJoseph Chen {
1063f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1064f95775d6SJoseph Chen int src_clk_div;
1065f95775d6SJoseph Chen u32 con_id;
1066f95775d6SJoseph Chen
1067f95775d6SJoseph Chen switch (clk_id) {
1068f95775d6SJoseph Chen case HCLK_SDMMC:
1069f95775d6SJoseph Chen case CLK_SDMMC:
1070f95775d6SJoseph Chen con_id = 55;
1071f95775d6SJoseph Chen break;
1072f95775d6SJoseph Chen case HCLK_SDIO:
1073f95775d6SJoseph Chen case CLK_SDIO:
1074f95775d6SJoseph Chen con_id = 56;
1075f95775d6SJoseph Chen break;
1076f95775d6SJoseph Chen case HCLK_EMMC:
1077f95775d6SJoseph Chen case CLK_EMMC:
1078f95775d6SJoseph Chen con_id = 57;
1079f95775d6SJoseph Chen break;
1080f95775d6SJoseph Chen default:
1081f95775d6SJoseph Chen return -ENOENT;
1082f95775d6SJoseph Chen }
1083f95775d6SJoseph Chen
1084f95775d6SJoseph Chen /* Select clk_sdmmc/emmc source from GPLL by default */
1085f95775d6SJoseph Chen /* mmc clock defaulg div 2 internal, need provide double in cru */
1086f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, rate);
1087f95775d6SJoseph Chen
1088f95775d6SJoseph Chen if (src_clk_div > 127) {
1089f95775d6SJoseph Chen /* use 24MHz source for 400KHz clock */
1090f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, rate);
1091f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[con_id],
1092f95775d6SJoseph Chen EMMC_SEL_MASK | EMMC_DIV_MASK,
1093f95775d6SJoseph Chen EMMC_SEL_XIN24M << EMMC_SEL_SHIFT |
1094f95775d6SJoseph Chen (src_clk_div - 1) << EMMC_DIV_SHIFT);
1095f95775d6SJoseph Chen } else {
1096f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[con_id],
1097f95775d6SJoseph Chen EMMC_SEL_MASK | EMMC_DIV_MASK,
1098f95775d6SJoseph Chen EMMC_SEL_GPLL << EMMC_SEL_SHIFT |
1099f95775d6SJoseph Chen (src_clk_div - 1) << EMMC_DIV_SHIFT);
1100f95775d6SJoseph Chen }
1101f95775d6SJoseph Chen
1102f95775d6SJoseph Chen return rv1126_mmc_get_clk(priv, clk_id);
1103f95775d6SJoseph Chen }
1104f95775d6SJoseph Chen
rv1126_sfc_get_clk(struct rv1126_clk_priv * priv)110557ae0852SFinley Xiao static ulong rv1126_sfc_get_clk(struct rv1126_clk_priv *priv)
110657ae0852SFinley Xiao {
110757ae0852SFinley Xiao struct rv1126_cru *cru = priv->cru;
110857ae0852SFinley Xiao u32 div, sel, con, parent;
110957ae0852SFinley Xiao
111057ae0852SFinley Xiao con = readl(&cru->clksel_con[58]);
111157ae0852SFinley Xiao div = (con & SCLK_SFC_DIV_MASK) >> SCLK_SFC_DIV_SHIFT;
111257ae0852SFinley Xiao sel = (con & SCLK_SFC_SEL_MASK) >> SCLK_SFC_SEL_SHIFT;
111357ae0852SFinley Xiao if (sel == SCLK_SFC_SEL_GPLL)
111457ae0852SFinley Xiao parent = priv->gpll_hz;
111557ae0852SFinley Xiao else if (sel == SCLK_SFC_SEL_CPLL)
111657ae0852SFinley Xiao parent = priv->cpll_hz;
111757ae0852SFinley Xiao else
111857ae0852SFinley Xiao return -ENOENT;
111957ae0852SFinley Xiao
112057ae0852SFinley Xiao return DIV_TO_RATE(parent, div);
112157ae0852SFinley Xiao }
112257ae0852SFinley Xiao
rv1126_sfc_set_clk(struct rv1126_clk_priv * priv,ulong rate)112357ae0852SFinley Xiao static ulong rv1126_sfc_set_clk(struct rv1126_clk_priv *priv, ulong rate)
112457ae0852SFinley Xiao {
112557ae0852SFinley Xiao struct rv1126_cru *cru = priv->cru;
112657ae0852SFinley Xiao int src_clk_div;
112757ae0852SFinley Xiao
112857ae0852SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
112957ae0852SFinley Xiao rk_clrsetreg(&cru->clksel_con[58],
113057ae0852SFinley Xiao SCLK_SFC_SEL_MASK | SCLK_SFC_DIV_MASK,
113157ae0852SFinley Xiao SCLK_SFC_SEL_GPLL << SCLK_SFC_SEL_SHIFT |
113257ae0852SFinley Xiao (src_clk_div - 1) << SCLK_SFC_DIV_SHIFT);
113357ae0852SFinley Xiao
113457ae0852SFinley Xiao return rv1126_sfc_get_clk(priv);
113557ae0852SFinley Xiao }
113657ae0852SFinley Xiao
rv1126_nand_get_clk(struct rv1126_clk_priv * priv)113757ae0852SFinley Xiao static ulong rv1126_nand_get_clk(struct rv1126_clk_priv *priv)
113857ae0852SFinley Xiao {
113957ae0852SFinley Xiao struct rv1126_cru *cru = priv->cru;
114057ae0852SFinley Xiao u32 div, sel, con, parent;
114157ae0852SFinley Xiao
114257ae0852SFinley Xiao con = readl(&cru->clksel_con[59]);
114357ae0852SFinley Xiao div = (con & CLK_NANDC_DIV_MASK) >> CLK_NANDC_DIV_SHIFT;
114457ae0852SFinley Xiao sel = (con & CLK_NANDC_SEL_MASK) >> CLK_NANDC_SEL_SHIFT;
114557ae0852SFinley Xiao if (sel == CLK_NANDC_SEL_GPLL)
114657ae0852SFinley Xiao parent = priv->gpll_hz;
114757ae0852SFinley Xiao else if (sel == CLK_NANDC_SEL_CPLL)
114857ae0852SFinley Xiao parent = priv->cpll_hz;
114957ae0852SFinley Xiao else
115057ae0852SFinley Xiao return -ENOENT;
115157ae0852SFinley Xiao
115257ae0852SFinley Xiao return DIV_TO_RATE(parent, div);
115357ae0852SFinley Xiao }
115457ae0852SFinley Xiao
rv1126_nand_set_clk(struct rv1126_clk_priv * priv,ulong rate)115557ae0852SFinley Xiao static ulong rv1126_nand_set_clk(struct rv1126_clk_priv *priv, ulong rate)
115657ae0852SFinley Xiao {
115757ae0852SFinley Xiao struct rv1126_cru *cru = priv->cru;
115857ae0852SFinley Xiao int src_clk_div;
115957ae0852SFinley Xiao
116057ae0852SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
116157ae0852SFinley Xiao rk_clrsetreg(&cru->clksel_con[59],
116257ae0852SFinley Xiao CLK_NANDC_SEL_MASK | CLK_NANDC_DIV_MASK,
116357ae0852SFinley Xiao CLK_NANDC_SEL_GPLL << CLK_NANDC_SEL_SHIFT |
116457ae0852SFinley Xiao (src_clk_div - 1) << CLK_NANDC_DIV_SHIFT);
116557ae0852SFinley Xiao
116657ae0852SFinley Xiao return rv1126_nand_get_clk(priv);
116757ae0852SFinley Xiao }
116857ae0852SFinley Xiao
rv1126_aclk_vop_get_clk(struct rv1126_clk_priv * priv)1169f95775d6SJoseph Chen static ulong rv1126_aclk_vop_get_clk(struct rv1126_clk_priv *priv)
1170f95775d6SJoseph Chen {
1171f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1172f95775d6SJoseph Chen u32 div, sel, con, parent;
1173f95775d6SJoseph Chen
1174f95775d6SJoseph Chen con = readl(&cru->clksel_con[45]);
1175f95775d6SJoseph Chen div = (con & ACLK_PDVO_DIV_MASK) >> ACLK_PDVO_DIV_SHIFT;
1176f95775d6SJoseph Chen sel = (con & ACLK_PDVO_SEL_MASK) >> ACLK_PDVO_SEL_SHIFT;
1177f95775d6SJoseph Chen if (sel == ACLK_PDVO_SEL_GPLL)
1178f95775d6SJoseph Chen parent = priv->gpll_hz;
1179f95775d6SJoseph Chen else if (sel == ACLK_PDVO_SEL_CPLL)
1180f95775d6SJoseph Chen parent = priv->cpll_hz;
1181f95775d6SJoseph Chen else
1182f95775d6SJoseph Chen return -ENOENT;
1183f95775d6SJoseph Chen
1184f95775d6SJoseph Chen return DIV_TO_RATE(parent, div);
1185f95775d6SJoseph Chen }
1186f95775d6SJoseph Chen
rv1126_aclk_vop_set_clk(struct rv1126_clk_priv * priv,ulong rate)1187f95775d6SJoseph Chen static ulong rv1126_aclk_vop_set_clk(struct rv1126_clk_priv *priv, ulong rate)
1188f95775d6SJoseph Chen {
1189f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1190f95775d6SJoseph Chen int src_clk_div;
1191f95775d6SJoseph Chen
1192f95775d6SJoseph Chen src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
1193f95775d6SJoseph Chen assert(src_clk_div - 1 <= 31);
1194f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[45],
1195f95775d6SJoseph Chen ACLK_PDVO_SEL_MASK | ACLK_PDVO_DIV_MASK,
1196f95775d6SJoseph Chen ACLK_PDVO_SEL_GPLL << ACLK_PDVO_SEL_SHIFT |
1197f95775d6SJoseph Chen (src_clk_div - 1) << ACLK_PDVO_DIV_SHIFT);
1198f95775d6SJoseph Chen
1199f95775d6SJoseph Chen return rv1126_aclk_vop_get_clk(priv);
1200f95775d6SJoseph Chen }
1201f95775d6SJoseph Chen
rv1126_dclk_vop_get_clk(struct rv1126_clk_priv * priv)1202f95775d6SJoseph Chen static ulong rv1126_dclk_vop_get_clk(struct rv1126_clk_priv *priv)
1203f95775d6SJoseph Chen {
1204f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1205f95775d6SJoseph Chen u32 div, sel, con, parent;
1206f95775d6SJoseph Chen
1207f95775d6SJoseph Chen con = readl(&cru->clksel_con[47]);
1208f95775d6SJoseph Chen div = (con & DCLK_VOP_DIV_MASK) >> DCLK_VOP_DIV_SHIFT;
1209f95775d6SJoseph Chen sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
1210f95775d6SJoseph Chen if (sel == DCLK_VOP_SEL_GPLL)
1211f95775d6SJoseph Chen parent = priv->gpll_hz;
1212f95775d6SJoseph Chen else if (sel == DCLK_VOP_SEL_CPLL)
1213f95775d6SJoseph Chen parent = priv->cpll_hz;
1214f95775d6SJoseph Chen else
1215f95775d6SJoseph Chen return -ENOENT;
1216f95775d6SJoseph Chen
1217f95775d6SJoseph Chen return DIV_TO_RATE(parent, div);
1218f95775d6SJoseph Chen }
1219f95775d6SJoseph Chen
rv1126_dclk_vop_set_clk(struct rv1126_clk_priv * priv,ulong rate)1220f95775d6SJoseph Chen static ulong rv1126_dclk_vop_set_clk(struct rv1126_clk_priv *priv, ulong rate)
1221f95775d6SJoseph Chen {
1222f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1223f95775d6SJoseph Chen ulong pll_rate, now, best_rate = 0;
1224f95775d6SJoseph Chen u32 i, div, best_div = 0, best_sel = 0;
1225f95775d6SJoseph Chen
1226f95775d6SJoseph Chen for (i = 0; i <= DCLK_VOP_SEL_CPLL; i++) {
1227f95775d6SJoseph Chen switch (i) {
1228f95775d6SJoseph Chen case DCLK_VOP_SEL_GPLL:
1229f95775d6SJoseph Chen pll_rate = priv->gpll_hz;
1230f95775d6SJoseph Chen break;
1231f95775d6SJoseph Chen case DCLK_VOP_SEL_CPLL:
1232f95775d6SJoseph Chen pll_rate = priv->cpll_hz;
1233f95775d6SJoseph Chen break;
1234f95775d6SJoseph Chen default:
1235f95775d6SJoseph Chen printf("do not support this vop pll sel\n");
1236f95775d6SJoseph Chen return -EINVAL;
1237f95775d6SJoseph Chen }
1238f95775d6SJoseph Chen
1239f95775d6SJoseph Chen div = DIV_ROUND_UP(pll_rate, rate);
1240f95775d6SJoseph Chen if (div > 255)
1241f95775d6SJoseph Chen continue;
1242f95775d6SJoseph Chen now = pll_rate / div;
1243f95775d6SJoseph Chen if (abs(rate - now) < abs(rate - best_rate)) {
1244f95775d6SJoseph Chen best_rate = now;
1245f95775d6SJoseph Chen best_div = div;
1246f95775d6SJoseph Chen best_sel = i;
1247f95775d6SJoseph Chen }
1248f95775d6SJoseph Chen debug("pll_rate=%lu, best_rate=%lu, best_div=%u, best_sel=%u\n",
1249f95775d6SJoseph Chen pll_rate, best_rate, best_div, best_sel);
1250f95775d6SJoseph Chen }
1251f95775d6SJoseph Chen
1252f95775d6SJoseph Chen if (best_rate) {
1253f95775d6SJoseph Chen rk_clrsetreg(&cru->clksel_con[47],
1254f95775d6SJoseph Chen DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK,
1255f95775d6SJoseph Chen best_sel << DCLK_VOP_SEL_SHIFT |
1256f95775d6SJoseph Chen (best_div - 1) << DCLK_VOP_DIV_SHIFT);
1257f95775d6SJoseph Chen } else {
1258f95775d6SJoseph Chen printf("do not support this vop freq %lu\n", rate);
1259f95775d6SJoseph Chen return -EINVAL;
1260f95775d6SJoseph Chen }
1261f95775d6SJoseph Chen
1262f95775d6SJoseph Chen
1263f95775d6SJoseph Chen return rv1126_dclk_vop_get_clk(priv);
1264f95775d6SJoseph Chen }
1265f95775d6SJoseph Chen
rv1126_scr1_get_clk(struct rv1126_clk_priv * priv)1266f8cddc3eSFinley Xiao static ulong rv1126_scr1_get_clk(struct rv1126_clk_priv *priv)
1267f8cddc3eSFinley Xiao {
1268f8cddc3eSFinley Xiao struct rv1126_cru *cru = priv->cru;
1269f8cddc3eSFinley Xiao u32 div, sel, con, parent;
1270f8cddc3eSFinley Xiao
1271f8cddc3eSFinley Xiao con = readl(&cru->clksel_con[3]);
1272f8cddc3eSFinley Xiao div = (con & CLK_SCR1_DIV_MASK) >> CLK_SCR1_DIV_SHIFT;
1273f8cddc3eSFinley Xiao sel = (con & CLK_SCR1_SEL_MASK) >> CLK_SCR1_SEL_SHIFT;
1274f8cddc3eSFinley Xiao if (sel == CLK_SCR1_SEL_GPLL)
1275f8cddc3eSFinley Xiao parent = priv->gpll_hz;
1276f8cddc3eSFinley Xiao else if (sel == CLK_SCR1_SEL_CPLL)
1277f8cddc3eSFinley Xiao parent = priv->cpll_hz;
1278f8cddc3eSFinley Xiao else
1279f8cddc3eSFinley Xiao return -ENOENT;
1280f8cddc3eSFinley Xiao
1281f8cddc3eSFinley Xiao return DIV_TO_RATE(parent, div);
1282f8cddc3eSFinley Xiao }
1283f8cddc3eSFinley Xiao
rv1126_scr1_set_clk(struct rv1126_clk_priv * priv,ulong rate)1284f8cddc3eSFinley Xiao static ulong rv1126_scr1_set_clk(struct rv1126_clk_priv *priv, ulong rate)
1285f8cddc3eSFinley Xiao {
1286f8cddc3eSFinley Xiao struct rv1126_cru *cru = priv->cru;
1287f8cddc3eSFinley Xiao int src_clk_div;
1288f8cddc3eSFinley Xiao
1289f8cddc3eSFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
1290f8cddc3eSFinley Xiao assert(src_clk_div - 1 <= 31);
1291f8cddc3eSFinley Xiao rk_clrsetreg(&cru->clksel_con[3],
1292f8cddc3eSFinley Xiao CLK_SCR1_SEL_MASK | CLK_SCR1_DIV_MASK,
1293f8cddc3eSFinley Xiao CLK_SCR1_SEL_GPLL << CLK_SCR1_SEL_SHIFT |
1294f8cddc3eSFinley Xiao (src_clk_div - 1) << CLK_SCR1_DIV_SHIFT);
1295f8cddc3eSFinley Xiao
1296f8cddc3eSFinley Xiao return rv1126_scr1_get_clk(priv);
1297f8cddc3eSFinley Xiao }
1298f8cddc3eSFinley Xiao
rv1126_gmac_src_get_clk(struct rv1126_clk_priv * priv)12992438a166SFinley Xiao static ulong rv1126_gmac_src_get_clk(struct rv1126_clk_priv *priv)
13002438a166SFinley Xiao {
13012438a166SFinley Xiao struct rv1126_cru *cru = priv->cru;
13022438a166SFinley Xiao u32 div, sel, con, parent;
13032438a166SFinley Xiao
13042438a166SFinley Xiao con = readl(&cru->clksel_con[63]);
13052438a166SFinley Xiao div = (con & CLK_GMAC_SRC_DIV_MASK) >> CLK_GMAC_SRC_DIV_SHIFT;
13062438a166SFinley Xiao sel = (con & CLK_GMAC_SRC_SEL_MASK) >> CLK_GMAC_SRC_SEL_SHIFT;
13072438a166SFinley Xiao if (sel == CLK_GMAC_SRC_SEL_CPLL)
13082438a166SFinley Xiao parent = priv->cpll_hz;
13092438a166SFinley Xiao else if (sel == CLK_GMAC_SRC_SEL_GPLL)
13102438a166SFinley Xiao parent = priv->gpll_hz;
13112438a166SFinley Xiao else
13122438a166SFinley Xiao return -ENOENT;
13132438a166SFinley Xiao
13142438a166SFinley Xiao return DIV_TO_RATE(parent, div);
13152438a166SFinley Xiao }
13162438a166SFinley Xiao
rv1126_gmac_src_set_clk(struct rv1126_clk_priv * priv,ulong rate)13172438a166SFinley Xiao static ulong rv1126_gmac_src_set_clk(struct rv1126_clk_priv *priv, ulong rate)
13182438a166SFinley Xiao {
13192438a166SFinley Xiao struct rv1126_cru *cru = priv->cru;
13202438a166SFinley Xiao int src_clk_div;
13212438a166SFinley Xiao
13222438a166SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate);
13232438a166SFinley Xiao assert(src_clk_div - 1 <= 31);
13242438a166SFinley Xiao rk_clrsetreg(&cru->clksel_con[63],
13252438a166SFinley Xiao CLK_GMAC_SRC_SEL_MASK | CLK_GMAC_SRC_DIV_MASK,
13262438a166SFinley Xiao CLK_GMAC_SRC_SEL_CPLL << CLK_GMAC_SRC_SEL_SHIFT |
13272438a166SFinley Xiao (src_clk_div - 1) << CLK_GMAC_SRC_DIV_SHIFT);
13282438a166SFinley Xiao
13292438a166SFinley Xiao return rv1126_gmac_src_get_clk(priv);
13302438a166SFinley Xiao }
13312438a166SFinley Xiao
rv1126_gmac_out_get_clk(struct rv1126_clk_priv * priv)13322438a166SFinley Xiao static ulong rv1126_gmac_out_get_clk(struct rv1126_clk_priv *priv)
13332438a166SFinley Xiao {
13342438a166SFinley Xiao struct rv1126_cru *cru = priv->cru;
13352438a166SFinley Xiao u32 div, sel, con, parent;
13362438a166SFinley Xiao
13372438a166SFinley Xiao con = readl(&cru->clksel_con[61]);
13382438a166SFinley Xiao div = (con & CLK_GMAC_OUT_DIV_MASK) >> CLK_GMAC_OUT_DIV_SHIFT;
13392438a166SFinley Xiao sel = (con & CLK_GMAC_OUT_SEL_MASK) >> CLK_GMAC_OUT_SEL_SHIFT;
13402438a166SFinley Xiao if (sel == CLK_GMAC_OUT_SEL_CPLL)
13412438a166SFinley Xiao parent = priv->cpll_hz;
13422438a166SFinley Xiao else if (sel == CLK_GMAC_OUT_SEL_GPLL)
13432438a166SFinley Xiao parent = priv->gpll_hz;
13442438a166SFinley Xiao else
13452438a166SFinley Xiao return -ENOENT;
13462438a166SFinley Xiao
13472438a166SFinley Xiao return DIV_TO_RATE(parent, div);
13482438a166SFinley Xiao }
13492438a166SFinley Xiao
rv1126_gmac_out_set_clk(struct rv1126_clk_priv * priv,ulong rate)13502438a166SFinley Xiao static ulong rv1126_gmac_out_set_clk(struct rv1126_clk_priv *priv, ulong rate)
13512438a166SFinley Xiao {
13522438a166SFinley Xiao struct rv1126_cru *cru = priv->cru;
13532438a166SFinley Xiao int src_clk_div;
13542438a166SFinley Xiao
13552438a166SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->cpll_hz, rate);
13562438a166SFinley Xiao assert(src_clk_div - 1 <= 31);
13572438a166SFinley Xiao rk_clrsetreg(&cru->clksel_con[61],
13582438a166SFinley Xiao CLK_GMAC_OUT_SEL_MASK | CLK_GMAC_OUT_DIV_MASK,
13592438a166SFinley Xiao CLK_GMAC_OUT_SEL_CPLL << CLK_GMAC_OUT_SEL_SHIFT |
13602438a166SFinley Xiao (src_clk_div - 1) << CLK_GMAC_OUT_DIV_SHIFT);
13612438a166SFinley Xiao
13622438a166SFinley Xiao return rv1126_gmac_out_get_clk(priv);
13632438a166SFinley Xiao }
13642438a166SFinley Xiao
rv1126_gmac_tx_rx_set_clk(struct rv1126_clk_priv * priv,ulong rate)13652438a166SFinley Xiao static ulong rv1126_gmac_tx_rx_set_clk(struct rv1126_clk_priv *priv, ulong rate)
13662438a166SFinley Xiao {
13672438a166SFinley Xiao struct rv1126_cru *cru = priv->cru;
13682438a166SFinley Xiao u32 con, sel, div_sel;
13692438a166SFinley Xiao
13702438a166SFinley Xiao con = readl(&cru->gmac_con);
13712438a166SFinley Xiao sel = (con & GMAC_MODE_SEL_MASK) >> GMAC_MODE_SEL_SHIFT;
13722438a166SFinley Xiao
13732438a166SFinley Xiao if (sel == GMAC_RGMII_MODE) {
13742438a166SFinley Xiao if (rate == 2500000)
13752438a166SFinley Xiao div_sel = RGMII_CLK_DIV50;
13762438a166SFinley Xiao else if (rate == 25000000)
13772438a166SFinley Xiao div_sel = RGMII_CLK_DIV5;
13782438a166SFinley Xiao else
13792438a166SFinley Xiao div_sel = RGMII_CLK_DIV0;
13802438a166SFinley Xiao rk_clrsetreg(&cru->gmac_con, RGMII_CLK_SEL_MASK,
13812438a166SFinley Xiao div_sel << RGMII_CLK_SEL_SHIFT);
13822438a166SFinley Xiao } else if (sel == GMAC_RMII_MODE) {
13832438a166SFinley Xiao if (rate == 2500000)
13842438a166SFinley Xiao div_sel = RMII_CLK_DIV20;
13852438a166SFinley Xiao else
13862438a166SFinley Xiao div_sel = RMII_CLK_DIV2;
13872438a166SFinley Xiao rk_clrsetreg(&cru->gmac_con, RMII_CLK_SEL_MASK,
13882438a166SFinley Xiao div_sel << RMII_CLK_SEL_SHIFT);
13892438a166SFinley Xiao }
13902438a166SFinley Xiao
13912438a166SFinley Xiao return 0;
13922438a166SFinley Xiao }
13932438a166SFinley Xiao
rv1126_pclk_gmac_get_clk(struct rv1126_clk_priv * priv)13942438a166SFinley Xiao static ulong rv1126_pclk_gmac_get_clk(struct rv1126_clk_priv *priv)
13952438a166SFinley Xiao {
13962438a166SFinley Xiao struct rv1126_cru *cru = priv->cru;
13972438a166SFinley Xiao u32 div, con, parent;
13982438a166SFinley Xiao
13992438a166SFinley Xiao parent = rv1126_pdphp_get_clk(priv, ACLK_PDPHP);
14002438a166SFinley Xiao
14012438a166SFinley Xiao con = readl(&cru->clksel_con[63]);
14022438a166SFinley Xiao div = (con & PCLK_GMAC_DIV_MASK) >> PCLK_GMAC_DIV_SHIFT;
14032438a166SFinley Xiao
14042438a166SFinley Xiao return DIV_TO_RATE(parent, div);
14052438a166SFinley Xiao }
14062438a166SFinley Xiao
1407c17ccbf6SFinley Xiao #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_KERNEL_BOOT)
rv1126_clk_mipicsi_out_get_clk(struct rv1126_clk_priv * priv)1408*2304b5d3SFinley Xiao static ulong rv1126_clk_mipicsi_out_get_clk(struct rv1126_clk_priv *priv)
1409*2304b5d3SFinley Xiao {
1410*2304b5d3SFinley Xiao struct rv1126_cru *cru = priv->cru;
1411*2304b5d3SFinley Xiao u32 div, fracdiv, sel, con, n, m, parent = priv->gpll_hz;
1412*2304b5d3SFinley Xiao
1413*2304b5d3SFinley Xiao con = readl(&cru->clksel_con[73]);
1414*2304b5d3SFinley Xiao div = (con & MIPICSI_OUT_DIV_MASK) >> MIPICSI_OUT_DIV_SHIFT;
1415*2304b5d3SFinley Xiao sel = (con & MIPICSI_OUT_SEL_MASK) >> MIPICSI_OUT_SEL_SHIFT;
1416*2304b5d3SFinley Xiao if (sel == MIPICSI_OUT_SEL_XIN24M) {
1417*2304b5d3SFinley Xiao return OSC_HZ;
1418*2304b5d3SFinley Xiao } else if (sel == MIPICSI_OUT_SEL_FRACDIV) {
1419*2304b5d3SFinley Xiao parent = DIV_TO_RATE(parent, div);
1420*2304b5d3SFinley Xiao fracdiv = readl(&cru->clksel_con[74]);
1421*2304b5d3SFinley Xiao n = (fracdiv & 0xffff0000) >> 16;
1422*2304b5d3SFinley Xiao m = fracdiv & 0xffff;
1423*2304b5d3SFinley Xiao return parent * n / m;
1424*2304b5d3SFinley Xiao }
1425*2304b5d3SFinley Xiao
1426*2304b5d3SFinley Xiao return DIV_TO_RATE(parent, div);
1427*2304b5d3SFinley Xiao }
1428*2304b5d3SFinley Xiao
rv1126_clk_mipicsi_out_set_clk(struct rv1126_clk_priv * priv,ulong rate)1429*2304b5d3SFinley Xiao static ulong rv1126_clk_mipicsi_out_set_clk(struct rv1126_clk_priv *priv,
1430*2304b5d3SFinley Xiao ulong rate)
1431*2304b5d3SFinley Xiao { struct rv1126_cru *cru = priv->cru;
1432*2304b5d3SFinley Xiao int src_clk_div;
1433*2304b5d3SFinley Xiao
1434*2304b5d3SFinley Xiao if (rate == OSC_HZ) {
1435*2304b5d3SFinley Xiao rk_clrsetreg(&cru->clksel_con[73], MIPICSI_OUT_SEL_MASK,
1436*2304b5d3SFinley Xiao MIPICSI_OUT_SEL_XIN24M << MIPICSI_OUT_SEL_SHIFT);
1437*2304b5d3SFinley Xiao } else if (rate == 27000000) {
1438*2304b5d3SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, 297000000);
1439*2304b5d3SFinley Xiao rk_clrsetreg(&cru->clksel_con[73], MIPICSI_OUT_DIV_MASK,
1440*2304b5d3SFinley Xiao (src_clk_div - 1) << MIPICSI_OUT_DIV_SHIFT);
1441*2304b5d3SFinley Xiao rk_clrsetreg(&cru->clksel_con[73], MIPICSI_OUT_SEL_MASK,
1442*2304b5d3SFinley Xiao MIPICSI_OUT_SEL_FRACDIV << MIPICSI_OUT_SEL_SHIFT);
1443*2304b5d3SFinley Xiao writel(4 << 16 | 44, &cru->clksel_con[74]);
1444*2304b5d3SFinley Xiao } else {
1445*2304b5d3SFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
1446*2304b5d3SFinley Xiao assert(src_clk_div - 1 <= 31);
1447*2304b5d3SFinley Xiao rk_clrsetreg(&cru->clksel_con[73], MIPICSI_OUT_DIV_MASK,
1448*2304b5d3SFinley Xiao (src_clk_div - 1) << MIPICSI_OUT_DIV_SHIFT);
1449*2304b5d3SFinley Xiao rk_clrsetreg(&cru->clksel_con[73], MIPICSI_OUT_SEL_MASK,
1450*2304b5d3SFinley Xiao MIPICSI_OUT_SEL_DIV << MIPICSI_OUT_SEL_SHIFT);
1451*2304b5d3SFinley Xiao }
1452*2304b5d3SFinley Xiao
1453*2304b5d3SFinley Xiao return rv1126_clk_mipicsi_out_get_clk(priv);
1454*2304b5d3SFinley Xiao }
1455*2304b5d3SFinley Xiao
rv1126_clk_pdvi_ispp_get_clk(struct rv1126_clk_priv * priv,ulong clk_id)1456c17ccbf6SFinley Xiao static ulong rv1126_clk_pdvi_ispp_get_clk(struct rv1126_clk_priv *priv,
1457c17ccbf6SFinley Xiao ulong clk_id)
1458c17ccbf6SFinley Xiao {
1459c17ccbf6SFinley Xiao struct rv1126_cru *cru = priv->cru;
1460c17ccbf6SFinley Xiao u32 div, sel, con, parent, con_id;
1461c17ccbf6SFinley Xiao
1462c17ccbf6SFinley Xiao switch (clk_id) {
1463c17ccbf6SFinley Xiao case ACLK_PDVI:
1464c17ccbf6SFinley Xiao con_id = 49;
1465c17ccbf6SFinley Xiao break;
1466c17ccbf6SFinley Xiao case ACLK_PDISPP:
1467c17ccbf6SFinley Xiao con_id = 68;
1468c17ccbf6SFinley Xiao break;
1469c17ccbf6SFinley Xiao case CLK_ISPP:
1470c17ccbf6SFinley Xiao con_id = 69;
1471c17ccbf6SFinley Xiao break;
1472c17ccbf6SFinley Xiao default:
1473c17ccbf6SFinley Xiao return -ENOENT;
1474c17ccbf6SFinley Xiao }
1475c17ccbf6SFinley Xiao
1476c17ccbf6SFinley Xiao con = readl(&cru->clksel_con[con_id]);
1477c17ccbf6SFinley Xiao div = (con & ACLK_PDVI_DIV_MASK) >> ACLK_PDVI_DIV_SHIFT;
1478c17ccbf6SFinley Xiao sel = (con & ACLK_PDVI_SEL_MASK) >> ACLK_PDVI_SEL_SHIFT;
1479c17ccbf6SFinley Xiao if (sel == ACLK_PDVI_SEL_GPLL)
1480c17ccbf6SFinley Xiao parent = priv->gpll_hz;
1481c17ccbf6SFinley Xiao else if (sel == ACLK_PDVI_SEL_CPLL)
1482c17ccbf6SFinley Xiao parent = priv->cpll_hz;
1483c17ccbf6SFinley Xiao else if (sel == ACLK_PDVI_SEL_HPLL)
1484c17ccbf6SFinley Xiao parent = priv->hpll_hz;
1485c17ccbf6SFinley Xiao else
1486c17ccbf6SFinley Xiao return -ENOENT;
1487c17ccbf6SFinley Xiao
1488c17ccbf6SFinley Xiao return DIV_TO_RATE(parent, div);
1489c17ccbf6SFinley Xiao }
1490c17ccbf6SFinley Xiao
rv1126_clk_pdvi_ispp_set_clk(struct rv1126_clk_priv * priv,ulong clk_id,ulong rate)1491c17ccbf6SFinley Xiao static ulong rv1126_clk_pdvi_ispp_set_clk(struct rv1126_clk_priv *priv,
1492c17ccbf6SFinley Xiao ulong clk_id, ulong rate)
1493c17ccbf6SFinley Xiao {
1494c17ccbf6SFinley Xiao struct rv1126_cru *cru = priv->cru;
1495c17ccbf6SFinley Xiao u32 parent, sel, src_clk_div, con_id;
1496c17ccbf6SFinley Xiao
1497c17ccbf6SFinley Xiao switch (clk_id) {
1498c17ccbf6SFinley Xiao case ACLK_PDVI:
1499c17ccbf6SFinley Xiao con_id = 49;
1500c17ccbf6SFinley Xiao break;
1501c17ccbf6SFinley Xiao case ACLK_PDISPP:
1502c17ccbf6SFinley Xiao con_id = 68;
1503c17ccbf6SFinley Xiao break;
1504c17ccbf6SFinley Xiao case CLK_ISPP:
1505c17ccbf6SFinley Xiao con_id = 69;
1506c17ccbf6SFinley Xiao break;
1507c17ccbf6SFinley Xiao default:
1508c17ccbf6SFinley Xiao return -ENOENT;
1509c17ccbf6SFinley Xiao }
1510c17ccbf6SFinley Xiao
1511c17ccbf6SFinley Xiao if (!(priv->cpll_hz % rate)) {
1512c17ccbf6SFinley Xiao parent = priv->cpll_hz;
1513c17ccbf6SFinley Xiao sel = ACLK_PDVI_SEL_CPLL;
1514c17ccbf6SFinley Xiao } else if (!(priv->hpll_hz % rate)) {
1515c17ccbf6SFinley Xiao parent = priv->hpll_hz;
1516c17ccbf6SFinley Xiao sel = ACLK_PDVI_SEL_HPLL;
1517c17ccbf6SFinley Xiao } else {
1518c17ccbf6SFinley Xiao parent = priv->gpll_hz;
1519c17ccbf6SFinley Xiao sel = ACLK_PDVI_SEL_GPLL;
1520c17ccbf6SFinley Xiao }
1521c17ccbf6SFinley Xiao
1522c17ccbf6SFinley Xiao src_clk_div = DIV_ROUND_UP(parent, rate);
1523c17ccbf6SFinley Xiao assert(src_clk_div - 1 <= 31);
1524c17ccbf6SFinley Xiao rk_clrsetreg(&cru->clksel_con[con_id],
1525c17ccbf6SFinley Xiao ACLK_PDVI_SEL_MASK | ACLK_PDVI_DIV_MASK,
1526c17ccbf6SFinley Xiao sel << ACLK_PDVI_SEL_SHIFT |
1527c17ccbf6SFinley Xiao (src_clk_div - 1) << ACLK_PDVI_DIV_SHIFT);
1528c17ccbf6SFinley Xiao
1529c17ccbf6SFinley Xiao return rv1126_clk_pdvi_ispp_get_clk(priv, clk_id);
1530c17ccbf6SFinley Xiao }
1531c17ccbf6SFinley Xiao
rv1126_clk_isp_get_clk(struct rv1126_clk_priv * priv)1532c17ccbf6SFinley Xiao static ulong rv1126_clk_isp_get_clk(struct rv1126_clk_priv *priv)
1533c17ccbf6SFinley Xiao {
1534c17ccbf6SFinley Xiao struct rv1126_cru *cru = priv->cru;
1535c17ccbf6SFinley Xiao u32 div, sel, con, parent;
1536c17ccbf6SFinley Xiao
1537c17ccbf6SFinley Xiao con = readl(&cru->clksel_con[50]);
1538c17ccbf6SFinley Xiao div = (con & CLK_ISP_DIV_MASK) >> CLK_ISP_DIV_SHIFT;
1539c17ccbf6SFinley Xiao sel = (con & CLK_ISP_SEL_MASK) >> CLK_ISP_SEL_SHIFT;
1540c17ccbf6SFinley Xiao if (sel == CLK_ISP_SEL_GPLL)
1541c17ccbf6SFinley Xiao parent = priv->gpll_hz;
1542c17ccbf6SFinley Xiao else if (sel == CLK_ISP_SEL_CPLL)
1543c17ccbf6SFinley Xiao parent = priv->cpll_hz;
1544c17ccbf6SFinley Xiao else if (sel == CLK_ISP_SEL_HPLL)
1545c17ccbf6SFinley Xiao parent = priv->hpll_hz;
1546c17ccbf6SFinley Xiao else
1547c17ccbf6SFinley Xiao return -ENOENT;
1548c17ccbf6SFinley Xiao
1549c17ccbf6SFinley Xiao return DIV_TO_RATE(parent, div);
1550c17ccbf6SFinley Xiao }
1551c17ccbf6SFinley Xiao
rv1126_clk_isp_set_clk(struct rv1126_clk_priv * priv,ulong rate)1552c17ccbf6SFinley Xiao static ulong rv1126_clk_isp_set_clk(struct rv1126_clk_priv *priv, ulong rate)
1553c17ccbf6SFinley Xiao {
1554c17ccbf6SFinley Xiao struct rv1126_cru *cru = priv->cru;
1555c17ccbf6SFinley Xiao u32 parent, sel, src_clk_div;
1556c17ccbf6SFinley Xiao
1557c17ccbf6SFinley Xiao if (!(priv->cpll_hz % rate)) {
1558c17ccbf6SFinley Xiao parent = priv->cpll_hz;
1559c17ccbf6SFinley Xiao sel = CLK_ISP_SEL_CPLL;
1560c17ccbf6SFinley Xiao } else if (!(priv->hpll_hz % rate)) {
1561c17ccbf6SFinley Xiao parent = priv->hpll_hz;
1562c17ccbf6SFinley Xiao sel = CLK_ISP_SEL_HPLL;
1563c17ccbf6SFinley Xiao } else {
1564c17ccbf6SFinley Xiao parent = priv->gpll_hz;
1565c17ccbf6SFinley Xiao sel = CLK_ISP_SEL_GPLL;
1566c17ccbf6SFinley Xiao }
1567c17ccbf6SFinley Xiao
1568c17ccbf6SFinley Xiao src_clk_div = DIV_ROUND_UP(parent, rate);
1569c17ccbf6SFinley Xiao assert(src_clk_div - 1 <= 31);
1570c17ccbf6SFinley Xiao rk_clrsetreg(&cru->clksel_con[50],
1571c17ccbf6SFinley Xiao CLK_ISP_SEL_MASK | CLK_ISP_DIV_MASK,
1572c17ccbf6SFinley Xiao sel << CLK_ISP_SEL_SHIFT |
1573c17ccbf6SFinley Xiao (src_clk_div - 1) << CLK_ISP_DIV_SHIFT);
1574c17ccbf6SFinley Xiao
1575c17ccbf6SFinley Xiao return rv1126_clk_isp_get_clk(priv);
1576c17ccbf6SFinley Xiao }
1577446ef41cSJoseph Chen #endif
15785ecc545eSFinley Xiao
rv1126_dclk_decom_get_clk(struct rv1126_clk_priv * priv)15795ecc545eSFinley Xiao static ulong rv1126_dclk_decom_get_clk(struct rv1126_clk_priv *priv)
15805ecc545eSFinley Xiao {
15815ecc545eSFinley Xiao struct rv1126_cru *cru = priv->cru;
15825ecc545eSFinley Xiao u32 div, sel, con, parent;
15835ecc545eSFinley Xiao
15845ecc545eSFinley Xiao con = readl(&cru->clksel_con[25]);
15855ecc545eSFinley Xiao div = (con & DCLK_DECOM_DIV_MASK) >> DCLK_DECOM_DIV_SHIFT;
15865ecc545eSFinley Xiao sel = (con & DCLK_DECOM_SEL_MASK) >> DCLK_DECOM_SEL_SHIFT;
15875ecc545eSFinley Xiao if (sel == DCLK_DECOM_SEL_GPLL)
15885ecc545eSFinley Xiao parent = priv->gpll_hz;
15895ecc545eSFinley Xiao else if (sel == DCLK_DECOM_SEL_CPLL)
15905ecc545eSFinley Xiao parent = priv->cpll_hz;
15915ecc545eSFinley Xiao else
15925ecc545eSFinley Xiao return -ENOENT;
15935ecc545eSFinley Xiao
15945ecc545eSFinley Xiao return DIV_TO_RATE(parent, div);
15955ecc545eSFinley Xiao }
15965ecc545eSFinley Xiao
rv1126_dclk_decom_set_clk(struct rv1126_clk_priv * priv,ulong rate)15975ecc545eSFinley Xiao static ulong rv1126_dclk_decom_set_clk(struct rv1126_clk_priv *priv, ulong rate)
15985ecc545eSFinley Xiao {
15995ecc545eSFinley Xiao struct rv1126_cru *cru = priv->cru;
16005ecc545eSFinley Xiao u32 src_clk_div;
16015ecc545eSFinley Xiao
16025ecc545eSFinley Xiao src_clk_div = DIV_ROUND_UP(priv->gpll_hz, rate);
16035ecc545eSFinley Xiao assert(src_clk_div - 1 <= 127);
16045ecc545eSFinley Xiao rk_clrsetreg(&cru->clksel_con[25],
16055ecc545eSFinley Xiao DCLK_DECOM_SEL_MASK | DCLK_DECOM_DIV_MASK,
16065ecc545eSFinley Xiao DCLK_DECOM_SEL_GPLL << DCLK_DECOM_SEL_SHIFT |
16075ecc545eSFinley Xiao (src_clk_div - 1) << DCLK_DECOM_DIV_SHIFT);
16085ecc545eSFinley Xiao
16095ecc545eSFinley Xiao return rv1126_dclk_decom_get_clk(priv);
16105ecc545eSFinley Xiao }
1611c17ccbf6SFinley Xiao
rv1126_clk_get_rate(struct clk * clk)1612f95775d6SJoseph Chen static ulong rv1126_clk_get_rate(struct clk *clk)
1613f95775d6SJoseph Chen {
1614f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(clk->dev);
1615f95775d6SJoseph Chen ulong rate = 0;
1616f95775d6SJoseph Chen
1617f95775d6SJoseph Chen if (!priv->gpll_hz) {
1618f95775d6SJoseph Chen printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1619f95775d6SJoseph Chen return -ENOENT;
1620f95775d6SJoseph Chen }
1621f95775d6SJoseph Chen
1622f95775d6SJoseph Chen switch (clk->id) {
1623f95775d6SJoseph Chen case PLL_APLL:
1624f95775d6SJoseph Chen case ARMCLK:
1625f95775d6SJoseph Chen rate = rockchip_pll_get_rate(&rv1126_pll_clks[APLL], priv->cru,
1626f95775d6SJoseph Chen APLL);
1627f95775d6SJoseph Chen break;
1628f95775d6SJoseph Chen case PLL_CPLL:
1629f95775d6SJoseph Chen rate = rockchip_pll_get_rate(&rv1126_pll_clks[CPLL], priv->cru,
1630f95775d6SJoseph Chen CPLL);
1631f95775d6SJoseph Chen break;
163256a06ac8SFinley Xiao case PLL_HPLL:
163356a06ac8SFinley Xiao rate = rockchip_pll_get_rate(&rv1126_pll_clks[HPLL], priv->cru,
163456a06ac8SFinley Xiao HPLL);
163556a06ac8SFinley Xiao break;
1636d47b686dSFinley Xiao case PLL_DPLL:
1637d47b686dSFinley Xiao rate = rockchip_pll_get_rate(&rv1126_pll_clks[DPLL], priv->cru,
1638d47b686dSFinley Xiao DPLL);
1639d47b686dSFinley Xiao break;
1640f95775d6SJoseph Chen case HCLK_PDCORE_NIU:
1641f95775d6SJoseph Chen rate = rv1126_pdcore_get_clk(priv);
1642f95775d6SJoseph Chen break;
1643f95775d6SJoseph Chen case ACLK_PDBUS:
1644f95775d6SJoseph Chen case HCLK_PDBUS:
1645f95775d6SJoseph Chen case PCLK_PDBUS:
16461abad17aSElaine Zhang case PCLK_WDT:
1647f95775d6SJoseph Chen rate = rv1126_pdbus_get_clk(priv, clk->id);
1648f95775d6SJoseph Chen break;
1649f95775d6SJoseph Chen case ACLK_PDPHP:
1650f95775d6SJoseph Chen case HCLK_PDPHP:
1651f95775d6SJoseph Chen rate = rv1126_pdphp_get_clk(priv, clk->id);
1652f95775d6SJoseph Chen break;
1653f95775d6SJoseph Chen case HCLK_PDAUDIO:
1654f95775d6SJoseph Chen rate = rv1126_pdaudio_get_clk(priv);
1655f95775d6SJoseph Chen break;
1656f95775d6SJoseph Chen case CLK_I2C1:
1657f95775d6SJoseph Chen case CLK_I2C3:
1658f95775d6SJoseph Chen case CLK_I2C4:
1659f95775d6SJoseph Chen case CLK_I2C5:
1660f95775d6SJoseph Chen rate = rv1126_i2c_get_clk(priv, clk->id);
1661f95775d6SJoseph Chen break;
1662f95775d6SJoseph Chen case CLK_SPI1:
1663f95775d6SJoseph Chen rate = rv1126_spi_get_clk(priv);
1664f95775d6SJoseph Chen break;
1665f95775d6SJoseph Chen case CLK_PWM2:
1666f95775d6SJoseph Chen rate = rv1126_pwm_get_clk(priv);
1667f95775d6SJoseph Chen break;
1668f95775d6SJoseph Chen case CLK_SARADC:
1669f95775d6SJoseph Chen rate = rv1126_saradc_get_clk(priv);
1670f95775d6SJoseph Chen break;
1671f95775d6SJoseph Chen case CLK_CRYPTO_CORE:
1672f95775d6SJoseph Chen case CLK_CRYPTO_PKA:
1673f95775d6SJoseph Chen case ACLK_CRYPTO:
1674f95775d6SJoseph Chen rate = rv1126_crypto_get_clk(priv, clk->id);
1675f95775d6SJoseph Chen break;
1676f95775d6SJoseph Chen case CLK_SDMMC:
1677f95775d6SJoseph Chen case HCLK_SDMMC:
1678f95775d6SJoseph Chen case CLK_SDIO:
1679f95775d6SJoseph Chen case HCLK_SDIO:
1680f95775d6SJoseph Chen case CLK_EMMC:
1681f95775d6SJoseph Chen case HCLK_EMMC:
1682f95775d6SJoseph Chen case SCLK_EMMC_SAMPLE:
1683f95775d6SJoseph Chen rate = rv1126_mmc_get_clk(priv, clk->id);
1684f95775d6SJoseph Chen break;
168557ae0852SFinley Xiao case SCLK_SFC:
168657ae0852SFinley Xiao rate = rv1126_sfc_get_clk(priv);
168757ae0852SFinley Xiao break;
168857ae0852SFinley Xiao case CLK_NANDC:
168957ae0852SFinley Xiao rate = rv1126_nand_get_clk(priv);
169057ae0852SFinley Xiao break;
1691f95775d6SJoseph Chen case ACLK_PDVO:
1692f95775d6SJoseph Chen case ACLK_VOP:
1693f95775d6SJoseph Chen rate = rv1126_aclk_vop_get_clk(priv);
1694f95775d6SJoseph Chen break;
1695f95775d6SJoseph Chen case DCLK_VOP:
1696f95775d6SJoseph Chen rate = rv1126_dclk_vop_get_clk(priv);
1697f95775d6SJoseph Chen break;
1698f8cddc3eSFinley Xiao case CLK_SCR1_CORE:
1699f8cddc3eSFinley Xiao rate = rv1126_scr1_get_clk(priv);
1700987a4915SFinley Xiao break;
17012438a166SFinley Xiao case CLK_GMAC_SRC:
17022438a166SFinley Xiao rate = rv1126_gmac_src_get_clk(priv);
17032438a166SFinley Xiao break;
17042438a166SFinley Xiao case CLK_GMAC_ETHERNET_OUT:
17052438a166SFinley Xiao rate = rv1126_gmac_out_get_clk(priv);
17062438a166SFinley Xiao break;
17072438a166SFinley Xiao case PCLK_GMAC:
17082438a166SFinley Xiao rate = rv1126_pclk_gmac_get_clk(priv);
17092438a166SFinley Xiao break;
1710c17ccbf6SFinley Xiao #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_KERNEL_BOOT)
1711*2304b5d3SFinley Xiao case CLK_MIPICSI_OUT:
1712*2304b5d3SFinley Xiao rate = rv1126_clk_mipicsi_out_get_clk(priv);
1713*2304b5d3SFinley Xiao break;
1714c17ccbf6SFinley Xiao case CLK_ISP:
1715c17ccbf6SFinley Xiao rate = rv1126_clk_isp_get_clk(priv);
1716c17ccbf6SFinley Xiao break;
1717c17ccbf6SFinley Xiao case ACLK_PDVI:
1718c17ccbf6SFinley Xiao case ACLK_PDISPP:
1719c17ccbf6SFinley Xiao case CLK_ISPP:
1720c17ccbf6SFinley Xiao rate = rv1126_clk_pdvi_ispp_get_clk(priv, clk->id);
1721c17ccbf6SFinley Xiao break;
1722446ef41cSJoseph Chen #endif
17235ecc545eSFinley Xiao case DCLK_DECOM:
17245ecc545eSFinley Xiao rate = rv1126_dclk_decom_get_clk(priv);
17255ecc545eSFinley Xiao break;
1726f95775d6SJoseph Chen default:
1727f95775d6SJoseph Chen return -ENOENT;
1728f95775d6SJoseph Chen }
1729f95775d6SJoseph Chen
1730f95775d6SJoseph Chen return rate;
1731f95775d6SJoseph Chen };
1732f95775d6SJoseph Chen
rv1126_clk_set_rate(struct clk * clk,ulong rate)1733f95775d6SJoseph Chen static ulong rv1126_clk_set_rate(struct clk *clk, ulong rate)
1734f95775d6SJoseph Chen {
1735f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(clk->dev);
1736f95775d6SJoseph Chen ulong ret = 0;
1737f95775d6SJoseph Chen
1738f95775d6SJoseph Chen if (!priv->gpll_hz) {
1739f95775d6SJoseph Chen printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1740f95775d6SJoseph Chen return -ENOENT;
1741f95775d6SJoseph Chen }
1742f95775d6SJoseph Chen
1743f95775d6SJoseph Chen switch (clk->id) {
1744f95775d6SJoseph Chen case PLL_APLL:
1745f95775d6SJoseph Chen case ARMCLK:
1746f95775d6SJoseph Chen if (priv->armclk_hz)
1747f95775d6SJoseph Chen rv1126_armclk_set_clk(priv, rate);
1748f95775d6SJoseph Chen priv->armclk_hz = rate;
1749f95775d6SJoseph Chen break;
1750f95775d6SJoseph Chen case PLL_CPLL:
1751f95775d6SJoseph Chen ret = rockchip_pll_set_rate(&rv1126_pll_clks[CPLL], priv->cru,
1752f95775d6SJoseph Chen CPLL, rate);
1753f95775d6SJoseph Chen break;
175456a06ac8SFinley Xiao case PLL_HPLL:
175556a06ac8SFinley Xiao ret = rockchip_pll_set_rate(&rv1126_pll_clks[HPLL], priv->cru,
175656a06ac8SFinley Xiao HPLL, rate);
175756a06ac8SFinley Xiao break;
1758f95775d6SJoseph Chen case ACLK_PDBUS:
1759f95775d6SJoseph Chen case HCLK_PDBUS:
1760f95775d6SJoseph Chen case PCLK_PDBUS:
17611abad17aSElaine Zhang case PCLK_WDT:
1762f95775d6SJoseph Chen ret = rv1126_pdbus_set_clk(priv, clk->id, rate);
1763f95775d6SJoseph Chen break;
1764f95775d6SJoseph Chen case ACLK_PDPHP:
1765f95775d6SJoseph Chen case HCLK_PDPHP:
1766f95775d6SJoseph Chen ret = rv1126_pdphp_set_clk(priv, clk->id, rate);
1767f95775d6SJoseph Chen break;
1768f95775d6SJoseph Chen case HCLK_PDCORE_NIU:
1769f95775d6SJoseph Chen ret = rv1126_pdcore_set_clk(priv, rate);
1770f95775d6SJoseph Chen break;
1771f95775d6SJoseph Chen case HCLK_PDAUDIO:
1772f95775d6SJoseph Chen ret = rv1126_pdaudio_set_clk(priv, rate);
1773f95775d6SJoseph Chen break;
1774f95775d6SJoseph Chen case CLK_I2C1:
1775f95775d6SJoseph Chen case CLK_I2C3:
1776f95775d6SJoseph Chen case CLK_I2C4:
1777f95775d6SJoseph Chen case CLK_I2C5:
1778f95775d6SJoseph Chen ret = rv1126_i2c_set_clk(priv, clk->id, rate);
1779f95775d6SJoseph Chen break;
1780f95775d6SJoseph Chen case CLK_SPI1:
1781f95775d6SJoseph Chen ret = rv1126_spi_set_clk(priv, rate);
1782f95775d6SJoseph Chen break;
1783f95775d6SJoseph Chen case CLK_PWM2:
1784f95775d6SJoseph Chen ret = rv1126_pwm_set_clk(priv, rate);
1785f95775d6SJoseph Chen break;
1786f95775d6SJoseph Chen case CLK_SARADC:
1787f95775d6SJoseph Chen ret = rv1126_saradc_set_clk(priv, rate);
1788f95775d6SJoseph Chen break;
1789f95775d6SJoseph Chen case CLK_CRYPTO_CORE:
1790f95775d6SJoseph Chen case CLK_CRYPTO_PKA:
1791f95775d6SJoseph Chen case ACLK_CRYPTO:
1792f95775d6SJoseph Chen ret = rv1126_crypto_set_clk(priv, clk->id, rate);
1793f95775d6SJoseph Chen break;
1794f95775d6SJoseph Chen case CLK_SDMMC:
1795f95775d6SJoseph Chen case HCLK_SDMMC:
1796f95775d6SJoseph Chen case CLK_SDIO:
1797f95775d6SJoseph Chen case HCLK_SDIO:
1798f95775d6SJoseph Chen case CLK_EMMC:
1799f95775d6SJoseph Chen case HCLK_EMMC:
1800f96f0122SFinley Xiao ret = rv1126_mmc_set_clk(priv, clk->id, rate);
1801f95775d6SJoseph Chen break;
180257ae0852SFinley Xiao case SCLK_SFC:
180357ae0852SFinley Xiao ret = rv1126_sfc_set_clk(priv, rate);
180457ae0852SFinley Xiao break;
180557ae0852SFinley Xiao case CLK_NANDC:
180657ae0852SFinley Xiao ret = rv1126_nand_set_clk(priv, rate);
180757ae0852SFinley Xiao break;
1808f95775d6SJoseph Chen case ACLK_PDVO:
1809f95775d6SJoseph Chen case ACLK_VOP:
1810f95775d6SJoseph Chen ret = rv1126_aclk_vop_set_clk(priv, rate);
1811f95775d6SJoseph Chen break;
1812f95775d6SJoseph Chen case DCLK_VOP:
1813f95775d6SJoseph Chen ret = rv1126_dclk_vop_set_clk(priv, rate);
1814f95775d6SJoseph Chen break;
1815f8cddc3eSFinley Xiao case CLK_SCR1_CORE:
1816f8cddc3eSFinley Xiao ret = rv1126_scr1_set_clk(priv, rate);
1817987a4915SFinley Xiao break;
18182438a166SFinley Xiao case CLK_GMAC_SRC:
18192438a166SFinley Xiao ret = rv1126_gmac_src_set_clk(priv, rate);
18202438a166SFinley Xiao break;
18212438a166SFinley Xiao case CLK_GMAC_ETHERNET_OUT:
18222438a166SFinley Xiao ret = rv1126_gmac_out_set_clk(priv, rate);
18232438a166SFinley Xiao break;
18242438a166SFinley Xiao case CLK_GMAC_TX_RX:
18252438a166SFinley Xiao ret = rv1126_gmac_tx_rx_set_clk(priv, rate);
18262438a166SFinley Xiao break;
1827c17ccbf6SFinley Xiao #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_KERNEL_BOOT)
1828*2304b5d3SFinley Xiao case CLK_MIPICSI_OUT:
1829*2304b5d3SFinley Xiao ret = rv1126_clk_mipicsi_out_set_clk(priv, rate);
1830*2304b5d3SFinley Xiao break;
1831c17ccbf6SFinley Xiao case CLK_ISP:
1832c17ccbf6SFinley Xiao ret = rv1126_clk_isp_set_clk(priv, rate);
1833c17ccbf6SFinley Xiao break;
1834c17ccbf6SFinley Xiao case ACLK_PDVI:
1835c17ccbf6SFinley Xiao case ACLK_PDISPP:
1836c17ccbf6SFinley Xiao case CLK_ISPP:
1837c17ccbf6SFinley Xiao ret = rv1126_clk_pdvi_ispp_set_clk(priv, clk->id, rate);
1838c17ccbf6SFinley Xiao break;
1839446ef41cSJoseph Chen #endif
18405ecc545eSFinley Xiao case DCLK_DECOM:
18415ecc545eSFinley Xiao ret = rv1126_dclk_decom_set_clk(priv, rate);
18425ecc545eSFinley Xiao break;
1843f95775d6SJoseph Chen default:
1844f95775d6SJoseph Chen return -ENOENT;
1845f95775d6SJoseph Chen }
1846f95775d6SJoseph Chen
1847f95775d6SJoseph Chen return ret;
1848f95775d6SJoseph Chen };
1849f95775d6SJoseph Chen
1850f95775d6SJoseph Chen #define ROCKCHIP_MMC_DELAY_SEL BIT(10)
1851f95775d6SJoseph Chen #define ROCKCHIP_MMC_DEGREE_MASK 0x3
1852f95775d6SJoseph Chen #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
1853f95775d6SJoseph Chen #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
1854f95775d6SJoseph Chen
1855f95775d6SJoseph Chen #define PSECS_PER_SEC 1000000000000LL
1856f95775d6SJoseph Chen /*
1857f95775d6SJoseph Chen * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
1858f95775d6SJoseph Chen * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
1859f95775d6SJoseph Chen */
1860f95775d6SJoseph Chen #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
1861f95775d6SJoseph Chen
rv1126_mmc_get_phase(struct clk * clk)1862f95775d6SJoseph Chen int rv1126_mmc_get_phase(struct clk *clk)
1863f95775d6SJoseph Chen {
1864f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(clk->dev);
1865f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1866f95775d6SJoseph Chen u32 raw_value, delay_num;
1867f95775d6SJoseph Chen u16 degrees = 0;
1868f95775d6SJoseph Chen ulong rate;
1869f95775d6SJoseph Chen
1870f95775d6SJoseph Chen rate = rv1126_clk_get_rate(clk);
1871f95775d6SJoseph Chen if (rate < 0)
1872f95775d6SJoseph Chen return rate;
1873f95775d6SJoseph Chen
1874f95775d6SJoseph Chen if (clk->id == SCLK_EMMC_SAMPLE)
1875f95775d6SJoseph Chen raw_value = readl(&cru->emmc_con[1]);
1876f95775d6SJoseph Chen else if (clk->id == SCLK_SDMMC_SAMPLE)
1877f95775d6SJoseph Chen raw_value = readl(&cru->sdmmc_con[1]);
1878f95775d6SJoseph Chen else
1879f95775d6SJoseph Chen raw_value = readl(&cru->sdio_con[1]);
1880f95775d6SJoseph Chen
1881f95775d6SJoseph Chen raw_value >>= 1;
1882f95775d6SJoseph Chen degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
1883f95775d6SJoseph Chen
1884f95775d6SJoseph Chen if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
1885f95775d6SJoseph Chen /* degrees/delaynum * 10000 */
1886f95775d6SJoseph Chen unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
1887f95775d6SJoseph Chen 36 * (rate / 1000000);
1888f95775d6SJoseph Chen
1889f95775d6SJoseph Chen delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
1890f95775d6SJoseph Chen delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
1891f95775d6SJoseph Chen degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
1892f95775d6SJoseph Chen }
1893f95775d6SJoseph Chen
1894f95775d6SJoseph Chen return degrees % 360;
1895f95775d6SJoseph Chen }
1896f95775d6SJoseph Chen
rv1126_mmc_set_phase(struct clk * clk,u32 degrees)1897f95775d6SJoseph Chen int rv1126_mmc_set_phase(struct clk *clk, u32 degrees)
1898f95775d6SJoseph Chen {
1899f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(clk->dev);
1900f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1901f95775d6SJoseph Chen u8 nineties, remainder, delay_num;
1902f95775d6SJoseph Chen u32 raw_value, delay;
1903f95775d6SJoseph Chen ulong rate;
1904f95775d6SJoseph Chen
1905f95775d6SJoseph Chen rate = rv1126_clk_get_rate(clk);
1906f95775d6SJoseph Chen if (rate < 0)
1907f95775d6SJoseph Chen return rate;
1908f95775d6SJoseph Chen
1909f95775d6SJoseph Chen nineties = degrees / 90;
1910f95775d6SJoseph Chen remainder = (degrees % 90);
1911f95775d6SJoseph Chen
1912f95775d6SJoseph Chen /*
1913f95775d6SJoseph Chen * Convert to delay; do a little extra work to make sure we
1914f95775d6SJoseph Chen * don't overflow 32-bit / 64-bit numbers.
1915f95775d6SJoseph Chen */
1916f95775d6SJoseph Chen delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
1917f95775d6SJoseph Chen delay *= remainder;
1918f95775d6SJoseph Chen delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
1919f95775d6SJoseph Chen (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
1920f95775d6SJoseph Chen
1921f95775d6SJoseph Chen delay_num = (u8)min_t(u32, delay, 255);
1922f95775d6SJoseph Chen
1923f95775d6SJoseph Chen raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
1924f95775d6SJoseph Chen raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
1925f95775d6SJoseph Chen raw_value |= nineties;
1926f95775d6SJoseph Chen
1927f95775d6SJoseph Chen raw_value <<= 1;
1928f95775d6SJoseph Chen if (clk->id == SCLK_EMMC_SAMPLE)
1929f95775d6SJoseph Chen writel(raw_value | 0xffff0000, &cru->emmc_con[1]);
1930f95775d6SJoseph Chen else if (clk->id == SCLK_SDMMC_SAMPLE)
1931f95775d6SJoseph Chen writel(raw_value | 0xffff0000, &cru->sdmmc_con[1]);
1932f95775d6SJoseph Chen else
1933f95775d6SJoseph Chen writel(raw_value | 0xffff0000, &cru->sdio_con[1]);
1934f95775d6SJoseph Chen
1935f95775d6SJoseph Chen debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
1936f95775d6SJoseph Chen degrees, delay_num, raw_value, rv1126_mmc_get_phase(clk));
1937f95775d6SJoseph Chen
1938f95775d6SJoseph Chen return 0;
1939f95775d6SJoseph Chen }
1940f95775d6SJoseph Chen
rv1126_clk_get_phase(struct clk * clk)1941f95775d6SJoseph Chen static int rv1126_clk_get_phase(struct clk *clk)
1942f95775d6SJoseph Chen {
1943f95775d6SJoseph Chen int ret;
1944f95775d6SJoseph Chen
1945f95775d6SJoseph Chen debug("%s %ld\n", __func__, clk->id);
1946f95775d6SJoseph Chen switch (clk->id) {
1947f95775d6SJoseph Chen case SCLK_EMMC_SAMPLE:
1948f95775d6SJoseph Chen case SCLK_SDMMC_SAMPLE:
1949f95775d6SJoseph Chen case SCLK_SDIO_SAMPLE:
1950f95775d6SJoseph Chen ret = rv1126_mmc_get_phase(clk);
1951f95775d6SJoseph Chen break;
1952f95775d6SJoseph Chen default:
1953f95775d6SJoseph Chen return -ENOENT;
1954f95775d6SJoseph Chen }
1955f95775d6SJoseph Chen
1956f95775d6SJoseph Chen return ret;
1957f95775d6SJoseph Chen }
1958f95775d6SJoseph Chen
rv1126_clk_set_phase(struct clk * clk,int degrees)1959f95775d6SJoseph Chen static int rv1126_clk_set_phase(struct clk *clk, int degrees)
1960f95775d6SJoseph Chen {
1961f95775d6SJoseph Chen int ret;
1962f95775d6SJoseph Chen
1963f95775d6SJoseph Chen debug("%s %ld\n", __func__, clk->id);
1964f95775d6SJoseph Chen switch (clk->id) {
1965f95775d6SJoseph Chen case SCLK_EMMC_SAMPLE:
1966f95775d6SJoseph Chen case SCLK_SDMMC_SAMPLE:
1967f95775d6SJoseph Chen case SCLK_SDIO_SAMPLE:
1968f95775d6SJoseph Chen ret = rv1126_mmc_set_phase(clk, degrees);
1969f95775d6SJoseph Chen break;
1970f95775d6SJoseph Chen default:
1971f95775d6SJoseph Chen return -ENOENT;
1972f95775d6SJoseph Chen }
1973f95775d6SJoseph Chen
1974f95775d6SJoseph Chen return ret;
1975f95775d6SJoseph Chen }
1976f95775d6SJoseph Chen
1977f95775d6SJoseph Chen #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
rv1126_gmac_src_set_parent(struct clk * clk,struct clk * parent)1978f95775d6SJoseph Chen static int rv1126_gmac_src_set_parent(struct clk *clk, struct clk *parent)
1979f95775d6SJoseph Chen {
1980f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(clk->dev);
1981f95775d6SJoseph Chen struct rv1126_grf *grf = priv->grf;
1982f95775d6SJoseph Chen
1983f95775d6SJoseph Chen if (parent->id == CLK_GMAC_SRC_M0)
1984f95775d6SJoseph Chen rk_clrsetreg(&grf->iofunc_con1, GMAC_SRC_SEL_MASK,
1985f95775d6SJoseph Chen GMAC_SRC_SEL_M0 << GMAC_SRC_SEL_SHIFT);
1986f95775d6SJoseph Chen else if(parent->id == CLK_GMAC_SRC_M1)
1987f95775d6SJoseph Chen rk_clrsetreg(&grf->iofunc_con1, GMAC_SRC_SEL_MASK,
1988f95775d6SJoseph Chen GMAC_SRC_SEL_M1 << GMAC_SRC_SEL_SHIFT);
1989f95775d6SJoseph Chen
1990f95775d6SJoseph Chen return 0;
1991f95775d6SJoseph Chen }
1992f95775d6SJoseph Chen
rv1126_gmac_src_m0_set_parent(struct clk * clk,struct clk * parent)1993f95775d6SJoseph Chen static int rv1126_gmac_src_m0_set_parent(struct clk *clk, struct clk *parent)
1994f95775d6SJoseph Chen {
1995f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(clk->dev);
1996f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
1997f95775d6SJoseph Chen
1998f95775d6SJoseph Chen if (parent->id == CLK_GMAC_DIV)
1999f95775d6SJoseph Chen rk_clrsetreg(&cru->gmac_con, GMAC_SRC_M0_SEL_MASK,
2000f95775d6SJoseph Chen GMAC_SRC_M0_SEL_INT << GMAC_SRC_M0_SEL_SHIFT);
2001f95775d6SJoseph Chen else
2002b85730d9SFinley Xiao rk_clrsetreg(&cru->gmac_con, GMAC_SRC_M0_SEL_MASK,
2003f95775d6SJoseph Chen GMAC_SRC_M0_SEL_EXT << GMAC_SRC_M0_SEL_SHIFT);
2004f95775d6SJoseph Chen
2005f95775d6SJoseph Chen return 0;
2006f95775d6SJoseph Chen }
2007f95775d6SJoseph Chen
rv1126_gmac_src_m1_set_parent(struct clk * clk,struct clk * parent)2008f95775d6SJoseph Chen static int rv1126_gmac_src_m1_set_parent(struct clk *clk, struct clk *parent)
2009f95775d6SJoseph Chen {
2010f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(clk->dev);
2011f95775d6SJoseph Chen struct rv1126_cru *cru = priv->cru;
2012f95775d6SJoseph Chen
2013f95775d6SJoseph Chen if (parent->id == CLK_GMAC_DIV)
2014b85730d9SFinley Xiao rk_clrsetreg(&cru->gmac_con, GMAC_SRC_M1_SEL_MASK,
2015f95775d6SJoseph Chen GMAC_SRC_M1_SEL_INT << GMAC_SRC_M1_SEL_SHIFT);
2016f95775d6SJoseph Chen else
2017b85730d9SFinley Xiao rk_clrsetreg(&cru->gmac_con, GMAC_SRC_M1_SEL_MASK,
2018f95775d6SJoseph Chen GMAC_SRC_M1_SEL_EXT << GMAC_SRC_M1_SEL_SHIFT);
2019f95775d6SJoseph Chen
2020f95775d6SJoseph Chen return 0;
2021f95775d6SJoseph Chen }
2022f95775d6SJoseph Chen
rv1126_gmac_tx_rx_set_parent(struct clk * clk,struct clk * parent)20232438a166SFinley Xiao static int rv1126_gmac_tx_rx_set_parent(struct clk *clk, struct clk *parent)
20242438a166SFinley Xiao {
20252438a166SFinley Xiao struct rv1126_clk_priv *priv = dev_get_priv(clk->dev);
20262438a166SFinley Xiao struct rv1126_cru *cru = priv->cru;
20272438a166SFinley Xiao
20282438a166SFinley Xiao if (parent->id == RGMII_MODE_CLK)
20292438a166SFinley Xiao rk_clrsetreg(&cru->gmac_con, GMAC_MODE_SEL_MASK,
20302438a166SFinley Xiao GMAC_RGMII_MODE << GMAC_MODE_SEL_SHIFT);
20312438a166SFinley Xiao else
20322438a166SFinley Xiao rk_clrsetreg(&cru->gmac_con, GMAC_MODE_SEL_MASK,
20332438a166SFinley Xiao GMAC_RMII_MODE << GMAC_MODE_SEL_SHIFT);
20342438a166SFinley Xiao
20352438a166SFinley Xiao return 0;
20362438a166SFinley Xiao }
20372438a166SFinley Xiao
rv1126_clk_set_parent(struct clk * clk,struct clk * parent)2038f95775d6SJoseph Chen static int rv1126_clk_set_parent(struct clk *clk, struct clk *parent)
2039f95775d6SJoseph Chen {
2040f95775d6SJoseph Chen switch (clk->id) {
2041f95775d6SJoseph Chen case CLK_GMAC_SRC:
2042f95775d6SJoseph Chen return rv1126_gmac_src_set_parent(clk, parent);
2043f95775d6SJoseph Chen case CLK_GMAC_SRC_M0:
2044f95775d6SJoseph Chen return rv1126_gmac_src_m0_set_parent(clk, parent);
2045f95775d6SJoseph Chen case CLK_GMAC_SRC_M1:
2046f95775d6SJoseph Chen return rv1126_gmac_src_m1_set_parent(clk, parent);
20472438a166SFinley Xiao case CLK_GMAC_TX_RX:
20482438a166SFinley Xiao return rv1126_gmac_tx_rx_set_parent(clk, parent);
2049f95775d6SJoseph Chen default:
2050f95775d6SJoseph Chen return -ENOENT;
2051f95775d6SJoseph Chen }
2052f95775d6SJoseph Chen
2053f95775d6SJoseph Chen return 0;
2054f95775d6SJoseph Chen }
2055f95775d6SJoseph Chen #endif
2056f95775d6SJoseph Chen
2057f95775d6SJoseph Chen static struct clk_ops rv1126_clk_ops = {
2058f95775d6SJoseph Chen .get_rate = rv1126_clk_get_rate,
2059f95775d6SJoseph Chen .set_rate = rv1126_clk_set_rate,
2060f95775d6SJoseph Chen .get_phase = rv1126_clk_get_phase,
2061f95775d6SJoseph Chen .set_phase = rv1126_clk_set_phase,
2062f95775d6SJoseph Chen #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
2063f95775d6SJoseph Chen .set_parent = rv1126_clk_set_parent,
2064f95775d6SJoseph Chen #endif
2065f95775d6SJoseph Chen };
2066f95775d6SJoseph Chen
rv1126_gpll_set_rate(struct rv1126_clk_priv * priv,struct rv1126_pmuclk_priv * pmu_priv,ulong rate)2067f96f0122SFinley Xiao static ulong rv1126_gpll_set_rate(struct rv1126_clk_priv *priv,
2068f96f0122SFinley Xiao struct rv1126_pmuclk_priv *pmu_priv,
2069f96f0122SFinley Xiao ulong rate)
2070f96f0122SFinley Xiao {
2071f96f0122SFinley Xiao ulong emmc_rate, sfc_rate, nandc_rate;
2072200899f9SFinley Xiao bool restore = false;
2073f96f0122SFinley Xiao
2074200899f9SFinley Xiao if (priv->gpll_hz != OSC_HZ) {
2075f96f0122SFinley Xiao emmc_rate = rv1126_mmc_get_clk(priv, CLK_EMMC);
2076f96f0122SFinley Xiao sfc_rate = rv1126_sfc_get_clk(priv);
2077f96f0122SFinley Xiao nandc_rate = rv1126_nand_get_clk(priv);
2078200899f9SFinley Xiao debug("%s emmc=%lu, sfc=%lu, nandc=%lu\n", __func__,
2079f96f0122SFinley Xiao emmc_rate, sfc_rate, nandc_rate);
2080200899f9SFinley Xiao restore = true;
2081200899f9SFinley Xiao }
2082f96f0122SFinley Xiao
2083f96f0122SFinley Xiao /*
2084f96f0122SFinley Xiao * the child div is big enough for gpll 1188MHz,
2085f96f0122SFinley Xiao * even maskrom has change some clocks.
2086f96f0122SFinley Xiao */
2087f96f0122SFinley Xiao if (rockchip_pll_set_rate(&rv1126_pll_clks[GPLL],
2088f96f0122SFinley Xiao pmu_priv->pmucru, GPLL, rate))
2089f96f0122SFinley Xiao return -EINVAL;
2090f96f0122SFinley Xiao pmu_priv->gpll_hz = rate;
2091f96f0122SFinley Xiao priv->gpll_hz = rate;
2092f96f0122SFinley Xiao
2093200899f9SFinley Xiao if (restore) {
2094f96f0122SFinley Xiao rv1126_mmc_set_clk(priv, CLK_EMMC, emmc_rate);
2095f96f0122SFinley Xiao rv1126_sfc_set_clk(priv, sfc_rate);
2096f96f0122SFinley Xiao rv1126_nand_set_clk(priv, nandc_rate);
2097200899f9SFinley Xiao }
2098f96f0122SFinley Xiao
2099ffe82b33SFinley Xiao return 0;
2100f96f0122SFinley Xiao }
2101f96f0122SFinley Xiao
rv1126_gpll_set_clk(struct rv1126_clk_priv * priv,ulong rate)2102f96f0122SFinley Xiao static int rv1126_gpll_set_clk(struct rv1126_clk_priv *priv, ulong rate)
2103f95775d6SJoseph Chen {
2104f95775d6SJoseph Chen struct udevice *pmucru_dev;
2105f96f0122SFinley Xiao struct rv1126_pmuclk_priv *pmu_priv;
2106f95775d6SJoseph Chen int ret;
2107f95775d6SJoseph Chen
2108f95775d6SJoseph Chen ret = uclass_get_device_by_driver(UCLASS_CLK,
2109f95775d6SJoseph Chen DM_GET_DRIVER(rockchip_rv1126_pmucru),
2110f95775d6SJoseph Chen &pmucru_dev);
2111f95775d6SJoseph Chen if (ret) {
2112f95775d6SJoseph Chen printf("%s: could not find pmucru device\n", __func__);
2113f95775d6SJoseph Chen return ret;
2114f95775d6SJoseph Chen }
2115f96f0122SFinley Xiao pmu_priv = dev_get_priv(pmucru_dev);
211609458791SFinley Xiao priv->gpll_hz = pmu_priv->gpll_hz;
2117f95775d6SJoseph Chen
2118f96f0122SFinley Xiao if (rv1126_gpll_set_rate(priv, pmu_priv, rate)) {
2119f95775d6SJoseph Chen printf("%s: failed to set gpll rate %lu\n", __func__, rate);
2120f96f0122SFinley Xiao return -EINVAL;
2121f95775d6SJoseph Chen }
2122f95775d6SJoseph Chen
2123f96f0122SFinley Xiao rv1126_pdpmu_set_pmuclk(pmu_priv, PCLK_PDPMU_HZ);
212456a06ac8SFinley Xiao rv1126_rtc32k_set_pmuclk(pmu_priv, CLK_OSC0_DIV_HZ);
2125f96f0122SFinley Xiao
2126f96f0122SFinley Xiao return 0;
2127f95775d6SJoseph Chen }
2128f95775d6SJoseph Chen
rv1126_clk_init(struct rv1126_clk_priv * priv)2129f95775d6SJoseph Chen static void rv1126_clk_init(struct rv1126_clk_priv *priv)
2130f95775d6SJoseph Chen {
2131f95775d6SJoseph Chen int ret;
2132f95775d6SJoseph Chen
2133f95775d6SJoseph Chen priv->sync_kernel = false;
2134f95775d6SJoseph Chen if (!priv->armclk_enter_hz) {
2135f95775d6SJoseph Chen priv->armclk_enter_hz =
2136f95775d6SJoseph Chen rockchip_pll_get_rate(&rv1126_pll_clks[APLL],
2137f95775d6SJoseph Chen priv->cru, APLL);
2138f95775d6SJoseph Chen priv->armclk_init_hz = priv->armclk_enter_hz ;
2139f95775d6SJoseph Chen }
2140f95775d6SJoseph Chen
2141f95775d6SJoseph Chen if (priv->armclk_init_hz != APLL_HZ) {
2142f95775d6SJoseph Chen ret = rv1126_armclk_set_clk(priv, APLL_HZ);
2143f95775d6SJoseph Chen if (!ret)
2144f95775d6SJoseph Chen priv->armclk_init_hz = APLL_HZ;
2145f95775d6SJoseph Chen }
2146f95775d6SJoseph Chen if (priv->cpll_hz != CPLL_HZ) {
2147f95775d6SJoseph Chen ret = rockchip_pll_set_rate(&rv1126_pll_clks[CPLL], priv->cru,
2148f95775d6SJoseph Chen CPLL, CPLL_HZ);
2149f95775d6SJoseph Chen if (!ret)
2150f95775d6SJoseph Chen priv->cpll_hz = CPLL_HZ;
2151f95775d6SJoseph Chen }
215256a06ac8SFinley Xiao if (priv->hpll_hz != HPLL_HZ) {
215356a06ac8SFinley Xiao ret = rockchip_pll_set_rate(&rv1126_pll_clks[HPLL], priv->cru,
215456a06ac8SFinley Xiao HPLL, HPLL_HZ);
215556a06ac8SFinley Xiao if (!ret)
215656a06ac8SFinley Xiao priv->hpll_hz = HPLL_HZ;
215756a06ac8SFinley Xiao }
2158200899f9SFinley Xiao if (priv->gpll_hz != GPLL_HZ)
2159200899f9SFinley Xiao rv1126_gpll_set_clk(priv, GPLL_HZ);
2160200899f9SFinley Xiao
2161f95775d6SJoseph Chen rv1126_pdbus_set_clk(priv, ACLK_PDBUS, ACLK_PDBUS_HZ);
2162f95775d6SJoseph Chen rv1126_pdbus_set_clk(priv, HCLK_PDBUS, HCLK_PDBUS_HZ);
2163f95775d6SJoseph Chen rv1126_pdbus_set_clk(priv, PCLK_PDBUS, PCLK_PDBUS_HZ);
2164f95775d6SJoseph Chen rv1126_pdphp_set_clk(priv, ACLK_PDPHP, ACLK_PDPHP_HZ);
2165f95775d6SJoseph Chen rv1126_pdphp_set_clk(priv, HCLK_PDPHP, HCLK_PDPHP_HZ);
2166f95775d6SJoseph Chen rv1126_pdcore_set_clk(priv, HCLK_PDCORE_HZ);
2167f95775d6SJoseph Chen rv1126_pdaudio_set_clk(priv, HCLK_PDAUDIO_HZ);
21685410c5c2SFinley Xiao #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_KERNEL_BOOT)
21695410c5c2SFinley Xiao rv1126_clk_pdvi_ispp_set_clk(priv, ACLK_PDVI, ACLK_PDVI_HZ);
21705410c5c2SFinley Xiao rv1126_clk_isp_set_clk(priv, CLK_ISP_HZ);
21715410c5c2SFinley Xiao rv1126_clk_pdvi_ispp_set_clk(priv, ACLK_PDISPP, ACLK_PDISPP_HZ);
21725410c5c2SFinley Xiao rv1126_clk_pdvi_ispp_set_clk(priv, CLK_ISPP, CLK_ISPP_HZ);
21735410c5c2SFinley Xiao rv1126_aclk_vop_set_clk(priv, ACLK_VOP_HZ);
21745410c5c2SFinley Xiao rv1126_dclk_vop_set_clk(priv, DCLK_VOP_HZ);
21755410c5c2SFinley Xiao #endif
2176f95775d6SJoseph Chen }
2177f95775d6SJoseph Chen
rv1126_clk_probe(struct udevice * dev)2178f95775d6SJoseph Chen static int rv1126_clk_probe(struct udevice *dev)
2179f95775d6SJoseph Chen {
2180f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(dev);
2181f95775d6SJoseph Chen int ret;
2182f95775d6SJoseph Chen
2183f95775d6SJoseph Chen priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
2184f95775d6SJoseph Chen if (IS_ERR(priv->grf))
2185f95775d6SJoseph Chen return PTR_ERR(priv->grf);
2186f95775d6SJoseph Chen
2187f95775d6SJoseph Chen rv1126_clk_init(priv);
2188f95775d6SJoseph Chen
2189f95775d6SJoseph Chen /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
2190f95775d6SJoseph Chen ret = clk_set_defaults(dev);
2191f95775d6SJoseph Chen if (ret)
2192f95775d6SJoseph Chen debug("%s clk_set_defaults failed %d\n", __func__, ret);
2193f95775d6SJoseph Chen else
2194f95775d6SJoseph Chen priv->sync_kernel = true;
2195f95775d6SJoseph Chen
2196f95775d6SJoseph Chen return 0;
2197f95775d6SJoseph Chen }
2198f95775d6SJoseph Chen
rv1126_clk_ofdata_to_platdata(struct udevice * dev)2199f95775d6SJoseph Chen static int rv1126_clk_ofdata_to_platdata(struct udevice *dev)
2200f95775d6SJoseph Chen {
2201f95775d6SJoseph Chen struct rv1126_clk_priv *priv = dev_get_priv(dev);
2202f95775d6SJoseph Chen
2203f95775d6SJoseph Chen priv->cru = dev_read_addr_ptr(dev);
2204f95775d6SJoseph Chen
2205f95775d6SJoseph Chen return 0;
2206f95775d6SJoseph Chen }
2207f95775d6SJoseph Chen
rv1126_clk_bind(struct udevice * dev)2208f95775d6SJoseph Chen static int rv1126_clk_bind(struct udevice *dev)
2209f95775d6SJoseph Chen {
2210f95775d6SJoseph Chen int ret;
2211f95775d6SJoseph Chen struct udevice *sys_child, *sf_child;
2212f95775d6SJoseph Chen struct sysreset_reg *priv;
2213f95775d6SJoseph Chen struct softreset_reg *sf_priv;
2214f95775d6SJoseph Chen
2215f95775d6SJoseph Chen /* The reset driver does not have a device node, so bind it here */
2216f95775d6SJoseph Chen ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
2217f95775d6SJoseph Chen &sys_child);
2218f95775d6SJoseph Chen if (ret) {
2219f95775d6SJoseph Chen debug("Warning: No sysreset driver: ret=%d\n", ret);
2220f95775d6SJoseph Chen } else {
2221f95775d6SJoseph Chen priv = malloc(sizeof(struct sysreset_reg));
2222f95775d6SJoseph Chen priv->glb_srst_fst_value = offsetof(struct rv1126_cru,
2223f95775d6SJoseph Chen glb_srst_fst);
2224f95775d6SJoseph Chen priv->glb_srst_snd_value = offsetof(struct rv1126_cru,
2225f95775d6SJoseph Chen glb_srst_snd);
2226f95775d6SJoseph Chen sys_child->priv = priv;
2227f95775d6SJoseph Chen }
2228f95775d6SJoseph Chen
2229f95775d6SJoseph Chen ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
2230f95775d6SJoseph Chen dev_ofnode(dev), &sf_child);
2231f95775d6SJoseph Chen if (ret) {
2232f95775d6SJoseph Chen debug("Warning: No rockchip reset driver: ret=%d\n", ret);
2233f95775d6SJoseph Chen } else {
2234f95775d6SJoseph Chen sf_priv = malloc(sizeof(struct softreset_reg));
2235f95775d6SJoseph Chen sf_priv->sf_reset_offset = offsetof(struct rv1126_cru,
2236f95775d6SJoseph Chen softrst_con[0]);
2237f95775d6SJoseph Chen sf_priv->sf_reset_num = 15;
2238f95775d6SJoseph Chen sf_child->priv = sf_priv;
2239f95775d6SJoseph Chen }
2240f95775d6SJoseph Chen
2241f95775d6SJoseph Chen return 0;
2242f95775d6SJoseph Chen }
2243f95775d6SJoseph Chen
2244f95775d6SJoseph Chen static const struct udevice_id rv1126_clk_ids[] = {
2245f95775d6SJoseph Chen { .compatible = "rockchip,rv1126-cru" },
2246f95775d6SJoseph Chen { }
2247f95775d6SJoseph Chen };
2248f95775d6SJoseph Chen
2249f95775d6SJoseph Chen U_BOOT_DRIVER(rockchip_rv1126_cru) = {
2250f95775d6SJoseph Chen .name = "rockchip_rv1126_cru",
2251f95775d6SJoseph Chen .id = UCLASS_CLK,
2252f95775d6SJoseph Chen .of_match = rv1126_clk_ids,
2253f95775d6SJoseph Chen .priv_auto_alloc_size = sizeof(struct rv1126_clk_priv),
2254f95775d6SJoseph Chen .ofdata_to_platdata = rv1126_clk_ofdata_to_platdata,
2255f95775d6SJoseph Chen .ops = &rv1126_clk_ops,
2256f95775d6SJoseph Chen .bind = rv1126_clk_bind,
2257f95775d6SJoseph Chen .probe = rv1126_clk_probe,
2258f95775d6SJoseph Chen };
2259f95775d6SJoseph Chen
2260f95775d6SJoseph Chen #ifndef CONFIG_SPL_BUILD
2261f95775d6SJoseph Chen /**
2262f95775d6SJoseph Chen * soc_clk_dump() - Print clock frequencies
2263f95775d6SJoseph Chen * Returns zero on success
2264f95775d6SJoseph Chen *
2265f95775d6SJoseph Chen * Implementation for the clk dump command.
2266f95775d6SJoseph Chen */
soc_clk_dump(void)2267f95775d6SJoseph Chen int soc_clk_dump(void)
2268f95775d6SJoseph Chen {
2269f95775d6SJoseph Chen struct udevice *cru_dev, *pmucru_dev;
2270f95775d6SJoseph Chen struct rv1126_clk_priv *priv;
2271f95775d6SJoseph Chen const struct rv1126_clk_info *clk_dump;
2272f95775d6SJoseph Chen struct clk clk;
2273f95775d6SJoseph Chen unsigned long clk_count = ARRAY_SIZE(clks_dump);
2274f95775d6SJoseph Chen unsigned long rate;
2275f95775d6SJoseph Chen int i, ret;
2276f95775d6SJoseph Chen
2277f95775d6SJoseph Chen ret = uclass_get_device_by_driver(UCLASS_CLK,
2278f95775d6SJoseph Chen DM_GET_DRIVER(rockchip_rv1126_cru),
2279f95775d6SJoseph Chen &cru_dev);
2280f95775d6SJoseph Chen if (ret) {
2281f95775d6SJoseph Chen printf("%s failed to get cru device\n", __func__);
2282f95775d6SJoseph Chen return ret;
2283f95775d6SJoseph Chen }
2284f95775d6SJoseph Chen
2285f95775d6SJoseph Chen ret = uclass_get_device_by_driver(UCLASS_CLK,
2286f95775d6SJoseph Chen DM_GET_DRIVER(rockchip_rv1126_pmucru),
2287f95775d6SJoseph Chen &pmucru_dev);
2288f95775d6SJoseph Chen if (ret) {
2289f95775d6SJoseph Chen printf("%s failed to get pmucru device\n", __func__);
2290f95775d6SJoseph Chen return ret;
2291f95775d6SJoseph Chen }
2292f95775d6SJoseph Chen
2293f95775d6SJoseph Chen priv = dev_get_priv(cru_dev);
2294f95775d6SJoseph Chen printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
2295f95775d6SJoseph Chen priv->sync_kernel ? "sync kernel" : "uboot",
2296f95775d6SJoseph Chen priv->armclk_enter_hz / 1000,
2297f95775d6SJoseph Chen priv->armclk_init_hz / 1000,
2298f95775d6SJoseph Chen priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
2299f95775d6SJoseph Chen priv->set_armclk_rate ? " KHz" : "N/A");
2300f95775d6SJoseph Chen for (i = 0; i < clk_count; i++) {
2301f95775d6SJoseph Chen clk_dump = &clks_dump[i];
2302f95775d6SJoseph Chen if (clk_dump->name) {
2303f95775d6SJoseph Chen clk.id = clk_dump->id;
2304f95775d6SJoseph Chen if (clk_dump->is_cru)
2305f95775d6SJoseph Chen ret = clk_request(cru_dev, &clk);
2306f95775d6SJoseph Chen else
2307f95775d6SJoseph Chen ret = clk_request(pmucru_dev, &clk);
2308f95775d6SJoseph Chen if (ret < 0)
2309f95775d6SJoseph Chen return ret;
2310f95775d6SJoseph Chen
2311f95775d6SJoseph Chen rate = clk_get_rate(&clk);
2312f95775d6SJoseph Chen clk_free(&clk);
2313f95775d6SJoseph Chen if (i == 0) {
2314f95775d6SJoseph Chen if (rate < 0)
2315f95775d6SJoseph Chen printf(" %s %s\n", clk_dump->name,
2316f95775d6SJoseph Chen "unknown");
2317f95775d6SJoseph Chen else
2318f95775d6SJoseph Chen printf(" %s %lu KHz\n", clk_dump->name,
2319f95775d6SJoseph Chen rate / 1000);
2320f95775d6SJoseph Chen } else {
2321f95775d6SJoseph Chen if (rate < 0)
2322f95775d6SJoseph Chen printf(" %s %s\n", clk_dump->name,
2323f95775d6SJoseph Chen "unknown");
2324f95775d6SJoseph Chen else
2325f95775d6SJoseph Chen printf(" %s %lu KHz\n", clk_dump->name,
2326f95775d6SJoseph Chen rate / 1000);
2327f95775d6SJoseph Chen }
2328f95775d6SJoseph Chen }
2329f95775d6SJoseph Chen }
2330f95775d6SJoseph Chen
2331f95775d6SJoseph Chen return 0;
2332f95775d6SJoseph Chen }
2333f95775d6SJoseph Chen #endif
2334