1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2020 Rockchip Electronics Co. Ltd.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author: Wyon Bi <bivvy.bi@rock-chips.com>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include "rk628.h"
9*4882a593Smuzhiyun #include "rk628_cru.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #define REFCLK_RATE 24000000UL
12*4882a593Smuzhiyun #define MIN_FREF_RATE 10000000UL
13*4882a593Smuzhiyun #define MAX_FREF_RATE 800000000UL
14*4882a593Smuzhiyun #define MIN_FREFDIV_RATE 1000000UL
15*4882a593Smuzhiyun #define MAX_FREFDIV_RATE 100000000UL
16*4882a593Smuzhiyun #define MIN_FVCO_RATE 600000000UL
17*4882a593Smuzhiyun #define MAX_FVCO_RATE 1600000000UL
18*4882a593Smuzhiyun #define MIN_FOUTPOSTDIV_RATE 12000000UL
19*4882a593Smuzhiyun #define MAX_FOUTPOSTDIV_RATE 1600000000UL
20*4882a593Smuzhiyun
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)21*4882a593Smuzhiyun static void rational_best_approximation(unsigned long given_numerator,
22*4882a593Smuzhiyun unsigned long given_denominator,
23*4882a593Smuzhiyun unsigned long max_numerator,
24*4882a593Smuzhiyun unsigned long max_denominator,
25*4882a593Smuzhiyun unsigned long *best_numerator,
26*4882a593Smuzhiyun unsigned long *best_denominator)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun unsigned long n, d, n0, d0, n1, d1;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun n = given_numerator;
31*4882a593Smuzhiyun d = given_denominator;
32*4882a593Smuzhiyun n0 = d1 = 0;
33*4882a593Smuzhiyun n1 = d0 = 1;
34*4882a593Smuzhiyun for (;;) {
35*4882a593Smuzhiyun unsigned long t, a;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun if ((n1 > max_numerator) || (d1 > max_denominator)) {
38*4882a593Smuzhiyun n1 = n0;
39*4882a593Smuzhiyun d1 = d0;
40*4882a593Smuzhiyun break;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun if (d == 0)
43*4882a593Smuzhiyun break;
44*4882a593Smuzhiyun t = d;
45*4882a593Smuzhiyun a = n / d;
46*4882a593Smuzhiyun d = n % d;
47*4882a593Smuzhiyun n = t;
48*4882a593Smuzhiyun t = n0 + a * n1;
49*4882a593Smuzhiyun n0 = n1;
50*4882a593Smuzhiyun n1 = t;
51*4882a593Smuzhiyun t = d0 + a * d1;
52*4882a593Smuzhiyun d0 = d1;
53*4882a593Smuzhiyun d1 = t;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun *best_numerator = n1;
56*4882a593Smuzhiyun *best_denominator = d1;
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
rk628_cru_clk_get_rate_pll(struct rk628 * rk628,unsigned int id)59*4882a593Smuzhiyun static unsigned long rk628_cru_clk_get_rate_pll(struct rk628 *rk628,
60*4882a593Smuzhiyun unsigned int id)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun unsigned long parent_rate = REFCLK_RATE;
63*4882a593Smuzhiyun u32 postdiv1, fbdiv, dsmpd, postdiv2, refdiv, frac, bypass;
64*4882a593Smuzhiyun u32 con0, con1, con2;
65*4882a593Smuzhiyun u64 foutvco, foutpostdiv;
66*4882a593Smuzhiyun u32 offset, val;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun rk628_i2c_read(rk628, CRU_MODE_CON00, &val);
69*4882a593Smuzhiyun if (id == CGU_CLK_CPLL) {
70*4882a593Smuzhiyun val &= CLK_CPLL_MODE_MASK;
71*4882a593Smuzhiyun val >>= CLK_CPLL_MODE_SHIFT;
72*4882a593Smuzhiyun if (val == CLK_CPLL_MODE_OSC)
73*4882a593Smuzhiyun return parent_rate;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun offset = 0x00;
76*4882a593Smuzhiyun } else {
77*4882a593Smuzhiyun val &= CLK_GPLL_MODE_MASK;
78*4882a593Smuzhiyun val >>= CLK_GPLL_MODE_SHIFT;
79*4882a593Smuzhiyun if (val == CLK_GPLL_MODE_OSC)
80*4882a593Smuzhiyun return parent_rate;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun offset = 0x20;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun rk628_i2c_read(rk628, offset + CRU_CPLL_CON0, &con0);
86*4882a593Smuzhiyun rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &con1);
87*4882a593Smuzhiyun rk628_i2c_read(rk628, offset + CRU_CPLL_CON2, &con2);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun bypass = (con0 & PLL_BYPASS_MASK) >> PLL_BYPASS_SHIFT;
90*4882a593Smuzhiyun postdiv1 = (con0 & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
91*4882a593Smuzhiyun fbdiv = (con0 & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
92*4882a593Smuzhiyun dsmpd = (con1 & PLL_DSMPD_MASK) >> PLL_DSMPD_SHIFT;
93*4882a593Smuzhiyun postdiv2 = (con1 & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
94*4882a593Smuzhiyun refdiv = (con1 & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
95*4882a593Smuzhiyun frac = (con2 & PLL_FRAC_MASK) >> PLL_FRAC_SHIFT;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun if (bypass)
98*4882a593Smuzhiyun return parent_rate;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun foutvco = parent_rate * fbdiv;
101*4882a593Smuzhiyun do_div(foutvco, refdiv);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun if (!dsmpd) {
104*4882a593Smuzhiyun u64 frac_rate = (u64)parent_rate * frac;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun do_div(frac_rate, refdiv);
107*4882a593Smuzhiyun foutvco += frac_rate >> 24;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun foutpostdiv = foutvco;
111*4882a593Smuzhiyun do_div(foutpostdiv, postdiv1);
112*4882a593Smuzhiyun do_div(foutpostdiv, postdiv2);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun return foutpostdiv;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
rk628_cru_clk_set_rate_pll(struct rk628 * rk628,unsigned int id,unsigned long rate)117*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
118*4882a593Smuzhiyun unsigned int id,
119*4882a593Smuzhiyun unsigned long rate)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun unsigned long fin = REFCLK_RATE, fout = rate;
122*4882a593Smuzhiyun u8 min_refdiv, max_refdiv, postdiv;
123*4882a593Smuzhiyun u8 dsmpd = 1, postdiv1 = 0, postdiv2 = 0, refdiv = 0;
124*4882a593Smuzhiyun u16 fbdiv = 0;
125*4882a593Smuzhiyun u32 frac = 0;
126*4882a593Smuzhiyun u64 foutvco, foutpostdiv;
127*4882a593Smuzhiyun u32 offset, val;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun /*
130*4882a593Smuzhiyun * FREF : 10MHz ~ 800MHz
131*4882a593Smuzhiyun * FREFDIV : 1MHz ~ 40MHz
132*4882a593Smuzhiyun * FOUTVCO : 400MHz ~ 1.6GHz
133*4882a593Smuzhiyun * FOUTPOSTDIV : 8MHz ~ 1.6GHz
134*4882a593Smuzhiyun */
135*4882a593Smuzhiyun if (fin < MIN_FREF_RATE || fin > MAX_FREF_RATE)
136*4882a593Smuzhiyun return 0;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (fout < MIN_FOUTPOSTDIV_RATE || fout > MAX_FOUTPOSTDIV_RATE)
139*4882a593Smuzhiyun return 0;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (id == CGU_CLK_CPLL)
142*4882a593Smuzhiyun offset = 0x00;
143*4882a593Smuzhiyun else
144*4882a593Smuzhiyun offset = 0x20;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(1));
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun if (fin == fout) {
149*4882a593Smuzhiyun rk628_i2c_write(rk628, offset + CRU_CPLL_CON0, PLL_BYPASS(1));
150*4882a593Smuzhiyun rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(0));
151*4882a593Smuzhiyun while (1) {
152*4882a593Smuzhiyun rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &val);
153*4882a593Smuzhiyun if (val & PLL_LOCK)
154*4882a593Smuzhiyun break;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun return fin;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun min_refdiv = fin / MAX_FREFDIV_RATE + 1;
160*4882a593Smuzhiyun max_refdiv = fin / MIN_FREFDIV_RATE;
161*4882a593Smuzhiyun if (max_refdiv > 64)
162*4882a593Smuzhiyun max_refdiv = 64;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (fout < MIN_FVCO_RATE) {
165*4882a593Smuzhiyun postdiv = MIN_FVCO_RATE / fout + 1;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun for (postdiv2 = 1; postdiv2 < 8; postdiv2++) {
168*4882a593Smuzhiyun if (postdiv % postdiv2)
169*4882a593Smuzhiyun continue;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun postdiv1 = postdiv / postdiv2;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun if (postdiv1 > 0 && postdiv1 < 8)
174*4882a593Smuzhiyun break;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (postdiv2 > 7)
178*4882a593Smuzhiyun return 0;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun fout *= postdiv1 * postdiv2;
181*4882a593Smuzhiyun } else {
182*4882a593Smuzhiyun postdiv1 = 1;
183*4882a593Smuzhiyun postdiv2 = 1;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun for (refdiv = min_refdiv; refdiv <= max_refdiv; refdiv++) {
187*4882a593Smuzhiyun u64 tmp, frac_rate;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun if (fin % refdiv)
190*4882a593Smuzhiyun continue;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun tmp = (u64)fout * refdiv;
193*4882a593Smuzhiyun do_div(tmp, fin);
194*4882a593Smuzhiyun fbdiv = tmp;
195*4882a593Smuzhiyun if (fbdiv < 10 || fbdiv > 1600)
196*4882a593Smuzhiyun continue;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun tmp = (u64)fbdiv * fin;
199*4882a593Smuzhiyun do_div(tmp, refdiv);
200*4882a593Smuzhiyun if (fout < MIN_FVCO_RATE || fout > MAX_FVCO_RATE)
201*4882a593Smuzhiyun continue;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun frac_rate = fout - tmp;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (frac_rate) {
206*4882a593Smuzhiyun tmp = (u64)frac_rate * refdiv;
207*4882a593Smuzhiyun tmp <<= 24;
208*4882a593Smuzhiyun do_div(tmp, fin);
209*4882a593Smuzhiyun frac = tmp;
210*4882a593Smuzhiyun dsmpd = 0;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun break;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun /*
217*4882a593Smuzhiyun * If DSMPD = 1 (DSM is disabled, "integer mode")
218*4882a593Smuzhiyun * FOUTVCO = FREF / REFDIV * FBDIV
219*4882a593Smuzhiyun * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
220*4882a593Smuzhiyun *
221*4882a593Smuzhiyun * If DSMPD = 0 (DSM is enabled, "fractional mode")
222*4882a593Smuzhiyun * FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 2^24)
223*4882a593Smuzhiyun * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
224*4882a593Smuzhiyun */
225*4882a593Smuzhiyun foutvco = fin * fbdiv;
226*4882a593Smuzhiyun do_div(foutvco, refdiv);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (!dsmpd) {
229*4882a593Smuzhiyun u64 frac_rate = (u64)fin * frac;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun do_div(frac_rate, refdiv);
232*4882a593Smuzhiyun foutvco += frac_rate >> 24;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun foutpostdiv = foutvco;
236*4882a593Smuzhiyun do_div(foutpostdiv, postdiv1);
237*4882a593Smuzhiyun do_div(foutpostdiv, postdiv2);
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun rk628_i2c_write(rk628, offset + CRU_CPLL_CON0,
240*4882a593Smuzhiyun PLL_BYPASS(0) | PLL_POSTDIV1(postdiv1) |
241*4882a593Smuzhiyun PLL_FBDIV(fbdiv));
242*4882a593Smuzhiyun rk628_i2c_write(rk628, offset + CRU_CPLL_CON1,
243*4882a593Smuzhiyun PLL_DSMPD(dsmpd) | PLL_POSTDIV2(postdiv2) |
244*4882a593Smuzhiyun PLL_REFDIV(refdiv));
245*4882a593Smuzhiyun rk628_i2c_write(rk628, offset + CRU_CPLL_CON2, PLL_FRAC(frac));
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(0));
248*4882a593Smuzhiyun while (1) {
249*4882a593Smuzhiyun rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &val);
250*4882a593Smuzhiyun if (val & PLL_LOCK)
251*4882a593Smuzhiyun break;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun return (unsigned long)foutpostdiv;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
rk628_cru_clk_set_rate_sclk_vop(struct rk628 * rk628,unsigned long rate)257*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_sclk_vop(struct rk628 *rk628,
258*4882a593Smuzhiyun unsigned long rate)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun unsigned long m, n, parent_rate;
261*4882a593Smuzhiyun u32 val;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &val);
264*4882a593Smuzhiyun val &= SCLK_VOP_SEL_MASK;
265*4882a593Smuzhiyun val >>= SCLK_VOP_SEL_SHIFT;
266*4882a593Smuzhiyun if (val == SCLK_VOP_SEL_GPLL)
267*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
268*4882a593Smuzhiyun else
269*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun rational_best_approximation(rate, parent_rate,
272*4882a593Smuzhiyun GENMASK(15, 0), GENMASK(15, 0),
273*4882a593Smuzhiyun &m, &n);
274*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON13, m << 16 | n);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun return rate;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
rk628_cru_clk_get_rate_sclk_vop(struct rk628 * rk628)279*4882a593Smuzhiyun static unsigned long rk628_cru_clk_get_rate_sclk_vop(struct rk628 *rk628)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun unsigned long rate, parent_rate, m, n;
282*4882a593Smuzhiyun u32 mux, div;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &mux);
285*4882a593Smuzhiyun mux &= CLK_UART_SRC_SEL_MASK;
286*4882a593Smuzhiyun mux >>= SCLK_VOP_SEL_SHIFT;
287*4882a593Smuzhiyun if (mux == SCLK_VOP_SEL_GPLL)
288*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
289*4882a593Smuzhiyun else
290*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun rk628_i2c_read(rk628, CRU_CLKSEL_CON13, &div);
293*4882a593Smuzhiyun m = div >> 16 & 0xffff;
294*4882a593Smuzhiyun n = div & 0xffff;
295*4882a593Smuzhiyun rate = parent_rate * m / n;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun return rate;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
rk628_cru_clk_set_rate_rx_read(struct rk628 * rk628,unsigned long rate)300*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_rx_read(struct rk628 *rk628,
301*4882a593Smuzhiyun unsigned long rate)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun unsigned long m, n, parent_rate;
304*4882a593Smuzhiyun u32 val;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &val);
307*4882a593Smuzhiyun val &= CLK_RX_READ_SEL_MASK;
308*4882a593Smuzhiyun val >>= CLK_RX_READ_SEL_SHIFT;
309*4882a593Smuzhiyun if (val == CLK_RX_READ_SEL_GPLL)
310*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
311*4882a593Smuzhiyun else
312*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun rational_best_approximation(rate, parent_rate,
315*4882a593Smuzhiyun GENMASK(15, 0), GENMASK(15, 0),
316*4882a593Smuzhiyun &m, &n);
317*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON14, m << 16 | n);
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun return rate;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
rk628_cru_clk_get_rate_uart_src(struct rk628 * rk628)322*4882a593Smuzhiyun static unsigned long rk628_cru_clk_get_rate_uart_src(struct rk628 *rk628)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun unsigned long rate, parent_rate;
325*4882a593Smuzhiyun u32 mux, div;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun rk628_i2c_read(rk628, CRU_CLKSEL_CON21, &mux);
328*4882a593Smuzhiyun mux &= SCLK_VOP_SEL_MASK;
329*4882a593Smuzhiyun if (mux == CLK_UART_SRC_SEL_GPLL)
330*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
331*4882a593Smuzhiyun else
332*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun rk628_i2c_read(rk628, CRU_CLKSEL_CON21, &div);
335*4882a593Smuzhiyun div &= CLK_UART_SRC_DIV_MASK;
336*4882a593Smuzhiyun div >>= CLK_UART_SRC_DIV_SHIFT;
337*4882a593Smuzhiyun rate = parent_rate / (div + 1);
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun return rate;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
rk628_cru_clk_set_rate_sclk_uart(struct rk628 * rk628,unsigned long rate)342*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_sclk_uart(struct rk628 *rk628,
343*4882a593Smuzhiyun unsigned long rate)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun unsigned long m, n, parent_rate;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_uart_src(rk628);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun if (rate == REFCLK_RATE) {
350*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
351*4882a593Smuzhiyun SCLK_UART_SEL(SCLK_UART_SEL_OSC));
352*4882a593Smuzhiyun return rate;
353*4882a593Smuzhiyun } else if (rate == parent_rate) {
354*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
355*4882a593Smuzhiyun SCLK_UART_SEL(SCLK_UART_SEL_UART_SRC));
356*4882a593Smuzhiyun return rate;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
360*4882a593Smuzhiyun SCLK_UART_SEL(SCLK_UART_SEL_UART_FRAC));
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun rational_best_approximation(rate, parent_rate,
363*4882a593Smuzhiyun GENMASK(15, 0), GENMASK(15, 0),
364*4882a593Smuzhiyun &m, &n);
365*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON20, m << 16 | n);
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun return rate;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun static unsigned long
rk628_cru_clk_get_rate_bt1120_dec_parent(struct rk628 * rk628)371*4882a593Smuzhiyun rk628_cru_clk_get_rate_bt1120_dec_parent(struct rk628 *rk628)
372*4882a593Smuzhiyun {
373*4882a593Smuzhiyun unsigned long parent_rate;
374*4882a593Smuzhiyun u32 mux;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &mux);
377*4882a593Smuzhiyun mux &= CLK_BT1120DEC_SEL_MASK;
378*4882a593Smuzhiyun if (mux == CLK_BT1120DEC_SEL_GPLL)
379*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
380*4882a593Smuzhiyun else
381*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun return parent_rate;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
rk628_cru_clk_set_rate_bt1120_dec(struct rk628 * rk628,unsigned long rate)386*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_bt1120_dec(struct rk628 *rk628,
387*4882a593Smuzhiyun unsigned long rate)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun unsigned long parent_rate;
390*4882a593Smuzhiyun u32 div;
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun parent_rate = rk628_cru_clk_get_rate_bt1120_dec_parent(rk628);
393*4882a593Smuzhiyun div = DIV_ROUND_UP(parent_rate, rate);
394*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON02, CLK_BT1120DEC_DIV(div-1));
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun return parent_rate / div;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
rk628_cru_clk_set_rate(struct rk628 * rk628,unsigned int id,unsigned long rate)399*4882a593Smuzhiyun int rk628_cru_clk_set_rate(struct rk628 *rk628, unsigned int id,
400*4882a593Smuzhiyun unsigned long rate)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun switch (id) {
403*4882a593Smuzhiyun case CGU_CLK_CPLL:
404*4882a593Smuzhiyun case CGU_CLK_GPLL:
405*4882a593Smuzhiyun rk628_cru_clk_set_rate_pll(rk628, id, rate);
406*4882a593Smuzhiyun break;
407*4882a593Smuzhiyun case CGU_CLK_RX_READ:
408*4882a593Smuzhiyun rk628_cru_clk_set_rate_rx_read(rk628, rate);
409*4882a593Smuzhiyun break;
410*4882a593Smuzhiyun case CGU_SCLK_VOP:
411*4882a593Smuzhiyun rk628_cru_clk_set_rate_sclk_vop(rk628, rate);
412*4882a593Smuzhiyun break;
413*4882a593Smuzhiyun case CGU_SCLK_UART:
414*4882a593Smuzhiyun rk628_cru_clk_set_rate_sclk_uart(rk628, rate);
415*4882a593Smuzhiyun break;
416*4882a593Smuzhiyun case CGU_BT1120DEC:
417*4882a593Smuzhiyun rk628_cru_clk_set_rate_bt1120_dec(rk628, rate);
418*4882a593Smuzhiyun break;
419*4882a593Smuzhiyun default:
420*4882a593Smuzhiyun return -1;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun return 0;
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
rk628_cru_clk_get_rate(struct rk628 * rk628,unsigned int id)426*4882a593Smuzhiyun unsigned long rk628_cru_clk_get_rate(struct rk628 *rk628, unsigned int id)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun unsigned long rate;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun switch (id) {
431*4882a593Smuzhiyun case CGU_CLK_CPLL:
432*4882a593Smuzhiyun case CGU_CLK_GPLL:
433*4882a593Smuzhiyun rate = rk628_cru_clk_get_rate_pll(rk628, id);
434*4882a593Smuzhiyun break;
435*4882a593Smuzhiyun case CGU_SCLK_VOP:
436*4882a593Smuzhiyun rate = rk628_cru_clk_get_rate_sclk_vop(rk628);
437*4882a593Smuzhiyun break;
438*4882a593Smuzhiyun default:
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun return rate;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
rk628_cru_init(struct rk628 * rk628)445*4882a593Smuzhiyun void rk628_cru_init(struct rk628 *rk628)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun u32 val;
448*4882a593Smuzhiyun u8 mcu_mode;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun rk628_i2c_read(rk628, GRF_SYSTEM_STATUS0, &val);
451*4882a593Smuzhiyun mcu_mode = (val & I2C_ONLY_FLAG) ? 0 : 1;
452*4882a593Smuzhiyun if (mcu_mode)
453*4882a593Smuzhiyun return;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_GPLL_CON0, 0xffff701d);
456*4882a593Smuzhiyun mdelay(1);
457*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_MODE_CON00, 0xffff0004);
458*4882a593Smuzhiyun mdelay(1);
459*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0080);
460*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0083);
461*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CPLL_CON0, 0xffff3063);
462*4882a593Smuzhiyun mdelay(1);
463*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_MODE_CON00, 0xffff0005);
464*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0003);
465*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff000b);
466*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_GPLL_CON0, 0xffff1028);
467*4882a593Smuzhiyun mdelay(1);
468*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff008b);
469*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CPLL_CON0, 0xffff1063);
470*4882a593Smuzhiyun mdelay(1);
471*4882a593Smuzhiyun rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff000b);
472*4882a593Smuzhiyun }
473