1*76f3cd6aSElaine Zhang // SPDX-License-Identifier: GPL-2.0
2*76f3cd6aSElaine Zhang /*
3*76f3cd6aSElaine Zhang * Copyright (c) 2024 Rockchip Electronics Co., Ltd
4*76f3cd6aSElaine Zhang * Author: Elaine Zhang <zhangqing@rock-chips.com>
5*76f3cd6aSElaine Zhang */
6*76f3cd6aSElaine Zhang
7*76f3cd6aSElaine Zhang #include <common.h>
8*76f3cd6aSElaine Zhang #include <bitfield.h>
9*76f3cd6aSElaine Zhang #include <clk-uclass.h>
10*76f3cd6aSElaine Zhang #include <dm.h>
11*76f3cd6aSElaine Zhang #include <errno.h>
12*76f3cd6aSElaine Zhang #include <syscon.h>
13*76f3cd6aSElaine Zhang #include <asm/arch/clock.h>
14*76f3cd6aSElaine Zhang #include <asm/arch/cru_rv1103b.h>
15*76f3cd6aSElaine Zhang #include <asm/arch/grf_rv1103b.h>
16*76f3cd6aSElaine Zhang #include <asm/arch/hardware.h>
17*76f3cd6aSElaine Zhang #include <asm/io.h>
18*76f3cd6aSElaine Zhang #include <dm/lists.h>
19*76f3cd6aSElaine Zhang #include <dt-bindings/clock/rockchip,rv1103b-cru.h>
20*76f3cd6aSElaine Zhang
21*76f3cd6aSElaine Zhang DECLARE_GLOBAL_DATA_PTR;
22*76f3cd6aSElaine Zhang
23*76f3cd6aSElaine Zhang #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
24*76f3cd6aSElaine Zhang
25*76f3cd6aSElaine Zhang #ifdef CONFIG_SPL_BUILD
26*76f3cd6aSElaine Zhang #ifndef BITS_WITH_WMASK
27*76f3cd6aSElaine Zhang #define BITS_WITH_WMASK(bits, msk, shift) \
28*76f3cd6aSElaine Zhang ((bits) << (shift)) | ((msk) << ((shift) + 16))
29*76f3cd6aSElaine Zhang #endif
30*76f3cd6aSElaine Zhang #endif
31*76f3cd6aSElaine Zhang
32*76f3cd6aSElaine Zhang static struct rockchip_pll_rate_table rv1103b_pll_rates[] = {
33*76f3cd6aSElaine Zhang /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
34*76f3cd6aSElaine Zhang RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
35*76f3cd6aSElaine Zhang RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
36*76f3cd6aSElaine Zhang { /* sentinel */ },
37*76f3cd6aSElaine Zhang };
38*76f3cd6aSElaine Zhang
39*76f3cd6aSElaine Zhang static struct rockchip_pll_clock rv1103b_pll_clks[] = {
40*76f3cd6aSElaine Zhang [GPLL] = PLL(pll_rk3328, PLL_GPLL, RV1103B_PLL_CON(24),
41*76f3cd6aSElaine Zhang RV1103B_MODE_CON, 0, 10, 0, rv1103b_pll_rates),
42*76f3cd6aSElaine Zhang };
43*76f3cd6aSElaine Zhang
44*76f3cd6aSElaine Zhang #ifndef CONFIG_SPL_BUILD
45*76f3cd6aSElaine Zhang #define RV1103B_CLK_DUMP(_id, _name, _iscru) \
46*76f3cd6aSElaine Zhang { \
47*76f3cd6aSElaine Zhang .id = _id, \
48*76f3cd6aSElaine Zhang .name = _name, \
49*76f3cd6aSElaine Zhang .is_cru = _iscru, \
50*76f3cd6aSElaine Zhang }
51*76f3cd6aSElaine Zhang
52*76f3cd6aSElaine Zhang static const struct rv1103b_clk_info clks_dump[] = {
53*76f3cd6aSElaine Zhang RV1103B_CLK_DUMP(PLL_GPLL, "gpll", true),
54*76f3cd6aSElaine Zhang RV1103B_CLK_DUMP(ACLK_PERI_SRC, "aclk_peri_src", true),
55*76f3cd6aSElaine Zhang RV1103B_CLK_DUMP(LSCLK_PERI_SRC, "lsclk_peri_src", true),
56*76f3cd6aSElaine Zhang RV1103B_CLK_DUMP(PCLK_PERI_ROOT, "pclk_peri_root", true),
57*76f3cd6aSElaine Zhang RV1103B_CLK_DUMP(PCLK_TOP_ROOT, "pclk_top_root", true),
58*76f3cd6aSElaine Zhang RV1103B_CLK_DUMP(LSCLK_PMU_ROOT, "lsclk_pmu_root", true),
59*76f3cd6aSElaine Zhang };
60*76f3cd6aSElaine Zhang #endif
61*76f3cd6aSElaine Zhang
rv1103b_peri_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)62*76f3cd6aSElaine Zhang static ulong rv1103b_peri_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
63*76f3cd6aSElaine Zhang {
64*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
65*76f3cd6aSElaine Zhang u32 con, sel, div, rate, prate;
66*76f3cd6aSElaine Zhang
67*76f3cd6aSElaine Zhang switch (clk_id) {
68*76f3cd6aSElaine Zhang case ACLK_PERI_SRC:
69*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[31]);
70*76f3cd6aSElaine Zhang sel = (con & ACLK_PERI_SEL_MASK) >> ACLK_PERI_SEL_SHIFT;
71*76f3cd6aSElaine Zhang if (sel == ACLK_PERI_SEL_600M)
72*76f3cd6aSElaine Zhang rate = 600 * MHz;
73*76f3cd6aSElaine Zhang else if (sel == ACLK_PERI_SEL_480M)
74*76f3cd6aSElaine Zhang rate = 480 * MHz;
75*76f3cd6aSElaine Zhang else
76*76f3cd6aSElaine Zhang rate = 400 * MHz;
77*76f3cd6aSElaine Zhang break;
78*76f3cd6aSElaine Zhang case LSCLK_PERI_SRC:
79*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[31]);
80*76f3cd6aSElaine Zhang sel = (con & LSCLK_PERI_SEL_MASK) >> LSCLK_PERI_SEL_SHIFT;
81*76f3cd6aSElaine Zhang if (sel == LSCLK_PERI_SEL_300M)
82*76f3cd6aSElaine Zhang rate = 300 * MHz;
83*76f3cd6aSElaine Zhang else
84*76f3cd6aSElaine Zhang rate = 200 * MHz;
85*76f3cd6aSElaine Zhang break;
86*76f3cd6aSElaine Zhang case PCLK_PERI_ROOT:
87*76f3cd6aSElaine Zhang con = readl(&cru->peri_clksel_con[0]);
88*76f3cd6aSElaine Zhang div = (con & PCLK_PERI_DIV_MASK) >> PCLK_PERI_DIV_SHIFT;
89*76f3cd6aSElaine Zhang rate = DIV_TO_RATE(rv1103b_peri_get_clk(priv, LSCLK_PERI_SRC),
90*76f3cd6aSElaine Zhang div);
91*76f3cd6aSElaine Zhang break;
92*76f3cd6aSElaine Zhang case PCLK_TOP_ROOT:
93*76f3cd6aSElaine Zhang rate = DIV_TO_RATE(priv->gpll_hz, 11);
94*76f3cd6aSElaine Zhang break;
95*76f3cd6aSElaine Zhang case LSCLK_PMU_ROOT:
96*76f3cd6aSElaine Zhang case PCLK_PMU:
97*76f3cd6aSElaine Zhang con = readl(&cru->pmu_clksel_con[2]);
98*76f3cd6aSElaine Zhang sel = (con & LSCLK_PMU_SEL_MASK) >> LSCLK_PMU_SEL_SHIFT;
99*76f3cd6aSElaine Zhang div = (con & LSCLK_PMU_DIV_MASK) >> LSCLK_PMU_DIV_SHIFT;
100*76f3cd6aSElaine Zhang if (sel == LSCLK_PMU_SEL_24M)
101*76f3cd6aSElaine Zhang prate = OSC_HZ;
102*76f3cd6aSElaine Zhang else
103*76f3cd6aSElaine Zhang prate = RC_OSC_HZ;
104*76f3cd6aSElaine Zhang rate = DIV_TO_RATE(prate, div);
105*76f3cd6aSElaine Zhang break;
106*76f3cd6aSElaine Zhang default:
107*76f3cd6aSElaine Zhang return -ENOENT;
108*76f3cd6aSElaine Zhang }
109*76f3cd6aSElaine Zhang
110*76f3cd6aSElaine Zhang return rate;
111*76f3cd6aSElaine Zhang }
112*76f3cd6aSElaine Zhang
rv1103b_peri_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)113*76f3cd6aSElaine Zhang static ulong rv1103b_peri_set_clk(struct rv1103b_clk_priv *priv,
114*76f3cd6aSElaine Zhang ulong clk_id, ulong rate)
115*76f3cd6aSElaine Zhang {
116*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
117*76f3cd6aSElaine Zhang int src_clk, div;
118*76f3cd6aSElaine Zhang
119*76f3cd6aSElaine Zhang switch (clk_id) {
120*76f3cd6aSElaine Zhang case ACLK_PERI_SRC:
121*76f3cd6aSElaine Zhang if (rate >= 594 * MHz)
122*76f3cd6aSElaine Zhang src_clk = ACLK_PERI_SEL_600M;
123*76f3cd6aSElaine Zhang else if (rate >= 480 * MHz)
124*76f3cd6aSElaine Zhang src_clk = ACLK_PERI_SEL_480M;
125*76f3cd6aSElaine Zhang else
126*76f3cd6aSElaine Zhang src_clk = ACLK_PERI_SEL_400M;
127*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[31],
128*76f3cd6aSElaine Zhang ACLK_PERI_SEL_MASK,
129*76f3cd6aSElaine Zhang src_clk << ACLK_PERI_SEL_SHIFT);
130*76f3cd6aSElaine Zhang break;
131*76f3cd6aSElaine Zhang case LSCLK_PERI_SRC:
132*76f3cd6aSElaine Zhang if (rate >= 297 * MHz)
133*76f3cd6aSElaine Zhang src_clk = LSCLK_PERI_SEL_300M;
134*76f3cd6aSElaine Zhang else
135*76f3cd6aSElaine Zhang src_clk = LSCLK_PERI_SEL_200M;
136*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[31],
137*76f3cd6aSElaine Zhang LSCLK_PERI_SEL_MASK,
138*76f3cd6aSElaine Zhang src_clk << LSCLK_PERI_SEL_SHIFT);
139*76f3cd6aSElaine Zhang break;
140*76f3cd6aSElaine Zhang case PCLK_PERI_ROOT:
141*76f3cd6aSElaine Zhang div = DIV_ROUND_UP(rv1103b_peri_get_clk(priv, LSCLK_PERI_SRC),
142*76f3cd6aSElaine Zhang rate);
143*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[0],
144*76f3cd6aSElaine Zhang PCLK_PERI_DIV_MASK,
145*76f3cd6aSElaine Zhang (div - 1) << PCLK_PERI_DIV_SHIFT);
146*76f3cd6aSElaine Zhang break;
147*76f3cd6aSElaine Zhang case PCLK_TOP_ROOT:
148*76f3cd6aSElaine Zhang break;
149*76f3cd6aSElaine Zhang case LSCLK_PMU_ROOT:
150*76f3cd6aSElaine Zhang case PCLK_PMU:
151*76f3cd6aSElaine Zhang if (!(OSC_HZ % rate)) {
152*76f3cd6aSElaine Zhang src_clk = LSCLK_PMU_SEL_24M;
153*76f3cd6aSElaine Zhang div = DIV_ROUND_UP(OSC_HZ, rate);
154*76f3cd6aSElaine Zhang } else {
155*76f3cd6aSElaine Zhang src_clk = LSCLK_PMU_SEL_RC_OSC;
156*76f3cd6aSElaine Zhang div = DIV_ROUND_UP(RC_OSC_HZ, rate);
157*76f3cd6aSElaine Zhang }
158*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->pmu_clksel_con[2],
159*76f3cd6aSElaine Zhang LSCLK_PMU_SEL_MASK | LSCLK_PMU_DIV_MASK,
160*76f3cd6aSElaine Zhang (src_clk << LSCLK_PMU_SEL_SHIFT) |
161*76f3cd6aSElaine Zhang ((div - 1) << LSCLK_PMU_DIV_SHIFT));
162*76f3cd6aSElaine Zhang break;
163*76f3cd6aSElaine Zhang default:
164*76f3cd6aSElaine Zhang printf("do not support this permid freq\n");
165*76f3cd6aSElaine Zhang return -EINVAL;
166*76f3cd6aSElaine Zhang }
167*76f3cd6aSElaine Zhang
168*76f3cd6aSElaine Zhang return rv1103b_peri_get_clk(priv, clk_id);
169*76f3cd6aSElaine Zhang }
170*76f3cd6aSElaine Zhang
rv1103b_i2c_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)171*76f3cd6aSElaine Zhang static ulong rv1103b_i2c_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
172*76f3cd6aSElaine Zhang {
173*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
174*76f3cd6aSElaine Zhang u32 sel, con;
175*76f3cd6aSElaine Zhang ulong rate;
176*76f3cd6aSElaine Zhang
177*76f3cd6aSElaine Zhang switch (clk_id) {
178*76f3cd6aSElaine Zhang case CLK_I2C1:
179*76f3cd6aSElaine Zhang case CLK_I2C2:
180*76f3cd6aSElaine Zhang case CLK_I2C3:
181*76f3cd6aSElaine Zhang case CLK_I2C4:
182*76f3cd6aSElaine Zhang case CLK_I2C_PERI:
183*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[34]);
184*76f3cd6aSElaine Zhang sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT;
185*76f3cd6aSElaine Zhang break;
186*76f3cd6aSElaine Zhang case CLK_I2C0:
187*76f3cd6aSElaine Zhang case CLK_I2C_PMU:
188*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[34]);
189*76f3cd6aSElaine Zhang sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT;
190*76f3cd6aSElaine Zhang break;
191*76f3cd6aSElaine Zhang default:
192*76f3cd6aSElaine Zhang return -ENOENT;
193*76f3cd6aSElaine Zhang }
194*76f3cd6aSElaine Zhang
195*76f3cd6aSElaine Zhang if (sel == CLK_I2C_SEL_100M)
196*76f3cd6aSElaine Zhang rate = 100 * MHz;
197*76f3cd6aSElaine Zhang else
198*76f3cd6aSElaine Zhang rate = OSC_HZ;
199*76f3cd6aSElaine Zhang
200*76f3cd6aSElaine Zhang return rate;
201*76f3cd6aSElaine Zhang }
202*76f3cd6aSElaine Zhang
rv1103b_crypto_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)203*76f3cd6aSElaine Zhang static ulong rv1103b_crypto_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
204*76f3cd6aSElaine Zhang {
205*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
206*76f3cd6aSElaine Zhang u32 sel, con, rate;
207*76f3cd6aSElaine Zhang
208*76f3cd6aSElaine Zhang switch (clk_id) {
209*76f3cd6aSElaine Zhang case ACLK_CRYPTO:
210*76f3cd6aSElaine Zhang case HCLK_CRYPTO:
211*76f3cd6aSElaine Zhang case HCLK_RK_RNG_NS:
212*76f3cd6aSElaine Zhang case HCLK_RK_RNG_S:
213*76f3cd6aSElaine Zhang return rv1103b_peri_get_clk(priv, LSCLK_PERI_SRC);
214*76f3cd6aSElaine Zhang case CLK_CORE_CRYPTO:
215*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[35]);
216*76f3cd6aSElaine Zhang sel = (con & CLK_CORE_CRYPTO_SEL_MASK) >>
217*76f3cd6aSElaine Zhang CLK_CORE_CRYPTO_SEL_SHIFT;
218*76f3cd6aSElaine Zhang break;
219*76f3cd6aSElaine Zhang case CLK_PKA_CRYPTO:
220*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[35]);
221*76f3cd6aSElaine Zhang sel = (con & CLK_PKA_CRYPTO_SEL_MASK) >>
222*76f3cd6aSElaine Zhang CLK_PKA_CRYPTO_SEL_SHIFT;
223*76f3cd6aSElaine Zhang break;
224*76f3cd6aSElaine Zhang default:
225*76f3cd6aSElaine Zhang return -ENOENT;
226*76f3cd6aSElaine Zhang }
227*76f3cd6aSElaine Zhang if (sel == CLK_CORE_CRYPTO_SEL_300M)
228*76f3cd6aSElaine Zhang rate = 300 * MHz;
229*76f3cd6aSElaine Zhang else if (sel == CLK_CORE_CRYPTO_SEL_200M)
230*76f3cd6aSElaine Zhang rate = 200 * MHz;
231*76f3cd6aSElaine Zhang else
232*76f3cd6aSElaine Zhang rate = 100 * MHz;
233*76f3cd6aSElaine Zhang
234*76f3cd6aSElaine Zhang return rate;
235*76f3cd6aSElaine Zhang
236*76f3cd6aSElaine Zhang }
237*76f3cd6aSElaine Zhang
rv1103b_crypto_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)238*76f3cd6aSElaine Zhang static ulong rv1103b_crypto_set_clk(struct rv1103b_clk_priv *priv,
239*76f3cd6aSElaine Zhang ulong clk_id, ulong rate)
240*76f3cd6aSElaine Zhang {
241*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
242*76f3cd6aSElaine Zhang u32 sel;
243*76f3cd6aSElaine Zhang
244*76f3cd6aSElaine Zhang if (rate >= 297 * MHz)
245*76f3cd6aSElaine Zhang sel = CLK_CORE_CRYPTO_SEL_300M;
246*76f3cd6aSElaine Zhang else if (rate >= 198 * MHz)
247*76f3cd6aSElaine Zhang sel = CLK_CORE_CRYPTO_SEL_200M;
248*76f3cd6aSElaine Zhang else
249*76f3cd6aSElaine Zhang sel = CLK_CORE_CRYPTO_SEL_100M;
250*76f3cd6aSElaine Zhang
251*76f3cd6aSElaine Zhang switch (clk_id) {
252*76f3cd6aSElaine Zhang case ACLK_CRYPTO:
253*76f3cd6aSElaine Zhang case HCLK_CRYPTO:
254*76f3cd6aSElaine Zhang case HCLK_RK_RNG_NS:
255*76f3cd6aSElaine Zhang case HCLK_RK_RNG_S:
256*76f3cd6aSElaine Zhang rv1103b_peri_set_clk(priv, LSCLK_PERI_SRC, rate);
257*76f3cd6aSElaine Zhang case CLK_CORE_CRYPTO:
258*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[35],
259*76f3cd6aSElaine Zhang CLK_CORE_CRYPTO_SEL_MASK,
260*76f3cd6aSElaine Zhang (sel << CLK_CORE_CRYPTO_SEL_SHIFT));
261*76f3cd6aSElaine Zhang break;
262*76f3cd6aSElaine Zhang case CLK_PKA_CRYPTO:
263*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[35],
264*76f3cd6aSElaine Zhang CLK_PKA_CRYPTO_SEL_MASK,
265*76f3cd6aSElaine Zhang (sel << CLK_PKA_CRYPTO_SEL_SHIFT));
266*76f3cd6aSElaine Zhang break;
267*76f3cd6aSElaine Zhang default:
268*76f3cd6aSElaine Zhang return -ENOENT;
269*76f3cd6aSElaine Zhang }
270*76f3cd6aSElaine Zhang return rv1103b_crypto_get_clk(priv, clk_id);
271*76f3cd6aSElaine Zhang }
272*76f3cd6aSElaine Zhang
rv1103b_mmc_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)273*76f3cd6aSElaine Zhang static ulong rv1103b_mmc_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
274*76f3cd6aSElaine Zhang {
275*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
276*76f3cd6aSElaine Zhang u32 div, sel, con, prate;
277*76f3cd6aSElaine Zhang
278*76f3cd6aSElaine Zhang switch (clk_id) {
279*76f3cd6aSElaine Zhang case CCLK_SDMMC1:
280*76f3cd6aSElaine Zhang case HCLK_SDMMC1:
281*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[36]);
282*76f3cd6aSElaine Zhang sel = (con & CLK_SDMMC_SEL_MASK) >>
283*76f3cd6aSElaine Zhang CLK_SDMMC_SEL_SHIFT;
284*76f3cd6aSElaine Zhang div = (con & CLK_SDMMC_DIV_MASK) >>
285*76f3cd6aSElaine Zhang CLK_SDMMC_DIV_SHIFT;
286*76f3cd6aSElaine Zhang if (sel == CLK_MMC_SEL_GPLL)
287*76f3cd6aSElaine Zhang prate = priv->gpll_hz;
288*76f3cd6aSElaine Zhang else
289*76f3cd6aSElaine Zhang prate = OSC_HZ;
290*76f3cd6aSElaine Zhang return DIV_TO_RATE(prate, div);
291*76f3cd6aSElaine Zhang case CCLK_SDMMC0:
292*76f3cd6aSElaine Zhang case HCLK_SDMMC0:
293*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[32]);
294*76f3cd6aSElaine Zhang sel = (con & CLK_SDMMC_SEL_MASK) >>
295*76f3cd6aSElaine Zhang CLK_SDMMC_SEL_SHIFT;
296*76f3cd6aSElaine Zhang div = (con & CLK_SDMMC_DIV_MASK) >>
297*76f3cd6aSElaine Zhang CLK_SDMMC_DIV_SHIFT;
298*76f3cd6aSElaine Zhang if (sel == CLK_MMC_SEL_GPLL)
299*76f3cd6aSElaine Zhang prate = priv->gpll_hz;
300*76f3cd6aSElaine Zhang else
301*76f3cd6aSElaine Zhang prate = OSC_HZ;
302*76f3cd6aSElaine Zhang return DIV_TO_RATE(prate, div);
303*76f3cd6aSElaine Zhang case CCLK_EMMC:
304*76f3cd6aSElaine Zhang case HCLK_EMMC:
305*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[31]);
306*76f3cd6aSElaine Zhang sel = (con & CLK_EMMC_SEL_MASK) >>
307*76f3cd6aSElaine Zhang CLK_EMMC_SEL_SHIFT;
308*76f3cd6aSElaine Zhang div = (con & CLK_EMMC_DIV_MASK) >>
309*76f3cd6aSElaine Zhang CLK_EMMC_DIV_SHIFT;
310*76f3cd6aSElaine Zhang if (sel == CLK_MMC_SEL_GPLL)
311*76f3cd6aSElaine Zhang prate = priv->gpll_hz;
312*76f3cd6aSElaine Zhang else
313*76f3cd6aSElaine Zhang prate = OSC_HZ;
314*76f3cd6aSElaine Zhang return DIV_TO_RATE(prate, div);
315*76f3cd6aSElaine Zhang case SCLK_SFC_2X:
316*76f3cd6aSElaine Zhang case HCLK_SFC:
317*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[33]);
318*76f3cd6aSElaine Zhang sel = (con & CLK_SFC_SEL_MASK) >>
319*76f3cd6aSElaine Zhang CLK_SFC_SEL_SHIFT;
320*76f3cd6aSElaine Zhang div = (con & CLK_SFC_DIV_MASK) >>
321*76f3cd6aSElaine Zhang CLK_SFC_DIV_SHIFT;
322*76f3cd6aSElaine Zhang if (sel == CLK_MMC_SEL_GPLL)
323*76f3cd6aSElaine Zhang prate = priv->gpll_hz;
324*76f3cd6aSElaine Zhang else
325*76f3cd6aSElaine Zhang prate = OSC_HZ;
326*76f3cd6aSElaine Zhang return DIV_TO_RATE(prate, div);
327*76f3cd6aSElaine Zhang default:
328*76f3cd6aSElaine Zhang return -ENOENT;
329*76f3cd6aSElaine Zhang }
330*76f3cd6aSElaine Zhang }
331*76f3cd6aSElaine Zhang
rv1103b_mmc_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)332*76f3cd6aSElaine Zhang static ulong rv1103b_mmc_set_clk(struct rv1103b_clk_priv *priv,
333*76f3cd6aSElaine Zhang ulong clk_id, ulong rate)
334*76f3cd6aSElaine Zhang {
335*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
336*76f3cd6aSElaine Zhang u32 sel, src_clk_div;
337*76f3cd6aSElaine Zhang ulong prate = 0;
338*76f3cd6aSElaine Zhang
339*76f3cd6aSElaine Zhang if ((OSC_HZ % rate) == 0) {
340*76f3cd6aSElaine Zhang sel = CLK_MMC_SEL_OSC;
341*76f3cd6aSElaine Zhang prate = OSC_HZ;
342*76f3cd6aSElaine Zhang } else {
343*76f3cd6aSElaine Zhang sel = CLK_MMC_SEL_GPLL;
344*76f3cd6aSElaine Zhang prate = priv->gpll_hz;
345*76f3cd6aSElaine Zhang }
346*76f3cd6aSElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
347*76f3cd6aSElaine Zhang
348*76f3cd6aSElaine Zhang switch (clk_id) {
349*76f3cd6aSElaine Zhang case CCLK_SDMMC1:
350*76f3cd6aSElaine Zhang case HCLK_SDMMC1:
351*76f3cd6aSElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
352*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[36],
353*76f3cd6aSElaine Zhang CLK_SDMMC_SEL_MASK |
354*76f3cd6aSElaine Zhang CLK_SDMMC_DIV_MASK,
355*76f3cd6aSElaine Zhang (sel << CLK_SDMMC_SEL_SHIFT) |
356*76f3cd6aSElaine Zhang ((src_clk_div - 1) <<
357*76f3cd6aSElaine Zhang CLK_SDMMC_DIV_SHIFT));
358*76f3cd6aSElaine Zhang break;
359*76f3cd6aSElaine Zhang case CCLK_SDMMC0:
360*76f3cd6aSElaine Zhang case HCLK_SDMMC0:
361*76f3cd6aSElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
362*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[32],
363*76f3cd6aSElaine Zhang CLK_SDMMC_SEL_MASK |
364*76f3cd6aSElaine Zhang CLK_SDMMC_DIV_MASK,
365*76f3cd6aSElaine Zhang (sel << CLK_SDMMC_SEL_SHIFT) |
366*76f3cd6aSElaine Zhang ((src_clk_div - 1) <<
367*76f3cd6aSElaine Zhang CLK_SDMMC_DIV_SHIFT));
368*76f3cd6aSElaine Zhang break;
369*76f3cd6aSElaine Zhang case CCLK_EMMC:
370*76f3cd6aSElaine Zhang case HCLK_EMMC:
371*76f3cd6aSElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
372*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[31],
373*76f3cd6aSElaine Zhang CLK_EMMC_SEL_MASK |
374*76f3cd6aSElaine Zhang CLK_EMMC_DIV_MASK,
375*76f3cd6aSElaine Zhang (sel << CLK_EMMC_SEL_SHIFT) |
376*76f3cd6aSElaine Zhang ((src_clk_div - 1) <<
377*76f3cd6aSElaine Zhang CLK_EMMC_DIV_SHIFT));
378*76f3cd6aSElaine Zhang break;
379*76f3cd6aSElaine Zhang case SCLK_SFC_2X:
380*76f3cd6aSElaine Zhang case HCLK_SFC:
381*76f3cd6aSElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
382*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[33],
383*76f3cd6aSElaine Zhang CLK_SFC_SEL_MASK |
384*76f3cd6aSElaine Zhang CLK_SFC_DIV_MASK,
385*76f3cd6aSElaine Zhang (sel << CLK_SFC_SEL_SHIFT) |
386*76f3cd6aSElaine Zhang ((src_clk_div - 1) <<
387*76f3cd6aSElaine Zhang CLK_SFC_DIV_SHIFT));
388*76f3cd6aSElaine Zhang break;
389*76f3cd6aSElaine Zhang default:
390*76f3cd6aSElaine Zhang return -ENOENT;
391*76f3cd6aSElaine Zhang }
392*76f3cd6aSElaine Zhang return rv1103b_mmc_get_clk(priv, clk_id);
393*76f3cd6aSElaine Zhang }
394*76f3cd6aSElaine Zhang
rv1103b_i2c_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)395*76f3cd6aSElaine Zhang static ulong rv1103b_i2c_set_clk(struct rv1103b_clk_priv *priv, ulong clk_id,
396*76f3cd6aSElaine Zhang ulong rate)
397*76f3cd6aSElaine Zhang {
398*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
399*76f3cd6aSElaine Zhang int src_clk;
400*76f3cd6aSElaine Zhang
401*76f3cd6aSElaine Zhang if (rate == OSC_HZ)
402*76f3cd6aSElaine Zhang src_clk = CLK_I2C_SEL_24M;
403*76f3cd6aSElaine Zhang else
404*76f3cd6aSElaine Zhang src_clk = CLK_I2C_SEL_100M;
405*76f3cd6aSElaine Zhang
406*76f3cd6aSElaine Zhang switch (clk_id) {
407*76f3cd6aSElaine Zhang case CLK_I2C1:
408*76f3cd6aSElaine Zhang case CLK_I2C2:
409*76f3cd6aSElaine Zhang case CLK_I2C3:
410*76f3cd6aSElaine Zhang case CLK_I2C4:
411*76f3cd6aSElaine Zhang case CLK_I2C_PERI:
412*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[34], CLK_I2C1_SEL_MASK,
413*76f3cd6aSElaine Zhang src_clk << CLK_I2C1_SEL_SHIFT);
414*76f3cd6aSElaine Zhang break;
415*76f3cd6aSElaine Zhang case CLK_I2C0:
416*76f3cd6aSElaine Zhang case CLK_I2C_PMU:
417*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[34], CLK_I2C0_SEL_MASK,
418*76f3cd6aSElaine Zhang src_clk << CLK_I2C0_SEL_SHIFT);
419*76f3cd6aSElaine Zhang break;
420*76f3cd6aSElaine Zhang default:
421*76f3cd6aSElaine Zhang return -ENOENT;
422*76f3cd6aSElaine Zhang }
423*76f3cd6aSElaine Zhang return rv1103b_i2c_get_clk(priv, clk_id);
424*76f3cd6aSElaine Zhang }
425*76f3cd6aSElaine Zhang
rv1103b_spi_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)426*76f3cd6aSElaine Zhang static ulong rv1103b_spi_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
427*76f3cd6aSElaine Zhang {
428*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
429*76f3cd6aSElaine Zhang u32 sel, con, rate;
430*76f3cd6aSElaine Zhang
431*76f3cd6aSElaine Zhang switch (clk_id) {
432*76f3cd6aSElaine Zhang case CLK_SPI0:
433*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[34]);
434*76f3cd6aSElaine Zhang sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
435*76f3cd6aSElaine Zhang break;
436*76f3cd6aSElaine Zhang default:
437*76f3cd6aSElaine Zhang return -ENOENT;
438*76f3cd6aSElaine Zhang }
439*76f3cd6aSElaine Zhang if (sel == CLK_SPI0_SEL_200M)
440*76f3cd6aSElaine Zhang rate = 200 * MHz;
441*76f3cd6aSElaine Zhang else if (sel == CLK_SPI0_SEL_100M)
442*76f3cd6aSElaine Zhang rate = 100 * MHz;
443*76f3cd6aSElaine Zhang else if (sel == CLK_SPI0_SEL_50M)
444*76f3cd6aSElaine Zhang rate = 50 * MHz;
445*76f3cd6aSElaine Zhang else
446*76f3cd6aSElaine Zhang rate = OSC_HZ;
447*76f3cd6aSElaine Zhang
448*76f3cd6aSElaine Zhang return rate;
449*76f3cd6aSElaine Zhang }
450*76f3cd6aSElaine Zhang
rv1103b_spi_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)451*76f3cd6aSElaine Zhang static ulong rv1103b_spi_set_clk(struct rv1103b_clk_priv *priv,
452*76f3cd6aSElaine Zhang ulong clk_id, ulong rate)
453*76f3cd6aSElaine Zhang {
454*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
455*76f3cd6aSElaine Zhang int src_clk;
456*76f3cd6aSElaine Zhang
457*76f3cd6aSElaine Zhang if (rate >= 198 * MHz)
458*76f3cd6aSElaine Zhang src_clk = CLK_SPI0_SEL_200M;
459*76f3cd6aSElaine Zhang else if (rate >= 99 * MHz)
460*76f3cd6aSElaine Zhang src_clk = CLK_SPI0_SEL_100M;
461*76f3cd6aSElaine Zhang else if (rate >= 48 * MHz)
462*76f3cd6aSElaine Zhang src_clk = CLK_SPI0_SEL_50M;
463*76f3cd6aSElaine Zhang else
464*76f3cd6aSElaine Zhang src_clk = CLK_SPI0_SEL_24M;
465*76f3cd6aSElaine Zhang
466*76f3cd6aSElaine Zhang switch (clk_id) {
467*76f3cd6aSElaine Zhang case CLK_SPI0:
468*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[34], CLK_SPI0_SEL_MASK,
469*76f3cd6aSElaine Zhang src_clk << CLK_SPI0_SEL_SHIFT);
470*76f3cd6aSElaine Zhang break;
471*76f3cd6aSElaine Zhang default:
472*76f3cd6aSElaine Zhang return -ENOENT;
473*76f3cd6aSElaine Zhang }
474*76f3cd6aSElaine Zhang
475*76f3cd6aSElaine Zhang return rv1103b_spi_get_clk(priv, clk_id);
476*76f3cd6aSElaine Zhang }
477*76f3cd6aSElaine Zhang
rv1103b_pwm_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)478*76f3cd6aSElaine Zhang static ulong rv1103b_pwm_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
479*76f3cd6aSElaine Zhang {
480*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
481*76f3cd6aSElaine Zhang u32 sel, con;
482*76f3cd6aSElaine Zhang
483*76f3cd6aSElaine Zhang switch (clk_id) {
484*76f3cd6aSElaine Zhang case CLK_PWM0:
485*76f3cd6aSElaine Zhang case CLK_PWM0_SRC:
486*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[34]);
487*76f3cd6aSElaine Zhang sel = (con & CLK_PWM0_SEL_MASK) >> CLK_PWM0_SEL_SHIFT;
488*76f3cd6aSElaine Zhang break;
489*76f3cd6aSElaine Zhang case CLK_PWM1:
490*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[34]);
491*76f3cd6aSElaine Zhang sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
492*76f3cd6aSElaine Zhang break;
493*76f3cd6aSElaine Zhang case CLK_PWM2:
494*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[34]);
495*76f3cd6aSElaine Zhang sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT;
496*76f3cd6aSElaine Zhang break;
497*76f3cd6aSElaine Zhang default:
498*76f3cd6aSElaine Zhang return -ENOENT;
499*76f3cd6aSElaine Zhang }
500*76f3cd6aSElaine Zhang
501*76f3cd6aSElaine Zhang switch (sel) {
502*76f3cd6aSElaine Zhang case CLK_PWM_SEL_100M:
503*76f3cd6aSElaine Zhang return 100 * MHz;
504*76f3cd6aSElaine Zhang case CLK_PWM_SEL_24M:
505*76f3cd6aSElaine Zhang return OSC_HZ;
506*76f3cd6aSElaine Zhang default:
507*76f3cd6aSElaine Zhang return -ENOENT;
508*76f3cd6aSElaine Zhang }
509*76f3cd6aSElaine Zhang }
510*76f3cd6aSElaine Zhang
rv1103b_pwm_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)511*76f3cd6aSElaine Zhang static ulong rv1103b_pwm_set_clk(struct rv1103b_clk_priv *priv,
512*76f3cd6aSElaine Zhang ulong clk_id, ulong rate)
513*76f3cd6aSElaine Zhang {
514*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
515*76f3cd6aSElaine Zhang int src_clk;
516*76f3cd6aSElaine Zhang
517*76f3cd6aSElaine Zhang if (rate >= 99 * MHz)
518*76f3cd6aSElaine Zhang src_clk = CLK_PWM_SEL_100M;
519*76f3cd6aSElaine Zhang else
520*76f3cd6aSElaine Zhang src_clk = CLK_PWM_SEL_24M;
521*76f3cd6aSElaine Zhang
522*76f3cd6aSElaine Zhang switch (clk_id) {
523*76f3cd6aSElaine Zhang case CLK_PWM0:
524*76f3cd6aSElaine Zhang case CLK_PWM0_SRC:
525*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[34],
526*76f3cd6aSElaine Zhang CLK_PWM0_SEL_MASK,
527*76f3cd6aSElaine Zhang src_clk << CLK_PWM0_SEL_SHIFT);
528*76f3cd6aSElaine Zhang break;
529*76f3cd6aSElaine Zhang case CLK_PWM1:
530*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[34],
531*76f3cd6aSElaine Zhang CLK_PWM1_SEL_MASK,
532*76f3cd6aSElaine Zhang src_clk << CLK_PWM1_SEL_SHIFT);
533*76f3cd6aSElaine Zhang break;
534*76f3cd6aSElaine Zhang case CLK_PWM2:
535*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[34],
536*76f3cd6aSElaine Zhang CLK_PWM2_SEL_MASK,
537*76f3cd6aSElaine Zhang src_clk << CLK_PWM2_SEL_SHIFT);
538*76f3cd6aSElaine Zhang break;
539*76f3cd6aSElaine Zhang default:
540*76f3cd6aSElaine Zhang return -ENOENT;
541*76f3cd6aSElaine Zhang }
542*76f3cd6aSElaine Zhang
543*76f3cd6aSElaine Zhang return rv1103b_pwm_get_clk(priv, clk_id);
544*76f3cd6aSElaine Zhang }
545*76f3cd6aSElaine Zhang
rv1103b_adc_get_clk(struct rv1103b_clk_priv * priv,ulong clk_id)546*76f3cd6aSElaine Zhang static ulong rv1103b_adc_get_clk(struct rv1103b_clk_priv *priv, ulong clk_id)
547*76f3cd6aSElaine Zhang {
548*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
549*76f3cd6aSElaine Zhang u32 div, con;
550*76f3cd6aSElaine Zhang
551*76f3cd6aSElaine Zhang switch (clk_id) {
552*76f3cd6aSElaine Zhang case CLK_SARADC:
553*76f3cd6aSElaine Zhang con = readl(&cru->peri_clksel_con[1]);
554*76f3cd6aSElaine Zhang div = (con & CLK_SARADC_DIV_MASK) >>
555*76f3cd6aSElaine Zhang CLK_SARADC_DIV_SHIFT;
556*76f3cd6aSElaine Zhang return DIV_TO_RATE(OSC_HZ, div);
557*76f3cd6aSElaine Zhang case CLK_TSADC_TSEN:
558*76f3cd6aSElaine Zhang con = readl(&cru->peri_clksel_con[0]);
559*76f3cd6aSElaine Zhang div = (con & CLK_TSADC_TSEN_DIV_MASK) >>
560*76f3cd6aSElaine Zhang CLK_TSADC_TSEN_DIV_SHIFT;
561*76f3cd6aSElaine Zhang return DIV_TO_RATE(OSC_HZ, div);
562*76f3cd6aSElaine Zhang case CLK_TSADC:
563*76f3cd6aSElaine Zhang con = readl(&cru->peri_clksel_con[0]);
564*76f3cd6aSElaine Zhang div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT;
565*76f3cd6aSElaine Zhang return DIV_TO_RATE(OSC_HZ, div);
566*76f3cd6aSElaine Zhang default:
567*76f3cd6aSElaine Zhang return -ENOENT;
568*76f3cd6aSElaine Zhang }
569*76f3cd6aSElaine Zhang }
570*76f3cd6aSElaine Zhang
rv1103b_adc_set_clk(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)571*76f3cd6aSElaine Zhang static ulong rv1103b_adc_set_clk(struct rv1103b_clk_priv *priv,
572*76f3cd6aSElaine Zhang ulong clk_id, ulong rate)
573*76f3cd6aSElaine Zhang {
574*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
575*76f3cd6aSElaine Zhang int src_clk_div;
576*76f3cd6aSElaine Zhang
577*76f3cd6aSElaine Zhang src_clk_div = DIV_ROUND_UP(OSC_HZ, rate);
578*76f3cd6aSElaine Zhang
579*76f3cd6aSElaine Zhang switch (clk_id) {
580*76f3cd6aSElaine Zhang case CLK_SARADC:
581*76f3cd6aSElaine Zhang assert(src_clk_div - 1 <= 7);
582*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[1],
583*76f3cd6aSElaine Zhang CLK_SARADC_DIV_MASK,
584*76f3cd6aSElaine Zhang (src_clk_div - 1) <<
585*76f3cd6aSElaine Zhang CLK_SARADC_DIV_SHIFT);
586*76f3cd6aSElaine Zhang break;
587*76f3cd6aSElaine Zhang case CLK_TSADC_TSEN:
588*76f3cd6aSElaine Zhang assert(src_clk_div - 1 <= 32);
589*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[0],
590*76f3cd6aSElaine Zhang CLK_TSADC_TSEN_DIV_MASK,
591*76f3cd6aSElaine Zhang (src_clk_div - 1) <<
592*76f3cd6aSElaine Zhang CLK_TSADC_TSEN_DIV_SHIFT);
593*76f3cd6aSElaine Zhang break;
594*76f3cd6aSElaine Zhang case CLK_TSADC:
595*76f3cd6aSElaine Zhang assert(src_clk_div - 1 <= 32);
596*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[0],
597*76f3cd6aSElaine Zhang CLK_TSADC_DIV_MASK,
598*76f3cd6aSElaine Zhang (src_clk_div - 1) <<
599*76f3cd6aSElaine Zhang CLK_TSADC_DIV_SHIFT);
600*76f3cd6aSElaine Zhang break;
601*76f3cd6aSElaine Zhang default:
602*76f3cd6aSElaine Zhang return -ENOENT;
603*76f3cd6aSElaine Zhang }
604*76f3cd6aSElaine Zhang return rv1103b_adc_get_clk(priv, clk_id);
605*76f3cd6aSElaine Zhang }
606*76f3cd6aSElaine Zhang
607*76f3cd6aSElaine Zhang /*
608*76f3cd6aSElaine Zhang *
609*76f3cd6aSElaine Zhang * rational_best_approximation(31415, 10000,
610*76f3cd6aSElaine Zhang * (1 << 8) - 1, (1 << 5) - 1, &n, &d);
611*76f3cd6aSElaine Zhang *
612*76f3cd6aSElaine Zhang * you may look at given_numerator as a fixed point number,
613*76f3cd6aSElaine Zhang * with the fractional part size described in given_denominator.
614*76f3cd6aSElaine Zhang *
615*76f3cd6aSElaine Zhang * for theoretical background, see:
616*76f3cd6aSElaine Zhang * http://en.wikipedia.org/wiki/Continued_fraction
617*76f3cd6aSElaine Zhang */
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)618*76f3cd6aSElaine Zhang static void rational_best_approximation(unsigned long given_numerator,
619*76f3cd6aSElaine Zhang unsigned long given_denominator,
620*76f3cd6aSElaine Zhang unsigned long max_numerator,
621*76f3cd6aSElaine Zhang unsigned long max_denominator,
622*76f3cd6aSElaine Zhang unsigned long *best_numerator,
623*76f3cd6aSElaine Zhang unsigned long *best_denominator)
624*76f3cd6aSElaine Zhang {
625*76f3cd6aSElaine Zhang unsigned long n, d, n0, d0, n1, d1;
626*76f3cd6aSElaine Zhang
627*76f3cd6aSElaine Zhang n = given_numerator;
628*76f3cd6aSElaine Zhang d = given_denominator;
629*76f3cd6aSElaine Zhang n0 = 0;
630*76f3cd6aSElaine Zhang d1 = 0;
631*76f3cd6aSElaine Zhang n1 = 1;
632*76f3cd6aSElaine Zhang d0 = 1;
633*76f3cd6aSElaine Zhang for (;;) {
634*76f3cd6aSElaine Zhang unsigned long t, a;
635*76f3cd6aSElaine Zhang
636*76f3cd6aSElaine Zhang if (n1 > max_numerator || d1 > max_denominator) {
637*76f3cd6aSElaine Zhang n1 = n0;
638*76f3cd6aSElaine Zhang d1 = d0;
639*76f3cd6aSElaine Zhang break;
640*76f3cd6aSElaine Zhang }
641*76f3cd6aSElaine Zhang if (d == 0)
642*76f3cd6aSElaine Zhang break;
643*76f3cd6aSElaine Zhang t = d;
644*76f3cd6aSElaine Zhang a = n / d;
645*76f3cd6aSElaine Zhang d = n % d;
646*76f3cd6aSElaine Zhang n = t;
647*76f3cd6aSElaine Zhang t = n0 + a * n1;
648*76f3cd6aSElaine Zhang n0 = n1;
649*76f3cd6aSElaine Zhang n1 = t;
650*76f3cd6aSElaine Zhang t = d0 + a * d1;
651*76f3cd6aSElaine Zhang d0 = d1;
652*76f3cd6aSElaine Zhang d1 = t;
653*76f3cd6aSElaine Zhang }
654*76f3cd6aSElaine Zhang *best_numerator = n1;
655*76f3cd6aSElaine Zhang *best_denominator = d1;
656*76f3cd6aSElaine Zhang }
657*76f3cd6aSElaine Zhang
rv1103b_uart_get_rate(struct rv1103b_clk_priv * priv,ulong clk_id)658*76f3cd6aSElaine Zhang static ulong rv1103b_uart_get_rate(struct rv1103b_clk_priv *priv, ulong clk_id)
659*76f3cd6aSElaine Zhang {
660*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
661*76f3cd6aSElaine Zhang u32 reg, con, fracdiv, div, src, p_rate;
662*76f3cd6aSElaine Zhang unsigned long m, n;
663*76f3cd6aSElaine Zhang
664*76f3cd6aSElaine Zhang switch (clk_id) {
665*76f3cd6aSElaine Zhang case SCLK_UART0:
666*76f3cd6aSElaine Zhang reg = 10;
667*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[32]);
668*76f3cd6aSElaine Zhang src = (con & CLK_UART0_SEL_MASK) >> CLK_UART0_SEL_SHIFT;
669*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[5]);
670*76f3cd6aSElaine Zhang div = (con & CLK_UART0_SRC_DIV_MASK) >> CLK_UART0_SRC_DIV_SHIFT;
671*76f3cd6aSElaine Zhang break;
672*76f3cd6aSElaine Zhang case SCLK_UART1:
673*76f3cd6aSElaine Zhang reg = 11;
674*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[32]);
675*76f3cd6aSElaine Zhang src = (con & CLK_UART1_SEL_MASK) >> CLK_UART1_SEL_SHIFT;
676*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[5]);
677*76f3cd6aSElaine Zhang div = (con & CLK_UART1_SRC_DIV_MASK) >> CLK_UART1_SRC_DIV_SHIFT;
678*76f3cd6aSElaine Zhang break;
679*76f3cd6aSElaine Zhang case SCLK_UART2:
680*76f3cd6aSElaine Zhang reg = 12;
681*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[32]);
682*76f3cd6aSElaine Zhang src = (con & CLK_UART2_SEL_MASK) >> CLK_UART2_SEL_SHIFT;
683*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[5]);
684*76f3cd6aSElaine Zhang div = (con & CLK_UART2_SRC_DIV_MASK) >> CLK_UART2_SRC_DIV_SHIFT;
685*76f3cd6aSElaine Zhang break;
686*76f3cd6aSElaine Zhang default:
687*76f3cd6aSElaine Zhang return -ENOENT;
688*76f3cd6aSElaine Zhang }
689*76f3cd6aSElaine Zhang
690*76f3cd6aSElaine Zhang p_rate = priv->gpll_hz;
691*76f3cd6aSElaine Zhang if (src == CLK_UART_SEL_SRC) {
692*76f3cd6aSElaine Zhang return DIV_TO_RATE(p_rate, div);
693*76f3cd6aSElaine Zhang } else if (src == CLK_UART_SEL_FRAC) {
694*76f3cd6aSElaine Zhang fracdiv = readl(&cru->clksel_con[reg]);
695*76f3cd6aSElaine Zhang n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK;
696*76f3cd6aSElaine Zhang n >>= CLK_UART_FRAC_NUMERATOR_SHIFT;
697*76f3cd6aSElaine Zhang m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK;
698*76f3cd6aSElaine Zhang m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT;
699*76f3cd6aSElaine Zhang return DIV_TO_RATE(p_rate, div) * n / m;
700*76f3cd6aSElaine Zhang } else {
701*76f3cd6aSElaine Zhang return OSC_HZ;
702*76f3cd6aSElaine Zhang }
703*76f3cd6aSElaine Zhang }
704*76f3cd6aSElaine Zhang
rv1103b_uart_set_rate(struct rv1103b_clk_priv * priv,ulong clk_id,ulong rate)705*76f3cd6aSElaine Zhang static ulong rv1103b_uart_set_rate(struct rv1103b_clk_priv *priv,
706*76f3cd6aSElaine Zhang ulong clk_id, ulong rate)
707*76f3cd6aSElaine Zhang {
708*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
709*76f3cd6aSElaine Zhang u32 reg, uart_src, div;
710*76f3cd6aSElaine Zhang unsigned long m = 0, n = 0, val;
711*76f3cd6aSElaine Zhang
712*76f3cd6aSElaine Zhang if (priv->gpll_hz % rate == 0) {
713*76f3cd6aSElaine Zhang uart_src = CLK_UART_SEL_SRC;
714*76f3cd6aSElaine Zhang div = DIV_ROUND_UP(priv->gpll_hz, rate);
715*76f3cd6aSElaine Zhang } else if (rate == OSC_HZ) {
716*76f3cd6aSElaine Zhang uart_src = CLK_UART_SEL_OSC;
717*76f3cd6aSElaine Zhang div = 2;
718*76f3cd6aSElaine Zhang } else {
719*76f3cd6aSElaine Zhang uart_src = CLK_UART_SEL_FRAC;
720*76f3cd6aSElaine Zhang div = 2;
721*76f3cd6aSElaine Zhang rational_best_approximation(rate, priv->gpll_hz / div,
722*76f3cd6aSElaine Zhang GENMASK(16 - 1, 0),
723*76f3cd6aSElaine Zhang GENMASK(16 - 1, 0),
724*76f3cd6aSElaine Zhang &m, &n);
725*76f3cd6aSElaine Zhang }
726*76f3cd6aSElaine Zhang
727*76f3cd6aSElaine Zhang switch (clk_id) {
728*76f3cd6aSElaine Zhang case SCLK_UART0:
729*76f3cd6aSElaine Zhang reg = 10;
730*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[5],
731*76f3cd6aSElaine Zhang CLK_UART0_SRC_DIV_MASK,
732*76f3cd6aSElaine Zhang div << CLK_UART0_SRC_DIV_SHIFT);
733*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[32],
734*76f3cd6aSElaine Zhang CLK_UART0_SEL_MASK,
735*76f3cd6aSElaine Zhang uart_src << CLK_UART0_SEL_SHIFT);
736*76f3cd6aSElaine Zhang break;
737*76f3cd6aSElaine Zhang case SCLK_UART1:
738*76f3cd6aSElaine Zhang reg = 11;
739*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[5],
740*76f3cd6aSElaine Zhang CLK_UART1_SRC_DIV_MASK,
741*76f3cd6aSElaine Zhang div << CLK_UART1_SRC_DIV_SHIFT);
742*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[32],
743*76f3cd6aSElaine Zhang CLK_UART1_SEL_MASK,
744*76f3cd6aSElaine Zhang uart_src << CLK_UART1_SEL_SHIFT);
745*76f3cd6aSElaine Zhang break;
746*76f3cd6aSElaine Zhang case SCLK_UART2:
747*76f3cd6aSElaine Zhang reg = 12;
748*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[5],
749*76f3cd6aSElaine Zhang CLK_UART2_SRC_DIV_MASK,
750*76f3cd6aSElaine Zhang div << CLK_UART2_SRC_DIV_SHIFT);
751*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[32],
752*76f3cd6aSElaine Zhang CLK_UART2_SEL_MASK,
753*76f3cd6aSElaine Zhang uart_src << CLK_UART2_SEL_SHIFT);
754*76f3cd6aSElaine Zhang break;
755*76f3cd6aSElaine Zhang default:
756*76f3cd6aSElaine Zhang return -ENOENT;
757*76f3cd6aSElaine Zhang }
758*76f3cd6aSElaine Zhang if (m && n) {
759*76f3cd6aSElaine Zhang val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n;
760*76f3cd6aSElaine Zhang writel(val, &cru->clksel_con[reg]);
761*76f3cd6aSElaine Zhang }
762*76f3cd6aSElaine Zhang
763*76f3cd6aSElaine Zhang return rv1103b_uart_get_rate(priv, clk_id);
764*76f3cd6aSElaine Zhang }
765*76f3cd6aSElaine Zhang
rv1103b_decom_get_clk(struct rv1103b_clk_priv * priv)766*76f3cd6aSElaine Zhang static ulong rv1103b_decom_get_clk(struct rv1103b_clk_priv *priv)
767*76f3cd6aSElaine Zhang {
768*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
769*76f3cd6aSElaine Zhang u32 sel, con, prate;
770*76f3cd6aSElaine Zhang
771*76f3cd6aSElaine Zhang con = readl(&cru->clksel_con[35]);
772*76f3cd6aSElaine Zhang sel = (con & DCLK_DECOM_SEL_MASK) >>
773*76f3cd6aSElaine Zhang DCLK_DECOM_SEL_SHIFT;
774*76f3cd6aSElaine Zhang if (sel == DCLK_DECOM_SEL_480M)
775*76f3cd6aSElaine Zhang prate = 480 * MHz;
776*76f3cd6aSElaine Zhang else if (sel == DCLK_DECOM_SEL_400M)
777*76f3cd6aSElaine Zhang prate = 400 * MHz;
778*76f3cd6aSElaine Zhang else
779*76f3cd6aSElaine Zhang prate = 300 * MHz;
780*76f3cd6aSElaine Zhang return prate;
781*76f3cd6aSElaine Zhang }
782*76f3cd6aSElaine Zhang
rv1103b_decom_set_clk(struct rv1103b_clk_priv * priv,ulong rate)783*76f3cd6aSElaine Zhang static ulong rv1103b_decom_set_clk(struct rv1103b_clk_priv *priv, ulong rate)
784*76f3cd6aSElaine Zhang {
785*76f3cd6aSElaine Zhang struct rv1103b_cru *cru = priv->cru;
786*76f3cd6aSElaine Zhang u32 sel;
787*76f3cd6aSElaine Zhang
788*76f3cd6aSElaine Zhang if (rate >= 480 * MHz)
789*76f3cd6aSElaine Zhang sel = DCLK_DECOM_SEL_480M;
790*76f3cd6aSElaine Zhang else if (rate >= 396 * MHz)
791*76f3cd6aSElaine Zhang sel = DCLK_DECOM_SEL_400M;
792*76f3cd6aSElaine Zhang else
793*76f3cd6aSElaine Zhang sel = DCLK_DECOM_SEL_300M;
794*76f3cd6aSElaine Zhang rk_clrsetreg(&cru->clksel_con[35], DCLK_DECOM_SEL_MASK,
795*76f3cd6aSElaine Zhang (sel << DCLK_DECOM_SEL_SHIFT));
796*76f3cd6aSElaine Zhang
797*76f3cd6aSElaine Zhang return rv1103b_decom_get_clk(priv);
798*76f3cd6aSElaine Zhang }
799*76f3cd6aSElaine Zhang
rv1103b_clk_get_rate(struct clk * clk)800*76f3cd6aSElaine Zhang static ulong rv1103b_clk_get_rate(struct clk *clk)
801*76f3cd6aSElaine Zhang {
802*76f3cd6aSElaine Zhang struct rv1103b_clk_priv *priv = dev_get_priv(clk->dev);
803*76f3cd6aSElaine Zhang ulong rate = 0;
804*76f3cd6aSElaine Zhang
805*76f3cd6aSElaine Zhang if (!priv->gpll_hz) {
806*76f3cd6aSElaine Zhang printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
807*76f3cd6aSElaine Zhang return -ENOENT;
808*76f3cd6aSElaine Zhang }
809*76f3cd6aSElaine Zhang
810*76f3cd6aSElaine Zhang switch (clk->id) {
811*76f3cd6aSElaine Zhang case PLL_GPLL:
812*76f3cd6aSElaine Zhang rate = rockchip_pll_get_rate(&rv1103b_pll_clks[GPLL], priv->cru,
813*76f3cd6aSElaine Zhang GPLL);
814*76f3cd6aSElaine Zhang break;
815*76f3cd6aSElaine Zhang case ACLK_PERI_SRC:
816*76f3cd6aSElaine Zhang case LSCLK_PERI_SRC:
817*76f3cd6aSElaine Zhang case PCLK_PERI_ROOT:
818*76f3cd6aSElaine Zhang case PCLK_TOP_ROOT:
819*76f3cd6aSElaine Zhang case LSCLK_PMU_ROOT:
820*76f3cd6aSElaine Zhang case PCLK_PMU:
821*76f3cd6aSElaine Zhang rate = rv1103b_peri_get_clk(priv, clk->id);
822*76f3cd6aSElaine Zhang break;
823*76f3cd6aSElaine Zhang case ACLK_CRYPTO:
824*76f3cd6aSElaine Zhang case HCLK_CRYPTO:
825*76f3cd6aSElaine Zhang case HCLK_RK_RNG_NS:
826*76f3cd6aSElaine Zhang case HCLK_RK_RNG_S:
827*76f3cd6aSElaine Zhang case CLK_CORE_CRYPTO:
828*76f3cd6aSElaine Zhang case CLK_PKA_CRYPTO:
829*76f3cd6aSElaine Zhang rate = rv1103b_crypto_get_clk(priv, clk->id);
830*76f3cd6aSElaine Zhang break;
831*76f3cd6aSElaine Zhang case CCLK_SDMMC1:
832*76f3cd6aSElaine Zhang case HCLK_SDMMC1:
833*76f3cd6aSElaine Zhang case CCLK_SDMMC0:
834*76f3cd6aSElaine Zhang case HCLK_SDMMC0:
835*76f3cd6aSElaine Zhang case CCLK_EMMC:
836*76f3cd6aSElaine Zhang case HCLK_EMMC:
837*76f3cd6aSElaine Zhang case SCLK_SFC_2X:
838*76f3cd6aSElaine Zhang case HCLK_SFC:
839*76f3cd6aSElaine Zhang rate = rv1103b_mmc_get_clk(priv, clk->id);
840*76f3cd6aSElaine Zhang break;
841*76f3cd6aSElaine Zhang case CLK_I2C1:
842*76f3cd6aSElaine Zhang case CLK_I2C2:
843*76f3cd6aSElaine Zhang case CLK_I2C3:
844*76f3cd6aSElaine Zhang case CLK_I2C4:
845*76f3cd6aSElaine Zhang case CLK_I2C_PERI:
846*76f3cd6aSElaine Zhang case CLK_I2C0:
847*76f3cd6aSElaine Zhang case CLK_I2C_PMU:
848*76f3cd6aSElaine Zhang rate = rv1103b_i2c_get_clk(priv, clk->id);
849*76f3cd6aSElaine Zhang break;
850*76f3cd6aSElaine Zhang case CLK_SPI0:
851*76f3cd6aSElaine Zhang rate = rv1103b_spi_get_clk(priv, clk->id);
852*76f3cd6aSElaine Zhang break;
853*76f3cd6aSElaine Zhang case CLK_PWM0:
854*76f3cd6aSElaine Zhang case CLK_PWM0_SRC:
855*76f3cd6aSElaine Zhang case CLK_PWM1:
856*76f3cd6aSElaine Zhang case CLK_PWM2:
857*76f3cd6aSElaine Zhang rate = rv1103b_pwm_get_clk(priv, clk->id);
858*76f3cd6aSElaine Zhang break;
859*76f3cd6aSElaine Zhang case CLK_SARADC:
860*76f3cd6aSElaine Zhang case CLK_TSADC_TSEN:
861*76f3cd6aSElaine Zhang case CLK_TSADC:
862*76f3cd6aSElaine Zhang rate = rv1103b_adc_get_clk(priv, clk->id);
863*76f3cd6aSElaine Zhang break;
864*76f3cd6aSElaine Zhang case SCLK_UART0:
865*76f3cd6aSElaine Zhang case SCLK_UART1:
866*76f3cd6aSElaine Zhang case SCLK_UART2:
867*76f3cd6aSElaine Zhang rate = rv1103b_uart_get_rate(priv, clk->id);
868*76f3cd6aSElaine Zhang break;
869*76f3cd6aSElaine Zhang case DCLK_DECOM_SRC:
870*76f3cd6aSElaine Zhang case DCLK_DECOM:
871*76f3cd6aSElaine Zhang rate = rv1103b_decom_get_clk(priv);
872*76f3cd6aSElaine Zhang break;
873*76f3cd6aSElaine Zhang case TCLK_WDT_LPMCU:
874*76f3cd6aSElaine Zhang case TCLK_WDT_HPMCU:
875*76f3cd6aSElaine Zhang case TCLK_WDT_NS:
876*76f3cd6aSElaine Zhang case TCLK_WDT_S:
877*76f3cd6aSElaine Zhang rate = OSC_HZ;
878*76f3cd6aSElaine Zhang break;
879*76f3cd6aSElaine Zhang default:
880*76f3cd6aSElaine Zhang return -ENOENT;
881*76f3cd6aSElaine Zhang }
882*76f3cd6aSElaine Zhang
883*76f3cd6aSElaine Zhang return rate;
884*76f3cd6aSElaine Zhang };
885*76f3cd6aSElaine Zhang
rv1103b_clk_set_rate(struct clk * clk,ulong rate)886*76f3cd6aSElaine Zhang static ulong rv1103b_clk_set_rate(struct clk *clk, ulong rate)
887*76f3cd6aSElaine Zhang {
888*76f3cd6aSElaine Zhang struct rv1103b_clk_priv *priv = dev_get_priv(clk->dev);
889*76f3cd6aSElaine Zhang ulong ret = 0;
890*76f3cd6aSElaine Zhang
891*76f3cd6aSElaine Zhang if (!priv->gpll_hz) {
892*76f3cd6aSElaine Zhang printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
893*76f3cd6aSElaine Zhang return -ENOENT;
894*76f3cd6aSElaine Zhang }
895*76f3cd6aSElaine Zhang
896*76f3cd6aSElaine Zhang switch (clk->id) {
897*76f3cd6aSElaine Zhang case PLL_GPLL:
898*76f3cd6aSElaine Zhang ret = rockchip_pll_set_rate(&rv1103b_pll_clks[GPLL], priv->cru,
899*76f3cd6aSElaine Zhang GPLL, rate);
900*76f3cd6aSElaine Zhang break;
901*76f3cd6aSElaine Zhang case ACLK_PERI_SRC:
902*76f3cd6aSElaine Zhang case LSCLK_PERI_SRC:
903*76f3cd6aSElaine Zhang case PCLK_PERI_ROOT:
904*76f3cd6aSElaine Zhang case PCLK_TOP_ROOT:
905*76f3cd6aSElaine Zhang case LSCLK_PMU_ROOT:
906*76f3cd6aSElaine Zhang case PCLK_PMU:
907*76f3cd6aSElaine Zhang ret = rv1103b_peri_set_clk(priv, clk->id, rate);
908*76f3cd6aSElaine Zhang break;
909*76f3cd6aSElaine Zhang case ACLK_CRYPTO:
910*76f3cd6aSElaine Zhang case HCLK_CRYPTO:
911*76f3cd6aSElaine Zhang case HCLK_RK_RNG_NS:
912*76f3cd6aSElaine Zhang case HCLK_RK_RNG_S:
913*76f3cd6aSElaine Zhang case CLK_CORE_CRYPTO:
914*76f3cd6aSElaine Zhang case CLK_PKA_CRYPTO:
915*76f3cd6aSElaine Zhang ret = rv1103b_crypto_set_clk(priv, clk->id, rate);
916*76f3cd6aSElaine Zhang break;
917*76f3cd6aSElaine Zhang case CCLK_SDMMC1:
918*76f3cd6aSElaine Zhang case HCLK_SDMMC1:
919*76f3cd6aSElaine Zhang case CCLK_SDMMC0:
920*76f3cd6aSElaine Zhang case HCLK_SDMMC0:
921*76f3cd6aSElaine Zhang case CCLK_EMMC:
922*76f3cd6aSElaine Zhang case HCLK_EMMC:
923*76f3cd6aSElaine Zhang case SCLK_SFC_2X:
924*76f3cd6aSElaine Zhang case HCLK_SFC:
925*76f3cd6aSElaine Zhang ret = rv1103b_mmc_set_clk(priv, clk->id, rate);
926*76f3cd6aSElaine Zhang break;
927*76f3cd6aSElaine Zhang case CLK_I2C1:
928*76f3cd6aSElaine Zhang case CLK_I2C2:
929*76f3cd6aSElaine Zhang case CLK_I2C3:
930*76f3cd6aSElaine Zhang case CLK_I2C4:
931*76f3cd6aSElaine Zhang case CLK_I2C_PERI:
932*76f3cd6aSElaine Zhang case CLK_I2C0:
933*76f3cd6aSElaine Zhang case CLK_I2C_PMU:
934*76f3cd6aSElaine Zhang ret = rv1103b_i2c_set_clk(priv, clk->id, rate);
935*76f3cd6aSElaine Zhang break;
936*76f3cd6aSElaine Zhang case CLK_SPI0:
937*76f3cd6aSElaine Zhang ret = rv1103b_spi_set_clk(priv, clk->id, rate);
938*76f3cd6aSElaine Zhang break;
939*76f3cd6aSElaine Zhang case CLK_PWM0:
940*76f3cd6aSElaine Zhang case CLK_PWM0_SRC:
941*76f3cd6aSElaine Zhang case CLK_PWM1:
942*76f3cd6aSElaine Zhang case CLK_PWM2:
943*76f3cd6aSElaine Zhang ret = rv1103b_pwm_set_clk(priv, clk->id, rate);
944*76f3cd6aSElaine Zhang break;
945*76f3cd6aSElaine Zhang case CLK_SARADC:
946*76f3cd6aSElaine Zhang case CLK_TSADC_TSEN:
947*76f3cd6aSElaine Zhang case CLK_TSADC:
948*76f3cd6aSElaine Zhang ret = rv1103b_adc_set_clk(priv, clk->id, rate);
949*76f3cd6aSElaine Zhang break;
950*76f3cd6aSElaine Zhang case SCLK_UART0:
951*76f3cd6aSElaine Zhang case SCLK_UART1:
952*76f3cd6aSElaine Zhang case SCLK_UART2:
953*76f3cd6aSElaine Zhang ret = rv1103b_uart_set_rate(priv, clk->id, rate);
954*76f3cd6aSElaine Zhang break;
955*76f3cd6aSElaine Zhang case DCLK_DECOM_SRC:
956*76f3cd6aSElaine Zhang case DCLK_DECOM:
957*76f3cd6aSElaine Zhang rate = rv1103b_decom_set_clk(priv, rate);
958*76f3cd6aSElaine Zhang break;
959*76f3cd6aSElaine Zhang default:
960*76f3cd6aSElaine Zhang return -ENOENT;
961*76f3cd6aSElaine Zhang }
962*76f3cd6aSElaine Zhang
963*76f3cd6aSElaine Zhang return ret;
964*76f3cd6aSElaine Zhang };
965*76f3cd6aSElaine Zhang
rv1103b_clk_set_parent(struct clk * clk,struct clk * parent)966*76f3cd6aSElaine Zhang static int rv1103b_clk_set_parent(struct clk *clk, struct clk *parent)
967*76f3cd6aSElaine Zhang {
968*76f3cd6aSElaine Zhang switch (clk->id) {
969*76f3cd6aSElaine Zhang default:
970*76f3cd6aSElaine Zhang return -ENOENT;
971*76f3cd6aSElaine Zhang }
972*76f3cd6aSElaine Zhang
973*76f3cd6aSElaine Zhang return 0;
974*76f3cd6aSElaine Zhang }
975*76f3cd6aSElaine Zhang
976*76f3cd6aSElaine Zhang static struct clk_ops rv1103b_clk_ops = {
977*76f3cd6aSElaine Zhang .get_rate = rv1103b_clk_get_rate,
978*76f3cd6aSElaine Zhang .set_rate = rv1103b_clk_set_rate,
979*76f3cd6aSElaine Zhang #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
980*76f3cd6aSElaine Zhang .set_parent = rv1103b_clk_set_parent,
981*76f3cd6aSElaine Zhang #endif
982*76f3cd6aSElaine Zhang };
983*76f3cd6aSElaine Zhang
rv1103b_clk_init(struct rv1103b_clk_priv * priv)984*76f3cd6aSElaine Zhang static void rv1103b_clk_init(struct rv1103b_clk_priv *priv)
985*76f3cd6aSElaine Zhang {
986*76f3cd6aSElaine Zhang int ret;
987*76f3cd6aSElaine Zhang u32 div;
988*76f3cd6aSElaine Zhang
989*76f3cd6aSElaine Zhang priv->sync_kernel = false;
990*76f3cd6aSElaine Zhang priv->gpll_hz = rockchip_pll_get_rate(&rv1103b_pll_clks[GPLL],
991*76f3cd6aSElaine Zhang priv->cru, GPLL);
992*76f3cd6aSElaine Zhang if (priv->gpll_hz != GPLL_HZ) {
993*76f3cd6aSElaine Zhang ret = rockchip_pll_set_rate(&rv1103b_pll_clks[GPLL], priv->cru,
994*76f3cd6aSElaine Zhang GPLL, GPLL_HZ);
995*76f3cd6aSElaine Zhang if (!ret)
996*76f3cd6aSElaine Zhang priv->gpll_hz = GPLL_HZ;
997*76f3cd6aSElaine Zhang }
998*76f3cd6aSElaine Zhang if (!priv->armclk_enter_hz) {
999*76f3cd6aSElaine Zhang div = (readl(&priv->cru->clksel_con[37]) &
1000*76f3cd6aSElaine Zhang CLK_CORE_GPLL_DIV_MASK) >>
1001*76f3cd6aSElaine Zhang CLK_CORE_GPLL_DIV_SHIFT;
1002*76f3cd6aSElaine Zhang priv->armclk_enter_hz = DIV_TO_RATE(priv->gpll_hz, div);
1003*76f3cd6aSElaine Zhang priv->armclk_init_hz = priv->armclk_enter_hz;
1004*76f3cd6aSElaine Zhang }
1005*76f3cd6aSElaine Zhang }
1006*76f3cd6aSElaine Zhang
rv1103b_clk_probe(struct udevice * dev)1007*76f3cd6aSElaine Zhang static int rv1103b_clk_probe(struct udevice *dev)
1008*76f3cd6aSElaine Zhang {
1009*76f3cd6aSElaine Zhang struct rv1103b_clk_priv *priv = dev_get_priv(dev);
1010*76f3cd6aSElaine Zhang int ret;
1011*76f3cd6aSElaine Zhang
1012*76f3cd6aSElaine Zhang #ifdef CONFIG_SPL_BUILD
1013*76f3cd6aSElaine Zhang /* fix lsclk_prei div */
1014*76f3cd6aSElaine Zhang writel(BITS_WITH_WMASK(1, 0x1U, 9),
1015*76f3cd6aSElaine Zhang RV1103B_CRU_BASE + RV1103B_CLKSEL_CON(31));
1016*76f3cd6aSElaine Zhang /* fix cpu div */
1017*76f3cd6aSElaine Zhang writel(BITS_WITH_WMASK(1, 0x7U, 13),
1018*76f3cd6aSElaine Zhang RV1103B_CRU_BASE + RV1103B_CLKSEL_CON(37));
1019*76f3cd6aSElaine Zhang /* fix gpll postdiv1 */
1020*76f3cd6aSElaine Zhang writel(BITS_WITH_WMASK(1, 0x7U, 12),
1021*76f3cd6aSElaine Zhang RV1103B_CRU_BASE + RV1103B_PLL_CON(24));
1022*76f3cd6aSElaine Zhang #endif
1023*76f3cd6aSElaine Zhang
1024*76f3cd6aSElaine Zhang rv1103b_clk_init(priv);
1025*76f3cd6aSElaine Zhang
1026*76f3cd6aSElaine Zhang /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1027*76f3cd6aSElaine Zhang ret = clk_set_defaults(dev);
1028*76f3cd6aSElaine Zhang if (ret)
1029*76f3cd6aSElaine Zhang debug("%s clk_set_defaults failed %d\n", __func__, ret);
1030*76f3cd6aSElaine Zhang else
1031*76f3cd6aSElaine Zhang priv->sync_kernel = true;
1032*76f3cd6aSElaine Zhang return 0;
1033*76f3cd6aSElaine Zhang }
1034*76f3cd6aSElaine Zhang
rv1103b_clk_ofdata_to_platdata(struct udevice * dev)1035*76f3cd6aSElaine Zhang static int rv1103b_clk_ofdata_to_platdata(struct udevice *dev)
1036*76f3cd6aSElaine Zhang {
1037*76f3cd6aSElaine Zhang struct rv1103b_clk_priv *priv = dev_get_priv(dev);
1038*76f3cd6aSElaine Zhang
1039*76f3cd6aSElaine Zhang priv->cru = dev_read_addr_ptr(dev);
1040*76f3cd6aSElaine Zhang
1041*76f3cd6aSElaine Zhang return 0;
1042*76f3cd6aSElaine Zhang }
1043*76f3cd6aSElaine Zhang
rv1103b_clk_bind(struct udevice * dev)1044*76f3cd6aSElaine Zhang static int rv1103b_clk_bind(struct udevice *dev)
1045*76f3cd6aSElaine Zhang {
1046*76f3cd6aSElaine Zhang int ret;
1047*76f3cd6aSElaine Zhang struct udevice *sys_child, *sf_child;
1048*76f3cd6aSElaine Zhang struct sysreset_reg *priv;
1049*76f3cd6aSElaine Zhang struct softreset_reg *sf_priv;
1050*76f3cd6aSElaine Zhang
1051*76f3cd6aSElaine Zhang /* The reset driver does not have a device node, so bind it here */
1052*76f3cd6aSElaine Zhang ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1053*76f3cd6aSElaine Zhang &sys_child);
1054*76f3cd6aSElaine Zhang if (ret) {
1055*76f3cd6aSElaine Zhang debug("Warning: No sysreset driver: ret=%d\n", ret);
1056*76f3cd6aSElaine Zhang } else {
1057*76f3cd6aSElaine Zhang priv = malloc(sizeof(struct sysreset_reg));
1058*76f3cd6aSElaine Zhang priv->glb_srst_fst_value = offsetof(struct rv1103b_cru,
1059*76f3cd6aSElaine Zhang glb_srst_fst);
1060*76f3cd6aSElaine Zhang priv->glb_srst_snd_value = offsetof(struct rv1103b_cru,
1061*76f3cd6aSElaine Zhang glb_srst_snd);
1062*76f3cd6aSElaine Zhang sys_child->priv = priv;
1063*76f3cd6aSElaine Zhang }
1064*76f3cd6aSElaine Zhang
1065*76f3cd6aSElaine Zhang ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1066*76f3cd6aSElaine Zhang dev_ofnode(dev), &sf_child);
1067*76f3cd6aSElaine Zhang if (ret) {
1068*76f3cd6aSElaine Zhang debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1069*76f3cd6aSElaine Zhang } else {
1070*76f3cd6aSElaine Zhang sf_priv = malloc(sizeof(struct softreset_reg));
1071*76f3cd6aSElaine Zhang sf_priv->sf_reset_offset = offsetof(struct rv1103b_cru,
1072*76f3cd6aSElaine Zhang peri_softrst_con[0]);
1073*76f3cd6aSElaine Zhang sf_priv->sf_reset_num = CLK_NR_SRST;
1074*76f3cd6aSElaine Zhang sf_child->priv = sf_priv;
1075*76f3cd6aSElaine Zhang }
1076*76f3cd6aSElaine Zhang
1077*76f3cd6aSElaine Zhang return 0;
1078*76f3cd6aSElaine Zhang }
1079*76f3cd6aSElaine Zhang
1080*76f3cd6aSElaine Zhang static const struct udevice_id rv1103b_clk_ids[] = {
1081*76f3cd6aSElaine Zhang { .compatible = "rockchip,rv1103b-cru" },
1082*76f3cd6aSElaine Zhang { }
1083*76f3cd6aSElaine Zhang };
1084*76f3cd6aSElaine Zhang
1085*76f3cd6aSElaine Zhang U_BOOT_DRIVER(rockchip_rv1103b_cru) = {
1086*76f3cd6aSElaine Zhang .name = "rockchip_rv1103b_cru",
1087*76f3cd6aSElaine Zhang .id = UCLASS_CLK,
1088*76f3cd6aSElaine Zhang .of_match = rv1103b_clk_ids,
1089*76f3cd6aSElaine Zhang .priv_auto_alloc_size = sizeof(struct rv1103b_clk_priv),
1090*76f3cd6aSElaine Zhang .ofdata_to_platdata = rv1103b_clk_ofdata_to_platdata,
1091*76f3cd6aSElaine Zhang .ops = &rv1103b_clk_ops,
1092*76f3cd6aSElaine Zhang .bind = rv1103b_clk_bind,
1093*76f3cd6aSElaine Zhang .probe = rv1103b_clk_probe,
1094*76f3cd6aSElaine Zhang };
1095*76f3cd6aSElaine Zhang
1096*76f3cd6aSElaine Zhang #ifndef CONFIG_SPL_BUILD
1097*76f3cd6aSElaine Zhang /**
1098*76f3cd6aSElaine Zhang * soc_clk_dump() - Print clock frequencies
1099*76f3cd6aSElaine Zhang * Returns zero on success
1100*76f3cd6aSElaine Zhang *
1101*76f3cd6aSElaine Zhang * Implementation for the clk dump command.
1102*76f3cd6aSElaine Zhang */
soc_clk_dump(void)1103*76f3cd6aSElaine Zhang int soc_clk_dump(void)
1104*76f3cd6aSElaine Zhang {
1105*76f3cd6aSElaine Zhang struct udevice *cru_dev;
1106*76f3cd6aSElaine Zhang struct rv1103b_clk_priv *priv;
1107*76f3cd6aSElaine Zhang const struct rv1103b_clk_info *clk_dump;
1108*76f3cd6aSElaine Zhang struct clk clk;
1109*76f3cd6aSElaine Zhang unsigned long clk_count = ARRAY_SIZE(clks_dump);
1110*76f3cd6aSElaine Zhang unsigned long rate;
1111*76f3cd6aSElaine Zhang int i, ret;
1112*76f3cd6aSElaine Zhang
1113*76f3cd6aSElaine Zhang ret = uclass_get_device_by_driver(UCLASS_CLK,
1114*76f3cd6aSElaine Zhang DM_GET_DRIVER(rockchip_rv1103b_cru),
1115*76f3cd6aSElaine Zhang &cru_dev);
1116*76f3cd6aSElaine Zhang if (ret) {
1117*76f3cd6aSElaine Zhang printf("%s failed to get cru device\n", __func__);
1118*76f3cd6aSElaine Zhang return ret;
1119*76f3cd6aSElaine Zhang }
1120*76f3cd6aSElaine Zhang
1121*76f3cd6aSElaine Zhang priv = dev_get_priv(cru_dev);
1122*76f3cd6aSElaine Zhang ret = (readl(&priv->cru->core_clksel_con[0]) &
1123*76f3cd6aSElaine Zhang CLK_CORE_SRC_SEL_MASK) >>
1124*76f3cd6aSElaine Zhang CLK_CORE_SRC_SEL_SHIFT;
1125*76f3cd6aSElaine Zhang if (ret == CLK_CORE_SRC_SEL_PVTPLL)
1126*76f3cd6aSElaine Zhang printf("CLK: (arm clk use pvtpll, rate = 1200M)\n");
1127*76f3cd6aSElaine Zhang else
1128*76f3cd6aSElaine Zhang printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1129*76f3cd6aSElaine Zhang priv->sync_kernel ? "sync kernel" : "uboot",
1130*76f3cd6aSElaine Zhang priv->armclk_enter_hz / 1000,
1131*76f3cd6aSElaine Zhang priv->armclk_init_hz / 1000,
1132*76f3cd6aSElaine Zhang priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1133*76f3cd6aSElaine Zhang priv->set_armclk_rate ? " KHz" : "N/A");
1134*76f3cd6aSElaine Zhang for (i = 0; i < clk_count; i++) {
1135*76f3cd6aSElaine Zhang clk_dump = &clks_dump[i];
1136*76f3cd6aSElaine Zhang if (clk_dump->name) {
1137*76f3cd6aSElaine Zhang clk.id = clk_dump->id;
1138*76f3cd6aSElaine Zhang if (clk_dump->is_cru)
1139*76f3cd6aSElaine Zhang ret = clk_request(cru_dev, &clk);
1140*76f3cd6aSElaine Zhang if (ret < 0)
1141*76f3cd6aSElaine Zhang return ret;
1142*76f3cd6aSElaine Zhang
1143*76f3cd6aSElaine Zhang rate = clk_get_rate(&clk);
1144*76f3cd6aSElaine Zhang clk_free(&clk);
1145*76f3cd6aSElaine Zhang if (i == 0) {
1146*76f3cd6aSElaine Zhang if (rate < 0)
1147*76f3cd6aSElaine Zhang printf(" %s %s\n", clk_dump->name,
1148*76f3cd6aSElaine Zhang "unknown");
1149*76f3cd6aSElaine Zhang else
1150*76f3cd6aSElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
1151*76f3cd6aSElaine Zhang rate / 1000);
1152*76f3cd6aSElaine Zhang } else {
1153*76f3cd6aSElaine Zhang if (rate < 0)
1154*76f3cd6aSElaine Zhang printf(" %s %s\n", clk_dump->name,
1155*76f3cd6aSElaine Zhang "unknown");
1156*76f3cd6aSElaine Zhang else
1157*76f3cd6aSElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
1158*76f3cd6aSElaine Zhang rate / 1000);
1159*76f3cd6aSElaine Zhang }
1160*76f3cd6aSElaine Zhang }
1161*76f3cd6aSElaine Zhang }
1162*76f3cd6aSElaine Zhang
1163*76f3cd6aSElaine Zhang return 0;
1164*76f3cd6aSElaine Zhang }
1165*76f3cd6aSElaine Zhang #endif
1166