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