xref: /OK3568_Linux_fs/kernel/drivers/media/i2c/rk628/rk628_cru.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2020 Rockchip Electronics Co. Ltd.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Author: Shunqing Chen <csq@rock-chips.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/delay.h>
9*4882a593Smuzhiyun #include "rk628.h"
10*4882a593Smuzhiyun #include "rk628_cru.h"
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #define REFCLK_RATE		24000000UL
13*4882a593Smuzhiyun #define MIN_FREF_RATE		10000000UL
14*4882a593Smuzhiyun #define MAX_FREF_RATE		800000000UL
15*4882a593Smuzhiyun #define MIN_FREFDIV_RATE	1000000UL
16*4882a593Smuzhiyun #define MAX_FREFDIV_RATE	100000000UL
17*4882a593Smuzhiyun #define MIN_FVCO_RATE		600000000UL
18*4882a593Smuzhiyun #define MAX_FVCO_RATE		1600000000UL
19*4882a593Smuzhiyun #define MIN_FOUTPOSTDIV_RATE	12000000UL
20*4882a593Smuzhiyun #define MAX_FOUTPOSTDIV_RATE	1600000000UL
21*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)22*4882a593Smuzhiyun static void rational_best_approximation(unsigned long given_numerator,
23*4882a593Smuzhiyun 					unsigned long given_denominator,
24*4882a593Smuzhiyun 					unsigned long max_numerator,
25*4882a593Smuzhiyun 					unsigned long max_denominator,
26*4882a593Smuzhiyun 					unsigned long *best_numerator,
27*4882a593Smuzhiyun 					unsigned long *best_denominator)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	unsigned long n, d, n0, d0, n1, d1;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	n = given_numerator;
32*4882a593Smuzhiyun 	d = given_denominator;
33*4882a593Smuzhiyun 	n0 = d1 = 0;
34*4882a593Smuzhiyun 	n1 = d0 = 1;
35*4882a593Smuzhiyun 	for (;;) {
36*4882a593Smuzhiyun 		unsigned long t, a;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 		if ((n1 > max_numerator) || (d1 > max_denominator)) {
39*4882a593Smuzhiyun 			n1 = n0;
40*4882a593Smuzhiyun 			d1 = d0;
41*4882a593Smuzhiyun 			break;
42*4882a593Smuzhiyun 		}
43*4882a593Smuzhiyun 		if (d == 0)
44*4882a593Smuzhiyun 			break;
45*4882a593Smuzhiyun 		t = d;
46*4882a593Smuzhiyun 		a = n / d;
47*4882a593Smuzhiyun 		d = n % d;
48*4882a593Smuzhiyun 		n = t;
49*4882a593Smuzhiyun 		t = n0 + a * n1;
50*4882a593Smuzhiyun 		n0 = n1;
51*4882a593Smuzhiyun 		n1 = t;
52*4882a593Smuzhiyun 		t = d0 + a * d1;
53*4882a593Smuzhiyun 		d0 = d1;
54*4882a593Smuzhiyun 		d1 = t;
55*4882a593Smuzhiyun 	}
56*4882a593Smuzhiyun 	*best_numerator = n1;
57*4882a593Smuzhiyun 	*best_denominator = d1;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
rk628_cru_clk_get_rate_pll(struct rk628 * rk628,unsigned int id)60*4882a593Smuzhiyun static unsigned long rk628_cru_clk_get_rate_pll(struct rk628 *rk628,
61*4882a593Smuzhiyun 						unsigned int id)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	unsigned long parent_rate = REFCLK_RATE;
64*4882a593Smuzhiyun 	u32 postdiv1, fbdiv, dsmpd, postdiv2, refdiv, frac, bypass;
65*4882a593Smuzhiyun 	u32 con0, con1, con2;
66*4882a593Smuzhiyun 	u64 foutvco, foutpostdiv;
67*4882a593Smuzhiyun 	u32 offset, val;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	rk628_i2c_read(rk628, CRU_MODE_CON00, &val);
70*4882a593Smuzhiyun 	if (id == CGU_CLK_CPLL) {
71*4882a593Smuzhiyun 		val &= CLK_CPLL_MODE_MASK;
72*4882a593Smuzhiyun 		val >>= CLK_CPLL_MODE_SHIFT;
73*4882a593Smuzhiyun 		if (val == CLK_CPLL_MODE_OSC)
74*4882a593Smuzhiyun 			return parent_rate;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 		offset = 0x00;
77*4882a593Smuzhiyun 	} else {
78*4882a593Smuzhiyun 		val &= CLK_GPLL_MODE_MASK;
79*4882a593Smuzhiyun 		val >>= CLK_GPLL_MODE_SHIFT;
80*4882a593Smuzhiyun 		if (val == CLK_GPLL_MODE_OSC)
81*4882a593Smuzhiyun 			return parent_rate;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 		offset = 0x20;
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	rk628_i2c_read(rk628, offset + CRU_CPLL_CON0, &con0);
87*4882a593Smuzhiyun 	rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &con1);
88*4882a593Smuzhiyun 	rk628_i2c_read(rk628, offset + CRU_CPLL_CON2, &con2);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	bypass = (con0 & PLL_BYPASS_MASK) >> PLL_BYPASS_SHIFT;
91*4882a593Smuzhiyun 	postdiv1 = (con0 & PLL_POSTDIV1_MASK) >> PLL_POSTDIV1_SHIFT;
92*4882a593Smuzhiyun 	fbdiv = (con0 & PLL_FBDIV_MASK) >> PLL_FBDIV_SHIFT;
93*4882a593Smuzhiyun 	dsmpd = (con1 & PLL_DSMPD_MASK) >> PLL_DSMPD_SHIFT;
94*4882a593Smuzhiyun 	postdiv2 = (con1 & PLL_POSTDIV2_MASK) >> PLL_POSTDIV2_SHIFT;
95*4882a593Smuzhiyun 	refdiv = (con1 & PLL_REFDIV_MASK) >> PLL_REFDIV_SHIFT;
96*4882a593Smuzhiyun 	frac = (con2 & PLL_FRAC_MASK) >> PLL_FRAC_SHIFT;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (bypass)
99*4882a593Smuzhiyun 		return parent_rate;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	foutvco = parent_rate * fbdiv;
102*4882a593Smuzhiyun 	do_div(foutvco, refdiv);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	if (!dsmpd) {
105*4882a593Smuzhiyun 		u64 frac_rate = (u64)parent_rate * frac;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 		do_div(frac_rate, refdiv);
108*4882a593Smuzhiyun 		foutvco += frac_rate >> 24;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	foutpostdiv = foutvco;
112*4882a593Smuzhiyun 	do_div(foutpostdiv, postdiv1);
113*4882a593Smuzhiyun 	do_div(foutpostdiv, postdiv2);
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	return foutpostdiv;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun 
rk628_cru_clk_set_rate_pll(struct rk628 * rk628,unsigned int id,unsigned long rate)118*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
119*4882a593Smuzhiyun 						unsigned int id,
120*4882a593Smuzhiyun 						unsigned long rate)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	unsigned long fin = REFCLK_RATE, fout = rate;
123*4882a593Smuzhiyun 	u8 min_refdiv, max_refdiv, postdiv, div1, div2;
124*4882a593Smuzhiyun 	u8 dsmpd = 1, postdiv1 = 0, postdiv2 = 0, refdiv = 0;
125*4882a593Smuzhiyun 	u16 fbdiv = 0;
126*4882a593Smuzhiyun 	u32 frac = 0;
127*4882a593Smuzhiyun 	u64 foutvco, foutpostdiv;
128*4882a593Smuzhiyun 	u32 offset, val;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	/*
131*4882a593Smuzhiyun 	 * FREF : 10MHz ~ 800MHz
132*4882a593Smuzhiyun 	 * FREFDIV : 1MHz ~ 40MHz
133*4882a593Smuzhiyun 	 * FOUTVCO : 400MHz ~ 1.6GHz
134*4882a593Smuzhiyun 	 * FOUTPOSTDIV : 8MHz ~ 1.6GHz
135*4882a593Smuzhiyun 	 */
136*4882a593Smuzhiyun 	if (fin < MIN_FREF_RATE || fin > MAX_FREF_RATE)
137*4882a593Smuzhiyun 		return 0;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (fout < MIN_FOUTPOSTDIV_RATE || fout > MAX_FOUTPOSTDIV_RATE)
140*4882a593Smuzhiyun 		return 0;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (id == CGU_CLK_CPLL)
143*4882a593Smuzhiyun 		offset = 0x00;
144*4882a593Smuzhiyun 	else
145*4882a593Smuzhiyun 		offset = 0x20;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (fin == fout) {
148*4882a593Smuzhiyun 		rk628_i2c_write(rk628, offset + CRU_CPLL_CON0, PLL_BYPASS(1));
149*4882a593Smuzhiyun 		rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(0));
150*4882a593Smuzhiyun 		while (1) {
151*4882a593Smuzhiyun 			rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &val);
152*4882a593Smuzhiyun 			if (val & PLL_LOCK)
153*4882a593Smuzhiyun 				break;
154*4882a593Smuzhiyun 		}
155*4882a593Smuzhiyun 		return fin;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	min_refdiv = fin / MAX_FREFDIV_RATE + 1;
159*4882a593Smuzhiyun 	max_refdiv = fin / MIN_FREFDIV_RATE;
160*4882a593Smuzhiyun 	if (max_refdiv > 64)
161*4882a593Smuzhiyun 		max_refdiv = 64;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (fout < MIN_FVCO_RATE) {
164*4882a593Smuzhiyun 		div1 = DIV_ROUND_UP(MIN_FVCO_RATE, fout);
165*4882a593Smuzhiyun 		div2 = DIV_ROUND_UP(MAX_FVCO_RATE, fout);
166*4882a593Smuzhiyun 		for (postdiv = div1; postdiv <= div2; postdiv++) {
167*4882a593Smuzhiyun 			/* fix prime number that can not find right div*/
168*4882a593Smuzhiyun 			for (postdiv2 = 1; postdiv2 < 8; postdiv2++) {
169*4882a593Smuzhiyun 				if (postdiv % postdiv2)
170*4882a593Smuzhiyun 					continue;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 				postdiv1 = postdiv / postdiv2;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 				if (postdiv1 > 0 && postdiv1 < 8)
175*4882a593Smuzhiyun 					break;
176*4882a593Smuzhiyun 			}
177*4882a593Smuzhiyun 			if (postdiv2 > 7)
178*4882a593Smuzhiyun 				continue;
179*4882a593Smuzhiyun 			else
180*4882a593Smuzhiyun 				break;
181*4882a593Smuzhiyun 		}
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		if (postdiv > div2)
184*4882a593Smuzhiyun 			return 0;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 		fout *= postdiv1 * postdiv2;
187*4882a593Smuzhiyun 	} else {
188*4882a593Smuzhiyun 		postdiv1 = 1;
189*4882a593Smuzhiyun 		postdiv2 = 1;
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	for (refdiv = min_refdiv; refdiv <= max_refdiv; refdiv++) {
193*4882a593Smuzhiyun 		u64 tmp, frac_rate;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 		if (fin % refdiv)
196*4882a593Smuzhiyun 			continue;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 		tmp = (u64)fout * refdiv;
199*4882a593Smuzhiyun 		do_div(tmp, fin);
200*4882a593Smuzhiyun 		fbdiv = tmp;
201*4882a593Smuzhiyun 		if (fbdiv < 10 || fbdiv > 1600)
202*4882a593Smuzhiyun 			continue;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 		tmp = (u64)fbdiv * fin;
205*4882a593Smuzhiyun 		do_div(tmp, refdiv);
206*4882a593Smuzhiyun 		if (fout < MIN_FVCO_RATE || fout > MAX_FVCO_RATE)
207*4882a593Smuzhiyun 			continue;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		frac_rate = fout - tmp;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 		if (frac_rate) {
212*4882a593Smuzhiyun 			tmp = (u64)frac_rate * refdiv;
213*4882a593Smuzhiyun 			tmp <<= 24;
214*4882a593Smuzhiyun 			do_div(tmp, fin);
215*4882a593Smuzhiyun 			frac = tmp;
216*4882a593Smuzhiyun 			dsmpd = 0;
217*4882a593Smuzhiyun 		}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 		break;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	/*
223*4882a593Smuzhiyun 	 * If DSMPD = 1 (DSM is disabled, "integer mode")
224*4882a593Smuzhiyun 	 * FOUTVCO = FREF / REFDIV * FBDIV
225*4882a593Smuzhiyun 	 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
226*4882a593Smuzhiyun 	 *
227*4882a593Smuzhiyun 	 * If DSMPD = 0 (DSM is enabled, "fractional mode")
228*4882a593Smuzhiyun 	 * FOUTVCO = FREF / REFDIV * (FBDIV + FRAC / 2^24)
229*4882a593Smuzhiyun 	 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
230*4882a593Smuzhiyun 	 */
231*4882a593Smuzhiyun 	foutvco = fin * fbdiv;
232*4882a593Smuzhiyun 	do_div(foutvco, refdiv);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	if (!dsmpd) {
235*4882a593Smuzhiyun 		u64 frac_rate = (u64)fin * frac;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 		do_div(frac_rate, refdiv);
238*4882a593Smuzhiyun 		foutvco += frac_rate >> 24;
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	foutpostdiv = foutvco;
242*4882a593Smuzhiyun 	do_div(foutpostdiv, postdiv1);
243*4882a593Smuzhiyun 	do_div(foutpostdiv, postdiv2);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	rk628_i2c_write(rk628, offset + CRU_CPLL_CON0,
246*4882a593Smuzhiyun 			PLL_BYPASS(0) | PLL_POSTDIV1(postdiv1) |
247*4882a593Smuzhiyun 			PLL_FBDIV(fbdiv));
248*4882a593Smuzhiyun 	rk628_i2c_write(rk628, offset + CRU_CPLL_CON1,
249*4882a593Smuzhiyun 			PLL_DSMPD(dsmpd) | PLL_POSTDIV2(postdiv2) |
250*4882a593Smuzhiyun 			PLL_REFDIV(refdiv));
251*4882a593Smuzhiyun 	rk628_i2c_write(rk628, offset + CRU_CPLL_CON2, PLL_FRAC(frac));
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	while (1) {
254*4882a593Smuzhiyun 		rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &val);
255*4882a593Smuzhiyun 		if (val & PLL_LOCK)
256*4882a593Smuzhiyun 			break;
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	return (unsigned long)foutpostdiv;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
rk628_cru_clk_set_rate_sclk_vop(struct rk628 * rk628,unsigned long rate)262*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_sclk_vop(struct rk628 *rk628,
263*4882a593Smuzhiyun 						     unsigned long rate)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	unsigned long m, n, parent_rate;
266*4882a593Smuzhiyun 	u32 val;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &val);
269*4882a593Smuzhiyun 	val &= SCLK_VOP_SEL_MASK;
270*4882a593Smuzhiyun 	val >>= SCLK_VOP_SEL_SHIFT;
271*4882a593Smuzhiyun 	if (val == SCLK_VOP_SEL_GPLL)
272*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
273*4882a593Smuzhiyun 	else
274*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	rational_best_approximation(rate, parent_rate,
277*4882a593Smuzhiyun 				    GENMASK(15, 0), GENMASK(15, 0),
278*4882a593Smuzhiyun 				    &m, &n);
279*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON13, m << 16 | n);
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	return rate;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun 
rk628_cru_clk_set_rate_sclk_hdmirx_aud(struct rk628 * rk628,unsigned long rate)284*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_sclk_hdmirx_aud(struct rk628 *rk628,
285*4882a593Smuzhiyun 						      unsigned long rate)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	u64 parent_rate;
288*4882a593Smuzhiyun 	u8 div;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	parent_rate = rk628_cru_clk_set_rate_pll(rk628, CGU_CLK_GPLL, rate*4);
291*4882a593Smuzhiyun 	div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate);
292*4882a593Smuzhiyun 	do_div(parent_rate, div);
293*4882a593Smuzhiyun 	rate = parent_rate;
294*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON05, 0x3fc0 << 16 | ((div - 1) << 6) |
295*4882a593Smuzhiyun 			CLK_HDMIRX_AUD_SEL << 16 | CLK_HDMIRX_AUD_SEL);
296*4882a593Smuzhiyun 	return rate;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun 
rk628_cru_clk_get_rate_sclk_hdmirx_aud(struct rk628 * rk628)299*4882a593Smuzhiyun static unsigned long rk628_cru_clk_get_rate_sclk_hdmirx_aud(struct rk628 *rk628)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun 	unsigned long rate;
302*4882a593Smuzhiyun 	u64 parent_rate;
303*4882a593Smuzhiyun 	u8 div;
304*4882a593Smuzhiyun 	u32 val;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	rk628_i2c_read(rk628, CRU_CLKSEL_CON05, &val);
307*4882a593Smuzhiyun 	if (val & CLK_HDMIRX_AUD_SEL)
308*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
309*4882a593Smuzhiyun 	else
310*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
311*4882a593Smuzhiyun 	div = ((val&0x3fc0) >> 6) + 1;
312*4882a593Smuzhiyun 	do_div(parent_rate, div);
313*4882a593Smuzhiyun 	rate = parent_rate;
314*4882a593Smuzhiyun 	return rate;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
rk628_cru_clk_get_rate_sclk_vop(struct rk628 * rk628)317*4882a593Smuzhiyun static unsigned long rk628_cru_clk_get_rate_sclk_vop(struct rk628 *rk628)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun 	unsigned long rate, parent_rate, m, n;
320*4882a593Smuzhiyun 	u32 mux, div;
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &mux);
323*4882a593Smuzhiyun 	mux &= CLK_UART_SRC_SEL_MASK;
324*4882a593Smuzhiyun 	mux >>= SCLK_VOP_SEL_SHIFT;
325*4882a593Smuzhiyun 	if (mux == SCLK_VOP_SEL_GPLL)
326*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
327*4882a593Smuzhiyun 	else
328*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	rk628_i2c_read(rk628, CRU_CLKSEL_CON13, &div);
331*4882a593Smuzhiyun 	m = div >> 16 & 0xffff;
332*4882a593Smuzhiyun 	n = div & 0xffff;
333*4882a593Smuzhiyun 	rate = parent_rate * m / n;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	return rate;
336*4882a593Smuzhiyun }
337*4882a593Smuzhiyun 
rk628_cru_clk_set_rate_rx_read(struct rk628 * rk628,unsigned long rate)338*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_rx_read(struct rk628 *rk628,
339*4882a593Smuzhiyun 						    unsigned long rate)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	unsigned long m, n, parent_rate;
342*4882a593Smuzhiyun 	u32 val;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	rk628_i2c_read(rk628, CRU_CLKSEL_CON02, &val);
345*4882a593Smuzhiyun 	val &= CLK_RX_READ_SEL_MASK;
346*4882a593Smuzhiyun 	val >>= CLK_RX_READ_SEL_SHIFT;
347*4882a593Smuzhiyun 	if (val == CLK_RX_READ_SEL_GPLL)
348*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
349*4882a593Smuzhiyun 	else
350*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	rational_best_approximation(rate, parent_rate,
353*4882a593Smuzhiyun 				    GENMASK(15, 0), GENMASK(15, 0),
354*4882a593Smuzhiyun 				    &m, &n);
355*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON14, m << 16 | n);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	return rate;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
rk628_cru_clk_get_rate_uart_src(struct rk628 * rk628)360*4882a593Smuzhiyun static unsigned long rk628_cru_clk_get_rate_uart_src(struct rk628 *rk628)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	unsigned long rate, parent_rate;
363*4882a593Smuzhiyun 	u32 mux, div;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	rk628_i2c_read(rk628, CRU_CLKSEL_CON21, &mux);
366*4882a593Smuzhiyun 	mux &= SCLK_VOP_SEL_MASK;
367*4882a593Smuzhiyun 	if (mux == CLK_UART_SRC_SEL_GPLL)
368*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
369*4882a593Smuzhiyun 	else
370*4882a593Smuzhiyun 		parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	rk628_i2c_read(rk628, CRU_CLKSEL_CON21, &div);
373*4882a593Smuzhiyun 	div &= CLK_UART_SRC_DIV_MASK;
374*4882a593Smuzhiyun 	div >>= CLK_UART_SRC_DIV_SHIFT;
375*4882a593Smuzhiyun 	rate = parent_rate / (div + 1);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	return rate;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
rk628_cru_clk_set_rate_sclk_uart(struct rk628 * rk628,unsigned long rate)380*4882a593Smuzhiyun static unsigned long rk628_cru_clk_set_rate_sclk_uart(struct rk628 *rk628,
381*4882a593Smuzhiyun 						      unsigned long rate)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	unsigned long m, n, parent_rate;
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	parent_rate = rk628_cru_clk_get_rate_uart_src(rk628);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	if (rate == REFCLK_RATE) {
388*4882a593Smuzhiyun 		rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
389*4882a593Smuzhiyun 				SCLK_UART_SEL(SCLK_UART_SEL_OSC));
390*4882a593Smuzhiyun 		return rate;
391*4882a593Smuzhiyun 	} else if (rate == parent_rate) {
392*4882a593Smuzhiyun 		rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
393*4882a593Smuzhiyun 				SCLK_UART_SEL(SCLK_UART_SEL_UART_SRC));
394*4882a593Smuzhiyun 		return rate;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON06,
398*4882a593Smuzhiyun 			SCLK_UART_SEL(SCLK_UART_SEL_UART_FRAC));
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	rational_best_approximation(rate, parent_rate,
401*4882a593Smuzhiyun 				    GENMASK(15, 0), GENMASK(15, 0),
402*4882a593Smuzhiyun 				    &m, &n);
403*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON20, m << 16 | n);
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	return rate;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
rk628_clk_mux_testout(struct rk628 * rk628,int id)408*4882a593Smuzhiyun void rk628_clk_mux_testout(struct rk628 *rk628, int id)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun 	switch (id) {
411*4882a593Smuzhiyun 	case CGU_CLK_CPLL:
412*4882a593Smuzhiyun 		rk628_i2c_write(rk628, CRU_CLKSEL_CON06, 0x000f0004);
413*4882a593Smuzhiyun 		break;
414*4882a593Smuzhiyun 	case CGU_CLK_GPLL:
415*4882a593Smuzhiyun 		rk628_i2c_write(rk628, CRU_CLKSEL_CON06, 0x000f0002);
416*4882a593Smuzhiyun 		break;
417*4882a593Smuzhiyun 	case CGU_CLK_HDMIRX_AUD:
418*4882a593Smuzhiyun 		rk628_i2c_write(rk628, CRU_CLKSEL_CON06, 0x000f000b);
419*4882a593Smuzhiyun 		break;
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun EXPORT_SYMBOL(rk628_clk_mux_testout);
423*4882a593Smuzhiyun 
rk628_clk_set_rate(struct rk628 * rk628,unsigned int id,unsigned long rate)424*4882a593Smuzhiyun int rk628_clk_set_rate(struct rk628 *rk628, unsigned int id,
425*4882a593Smuzhiyun 		       unsigned long rate)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	switch (id) {
428*4882a593Smuzhiyun 	case CGU_CLK_CPLL:
429*4882a593Smuzhiyun 	case CGU_CLK_GPLL:
430*4882a593Smuzhiyun 		rk628_cru_clk_set_rate_pll(rk628, id, rate);
431*4882a593Smuzhiyun 		break;
432*4882a593Smuzhiyun 	case CGU_CLK_RX_READ:
433*4882a593Smuzhiyun 		rk628_cru_clk_set_rate_rx_read(rk628, rate);
434*4882a593Smuzhiyun 		break;
435*4882a593Smuzhiyun 	case CGU_SCLK_VOP:
436*4882a593Smuzhiyun 		rk628_cru_clk_set_rate_sclk_vop(rk628, rate);
437*4882a593Smuzhiyun 		break;
438*4882a593Smuzhiyun 	case CGU_SCLK_UART:
439*4882a593Smuzhiyun 		rk628_cru_clk_set_rate_sclk_uart(rk628, rate);
440*4882a593Smuzhiyun 		break;
441*4882a593Smuzhiyun 	case CGU_CLK_HDMIRX_AUD:
442*4882a593Smuzhiyun 		rk628_cru_clk_set_rate_sclk_hdmirx_aud(rk628, rate);
443*4882a593Smuzhiyun 		break;
444*4882a593Smuzhiyun 	default:
445*4882a593Smuzhiyun 		return -1;
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	return 0;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun EXPORT_SYMBOL(rk628_clk_set_rate);
451*4882a593Smuzhiyun 
rk628_clk_get_rate(struct rk628 * rk628,unsigned int id)452*4882a593Smuzhiyun unsigned long rk628_clk_get_rate(struct rk628 *rk628, unsigned int id)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun 	unsigned long rate;
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	switch (id) {
457*4882a593Smuzhiyun 	case CGU_CLK_CPLL:
458*4882a593Smuzhiyun 	case CGU_CLK_GPLL:
459*4882a593Smuzhiyun 		rate = rk628_cru_clk_get_rate_pll(rk628, id);
460*4882a593Smuzhiyun 		break;
461*4882a593Smuzhiyun 	case CGU_SCLK_VOP:
462*4882a593Smuzhiyun 		rate = rk628_cru_clk_get_rate_sclk_vop(rk628);
463*4882a593Smuzhiyun 		break;
464*4882a593Smuzhiyun 	case CGU_CLK_HDMIRX_AUD:
465*4882a593Smuzhiyun 		rate = rk628_cru_clk_get_rate_sclk_hdmirx_aud(rk628);
466*4882a593Smuzhiyun 		break;
467*4882a593Smuzhiyun 	default:
468*4882a593Smuzhiyun 		return 0;
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	return rate;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun EXPORT_SYMBOL(rk628_clk_get_rate);
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun struct rk628_rgu_data {
476*4882a593Smuzhiyun 	unsigned int id;
477*4882a593Smuzhiyun 	unsigned int reg;
478*4882a593Smuzhiyun 	unsigned int bit;
479*4882a593Smuzhiyun };
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun #define RSTGEN(_id, _reg, _bit)	\
482*4882a593Smuzhiyun 	{	\
483*4882a593Smuzhiyun 		.id = (_id),	\
484*4882a593Smuzhiyun 		.reg = (_reg),	\
485*4882a593Smuzhiyun 		.bit = (_bit),	\
486*4882a593Smuzhiyun 	}
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun static const struct rk628_rgu_data rk628_rgu_data[] = {
489*4882a593Smuzhiyun 	RSTGEN(RGU_LOGIC,	CRU_SOFTRST_CON00,  0),
490*4882a593Smuzhiyun 	RSTGEN(RGU_CRU,		CRU_SOFTRST_CON00,  1),
491*4882a593Smuzhiyun 	RSTGEN(RGU_REGFILE,	CRU_SOFTRST_CON00,  2),
492*4882a593Smuzhiyun 	RSTGEN(RGU_I2C2APB,	CRU_SOFTRST_CON00,  3),
493*4882a593Smuzhiyun 	RSTGEN(RGU_EFUSE,	CRU_SOFTRST_CON00,  5),
494*4882a593Smuzhiyun 	RSTGEN(RGU_ADAPTER,	CRU_SOFTRST_CON00,  7),
495*4882a593Smuzhiyun 	RSTGEN(RGU_CLK_RX,	CRU_SOFTRST_CON00, 11),
496*4882a593Smuzhiyun 	RSTGEN(RGU_BT1120DEC,	CRU_SOFTRST_CON00, 12),
497*4882a593Smuzhiyun 	RSTGEN(RGU_VOP,		CRU_SOFTRST_CON00, 13),
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	RSTGEN(RGU_GPIO0,	CRU_SOFTRST_CON01,  0),
500*4882a593Smuzhiyun 	RSTGEN(RGU_GPIO1,	CRU_SOFTRST_CON01,  1),
501*4882a593Smuzhiyun 	RSTGEN(RGU_GPIO2,	CRU_SOFTRST_CON01,  2),
502*4882a593Smuzhiyun 	RSTGEN(RGU_GPIO3,	CRU_SOFTRST_CON01,  3),
503*4882a593Smuzhiyun 	RSTGEN(RGU_GPIO_DB0,	CRU_SOFTRST_CON01,  4),
504*4882a593Smuzhiyun 	RSTGEN(RGU_GPIO_DB1,	CRU_SOFTRST_CON01,  5),
505*4882a593Smuzhiyun 	RSTGEN(RGU_GPIO_DB2,	CRU_SOFTRST_CON01,  6),
506*4882a593Smuzhiyun 	RSTGEN(RGU_GPIO_DB3,	CRU_SOFTRST_CON01,  7),
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	RSTGEN(RGU_RXPHY,	CRU_SOFTRST_CON02,  0),
509*4882a593Smuzhiyun 	RSTGEN(RGU_HDMIRX,	CRU_SOFTRST_CON02,  2),
510*4882a593Smuzhiyun 	RSTGEN(RGU_TXPHY_CON,	CRU_SOFTRST_CON02,  3),
511*4882a593Smuzhiyun 	RSTGEN(RGU_HDMITX,	CRU_SOFTRST_CON02,  4),
512*4882a593Smuzhiyun 	RSTGEN(RGU_GVIHOST,	CRU_SOFTRST_CON02,  5),
513*4882a593Smuzhiyun 	RSTGEN(RGU_DSI0,	CRU_SOFTRST_CON02,  6),
514*4882a593Smuzhiyun 	RSTGEN(RGU_DSI1,	CRU_SOFTRST_CON02,  7),
515*4882a593Smuzhiyun 	RSTGEN(RGU_CSI,		CRU_SOFTRST_CON02,  8),
516*4882a593Smuzhiyun 	RSTGEN(RGU_TXDATA,	CRU_SOFTRST_CON02,  9),
517*4882a593Smuzhiyun 	RSTGEN(RGU_DECODER,	CRU_SOFTRST_CON02, 10),
518*4882a593Smuzhiyun 	RSTGEN(RGU_ENCODER,	CRU_SOFTRST_CON02, 11),
519*4882a593Smuzhiyun 	RSTGEN(RGU_HDMIRX_PON,	CRU_SOFTRST_CON02, 12),
520*4882a593Smuzhiyun 	RSTGEN(RGU_TXBYTEHS,	CRU_SOFTRST_CON02, 13),
521*4882a593Smuzhiyun 	RSTGEN(RGU_TXESC,	CRU_SOFTRST_CON02, 14),
522*4882a593Smuzhiyun };
523*4882a593Smuzhiyun 
rk628_rgu_update(struct rk628 * rk628,unsigned long id,int assert)524*4882a593Smuzhiyun static int rk628_rgu_update(struct rk628 *rk628, unsigned long id, int assert)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun 	const struct rk628_rgu_data *data = &rk628_rgu_data[id];
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	return rk628_i2c_write(rk628, data->reg,
529*4882a593Smuzhiyun 			    BIT(data->bit + 16) | (assert << data->bit));
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun 
rk628_control_assert(struct rk628 * rk628,unsigned long id)532*4882a593Smuzhiyun int rk628_control_assert(struct rk628 *rk628, unsigned long id)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun 	return rk628_rgu_update(rk628, id, 1);
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun EXPORT_SYMBOL(rk628_control_assert);
537*4882a593Smuzhiyun 
rk628_control_deassert(struct rk628 * rk628,unsigned long id)538*4882a593Smuzhiyun int rk628_control_deassert(struct rk628 *rk628, unsigned long id)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	return rk628_rgu_update(rk628, id, 0);
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun EXPORT_SYMBOL(rk628_control_deassert);
543*4882a593Smuzhiyun 
rk628_cru_initialize(struct rk628 * rk628)544*4882a593Smuzhiyun void rk628_cru_initialize(struct rk628 *rk628)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	u32 val;
547*4882a593Smuzhiyun 	u8 mcu_mode;
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	rk628_i2c_read(rk628, GRF_SYSTEM_STATUS0, &val);
550*4882a593Smuzhiyun 	mcu_mode = (val & I2C_ONLY_FLAG) ? 0 : 1;
551*4882a593Smuzhiyun 	if (mcu_mode) {
552*4882a593Smuzhiyun 		dev_info(rk628->dev, "RK628 MCU + I2C Mode\n");
553*4882a593Smuzhiyun 		return;
554*4882a593Smuzhiyun 	}
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	dev_info(rk628->dev, "RK628 I2C Mode Only\n");
557*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_GPLL_CON0, 0xffff701d);
558*4882a593Smuzhiyun 	mdelay(1);
559*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_MODE_CON00, 0xffff0004);
560*4882a593Smuzhiyun 	mdelay(1);
561*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0080);
562*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0083);
563*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CPLL_CON0, 0xffff3063);
564*4882a593Smuzhiyun 	mdelay(1);
565*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_MODE_CON00, 0xffff0005);
566*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff0003);
567*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff000b);
568*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_GPLL_CON0, 0xffff1028);
569*4882a593Smuzhiyun 	mdelay(1);
570*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff008b);
571*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CPLL_CON0, 0xffff1063);
572*4882a593Smuzhiyun 	mdelay(1);
573*4882a593Smuzhiyun 	rk628_i2c_write(rk628, CRU_CLKSEL_CON00, 0x00ff000b);
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun EXPORT_SYMBOL(rk628_cru_initialize);
576