ARM: EXYNOS: fixed compiler warning message
[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                 default:
177                         fout_sel = -1;
178                         break;
179                 }
180
181                 if (fout_sel == 0)
182                         fout /= 2;
183         }
184
185         return fout;
186 }
187
188 /* exynos4: return ARM clock frequency */
189 static unsigned long exynos4_get_arm_clk(void)
190 {
191         struct exynos4_clock *clk =
192                 (struct exynos4_clock *)samsung_get_base_clock();
193         unsigned long div;
194         unsigned long armclk;
195         unsigned int core_ratio;
196         unsigned int core2_ratio;
197
198         div = readl(&clk->div_cpu0);
199
200         /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
201         core_ratio = (div >> 0) & 0x7;
202         core2_ratio = (div >> 28) & 0x7;
203
204         armclk = get_pll_clk(APLL) / (core_ratio + 1);
205         armclk /= (core2_ratio + 1);
206
207         return armclk;
208 }
209
210 /* exynos5: return ARM clock frequency */
211 static unsigned long exynos5_get_arm_clk(void)
212 {
213         struct exynos5_clock *clk =
214                 (struct exynos5_clock *)samsung_get_base_clock();
215         unsigned long div;
216         unsigned long armclk;
217         unsigned int arm_ratio;
218         unsigned int arm2_ratio;
219
220         div = readl(&clk->div_cpu0);
221
222         /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
223         arm_ratio = (div >> 0) & 0x7;
224         arm2_ratio = (div >> 28) & 0x7;
225
226         armclk = get_pll_clk(APLL) / (arm_ratio + 1);
227         armclk /= (arm2_ratio + 1);
228
229         return armclk;
230 }
231
232 /* exynos4: return pwm clock frequency */
233 static unsigned long exynos4_get_pwm_clk(void)
234 {
235         struct exynos4_clock *clk =
236                 (struct exynos4_clock *)samsung_get_base_clock();
237         unsigned long pclk, sclk;
238         unsigned int sel;
239         unsigned int ratio;
240
241         if (s5p_get_cpu_rev() == 0) {
242                 /*
243                  * CLK_SRC_PERIL0
244                  * PWM_SEL [27:24]
245                  */
246                 sel = readl(&clk->src_peril0);
247                 sel = (sel >> 24) & 0xf;
248
249                 if (sel == 0x6)
250                         sclk = get_pll_clk(MPLL);
251                 else if (sel == 0x7)
252                         sclk = get_pll_clk(EPLL);
253                 else if (sel == 0x8)
254                         sclk = get_pll_clk(VPLL);
255                 else
256                         return 0;
257
258                 /*
259                  * CLK_DIV_PERIL3
260                  * PWM_RATIO [3:0]
261                  */
262                 ratio = readl(&clk->div_peril3);
263                 ratio = ratio & 0xf;
264         } else if (s5p_get_cpu_rev() == 1) {
265                 sclk = get_pll_clk(MPLL);
266                 ratio = 8;
267         } else
268                 return 0;
269
270         pclk = sclk / (ratio + 1);
271
272         return pclk;
273 }
274
275 /* exynos5: return pwm clock frequency */
276 static unsigned long exynos5_get_pwm_clk(void)
277 {
278         struct exynos5_clock *clk =
279                 (struct exynos5_clock *)samsung_get_base_clock();
280         unsigned long pclk, sclk;
281         unsigned int ratio;
282
283         /*
284          * CLK_DIV_PERIC3
285          * PWM_RATIO [3:0]
286          */
287         ratio = readl(&clk->div_peric3);
288         ratio = ratio & 0xf;
289         sclk = get_pll_clk(MPLL);
290
291         pclk = sclk / (ratio + 1);
292
293         return pclk;
294 }
295
296 /* exynos4: return uart clock frequency */
297 static unsigned long exynos4_get_uart_clk(int dev_index)
298 {
299         struct exynos4_clock *clk =
300                 (struct exynos4_clock *)samsung_get_base_clock();
301         unsigned long uclk, sclk;
302         unsigned int sel;
303         unsigned int ratio;
304
305         /*
306          * CLK_SRC_PERIL0
307          * UART0_SEL [3:0]
308          * UART1_SEL [7:4]
309          * UART2_SEL [8:11]
310          * UART3_SEL [12:15]
311          * UART4_SEL [16:19]
312          * UART5_SEL [23:20]
313          */
314         sel = readl(&clk->src_peril0);
315         sel = (sel >> (dev_index << 2)) & 0xf;
316
317         if (sel == 0x6)
318                 sclk = get_pll_clk(MPLL);
319         else if (sel == 0x7)
320                 sclk = get_pll_clk(EPLL);
321         else if (sel == 0x8)
322                 sclk = get_pll_clk(VPLL);
323         else
324                 return 0;
325
326         /*
327          * CLK_DIV_PERIL0
328          * UART0_RATIO [3:0]
329          * UART1_RATIO [7:4]
330          * UART2_RATIO [8:11]
331          * UART3_RATIO [12:15]
332          * UART4_RATIO [16:19]
333          * UART5_RATIO [23:20]
334          */
335         ratio = readl(&clk->div_peril0);
336         ratio = (ratio >> (dev_index << 2)) & 0xf;
337
338         uclk = sclk / (ratio + 1);
339
340         return uclk;
341 }
342
343 /* exynos5: return uart clock frequency */
344 static unsigned long exynos5_get_uart_clk(int dev_index)
345 {
346         struct exynos5_clock *clk =
347                 (struct exynos5_clock *)samsung_get_base_clock();
348         unsigned long uclk, sclk;
349         unsigned int sel;
350         unsigned int ratio;
351
352         /*
353          * CLK_SRC_PERIC0
354          * UART0_SEL [3:0]
355          * UART1_SEL [7:4]
356          * UART2_SEL [8:11]
357          * UART3_SEL [12:15]
358          * UART4_SEL [16:19]
359          * UART5_SEL [23:20]
360          */
361         sel = readl(&clk->src_peric0);
362         sel = (sel >> (dev_index << 2)) & 0xf;
363
364         if (sel == 0x6)
365                 sclk = get_pll_clk(MPLL);
366         else if (sel == 0x7)
367                 sclk = get_pll_clk(EPLL);
368         else if (sel == 0x8)
369                 sclk = get_pll_clk(VPLL);
370         else
371                 return 0;
372
373         /*
374          * CLK_DIV_PERIC0
375          * UART0_RATIO [3:0]
376          * UART1_RATIO [7:4]
377          * UART2_RATIO [8:11]
378          * UART3_RATIO [12:15]
379          * UART4_RATIO [16:19]
380          * UART5_RATIO [23:20]
381          */
382         ratio = readl(&clk->div_peric0);
383         ratio = (ratio >> (dev_index << 2)) & 0xf;
384
385         uclk = sclk / (ratio + 1);
386
387         return uclk;
388 }
389
390 /* exynos4: set the mmc clock */
391 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
392 {
393         struct exynos4_clock *clk =
394                 (struct exynos4_clock *)samsung_get_base_clock();
395         unsigned int addr;
396         unsigned int val;
397
398         /*
399          * CLK_DIV_FSYS1
400          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
401          * CLK_DIV_FSYS2
402          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
403          */
404         if (dev_index < 2) {
405                 addr = (unsigned int)&clk->div_fsys1;
406         } else {
407                 addr = (unsigned int)&clk->div_fsys2;
408                 dev_index -= 2;
409         }
410
411         val = readl(addr);
412         val &= ~(0xff << ((dev_index << 4) + 8));
413         val |= (div & 0xff) << ((dev_index << 4) + 8);
414         writel(val, addr);
415 }
416
417 /* exynos5: set the mmc clock */
418 static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
419 {
420         struct exynos5_clock *clk =
421                 (struct exynos5_clock *)samsung_get_base_clock();
422         unsigned int addr;
423         unsigned int val;
424
425         /*
426          * CLK_DIV_FSYS1
427          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
428          * CLK_DIV_FSYS2
429          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
430          */
431         if (dev_index < 2) {
432                 addr = (unsigned int)&clk->div_fsys1;
433         } else {
434                 addr = (unsigned int)&clk->div_fsys2;
435                 dev_index -= 2;
436         }
437
438         val = readl(addr);
439         val &= ~(0xff << ((dev_index << 4) + 8));
440         val |= (div & 0xff) << ((dev_index << 4) + 8);
441         writel(val, addr);
442 }
443
444 /* get_lcd_clk: return lcd clock frequency */
445 static unsigned long exynos4_get_lcd_clk(void)
446 {
447         struct exynos4_clock *clk =
448                 (struct exynos4_clock *)samsung_get_base_clock();
449         unsigned long pclk, sclk;
450         unsigned int sel;
451         unsigned int ratio;
452
453         /*
454          * CLK_SRC_LCD0
455          * FIMD0_SEL [3:0]
456          */
457         sel = readl(&clk->src_lcd0);
458         sel = sel & 0xf;
459
460         /*
461          * 0x6: SCLK_MPLL
462          * 0x7: SCLK_EPLL
463          * 0x8: SCLK_VPLL
464          */
465         if (sel == 0x6)
466                 sclk = get_pll_clk(MPLL);
467         else if (sel == 0x7)
468                 sclk = get_pll_clk(EPLL);
469         else if (sel == 0x8)
470                 sclk = get_pll_clk(VPLL);
471         else
472                 return 0;
473
474         /*
475          * CLK_DIV_LCD0
476          * FIMD0_RATIO [3:0]
477          */
478         ratio = readl(&clk->div_lcd0);
479         ratio = ratio & 0xf;
480
481         pclk = sclk / (ratio + 1);
482
483         return pclk;
484 }
485
486 void exynos4_set_lcd_clk(void)
487 {
488         struct exynos4_clock *clk =
489             (struct exynos4_clock *)samsung_get_base_clock();
490         unsigned int cfg = 0;
491
492         /*
493          * CLK_GATE_BLOCK
494          * CLK_CAM      [0]
495          * CLK_TV       [1]
496          * CLK_MFC      [2]
497          * CLK_G3D      [3]
498          * CLK_LCD0     [4]
499          * CLK_LCD1     [5]
500          * CLK_GPS      [7]
501          */
502         cfg = readl(&clk->gate_block);
503         cfg |= 1 << 4;
504         writel(cfg, &clk->gate_block);
505
506         /*
507          * CLK_SRC_LCD0
508          * FIMD0_SEL            [3:0]
509          * MDNIE0_SEL           [7:4]
510          * MDNIE_PWM0_SEL       [8:11]
511          * MIPI0_SEL            [12:15]
512          * set lcd0 src clock 0x6: SCLK_MPLL
513          */
514         cfg = readl(&clk->src_lcd0);
515         cfg &= ~(0xf);
516         cfg |= 0x6;
517         writel(cfg, &clk->src_lcd0);
518
519         /*
520          * CLK_GATE_IP_LCD0
521          * CLK_FIMD0            [0]
522          * CLK_MIE0             [1]
523          * CLK_MDNIE0           [2]
524          * CLK_DSIM0            [3]
525          * CLK_SMMUFIMD0        [4]
526          * CLK_PPMULCD0         [5]
527          * Gating all clocks for FIMD0
528          */
529         cfg = readl(&clk->gate_ip_lcd0);
530         cfg |= 1 << 0;
531         writel(cfg, &clk->gate_ip_lcd0);
532
533         /*
534          * CLK_DIV_LCD0
535          * FIMD0_RATIO          [3:0]
536          * MDNIE0_RATIO         [7:4]
537          * MDNIE_PWM0_RATIO     [11:8]
538          * MDNIE_PWM_PRE_RATIO  [15:12]
539          * MIPI0_RATIO          [19:16]
540          * MIPI0_PRE_RATIO      [23:20]
541          * set fimd ratio
542          */
543         cfg &= ~(0xf);
544         cfg |= 0x1;
545         writel(cfg, &clk->div_lcd0);
546 }
547
548 void exynos4_set_mipi_clk(void)
549 {
550         struct exynos4_clock *clk =
551             (struct exynos4_clock *)samsung_get_base_clock();
552         unsigned int cfg = 0;
553
554         /*
555          * CLK_SRC_LCD0
556          * FIMD0_SEL            [3:0]
557          * MDNIE0_SEL           [7:4]
558          * MDNIE_PWM0_SEL       [8:11]
559          * MIPI0_SEL            [12:15]
560          * set mipi0 src clock 0x6: SCLK_MPLL
561          */
562         cfg = readl(&clk->src_lcd0);
563         cfg &= ~(0xf << 12);
564         cfg |= (0x6 << 12);
565         writel(cfg, &clk->src_lcd0);
566
567         /*
568          * CLK_SRC_MASK_LCD0
569          * FIMD0_MASK           [0]
570          * MDNIE0_MASK          [4]
571          * MDNIE_PWM0_MASK      [8]
572          * MIPI0_MASK           [12]
573          * set src mask mipi0 0x1: Unmask
574          */
575         cfg = readl(&clk->src_mask_lcd0);
576         cfg |= (0x1 << 12);
577         writel(cfg, &clk->src_mask_lcd0);
578
579         /*
580          * CLK_GATE_IP_LCD0
581          * CLK_FIMD0            [0]
582          * CLK_MIE0             [1]
583          * CLK_MDNIE0           [2]
584          * CLK_DSIM0            [3]
585          * CLK_SMMUFIMD0        [4]
586          * CLK_PPMULCD0         [5]
587          * Gating all clocks for MIPI0
588          */
589         cfg = readl(&clk->gate_ip_lcd0);
590         cfg |= 1 << 3;
591         writel(cfg, &clk->gate_ip_lcd0);
592
593         /*
594          * CLK_DIV_LCD0
595          * FIMD0_RATIO          [3:0]
596          * MDNIE0_RATIO         [7:4]
597          * MDNIE_PWM0_RATIO     [11:8]
598          * MDNIE_PWM_PRE_RATIO  [15:12]
599          * MIPI0_RATIO          [19:16]
600          * MIPI0_PRE_RATIO      [23:20]
601          * set mipi ratio
602          */
603         cfg &= ~(0xf << 16);
604         cfg |= (0x1 << 16);
605         writel(cfg, &clk->div_lcd0);
606 }
607
608 /*
609  * I2C
610  *
611  * exynos5: obtaining the I2C clock
612  */
613 static unsigned long exynos5_get_i2c_clk(void)
614 {
615         struct exynos5_clock *clk =
616                 (struct exynos5_clock *)samsung_get_base_clock();
617         unsigned long aclk_66, aclk_66_pre, sclk;
618         unsigned int ratio;
619
620         sclk = get_pll_clk(MPLL);
621
622         ratio = (readl(&clk->div_top1)) >> 24;
623         ratio &= 0x7;
624         aclk_66_pre = sclk / (ratio + 1);
625         ratio = readl(&clk->div_top0);
626         ratio &= 0x7;
627         aclk_66 = aclk_66_pre / (ratio + 1);
628         return aclk_66;
629 }
630
631 unsigned long get_pll_clk(int pllreg)
632 {
633         if (cpu_is_exynos5())
634                 return exynos5_get_pll_clk(pllreg);
635         else
636                 return exynos4_get_pll_clk(pllreg);
637 }
638
639 unsigned long get_arm_clk(void)
640 {
641         if (cpu_is_exynos5())
642                 return exynos5_get_arm_clk();
643         else
644                 return exynos4_get_arm_clk();
645 }
646
647 unsigned long get_i2c_clk(void)
648 {
649         if (cpu_is_exynos5()) {
650                 return exynos5_get_i2c_clk();
651         } else {
652                 debug("I2C clock is not set for this CPU\n");
653                 return 0;
654         }
655 }
656
657 unsigned long get_pwm_clk(void)
658 {
659         if (cpu_is_exynos5())
660                 return exynos5_get_pwm_clk();
661         else
662                 return exynos4_get_pwm_clk();
663 }
664
665 unsigned long get_uart_clk(int dev_index)
666 {
667         if (cpu_is_exynos5())
668                 return exynos5_get_uart_clk(dev_index);
669         else
670                 return exynos4_get_uart_clk(dev_index);
671 }
672
673 void set_mmc_clk(int dev_index, unsigned int div)
674 {
675         if (cpu_is_exynos5())
676                 exynos5_set_mmc_clk(dev_index, div);
677         else
678                 exynos4_set_mmc_clk(dev_index, div);
679 }
680
681 unsigned long get_lcd_clk(void)
682 {
683         if (cpu_is_exynos4())
684                 return exynos4_get_lcd_clk();
685         else
686                 return 0;
687 }
688
689 void set_lcd_clk(void)
690 {
691         if (cpu_is_exynos4())
692                 exynos4_set_lcd_clk();
693 }
694
695 void set_mipi_clk(void)
696 {
697         if (cpu_is_exynos4())
698                 exynos4_set_mipi_clk();
699 }