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