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