]> git.ipfire.org Git - people/ms/u-boot.git/blob - arch/arm/cpu/armv7/exynos/clock.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[people/ms/u-boot.git] / arch / arm / cpu / armv7 / exynos / clock.c
1 /*
2 * Copyright (C) 2010 Samsung Electronics
3 * Minkyu Kang <mk7.kang@samsung.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24 #include <common.h>
25 #include <asm/io.h>
26 #include <asm/arch/clock.h>
27 #include <asm/arch/clk.h>
28 #include <asm/arch/periph.h>
29
30 /* Epll Clock division values to achive different frequency output */
31 static struct set_epll_con_val exynos5_epll_div[] = {
32 { 192000000, 0, 48, 3, 1, 0 },
33 { 180000000, 0, 45, 3, 1, 0 },
34 { 73728000, 1, 73, 3, 3, 47710 },
35 { 67737600, 1, 90, 4, 3, 20762 },
36 { 49152000, 0, 49, 3, 3, 9961 },
37 { 45158400, 0, 45, 3, 3, 10381 },
38 { 180633600, 0, 45, 3, 1, 10381 }
39 };
40
41 /* exynos: return pll clock frequency */
42 static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)
43 {
44 unsigned long m, p, s = 0, mask, fout;
45 unsigned int freq;
46 /*
47 * APLL_CON: MIDV [25:16]
48 * MPLL_CON: MIDV [25:16]
49 * EPLL_CON: MIDV [24:16]
50 * VPLL_CON: MIDV [24:16]
51 * BPLL_CON: MIDV [25:16]: Exynos5
52 */
53 if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL)
54 mask = 0x3ff;
55 else
56 mask = 0x1ff;
57
58 m = (r >> 16) & mask;
59
60 /* PDIV [13:8] */
61 p = (r >> 8) & 0x3f;
62 /* SDIV [2:0] */
63 s = r & 0x7;
64
65 freq = CONFIG_SYS_CLK_FREQ;
66
67 if (pllreg == EPLL) {
68 k = k & 0xffff;
69 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
70 fout = (m + k / 65536) * (freq / (p * (1 << s)));
71 } else if (pllreg == VPLL) {
72 k = k & 0xfff;
73 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
74 fout = (m + k / 1024) * (freq / (p * (1 << s)));
75 } else {
76 if (s < 1)
77 s = 1;
78 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
79 fout = m * (freq / (p * (1 << (s - 1))));
80 }
81
82 return fout;
83 }
84
85 /* exynos4: return pll clock frequency */
86 static unsigned long exynos4_get_pll_clk(int pllreg)
87 {
88 struct exynos4_clock *clk =
89 (struct exynos4_clock *)samsung_get_base_clock();
90 unsigned long r, k = 0;
91
92 switch (pllreg) {
93 case APLL:
94 r = readl(&clk->apll_con0);
95 break;
96 case MPLL:
97 r = readl(&clk->mpll_con0);
98 break;
99 case EPLL:
100 r = readl(&clk->epll_con0);
101 k = readl(&clk->epll_con1);
102 break;
103 case VPLL:
104 r = readl(&clk->vpll_con0);
105 k = readl(&clk->vpll_con1);
106 break;
107 default:
108 printf("Unsupported PLL (%d)\n", pllreg);
109 return 0;
110 }
111
112 return exynos_get_pll_clk(pllreg, r, k);
113 }
114
115 /* exynos5: return pll clock frequency */
116 static unsigned long exynos5_get_pll_clk(int pllreg)
117 {
118 struct exynos5_clock *clk =
119 (struct exynos5_clock *)samsung_get_base_clock();
120 unsigned long r, k = 0, fout;
121 unsigned int pll_div2_sel, fout_sel;
122
123 switch (pllreg) {
124 case APLL:
125 r = readl(&clk->apll_con0);
126 break;
127 case MPLL:
128 r = readl(&clk->mpll_con0);
129 break;
130 case EPLL:
131 r = readl(&clk->epll_con0);
132 k = readl(&clk->epll_con1);
133 break;
134 case VPLL:
135 r = readl(&clk->vpll_con0);
136 k = readl(&clk->vpll_con1);
137 break;
138 case BPLL:
139 r = readl(&clk->bpll_con0);
140 break;
141 default:
142 printf("Unsupported PLL (%d)\n", pllreg);
143 return 0;
144 }
145
146 fout = exynos_get_pll_clk(pllreg, r, k);
147
148 /* According to the user manual, in EVT1 MPLL and BPLL always gives
149 * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/
150 if (pllreg == MPLL || pllreg == BPLL) {
151 pll_div2_sel = readl(&clk->pll_div2_sel);
152
153 switch (pllreg) {
154 case MPLL:
155 fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
156 & MPLL_FOUT_SEL_MASK;
157 break;
158 case BPLL:
159 fout_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT)
160 & BPLL_FOUT_SEL_MASK;
161 break;
162 default:
163 fout_sel = -1;
164 break;
165 }
166
167 if (fout_sel == 0)
168 fout /= 2;
169 }
170
171 return fout;
172 }
173
174 /* exynos4: return ARM clock frequency */
175 static unsigned long exynos4_get_arm_clk(void)
176 {
177 struct exynos4_clock *clk =
178 (struct exynos4_clock *)samsung_get_base_clock();
179 unsigned long div;
180 unsigned long armclk;
181 unsigned int core_ratio;
182 unsigned int core2_ratio;
183
184 div = readl(&clk->div_cpu0);
185
186 /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
187 core_ratio = (div >> 0) & 0x7;
188 core2_ratio = (div >> 28) & 0x7;
189
190 armclk = get_pll_clk(APLL) / (core_ratio + 1);
191 armclk /= (core2_ratio + 1);
192
193 return armclk;
194 }
195
196 /* exynos5: return ARM clock frequency */
197 static unsigned long exynos5_get_arm_clk(void)
198 {
199 struct exynos5_clock *clk =
200 (struct exynos5_clock *)samsung_get_base_clock();
201 unsigned long div;
202 unsigned long armclk;
203 unsigned int arm_ratio;
204 unsigned int arm2_ratio;
205
206 div = readl(&clk->div_cpu0);
207
208 /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
209 arm_ratio = (div >> 0) & 0x7;
210 arm2_ratio = (div >> 28) & 0x7;
211
212 armclk = get_pll_clk(APLL) / (arm_ratio + 1);
213 armclk /= (arm2_ratio + 1);
214
215 return armclk;
216 }
217
218 /* exynos4: return pwm clock frequency */
219 static unsigned long exynos4_get_pwm_clk(void)
220 {
221 struct exynos4_clock *clk =
222 (struct exynos4_clock *)samsung_get_base_clock();
223 unsigned long pclk, sclk;
224 unsigned int sel;
225 unsigned int ratio;
226
227 if (s5p_get_cpu_rev() == 0) {
228 /*
229 * CLK_SRC_PERIL0
230 * PWM_SEL [27:24]
231 */
232 sel = readl(&clk->src_peril0);
233 sel = (sel >> 24) & 0xf;
234
235 if (sel == 0x6)
236 sclk = get_pll_clk(MPLL);
237 else if (sel == 0x7)
238 sclk = get_pll_clk(EPLL);
239 else if (sel == 0x8)
240 sclk = get_pll_clk(VPLL);
241 else
242 return 0;
243
244 /*
245 * CLK_DIV_PERIL3
246 * PWM_RATIO [3:0]
247 */
248 ratio = readl(&clk->div_peril3);
249 ratio = ratio & 0xf;
250 } else if (s5p_get_cpu_rev() == 1) {
251 sclk = get_pll_clk(MPLL);
252 ratio = 8;
253 } else
254 return 0;
255
256 pclk = sclk / (ratio + 1);
257
258 return pclk;
259 }
260
261 /* exynos5: return pwm clock frequency */
262 static unsigned long exynos5_get_pwm_clk(void)
263 {
264 struct exynos5_clock *clk =
265 (struct exynos5_clock *)samsung_get_base_clock();
266 unsigned long pclk, sclk;
267 unsigned int ratio;
268
269 /*
270 * CLK_DIV_PERIC3
271 * PWM_RATIO [3:0]
272 */
273 ratio = readl(&clk->div_peric3);
274 ratio = ratio & 0xf;
275 sclk = get_pll_clk(MPLL);
276
277 pclk = sclk / (ratio + 1);
278
279 return pclk;
280 }
281
282 /* exynos4: return uart clock frequency */
283 static unsigned long exynos4_get_uart_clk(int dev_index)
284 {
285 struct exynos4_clock *clk =
286 (struct exynos4_clock *)samsung_get_base_clock();
287 unsigned long uclk, sclk;
288 unsigned int sel;
289 unsigned int ratio;
290
291 /*
292 * CLK_SRC_PERIL0
293 * UART0_SEL [3:0]
294 * UART1_SEL [7:4]
295 * UART2_SEL [8:11]
296 * UART3_SEL [12:15]
297 * UART4_SEL [16:19]
298 * UART5_SEL [23:20]
299 */
300 sel = readl(&clk->src_peril0);
301 sel = (sel >> (dev_index << 2)) & 0xf;
302
303 if (sel == 0x6)
304 sclk = get_pll_clk(MPLL);
305 else if (sel == 0x7)
306 sclk = get_pll_clk(EPLL);
307 else if (sel == 0x8)
308 sclk = get_pll_clk(VPLL);
309 else
310 return 0;
311
312 /*
313 * CLK_DIV_PERIL0
314 * UART0_RATIO [3:0]
315 * UART1_RATIO [7:4]
316 * UART2_RATIO [8:11]
317 * UART3_RATIO [12:15]
318 * UART4_RATIO [16:19]
319 * UART5_RATIO [23:20]
320 */
321 ratio = readl(&clk->div_peril0);
322 ratio = (ratio >> (dev_index << 2)) & 0xf;
323
324 uclk = sclk / (ratio + 1);
325
326 return uclk;
327 }
328
329 /* exynos5: return uart clock frequency */
330 static unsigned long exynos5_get_uart_clk(int dev_index)
331 {
332 struct exynos5_clock *clk =
333 (struct exynos5_clock *)samsung_get_base_clock();
334 unsigned long uclk, sclk;
335 unsigned int sel;
336 unsigned int ratio;
337
338 /*
339 * CLK_SRC_PERIC0
340 * UART0_SEL [3:0]
341 * UART1_SEL [7:4]
342 * UART2_SEL [8:11]
343 * UART3_SEL [12:15]
344 * UART4_SEL [16:19]
345 * UART5_SEL [23:20]
346 */
347 sel = readl(&clk->src_peric0);
348 sel = (sel >> (dev_index << 2)) & 0xf;
349
350 if (sel == 0x6)
351 sclk = get_pll_clk(MPLL);
352 else if (sel == 0x7)
353 sclk = get_pll_clk(EPLL);
354 else if (sel == 0x8)
355 sclk = get_pll_clk(VPLL);
356 else
357 return 0;
358
359 /*
360 * CLK_DIV_PERIC0
361 * UART0_RATIO [3:0]
362 * UART1_RATIO [7:4]
363 * UART2_RATIO [8:11]
364 * UART3_RATIO [12:15]
365 * UART4_RATIO [16:19]
366 * UART5_RATIO [23:20]
367 */
368 ratio = readl(&clk->div_peric0);
369 ratio = (ratio >> (dev_index << 2)) & 0xf;
370
371 uclk = sclk / (ratio + 1);
372
373 return uclk;
374 }
375
376 /* exynos4: set the mmc clock */
377 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
378 {
379 struct exynos4_clock *clk =
380 (struct exynos4_clock *)samsung_get_base_clock();
381 unsigned int addr;
382 unsigned int val;
383
384 /*
385 * CLK_DIV_FSYS1
386 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
387 * CLK_DIV_FSYS2
388 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
389 */
390 if (dev_index < 2) {
391 addr = (unsigned int)&clk->div_fsys1;
392 } else {
393 addr = (unsigned int)&clk->div_fsys2;
394 dev_index -= 2;
395 }
396
397 val = readl(addr);
398 val &= ~(0xff << ((dev_index << 4) + 8));
399 val |= (div & 0xff) << ((dev_index << 4) + 8);
400 writel(val, addr);
401 }
402
403 /* exynos5: set the mmc clock */
404 static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
405 {
406 struct exynos5_clock *clk =
407 (struct exynos5_clock *)samsung_get_base_clock();
408 unsigned int addr;
409 unsigned int val;
410
411 /*
412 * CLK_DIV_FSYS1
413 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
414 * CLK_DIV_FSYS2
415 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
416 */
417 if (dev_index < 2) {
418 addr = (unsigned int)&clk->div_fsys1;
419 } else {
420 addr = (unsigned int)&clk->div_fsys2;
421 dev_index -= 2;
422 }
423
424 val = readl(addr);
425 val &= ~(0xff << ((dev_index << 4) + 8));
426 val |= (div & 0xff) << ((dev_index << 4) + 8);
427 writel(val, addr);
428 }
429
430 /* get_lcd_clk: return lcd clock frequency */
431 static unsigned long exynos4_get_lcd_clk(void)
432 {
433 struct exynos4_clock *clk =
434 (struct exynos4_clock *)samsung_get_base_clock();
435 unsigned long pclk, sclk;
436 unsigned int sel;
437 unsigned int ratio;
438
439 /*
440 * CLK_SRC_LCD0
441 * FIMD0_SEL [3:0]
442 */
443 sel = readl(&clk->src_lcd0);
444 sel = sel & 0xf;
445
446 /*
447 * 0x6: SCLK_MPLL
448 * 0x7: SCLK_EPLL
449 * 0x8: SCLK_VPLL
450 */
451 if (sel == 0x6)
452 sclk = get_pll_clk(MPLL);
453 else if (sel == 0x7)
454 sclk = get_pll_clk(EPLL);
455 else if (sel == 0x8)
456 sclk = get_pll_clk(VPLL);
457 else
458 return 0;
459
460 /*
461 * CLK_DIV_LCD0
462 * FIMD0_RATIO [3:0]
463 */
464 ratio = readl(&clk->div_lcd0);
465 ratio = ratio & 0xf;
466
467 pclk = sclk / (ratio + 1);
468
469 return pclk;
470 }
471
472 /* get_lcd_clk: return lcd clock frequency */
473 static unsigned long exynos5_get_lcd_clk(void)
474 {
475 struct exynos5_clock *clk =
476 (struct exynos5_clock *)samsung_get_base_clock();
477 unsigned long pclk, sclk;
478 unsigned int sel;
479 unsigned int ratio;
480
481 /*
482 * CLK_SRC_LCD0
483 * FIMD0_SEL [3:0]
484 */
485 sel = readl(&clk->src_disp1_0);
486 sel = sel & 0xf;
487
488 /*
489 * 0x6: SCLK_MPLL
490 * 0x7: SCLK_EPLL
491 * 0x8: SCLK_VPLL
492 */
493 if (sel == 0x6)
494 sclk = get_pll_clk(MPLL);
495 else if (sel == 0x7)
496 sclk = get_pll_clk(EPLL);
497 else if (sel == 0x8)
498 sclk = get_pll_clk(VPLL);
499 else
500 return 0;
501
502 /*
503 * CLK_DIV_LCD0
504 * FIMD0_RATIO [3:0]
505 */
506 ratio = readl(&clk->div_disp1_0);
507 ratio = ratio & 0xf;
508
509 pclk = sclk / (ratio + 1);
510
511 return pclk;
512 }
513
514 void exynos4_set_lcd_clk(void)
515 {
516 struct exynos4_clock *clk =
517 (struct exynos4_clock *)samsung_get_base_clock();
518 unsigned int cfg = 0;
519
520 /*
521 * CLK_GATE_BLOCK
522 * CLK_CAM [0]
523 * CLK_TV [1]
524 * CLK_MFC [2]
525 * CLK_G3D [3]
526 * CLK_LCD0 [4]
527 * CLK_LCD1 [5]
528 * CLK_GPS [7]
529 */
530 cfg = readl(&clk->gate_block);
531 cfg |= 1 << 4;
532 writel(cfg, &clk->gate_block);
533
534 /*
535 * CLK_SRC_LCD0
536 * FIMD0_SEL [3:0]
537 * MDNIE0_SEL [7:4]
538 * MDNIE_PWM0_SEL [8:11]
539 * MIPI0_SEL [12:15]
540 * set lcd0 src clock 0x6: SCLK_MPLL
541 */
542 cfg = readl(&clk->src_lcd0);
543 cfg &= ~(0xf);
544 cfg |= 0x6;
545 writel(cfg, &clk->src_lcd0);
546
547 /*
548 * CLK_GATE_IP_LCD0
549 * CLK_FIMD0 [0]
550 * CLK_MIE0 [1]
551 * CLK_MDNIE0 [2]
552 * CLK_DSIM0 [3]
553 * CLK_SMMUFIMD0 [4]
554 * CLK_PPMULCD0 [5]
555 * Gating all clocks for FIMD0
556 */
557 cfg = readl(&clk->gate_ip_lcd0);
558 cfg |= 1 << 0;
559 writel(cfg, &clk->gate_ip_lcd0);
560
561 /*
562 * CLK_DIV_LCD0
563 * FIMD0_RATIO [3:0]
564 * MDNIE0_RATIO [7:4]
565 * MDNIE_PWM0_RATIO [11:8]
566 * MDNIE_PWM_PRE_RATIO [15:12]
567 * MIPI0_RATIO [19:16]
568 * MIPI0_PRE_RATIO [23:20]
569 * set fimd ratio
570 */
571 cfg &= ~(0xf);
572 cfg |= 0x1;
573 writel(cfg, &clk->div_lcd0);
574 }
575
576 void exynos5_set_lcd_clk(void)
577 {
578 struct exynos5_clock *clk =
579 (struct exynos5_clock *)samsung_get_base_clock();
580 unsigned int cfg = 0;
581
582 /*
583 * CLK_GATE_BLOCK
584 * CLK_CAM [0]
585 * CLK_TV [1]
586 * CLK_MFC [2]
587 * CLK_G3D [3]
588 * CLK_LCD0 [4]
589 * CLK_LCD1 [5]
590 * CLK_GPS [7]
591 */
592 cfg = readl(&clk->gate_block);
593 cfg |= 1 << 4;
594 writel(cfg, &clk->gate_block);
595
596 /*
597 * CLK_SRC_LCD0
598 * FIMD0_SEL [3:0]
599 * MDNIE0_SEL [7:4]
600 * MDNIE_PWM0_SEL [8:11]
601 * MIPI0_SEL [12:15]
602 * set lcd0 src clock 0x6: SCLK_MPLL
603 */
604 cfg = readl(&clk->src_disp1_0);
605 cfg &= ~(0xf);
606 cfg |= 0x8;
607 writel(cfg, &clk->src_disp1_0);
608
609 /*
610 * CLK_GATE_IP_LCD0
611 * CLK_FIMD0 [0]
612 * CLK_MIE0 [1]
613 * CLK_MDNIE0 [2]
614 * CLK_DSIM0 [3]
615 * CLK_SMMUFIMD0 [4]
616 * CLK_PPMULCD0 [5]
617 * Gating all clocks for FIMD0
618 */
619 cfg = readl(&clk->gate_ip_disp1);
620 cfg |= 1 << 0;
621 writel(cfg, &clk->gate_ip_disp1);
622
623 /*
624 * CLK_DIV_LCD0
625 * FIMD0_RATIO [3:0]
626 * MDNIE0_RATIO [7:4]
627 * MDNIE_PWM0_RATIO [11:8]
628 * MDNIE_PWM_PRE_RATIO [15:12]
629 * MIPI0_RATIO [19:16]
630 * MIPI0_PRE_RATIO [23:20]
631 * set fimd ratio
632 */
633 cfg &= ~(0xf);
634 cfg |= 0x0;
635 writel(cfg, &clk->div_disp1_0);
636 }
637
638 void exynos4_set_mipi_clk(void)
639 {
640 struct exynos4_clock *clk =
641 (struct exynos4_clock *)samsung_get_base_clock();
642 unsigned int cfg = 0;
643
644 /*
645 * CLK_SRC_LCD0
646 * FIMD0_SEL [3:0]
647 * MDNIE0_SEL [7:4]
648 * MDNIE_PWM0_SEL [8:11]
649 * MIPI0_SEL [12:15]
650 * set mipi0 src clock 0x6: SCLK_MPLL
651 */
652 cfg = readl(&clk->src_lcd0);
653 cfg &= ~(0xf << 12);
654 cfg |= (0x6 << 12);
655 writel(cfg, &clk->src_lcd0);
656
657 /*
658 * CLK_SRC_MASK_LCD0
659 * FIMD0_MASK [0]
660 * MDNIE0_MASK [4]
661 * MDNIE_PWM0_MASK [8]
662 * MIPI0_MASK [12]
663 * set src mask mipi0 0x1: Unmask
664 */
665 cfg = readl(&clk->src_mask_lcd0);
666 cfg |= (0x1 << 12);
667 writel(cfg, &clk->src_mask_lcd0);
668
669 /*
670 * CLK_GATE_IP_LCD0
671 * CLK_FIMD0 [0]
672 * CLK_MIE0 [1]
673 * CLK_MDNIE0 [2]
674 * CLK_DSIM0 [3]
675 * CLK_SMMUFIMD0 [4]
676 * CLK_PPMULCD0 [5]
677 * Gating all clocks for MIPI0
678 */
679 cfg = readl(&clk->gate_ip_lcd0);
680 cfg |= 1 << 3;
681 writel(cfg, &clk->gate_ip_lcd0);
682
683 /*
684 * CLK_DIV_LCD0
685 * FIMD0_RATIO [3:0]
686 * MDNIE0_RATIO [7:4]
687 * MDNIE_PWM0_RATIO [11:8]
688 * MDNIE_PWM_PRE_RATIO [15:12]
689 * MIPI0_RATIO [19:16]
690 * MIPI0_PRE_RATIO [23:20]
691 * set mipi ratio
692 */
693 cfg &= ~(0xf << 16);
694 cfg |= (0x1 << 16);
695 writel(cfg, &clk->div_lcd0);
696 }
697
698 /*
699 * I2C
700 *
701 * exynos5: obtaining the I2C clock
702 */
703 static unsigned long exynos5_get_i2c_clk(void)
704 {
705 struct exynos5_clock *clk =
706 (struct exynos5_clock *)samsung_get_base_clock();
707 unsigned long aclk_66, aclk_66_pre, sclk;
708 unsigned int ratio;
709
710 sclk = get_pll_clk(MPLL);
711
712 ratio = (readl(&clk->div_top1)) >> 24;
713 ratio &= 0x7;
714 aclk_66_pre = sclk / (ratio + 1);
715 ratio = readl(&clk->div_top0);
716 ratio &= 0x7;
717 aclk_66 = aclk_66_pre / (ratio + 1);
718 return aclk_66;
719 }
720
721 int exynos5_set_epll_clk(unsigned long rate)
722 {
723 unsigned int epll_con, epll_con_k;
724 unsigned int i;
725 unsigned int lockcnt;
726 unsigned int start;
727 struct exynos5_clock *clk =
728 (struct exynos5_clock *)samsung_get_base_clock();
729
730 epll_con = readl(&clk->epll_con0);
731 epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
732 EPLL_CON0_LOCK_DET_EN_SHIFT) |
733 EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
734 EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
735 EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
736
737 for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) {
738 if (exynos5_epll_div[i].freq_out == rate)
739 break;
740 }
741
742 if (i == ARRAY_SIZE(exynos5_epll_div))
743 return -1;
744
745 epll_con_k = exynos5_epll_div[i].k_dsm << 0;
746 epll_con |= exynos5_epll_div[i].en_lock_det <<
747 EPLL_CON0_LOCK_DET_EN_SHIFT;
748 epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
749 epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
750 epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
751
752 /*
753 * Required period ( in cycles) to genarate a stable clock output.
754 * The maximum clock time can be up to 3000 * PDIV cycles of PLLs
755 * frequency input (as per spec)
756 */
757 lockcnt = 3000 * exynos5_epll_div[i].p_div;
758
759 writel(lockcnt, &clk->epll_lock);
760 writel(epll_con, &clk->epll_con0);
761 writel(epll_con_k, &clk->epll_con1);
762
763 start = get_timer(0);
764
765 while (!(readl(&clk->epll_con0) &
766 (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
767 if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
768 debug("%s: Timeout waiting for EPLL lock\n", __func__);
769 return -1;
770 }
771 }
772 return 0;
773 }
774
775 void exynos5_set_i2s_clk_source(void)
776 {
777 struct exynos5_clock *clk =
778 (struct exynos5_clock *)samsung_get_base_clock();
779
780 clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
781 (CLK_SRC_SCLK_EPLL));
782 }
783
784 int exynos5_set_i2s_clk_prescaler(unsigned int src_frq,
785 unsigned int dst_frq)
786 {
787 struct exynos5_clock *clk =
788 (struct exynos5_clock *)samsung_get_base_clock();
789 unsigned int div;
790
791 if ((dst_frq == 0) || (src_frq == 0)) {
792 debug("%s: Invalid requency input for prescaler\n", __func__);
793 debug("src frq = %d des frq = %d ", src_frq, dst_frq);
794 return -1;
795 }
796
797 div = (src_frq / dst_frq);
798 if (div > AUDIO_1_RATIO_MASK) {
799 debug("%s: Frequency ratio is out of range\n", __func__);
800 debug("src frq = %d des frq = %d ", src_frq, dst_frq);
801 return -1;
802 }
803 clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
804 (div & AUDIO_1_RATIO_MASK));
805 return 0;
806 }
807
808 /**
809 * Linearly searches for the most accurate main and fine stage clock scalars
810 * (divisors) for a specified target frequency and scalar bit sizes by checking
811 * all multiples of main_scalar_bits values. Will always return scalars up to or
812 * slower than target.
813 *
814 * @param main_scalar_bits Number of main scalar bits, must be > 0 and < 32
815 * @param fine_scalar_bits Number of fine scalar bits, must be > 0 and < 32
816 * @param input_freq Clock frequency to be scaled in Hz
817 * @param target_freq Desired clock frequency in Hz
818 * @param best_fine_scalar Pointer to store the fine stage divisor
819 *
820 * @return best_main_scalar Main scalar for desired frequency or -1 if none
821 * found
822 */
823 static int clock_calc_best_scalar(unsigned int main_scaler_bits,
824 unsigned int fine_scalar_bits, unsigned int input_rate,
825 unsigned int target_rate, unsigned int *best_fine_scalar)
826 {
827 int i;
828 int best_main_scalar = -1;
829 unsigned int best_error = target_rate;
830 const unsigned int cap = (1 << fine_scalar_bits) - 1;
831 const unsigned int loops = 1 << main_scaler_bits;
832
833 debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate,
834 target_rate, cap);
835
836 assert(best_fine_scalar != NULL);
837 assert(main_scaler_bits <= fine_scalar_bits);
838
839 *best_fine_scalar = 1;
840
841 if (input_rate == 0 || target_rate == 0)
842 return -1;
843
844 if (target_rate >= input_rate)
845 return 1;
846
847 for (i = 1; i <= loops; i++) {
848 const unsigned int effective_div = max(min(input_rate / i /
849 target_rate, cap), 1);
850 const unsigned int effective_rate = input_rate / i /
851 effective_div;
852 const int error = target_rate - effective_rate;
853
854 debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div,
855 effective_rate, error);
856
857 if (error >= 0 && error <= best_error) {
858 best_error = error;
859 best_main_scalar = i;
860 *best_fine_scalar = effective_div;
861 }
862 }
863
864 return best_main_scalar;
865 }
866
867 static int exynos5_set_spi_clk(enum periph_id periph_id,
868 unsigned int rate)
869 {
870 struct exynos5_clock *clk =
871 (struct exynos5_clock *)samsung_get_base_clock();
872 int main;
873 unsigned int fine;
874 unsigned shift, pre_shift;
875 unsigned mask = 0xff;
876 u32 *reg;
877
878 main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
879 if (main < 0) {
880 debug("%s: Cannot set clock rate for periph %d",
881 __func__, periph_id);
882 return -1;
883 }
884 main = main - 1;
885 fine = fine - 1;
886
887 switch (periph_id) {
888 case PERIPH_ID_SPI0:
889 reg = &clk->div_peric1;
890 shift = 0;
891 pre_shift = 8;
892 break;
893 case PERIPH_ID_SPI1:
894 reg = &clk->div_peric1;
895 shift = 16;
896 pre_shift = 24;
897 break;
898 case PERIPH_ID_SPI2:
899 reg = &clk->div_peric2;
900 shift = 0;
901 pre_shift = 8;
902 break;
903 case PERIPH_ID_SPI3:
904 reg = &clk->sclk_div_isp;
905 shift = 0;
906 pre_shift = 4;
907 break;
908 case PERIPH_ID_SPI4:
909 reg = &clk->sclk_div_isp;
910 shift = 12;
911 pre_shift = 16;
912 break;
913 default:
914 debug("%s: Unsupported peripheral ID %d\n", __func__,
915 periph_id);
916 return -1;
917 }
918 clrsetbits_le32(reg, mask << shift, (main & mask) << shift);
919 clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift);
920
921 return 0;
922 }
923
924 unsigned long get_pll_clk(int pllreg)
925 {
926 if (cpu_is_exynos5())
927 return exynos5_get_pll_clk(pllreg);
928 else
929 return exynos4_get_pll_clk(pllreg);
930 }
931
932 unsigned long get_arm_clk(void)
933 {
934 if (cpu_is_exynos5())
935 return exynos5_get_arm_clk();
936 else
937 return exynos4_get_arm_clk();
938 }
939
940 unsigned long get_i2c_clk(void)
941 {
942 if (cpu_is_exynos5()) {
943 return exynos5_get_i2c_clk();
944 } else {
945 debug("I2C clock is not set for this CPU\n");
946 return 0;
947 }
948 }
949
950 unsigned long get_pwm_clk(void)
951 {
952 if (cpu_is_exynos5())
953 return exynos5_get_pwm_clk();
954 else
955 return exynos4_get_pwm_clk();
956 }
957
958 unsigned long get_uart_clk(int dev_index)
959 {
960 if (cpu_is_exynos5())
961 return exynos5_get_uart_clk(dev_index);
962 else
963 return exynos4_get_uart_clk(dev_index);
964 }
965
966 void set_mmc_clk(int dev_index, unsigned int div)
967 {
968 if (cpu_is_exynos5())
969 exynos5_set_mmc_clk(dev_index, div);
970 else
971 exynos4_set_mmc_clk(dev_index, div);
972 }
973
974 unsigned long get_lcd_clk(void)
975 {
976 if (cpu_is_exynos4())
977 return exynos4_get_lcd_clk();
978 else
979 return exynos5_get_lcd_clk();
980 }
981
982 void set_lcd_clk(void)
983 {
984 if (cpu_is_exynos4())
985 exynos4_set_lcd_clk();
986 else
987 exynos5_set_lcd_clk();
988 }
989
990 void set_mipi_clk(void)
991 {
992 if (cpu_is_exynos4())
993 exynos4_set_mipi_clk();
994 }
995
996 int set_spi_clk(int periph_id, unsigned int rate)
997 {
998 if (cpu_is_exynos5())
999 return exynos5_set_spi_clk(periph_id, rate);
1000 else
1001 return 0;
1002 }
1003
1004 int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
1005 {
1006
1007 if (cpu_is_exynos5())
1008 return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq);
1009 else
1010 return 0;
1011 }
1012
1013 void set_i2s_clk_source(void)
1014 {
1015 if (cpu_is_exynos5())
1016 exynos5_set_i2s_clk_source();
1017 }
1018
1019 int set_epll_clk(unsigned long rate)
1020 {
1021 if (cpu_is_exynos5())
1022 return exynos5_set_epll_clk(rate);
1023 else
1024 return 0;
1025 }