EXYNOS5: CLOCK: Add BPLL support
[platform/kernel/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
29 /* exynos4: return pll clock frequency */
30 static unsigned long exynos4_get_pll_clk(int pllreg)
31 {
32         struct exynos4_clock *clk =
33                 (struct exynos4_clock *)samsung_get_base_clock();
34         unsigned long r, m, p, s, k = 0, mask, fout;
35         unsigned int freq;
36
37         switch (pllreg) {
38         case APLL:
39                 r = readl(&clk->apll_con0);
40                 break;
41         case MPLL:
42                 r = readl(&clk->mpll_con0);
43                 break;
44         case EPLL:
45                 r = readl(&clk->epll_con0);
46                 k = readl(&clk->epll_con1);
47                 break;
48         case VPLL:
49                 r = readl(&clk->vpll_con0);
50                 k = readl(&clk->vpll_con1);
51                 break;
52         default:
53                 printf("Unsupported PLL (%d)\n", pllreg);
54                 return 0;
55         }
56
57         /*
58          * APLL_CON: MIDV [25:16]
59          * MPLL_CON: MIDV [25:16]
60          * EPLL_CON: MIDV [24:16]
61          * VPLL_CON: MIDV [24:16]
62          */
63         if (pllreg == APLL || pllreg == MPLL)
64                 mask = 0x3ff;
65         else
66                 mask = 0x1ff;
67
68         m = (r >> 16) & mask;
69
70         /* PDIV [13:8] */
71         p = (r >> 8) & 0x3f;
72         /* SDIV [2:0] */
73         s = r & 0x7;
74
75         freq = CONFIG_SYS_CLK_FREQ;
76
77         if (pllreg == EPLL) {
78                 k = k & 0xffff;
79                 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
80                 fout = (m + k / 65536) * (freq / (p * (1 << s)));
81         } else if (pllreg == VPLL) {
82                 k = k & 0xfff;
83                 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
84                 fout = (m + k / 1024) * (freq / (p * (1 << s)));
85         } else {
86                 if (s < 1)
87                         s = 1;
88                 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
89                 fout = m * (freq / (p * (1 << (s - 1))));
90         }
91
92         return fout;
93 }
94
95 /* exynos5: return pll clock frequency */
96 static unsigned long exynos5_get_pll_clk(int pllreg)
97 {
98         struct exynos5_clock *clk =
99                 (struct exynos5_clock *)samsung_get_base_clock();
100         unsigned long r, m, p, s, k = 0, mask, fout;
101         unsigned int freq, pll_div2_sel, fout_sel;
102
103         switch (pllreg) {
104         case APLL:
105                 r = readl(&clk->apll_con0);
106                 break;
107         case MPLL:
108                 r = readl(&clk->mpll_con0);
109                 break;
110         case EPLL:
111                 r = readl(&clk->epll_con0);
112                 k = readl(&clk->epll_con1);
113                 break;
114         case VPLL:
115                 r = readl(&clk->vpll_con0);
116                 k = readl(&clk->vpll_con1);
117                 break;
118         case BPLL:
119                 r = readl(&clk->bpll_con0);
120                 break;
121         default:
122                 printf("Unsupported PLL (%d)\n", pllreg);
123                 return 0;
124         }
125
126         /*
127          * APLL_CON: MIDV [25:16]
128          * MPLL_CON: MIDV [25:16]
129          * EPLL_CON: MIDV [24:16]
130          * VPLL_CON: MIDV [24:16]
131          * BPLL_CON: MIDV [25:16]
132          */
133         if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL)
134                 mask = 0x3ff;
135         else
136                 mask = 0x1ff;
137
138         m = (r >> 16) & mask;
139
140         /* PDIV [13:8] */
141         p = (r >> 8) & 0x3f;
142         /* SDIV [2:0] */
143         s = r & 0x7;
144
145         freq = CONFIG_SYS_CLK_FREQ;
146
147         if (pllreg == EPLL) {
148                 k = k & 0xffff;
149                 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
150                 fout = (m + k / 65536) * (freq / (p * (1 << s)));
151         } else if (pllreg == VPLL) {
152                 k = k & 0xfff;
153                 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
154                 fout = (m + k / 1024) * (freq / (p * (1 << s)));
155         } else {
156                 if (s < 1)
157                         s = 1;
158                 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
159                 fout = m * (freq / (p * (1 << (s - 1))));
160         }
161
162         /* According to the user manual, in EVT1 MPLL and BPLL always gives
163          * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/
164         if (pllreg == MPLL || pllreg == BPLL) {
165                 pll_div2_sel = readl(&clk->pll_div2_sel);
166
167                 switch (pllreg) {
168                 case MPLL:
169                         fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
170                                         & MPLL_FOUT_SEL_MASK;
171                         break;
172                 case BPLL:
173                         fout_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT)
174                                         & BPLL_FOUT_SEL_MASK;
175                         break;
176                 }
177
178                 if (fout_sel == 0)
179                         fout /= 2;
180         }
181
182         return fout;
183 }
184
185 /* exynos4: return ARM clock frequency */
186 static unsigned long exynos4_get_arm_clk(void)
187 {
188         struct exynos4_clock *clk =
189                 (struct exynos4_clock *)samsung_get_base_clock();
190         unsigned long div;
191         unsigned long armclk;
192         unsigned int core_ratio;
193         unsigned int core2_ratio;
194
195         div = readl(&clk->div_cpu0);
196
197         /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
198         core_ratio = (div >> 0) & 0x7;
199         core2_ratio = (div >> 28) & 0x7;
200
201         armclk = get_pll_clk(APLL) / (core_ratio + 1);
202         armclk /= (core2_ratio + 1);
203
204         return armclk;
205 }
206
207 /* exynos5: return ARM clock frequency */
208 static unsigned long exynos5_get_arm_clk(void)
209 {
210         struct exynos5_clock *clk =
211                 (struct exynos5_clock *)samsung_get_base_clock();
212         unsigned long div;
213         unsigned long armclk;
214         unsigned int arm_ratio;
215         unsigned int arm2_ratio;
216
217         div = readl(&clk->div_cpu0);
218
219         /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
220         arm_ratio = (div >> 0) & 0x7;
221         arm2_ratio = (div >> 28) & 0x7;
222
223         armclk = get_pll_clk(APLL) / (arm_ratio + 1);
224         armclk /= (arm2_ratio + 1);
225
226         return armclk;
227 }
228
229 /* exynos4: return pwm clock frequency */
230 static unsigned long exynos4_get_pwm_clk(void)
231 {
232         struct exynos4_clock *clk =
233                 (struct exynos4_clock *)samsung_get_base_clock();
234         unsigned long pclk, sclk;
235         unsigned int sel;
236         unsigned int ratio;
237
238         if (s5p_get_cpu_rev() == 0) {
239                 /*
240                  * CLK_SRC_PERIL0
241                  * PWM_SEL [27:24]
242                  */
243                 sel = readl(&clk->src_peril0);
244                 sel = (sel >> 24) & 0xf;
245
246                 if (sel == 0x6)
247                         sclk = get_pll_clk(MPLL);
248                 else if (sel == 0x7)
249                         sclk = get_pll_clk(EPLL);
250                 else if (sel == 0x8)
251                         sclk = get_pll_clk(VPLL);
252                 else
253                         return 0;
254
255                 /*
256                  * CLK_DIV_PERIL3
257                  * PWM_RATIO [3:0]
258                  */
259                 ratio = readl(&clk->div_peril3);
260                 ratio = ratio & 0xf;
261         } else if (s5p_get_cpu_rev() == 1) {
262                 sclk = get_pll_clk(MPLL);
263                 ratio = 8;
264         } else
265                 return 0;
266
267         pclk = sclk / (ratio + 1);
268
269         return pclk;
270 }
271
272 /* exynos5: return pwm clock frequency */
273 static unsigned long exynos5_get_pwm_clk(void)
274 {
275         struct exynos5_clock *clk =
276                 (struct exynos5_clock *)samsung_get_base_clock();
277         unsigned long pclk, sclk;
278         unsigned int ratio;
279
280         /*
281          * CLK_DIV_PERIC3
282          * PWM_RATIO [3:0]
283          */
284         ratio = readl(&clk->div_peric3);
285         ratio = ratio & 0xf;
286         sclk = get_pll_clk(MPLL);
287
288         pclk = sclk / (ratio + 1);
289
290         return pclk;
291 }
292
293 /* exynos4: return uart clock frequency */
294 static unsigned long exynos4_get_uart_clk(int dev_index)
295 {
296         struct exynos4_clock *clk =
297                 (struct exynos4_clock *)samsung_get_base_clock();
298         unsigned long uclk, sclk;
299         unsigned int sel;
300         unsigned int ratio;
301
302         /*
303          * CLK_SRC_PERIL0
304          * UART0_SEL [3:0]
305          * UART1_SEL [7:4]
306          * UART2_SEL [8:11]
307          * UART3_SEL [12:15]
308          * UART4_SEL [16:19]
309          * UART5_SEL [23:20]
310          */
311         sel = readl(&clk->src_peril0);
312         sel = (sel >> (dev_index << 2)) & 0xf;
313
314         if (sel == 0x6)
315                 sclk = get_pll_clk(MPLL);
316         else if (sel == 0x7)
317                 sclk = get_pll_clk(EPLL);
318         else if (sel == 0x8)
319                 sclk = get_pll_clk(VPLL);
320         else
321                 return 0;
322
323         /*
324          * CLK_DIV_PERIL0
325          * UART0_RATIO [3:0]
326          * UART1_RATIO [7:4]
327          * UART2_RATIO [8:11]
328          * UART3_RATIO [12:15]
329          * UART4_RATIO [16:19]
330          * UART5_RATIO [23:20]
331          */
332         ratio = readl(&clk->div_peril0);
333         ratio = (ratio >> (dev_index << 2)) & 0xf;
334
335         uclk = sclk / (ratio + 1);
336
337         return uclk;
338 }
339
340 /* exynos5: return uart clock frequency */
341 static unsigned long exynos5_get_uart_clk(int dev_index)
342 {
343         struct exynos5_clock *clk =
344                 (struct exynos5_clock *)samsung_get_base_clock();
345         unsigned long uclk, sclk;
346         unsigned int sel;
347         unsigned int ratio;
348
349         /*
350          * CLK_SRC_PERIC0
351          * UART0_SEL [3:0]
352          * UART1_SEL [7:4]
353          * UART2_SEL [8:11]
354          * UART3_SEL [12:15]
355          * UART4_SEL [16:19]
356          * UART5_SEL [23:20]
357          */
358         sel = readl(&clk->src_peric0);
359         sel = (sel >> (dev_index << 2)) & 0xf;
360
361         if (sel == 0x6)
362                 sclk = get_pll_clk(MPLL);
363         else if (sel == 0x7)
364                 sclk = get_pll_clk(EPLL);
365         else if (sel == 0x8)
366                 sclk = get_pll_clk(VPLL);
367         else
368                 return 0;
369
370         /*
371          * CLK_DIV_PERIC0
372          * UART0_RATIO [3:0]
373          * UART1_RATIO [7:4]
374          * UART2_RATIO [8:11]
375          * UART3_RATIO [12:15]
376          * UART4_RATIO [16:19]
377          * UART5_RATIO [23:20]
378          */
379         ratio = readl(&clk->div_peric0);
380         ratio = (ratio >> (dev_index << 2)) & 0xf;
381
382         uclk = sclk / (ratio + 1);
383
384         return uclk;
385 }
386
387 /* exynos4: set the mmc clock */
388 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
389 {
390         struct exynos4_clock *clk =
391                 (struct exynos4_clock *)samsung_get_base_clock();
392         unsigned int addr;
393         unsigned int val;
394
395         /*
396          * CLK_DIV_FSYS1
397          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
398          * CLK_DIV_FSYS2
399          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
400          */
401         if (dev_index < 2) {
402                 addr = (unsigned int)&clk->div_fsys1;
403         } else {
404                 addr = (unsigned int)&clk->div_fsys2;
405                 dev_index -= 2;
406         }
407
408         val = readl(addr);
409         val &= ~(0xff << ((dev_index << 4) + 8));
410         val |= (div & 0xff) << ((dev_index << 4) + 8);
411         writel(val, addr);
412 }
413
414 /* exynos5: set the mmc clock */
415 static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
416 {
417         struct exynos5_clock *clk =
418                 (struct exynos5_clock *)samsung_get_base_clock();
419         unsigned int addr;
420         unsigned int val;
421
422         /*
423          * CLK_DIV_FSYS1
424          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
425          * CLK_DIV_FSYS2
426          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
427          */
428         if (dev_index < 2) {
429                 addr = (unsigned int)&clk->div_fsys1;
430         } else {
431                 addr = (unsigned int)&clk->div_fsys2;
432                 dev_index -= 2;
433         }
434
435         val = readl(addr);
436         val &= ~(0xff << ((dev_index << 4) + 8));
437         val |= (div & 0xff) << ((dev_index << 4) + 8);
438         writel(val, addr);
439 }
440
441 /* get_lcd_clk: return lcd clock frequency */
442 static unsigned long exynos4_get_lcd_clk(void)
443 {
444         struct exynos4_clock *clk =
445                 (struct exynos4_clock *)samsung_get_base_clock();
446         unsigned long pclk, sclk;
447         unsigned int sel;
448         unsigned int ratio;
449
450         /*
451          * CLK_SRC_LCD0
452          * FIMD0_SEL [3:0]
453          */
454         sel = readl(&clk->src_lcd0);
455         sel = sel & 0xf;
456
457         /*
458          * 0x6: SCLK_MPLL
459          * 0x7: SCLK_EPLL
460          * 0x8: SCLK_VPLL
461          */
462         if (sel == 0x6)
463                 sclk = get_pll_clk(MPLL);
464         else if (sel == 0x7)
465                 sclk = get_pll_clk(EPLL);
466         else if (sel == 0x8)
467                 sclk = get_pll_clk(VPLL);
468         else
469                 return 0;
470
471         /*
472          * CLK_DIV_LCD0
473          * FIMD0_RATIO [3:0]
474          */
475         ratio = readl(&clk->div_lcd0);
476         ratio = ratio & 0xf;
477
478         pclk = sclk / (ratio + 1);
479
480         return pclk;
481 }
482
483 void exynos4_set_lcd_clk(void)
484 {
485         struct exynos4_clock *clk =
486             (struct exynos4_clock *)samsung_get_base_clock();
487         unsigned int cfg = 0;
488
489         /*
490          * CLK_GATE_BLOCK
491          * CLK_CAM      [0]
492          * CLK_TV       [1]
493          * CLK_MFC      [2]
494          * CLK_G3D      [3]
495          * CLK_LCD0     [4]
496          * CLK_LCD1     [5]
497          * CLK_GPS      [7]
498          */
499         cfg = readl(&clk->gate_block);
500         cfg |= 1 << 4;
501         writel(cfg, &clk->gate_block);
502
503         /*
504          * CLK_SRC_LCD0
505          * FIMD0_SEL            [3:0]
506          * MDNIE0_SEL           [7:4]
507          * MDNIE_PWM0_SEL       [8:11]
508          * MIPI0_SEL            [12:15]
509          * set lcd0 src clock 0x6: SCLK_MPLL
510          */
511         cfg = readl(&clk->src_lcd0);
512         cfg &= ~(0xf);
513         cfg |= 0x6;
514         writel(cfg, &clk->src_lcd0);
515
516         /*
517          * CLK_GATE_IP_LCD0
518          * CLK_FIMD0            [0]
519          * CLK_MIE0             [1]
520          * CLK_MDNIE0           [2]
521          * CLK_DSIM0            [3]
522          * CLK_SMMUFIMD0        [4]
523          * CLK_PPMULCD0         [5]
524          * Gating all clocks for FIMD0
525          */
526         cfg = readl(&clk->gate_ip_lcd0);
527         cfg |= 1 << 0;
528         writel(cfg, &clk->gate_ip_lcd0);
529
530         /*
531          * CLK_DIV_LCD0
532          * FIMD0_RATIO          [3:0]
533          * MDNIE0_RATIO         [7:4]
534          * MDNIE_PWM0_RATIO     [11:8]
535          * MDNIE_PWM_PRE_RATIO  [15:12]
536          * MIPI0_RATIO          [19:16]
537          * MIPI0_PRE_RATIO      [23:20]
538          * set fimd ratio
539          */
540         cfg &= ~(0xf);
541         cfg |= 0x1;
542         writel(cfg, &clk->div_lcd0);
543 }
544
545 void exynos4_set_mipi_clk(void)
546 {
547         struct exynos4_clock *clk =
548             (struct exynos4_clock *)samsung_get_base_clock();
549         unsigned int cfg = 0;
550
551         /*
552          * CLK_SRC_LCD0
553          * FIMD0_SEL            [3:0]
554          * MDNIE0_SEL           [7:4]
555          * MDNIE_PWM0_SEL       [8:11]
556          * MIPI0_SEL            [12:15]
557          * set mipi0 src clock 0x6: SCLK_MPLL
558          */
559         cfg = readl(&clk->src_lcd0);
560         cfg &= ~(0xf << 12);
561         cfg |= (0x6 << 12);
562         writel(cfg, &clk->src_lcd0);
563
564         /*
565          * CLK_SRC_MASK_LCD0
566          * FIMD0_MASK           [0]
567          * MDNIE0_MASK          [4]
568          * MDNIE_PWM0_MASK      [8]
569          * MIPI0_MASK           [12]
570          * set src mask mipi0 0x1: Unmask
571          */
572         cfg = readl(&clk->src_mask_lcd0);
573         cfg |= (0x1 << 12);
574         writel(cfg, &clk->src_mask_lcd0);
575
576         /*
577          * CLK_GATE_IP_LCD0
578          * CLK_FIMD0            [0]
579          * CLK_MIE0             [1]
580          * CLK_MDNIE0           [2]
581          * CLK_DSIM0            [3]
582          * CLK_SMMUFIMD0        [4]
583          * CLK_PPMULCD0         [5]
584          * Gating all clocks for MIPI0
585          */
586         cfg = readl(&clk->gate_ip_lcd0);
587         cfg |= 1 << 3;
588         writel(cfg, &clk->gate_ip_lcd0);
589
590         /*
591          * CLK_DIV_LCD0
592          * FIMD0_RATIO          [3:0]
593          * MDNIE0_RATIO         [7:4]
594          * MDNIE_PWM0_RATIO     [11:8]
595          * MDNIE_PWM_PRE_RATIO  [15:12]
596          * MIPI0_RATIO          [19:16]
597          * MIPI0_PRE_RATIO      [23:20]
598          * set mipi ratio
599          */
600         cfg &= ~(0xf << 16);
601         cfg |= (0x1 << 16);
602         writel(cfg, &clk->div_lcd0);
603 }
604
605 /*
606  * I2C
607  *
608  * exynos5: obtaining the I2C clock
609  */
610 static unsigned long exynos5_get_i2c_clk(void)
611 {
612         struct exynos5_clock *clk =
613                 (struct exynos5_clock *)samsung_get_base_clock();
614         unsigned long aclk_66, aclk_66_pre, sclk;
615         unsigned int ratio;
616
617         sclk = get_pll_clk(MPLL);
618
619         ratio = (readl(&clk->div_top1)) >> 24;
620         ratio &= 0x7;
621         aclk_66_pre = sclk / (ratio + 1);
622         ratio = readl(&clk->div_top0);
623         ratio &= 0x7;
624         aclk_66 = aclk_66_pre / (ratio + 1);
625         return aclk_66;
626 }
627
628 unsigned long get_pll_clk(int pllreg)
629 {
630         if (cpu_is_exynos5())
631                 return exynos5_get_pll_clk(pllreg);
632         else
633                 return exynos4_get_pll_clk(pllreg);
634 }
635
636 unsigned long get_arm_clk(void)
637 {
638         if (cpu_is_exynos5())
639                 return exynos5_get_arm_clk();
640         else
641                 return exynos4_get_arm_clk();
642 }
643
644 unsigned long get_i2c_clk(void)
645 {
646         if (cpu_is_exynos5()) {
647                 return exynos5_get_i2c_clk();
648         } else {
649                 debug("I2C clock is not set for this CPU\n");
650                 return 0;
651         }
652 }
653
654 unsigned long get_pwm_clk(void)
655 {
656         if (cpu_is_exynos5())
657                 return exynos5_get_pwm_clk();
658         else
659                 return exynos4_get_pwm_clk();
660 }
661
662 unsigned long get_uart_clk(int dev_index)
663 {
664         if (cpu_is_exynos5())
665                 return exynos5_get_uart_clk(dev_index);
666         else
667                 return exynos4_get_uart_clk(dev_index);
668 }
669
670 void set_mmc_clk(int dev_index, unsigned int div)
671 {
672         if (cpu_is_exynos5())
673                 exynos5_set_mmc_clk(dev_index, div);
674         else
675                 exynos4_set_mmc_clk(dev_index, div);
676 }
677
678 unsigned long get_lcd_clk(void)
679 {
680         if (cpu_is_exynos4())
681                 return exynos4_get_lcd_clk();
682         else
683                 return 0;
684 }
685
686 void set_lcd_clk(void)
687 {
688         if (cpu_is_exynos4())
689                 exynos4_set_lcd_clk();
690 }
691
692 void set_mipi_clk(void)
693 {
694         if (cpu_is_exynos4())
695                 exynos4_set_mipi_clk();
696 }