]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/exynos/clock.c
Merge branch 'agust@denx.de' of git://git.denx.de/u-boot-staging
[karo-tx-uboot.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 /* exynos4x12: return pll clock frequency */
116 static unsigned long exynos4x12_get_pll_clk(int pllreg)
117 {
118         struct exynos4x12_clock *clk =
119                 (struct exynos4x12_clock *)samsung_get_base_clock();
120         unsigned long r, k = 0;
121
122         switch (pllreg) {
123         case APLL:
124                 r = readl(&clk->apll_con0);
125                 break;
126         case MPLL:
127                 r = readl(&clk->mpll_con0);
128                 break;
129         case EPLL:
130                 r = readl(&clk->epll_con0);
131                 k = readl(&clk->epll_con1);
132                 break;
133         case VPLL:
134                 r = readl(&clk->vpll_con0);
135                 k = readl(&clk->vpll_con1);
136                 break;
137         default:
138                 printf("Unsupported PLL (%d)\n", pllreg);
139                 return 0;
140         }
141
142         return exynos_get_pll_clk(pllreg, r, k);
143 }
144
145 /* exynos5: return pll clock frequency */
146 static unsigned long exynos5_get_pll_clk(int pllreg)
147 {
148         struct exynos5_clock *clk =
149                 (struct exynos5_clock *)samsung_get_base_clock();
150         unsigned long r, k = 0, fout;
151         unsigned int pll_div2_sel, fout_sel;
152
153         switch (pllreg) {
154         case APLL:
155                 r = readl(&clk->apll_con0);
156                 break;
157         case MPLL:
158                 r = readl(&clk->mpll_con0);
159                 break;
160         case EPLL:
161                 r = readl(&clk->epll_con0);
162                 k = readl(&clk->epll_con1);
163                 break;
164         case VPLL:
165                 r = readl(&clk->vpll_con0);
166                 k = readl(&clk->vpll_con1);
167                 break;
168         case BPLL:
169                 r = readl(&clk->bpll_con0);
170                 break;
171         default:
172                 printf("Unsupported PLL (%d)\n", pllreg);
173                 return 0;
174         }
175
176         fout = exynos_get_pll_clk(pllreg, r, k);
177
178         /* According to the user manual, in EVT1 MPLL and BPLL always gives
179          * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/
180         if (pllreg == MPLL || pllreg == BPLL) {
181                 pll_div2_sel = readl(&clk->pll_div2_sel);
182
183                 switch (pllreg) {
184                 case MPLL:
185                         fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
186                                         & MPLL_FOUT_SEL_MASK;
187                         break;
188                 case BPLL:
189                         fout_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT)
190                                         & BPLL_FOUT_SEL_MASK;
191                         break;
192                 default:
193                         fout_sel = -1;
194                         break;
195                 }
196
197                 if (fout_sel == 0)
198                         fout /= 2;
199         }
200
201         return fout;
202 }
203
204 /* exynos4: return ARM clock frequency */
205 static unsigned long exynos4_get_arm_clk(void)
206 {
207         struct exynos4_clock *clk =
208                 (struct exynos4_clock *)samsung_get_base_clock();
209         unsigned long div;
210         unsigned long armclk;
211         unsigned int core_ratio;
212         unsigned int core2_ratio;
213
214         div = readl(&clk->div_cpu0);
215
216         /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
217         core_ratio = (div >> 0) & 0x7;
218         core2_ratio = (div >> 28) & 0x7;
219
220         armclk = get_pll_clk(APLL) / (core_ratio + 1);
221         armclk /= (core2_ratio + 1);
222
223         return armclk;
224 }
225
226 /* exynos4x12: return ARM clock frequency */
227 static unsigned long exynos4x12_get_arm_clk(void)
228 {
229         struct exynos4x12_clock *clk =
230                 (struct exynos4x12_clock *)samsung_get_base_clock();
231         unsigned long div;
232         unsigned long armclk;
233         unsigned int core_ratio;
234         unsigned int core2_ratio;
235
236         div = readl(&clk->div_cpu0);
237
238         /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
239         core_ratio = (div >> 0) & 0x7;
240         core2_ratio = (div >> 28) & 0x7;
241
242         armclk = get_pll_clk(APLL) / (core_ratio + 1);
243         armclk /= (core2_ratio + 1);
244
245         return armclk;
246 }
247
248 /* exynos5: return ARM clock frequency */
249 static unsigned long exynos5_get_arm_clk(void)
250 {
251         struct exynos5_clock *clk =
252                 (struct exynos5_clock *)samsung_get_base_clock();
253         unsigned long div;
254         unsigned long armclk;
255         unsigned int arm_ratio;
256         unsigned int arm2_ratio;
257
258         div = readl(&clk->div_cpu0);
259
260         /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
261         arm_ratio = (div >> 0) & 0x7;
262         arm2_ratio = (div >> 28) & 0x7;
263
264         armclk = get_pll_clk(APLL) / (arm_ratio + 1);
265         armclk /= (arm2_ratio + 1);
266
267         return armclk;
268 }
269
270 /* exynos4: return pwm clock frequency */
271 static unsigned long exynos4_get_pwm_clk(void)
272 {
273         struct exynos4_clock *clk =
274                 (struct exynos4_clock *)samsung_get_base_clock();
275         unsigned long pclk, sclk;
276         unsigned int sel;
277         unsigned int ratio;
278
279         if (s5p_get_cpu_rev() == 0) {
280                 /*
281                  * CLK_SRC_PERIL0
282                  * PWM_SEL [27:24]
283                  */
284                 sel = readl(&clk->src_peril0);
285                 sel = (sel >> 24) & 0xf;
286
287                 if (sel == 0x6)
288                         sclk = get_pll_clk(MPLL);
289                 else if (sel == 0x7)
290                         sclk = get_pll_clk(EPLL);
291                 else if (sel == 0x8)
292                         sclk = get_pll_clk(VPLL);
293                 else
294                         return 0;
295
296                 /*
297                  * CLK_DIV_PERIL3
298                  * PWM_RATIO [3:0]
299                  */
300                 ratio = readl(&clk->div_peril3);
301                 ratio = ratio & 0xf;
302         } else if (s5p_get_cpu_rev() == 1) {
303                 sclk = get_pll_clk(MPLL);
304                 ratio = 8;
305         } else
306                 return 0;
307
308         pclk = sclk / (ratio + 1);
309
310         return pclk;
311 }
312
313 /* exynos4x12: return pwm clock frequency */
314 static unsigned long exynos4x12_get_pwm_clk(void)
315 {
316         unsigned long pclk, sclk;
317         unsigned int ratio;
318
319         sclk = get_pll_clk(MPLL);
320         ratio = 8;
321
322         pclk = sclk / (ratio + 1);
323
324         return pclk;
325 }
326
327 /* exynos5: return pwm clock frequency */
328 static unsigned long exynos5_get_pwm_clk(void)
329 {
330         struct exynos5_clock *clk =
331                 (struct exynos5_clock *)samsung_get_base_clock();
332         unsigned long pclk, sclk;
333         unsigned int ratio;
334
335         /*
336          * CLK_DIV_PERIC3
337          * PWM_RATIO [3:0]
338          */
339         ratio = readl(&clk->div_peric3);
340         ratio = ratio & 0xf;
341         sclk = get_pll_clk(MPLL);
342
343         pclk = sclk / (ratio + 1);
344
345         return pclk;
346 }
347
348 /* exynos4: return uart clock frequency */
349 static unsigned long exynos4_get_uart_clk(int dev_index)
350 {
351         struct exynos4_clock *clk =
352                 (struct exynos4_clock *)samsung_get_base_clock();
353         unsigned long uclk, sclk;
354         unsigned int sel;
355         unsigned int ratio;
356
357         /*
358          * CLK_SRC_PERIL0
359          * UART0_SEL [3:0]
360          * UART1_SEL [7:4]
361          * UART2_SEL [8:11]
362          * UART3_SEL [12:15]
363          * UART4_SEL [16:19]
364          * UART5_SEL [23:20]
365          */
366         sel = readl(&clk->src_peril0);
367         sel = (sel >> (dev_index << 2)) & 0xf;
368
369         if (sel == 0x6)
370                 sclk = get_pll_clk(MPLL);
371         else if (sel == 0x7)
372                 sclk = get_pll_clk(EPLL);
373         else if (sel == 0x8)
374                 sclk = get_pll_clk(VPLL);
375         else
376                 return 0;
377
378         /*
379          * CLK_DIV_PERIL0
380          * UART0_RATIO [3:0]
381          * UART1_RATIO [7:4]
382          * UART2_RATIO [8:11]
383          * UART3_RATIO [12:15]
384          * UART4_RATIO [16:19]
385          * UART5_RATIO [23:20]
386          */
387         ratio = readl(&clk->div_peril0);
388         ratio = (ratio >> (dev_index << 2)) & 0xf;
389
390         uclk = sclk / (ratio + 1);
391
392         return uclk;
393 }
394
395 /* exynos4x12: return uart clock frequency */
396 static unsigned long exynos4x12_get_uart_clk(int dev_index)
397 {
398         struct exynos4x12_clock *clk =
399                 (struct exynos4x12_clock *)samsung_get_base_clock();
400         unsigned long uclk, sclk;
401         unsigned int sel;
402         unsigned int ratio;
403
404         /*
405          * CLK_SRC_PERIL0
406          * UART0_SEL [3:0]
407          * UART1_SEL [7:4]
408          * UART2_SEL [8:11]
409          * UART3_SEL [12:15]
410          * UART4_SEL [16:19]
411          */
412         sel = readl(&clk->src_peril0);
413         sel = (sel >> (dev_index << 2)) & 0xf;
414
415         if (sel == 0x6)
416                 sclk = get_pll_clk(MPLL);
417         else if (sel == 0x7)
418                 sclk = get_pll_clk(EPLL);
419         else if (sel == 0x8)
420                 sclk = get_pll_clk(VPLL);
421         else
422                 return 0;
423
424         /*
425          * CLK_DIV_PERIL0
426          * UART0_RATIO [3:0]
427          * UART1_RATIO [7:4]
428          * UART2_RATIO [8:11]
429          * UART3_RATIO [12:15]
430          * UART4_RATIO [16:19]
431          */
432         ratio = readl(&clk->div_peril0);
433         ratio = (ratio >> (dev_index << 2)) & 0xf;
434
435         uclk = sclk / (ratio + 1);
436
437         return uclk;
438 }
439
440 /* exynos5: return uart clock frequency */
441 static unsigned long exynos5_get_uart_clk(int dev_index)
442 {
443         struct exynos5_clock *clk =
444                 (struct exynos5_clock *)samsung_get_base_clock();
445         unsigned long uclk, sclk;
446         unsigned int sel;
447         unsigned int ratio;
448
449         /*
450          * CLK_SRC_PERIC0
451          * UART0_SEL [3:0]
452          * UART1_SEL [7:4]
453          * UART2_SEL [8:11]
454          * UART3_SEL [12:15]
455          * UART4_SEL [16:19]
456          * UART5_SEL [23:20]
457          */
458         sel = readl(&clk->src_peric0);
459         sel = (sel >> (dev_index << 2)) & 0xf;
460
461         if (sel == 0x6)
462                 sclk = get_pll_clk(MPLL);
463         else if (sel == 0x7)
464                 sclk = get_pll_clk(EPLL);
465         else if (sel == 0x8)
466                 sclk = get_pll_clk(VPLL);
467         else
468                 return 0;
469
470         /*
471          * CLK_DIV_PERIC0
472          * UART0_RATIO [3:0]
473          * UART1_RATIO [7:4]
474          * UART2_RATIO [8:11]
475          * UART3_RATIO [12:15]
476          * UART4_RATIO [16:19]
477          * UART5_RATIO [23:20]
478          */
479         ratio = readl(&clk->div_peric0);
480         ratio = (ratio >> (dev_index << 2)) & 0xf;
481
482         uclk = sclk / (ratio + 1);
483
484         return uclk;
485 }
486
487 static unsigned long exynos4_get_mmc_clk(int dev_index)
488 {
489         struct exynos4_clock *clk =
490                 (struct exynos4_clock *)samsung_get_base_clock();
491         unsigned long uclk, sclk;
492         unsigned int sel, ratio, pre_ratio;
493         int shift;
494
495         sel = readl(&clk->src_fsys);
496         sel = (sel >> (dev_index << 2)) & 0xf;
497
498         if (sel == 0x6)
499                 sclk = get_pll_clk(MPLL);
500         else if (sel == 0x7)
501                 sclk = get_pll_clk(EPLL);
502         else if (sel == 0x8)
503                 sclk = get_pll_clk(VPLL);
504         else
505                 return 0;
506
507         switch (dev_index) {
508         case 0:
509         case 1:
510                 ratio = readl(&clk->div_fsys1);
511                 pre_ratio = readl(&clk->div_fsys1);
512                 break;
513         case 2:
514         case 3:
515                 ratio = readl(&clk->div_fsys2);
516                 pre_ratio = readl(&clk->div_fsys2);
517                 break;
518         case 4:
519                 ratio = readl(&clk->div_fsys3);
520                 pre_ratio = readl(&clk->div_fsys3);
521                 break;
522         default:
523                 return 0;
524         }
525
526         if (dev_index == 1 || dev_index == 3)
527                 shift = 16;
528
529         ratio = (ratio >> shift) & 0xf;
530         pre_ratio = (pre_ratio >> (shift + 8)) & 0xff;
531         uclk = (sclk / (ratio + 1)) / (pre_ratio + 1);
532
533         return uclk;
534 }
535
536 static unsigned long exynos5_get_mmc_clk(int dev_index)
537 {
538         struct exynos5_clock *clk =
539                 (struct exynos5_clock *)samsung_get_base_clock();
540         unsigned long uclk, sclk;
541         unsigned int sel, ratio, pre_ratio;
542         int shift;
543
544         sel = readl(&clk->src_fsys);
545         sel = (sel >> (dev_index << 2)) & 0xf;
546
547         if (sel == 0x6)
548                 sclk = get_pll_clk(MPLL);
549         else if (sel == 0x7)
550                 sclk = get_pll_clk(EPLL);
551         else if (sel == 0x8)
552                 sclk = get_pll_clk(VPLL);
553         else
554                 return 0;
555
556         switch (dev_index) {
557         case 0:
558         case 1:
559                 ratio = readl(&clk->div_fsys1);
560                 pre_ratio = readl(&clk->div_fsys1);
561                 break;
562         case 2:
563         case 3:
564                 ratio = readl(&clk->div_fsys2);
565                 pre_ratio = readl(&clk->div_fsys2);
566                 break;
567         default:
568                 return 0;
569         }
570
571         if (dev_index == 1 || dev_index == 3)
572                 shift = 16;
573
574         ratio = (ratio >> shift) & 0xf;
575         pre_ratio = (pre_ratio >> (shift + 8)) & 0xff;
576         uclk = (sclk / (ratio + 1)) / (pre_ratio + 1);
577
578         return uclk;
579 }
580
581 /* exynos4: set the mmc clock */
582 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
583 {
584         struct exynos4_clock *clk =
585                 (struct exynos4_clock *)samsung_get_base_clock();
586         unsigned int addr;
587         unsigned int val;
588
589         /*
590          * CLK_DIV_FSYS1
591          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
592          * CLK_DIV_FSYS2
593          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
594          * CLK_DIV_FSYS3
595          * MMC4_PRE_RATIO [15:8]
596          */
597         if (dev_index < 2) {
598                 addr = (unsigned int)&clk->div_fsys1;
599         }  else if (dev_index == 4) {
600                 addr = (unsigned int)&clk->div_fsys3;
601                 dev_index -= 4;
602         } else {
603                 addr = (unsigned int)&clk->div_fsys2;
604                 dev_index -= 2;
605         }
606
607         val = readl(addr);
608         val &= ~(0xff << ((dev_index << 4) + 8));
609         val |= (div & 0xff) << ((dev_index << 4) + 8);
610         writel(val, addr);
611 }
612
613 /* exynos4x12: set the mmc clock */
614 static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div)
615 {
616         struct exynos4x12_clock *clk =
617                 (struct exynos4x12_clock *)samsung_get_base_clock();
618         unsigned int addr;
619         unsigned int val;
620
621         /*
622          * CLK_DIV_FSYS1
623          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
624          * CLK_DIV_FSYS2
625          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
626          */
627         if (dev_index < 2) {
628                 addr = (unsigned int)&clk->div_fsys1;
629         } else {
630                 addr = (unsigned int)&clk->div_fsys2;
631                 dev_index -= 2;
632         }
633
634         val = readl(addr);
635         val &= ~(0xff << ((dev_index << 4) + 8));
636         val |= (div & 0xff) << ((dev_index << 4) + 8);
637         writel(val, addr);
638 }
639
640 /* exynos5: set the mmc clock */
641 static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
642 {
643         struct exynos5_clock *clk =
644                 (struct exynos5_clock *)samsung_get_base_clock();
645         unsigned int addr;
646         unsigned int val;
647
648         /*
649          * CLK_DIV_FSYS1
650          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
651          * CLK_DIV_FSYS2
652          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
653          */
654         if (dev_index < 2) {
655                 addr = (unsigned int)&clk->div_fsys1;
656         } else {
657                 addr = (unsigned int)&clk->div_fsys2;
658                 dev_index -= 2;
659         }
660
661         val = readl(addr);
662         val &= ~(0xff << ((dev_index << 4) + 8));
663         val |= (div & 0xff) << ((dev_index << 4) + 8);
664         writel(val, addr);
665 }
666
667 /* get_lcd_clk: return lcd clock frequency */
668 static unsigned long exynos4_get_lcd_clk(void)
669 {
670         struct exynos4_clock *clk =
671                 (struct exynos4_clock *)samsung_get_base_clock();
672         unsigned long pclk, sclk;
673         unsigned int sel;
674         unsigned int ratio;
675
676         /*
677          * CLK_SRC_LCD0
678          * FIMD0_SEL [3:0]
679          */
680         sel = readl(&clk->src_lcd0);
681         sel = sel & 0xf;
682
683         /*
684          * 0x6: SCLK_MPLL
685          * 0x7: SCLK_EPLL
686          * 0x8: SCLK_VPLL
687          */
688         if (sel == 0x6)
689                 sclk = get_pll_clk(MPLL);
690         else if (sel == 0x7)
691                 sclk = get_pll_clk(EPLL);
692         else if (sel == 0x8)
693                 sclk = get_pll_clk(VPLL);
694         else
695                 return 0;
696
697         /*
698          * CLK_DIV_LCD0
699          * FIMD0_RATIO [3:0]
700          */
701         ratio = readl(&clk->div_lcd0);
702         ratio = ratio & 0xf;
703
704         pclk = sclk / (ratio + 1);
705
706         return pclk;
707 }
708
709 /* get_lcd_clk: return lcd clock frequency */
710 static unsigned long exynos5_get_lcd_clk(void)
711 {
712         struct exynos5_clock *clk =
713                 (struct exynos5_clock *)samsung_get_base_clock();
714         unsigned long pclk, sclk;
715         unsigned int sel;
716         unsigned int ratio;
717
718         /*
719          * CLK_SRC_LCD0
720          * FIMD0_SEL [3:0]
721          */
722         sel = readl(&clk->src_disp1_0);
723         sel = sel & 0xf;
724
725         /*
726          * 0x6: SCLK_MPLL
727          * 0x7: SCLK_EPLL
728          * 0x8: SCLK_VPLL
729          */
730         if (sel == 0x6)
731                 sclk = get_pll_clk(MPLL);
732         else if (sel == 0x7)
733                 sclk = get_pll_clk(EPLL);
734         else if (sel == 0x8)
735                 sclk = get_pll_clk(VPLL);
736         else
737                 return 0;
738
739         /*
740          * CLK_DIV_LCD0
741          * FIMD0_RATIO [3:0]
742          */
743         ratio = readl(&clk->div_disp1_0);
744         ratio = ratio & 0xf;
745
746         pclk = sclk / (ratio + 1);
747
748         return pclk;
749 }
750
751 void exynos4_set_lcd_clk(void)
752 {
753         struct exynos4_clock *clk =
754             (struct exynos4_clock *)samsung_get_base_clock();
755         unsigned int cfg = 0;
756
757         /*
758          * CLK_GATE_BLOCK
759          * CLK_CAM      [0]
760          * CLK_TV       [1]
761          * CLK_MFC      [2]
762          * CLK_G3D      [3]
763          * CLK_LCD0     [4]
764          * CLK_LCD1     [5]
765          * CLK_GPS      [7]
766          */
767         cfg = readl(&clk->gate_block);
768         cfg |= 1 << 4;
769         writel(cfg, &clk->gate_block);
770
771         /*
772          * CLK_SRC_LCD0
773          * FIMD0_SEL            [3:0]
774          * MDNIE0_SEL           [7:4]
775          * MDNIE_PWM0_SEL       [8:11]
776          * MIPI0_SEL            [12:15]
777          * set lcd0 src clock 0x6: SCLK_MPLL
778          */
779         cfg = readl(&clk->src_lcd0);
780         cfg &= ~(0xf);
781         cfg |= 0x6;
782         writel(cfg, &clk->src_lcd0);
783
784         /*
785          * CLK_GATE_IP_LCD0
786          * CLK_FIMD0            [0]
787          * CLK_MIE0             [1]
788          * CLK_MDNIE0           [2]
789          * CLK_DSIM0            [3]
790          * CLK_SMMUFIMD0        [4]
791          * CLK_PPMULCD0         [5]
792          * Gating all clocks for FIMD0
793          */
794         cfg = readl(&clk->gate_ip_lcd0);
795         cfg |= 1 << 0;
796         writel(cfg, &clk->gate_ip_lcd0);
797
798         /*
799          * CLK_DIV_LCD0
800          * FIMD0_RATIO          [3:0]
801          * MDNIE0_RATIO         [7:4]
802          * MDNIE_PWM0_RATIO     [11:8]
803          * MDNIE_PWM_PRE_RATIO  [15:12]
804          * MIPI0_RATIO          [19:16]
805          * MIPI0_PRE_RATIO      [23:20]
806          * set fimd ratio
807          */
808         cfg &= ~(0xf);
809         cfg |= 0x1;
810         writel(cfg, &clk->div_lcd0);
811 }
812
813 void exynos5_set_lcd_clk(void)
814 {
815         struct exynos5_clock *clk =
816             (struct exynos5_clock *)samsung_get_base_clock();
817         unsigned int cfg = 0;
818
819         /*
820          * CLK_GATE_BLOCK
821          * CLK_CAM      [0]
822          * CLK_TV       [1]
823          * CLK_MFC      [2]
824          * CLK_G3D      [3]
825          * CLK_LCD0     [4]
826          * CLK_LCD1     [5]
827          * CLK_GPS      [7]
828          */
829         cfg = readl(&clk->gate_block);
830         cfg |= 1 << 4;
831         writel(cfg, &clk->gate_block);
832
833         /*
834          * CLK_SRC_LCD0
835          * FIMD0_SEL            [3:0]
836          * MDNIE0_SEL           [7:4]
837          * MDNIE_PWM0_SEL       [8:11]
838          * MIPI0_SEL            [12:15]
839          * set lcd0 src clock 0x6: SCLK_MPLL
840          */
841         cfg = readl(&clk->src_disp1_0);
842         cfg &= ~(0xf);
843         cfg |= 0x6;
844         writel(cfg, &clk->src_disp1_0);
845
846         /*
847          * CLK_GATE_IP_LCD0
848          * CLK_FIMD0            [0]
849          * CLK_MIE0             [1]
850          * CLK_MDNIE0           [2]
851          * CLK_DSIM0            [3]
852          * CLK_SMMUFIMD0        [4]
853          * CLK_PPMULCD0         [5]
854          * Gating all clocks for FIMD0
855          */
856         cfg = readl(&clk->gate_ip_disp1);
857         cfg |= 1 << 0;
858         writel(cfg, &clk->gate_ip_disp1);
859
860         /*
861          * CLK_DIV_LCD0
862          * FIMD0_RATIO          [3:0]
863          * MDNIE0_RATIO         [7:4]
864          * MDNIE_PWM0_RATIO     [11:8]
865          * MDNIE_PWM_PRE_RATIO  [15:12]
866          * MIPI0_RATIO          [19:16]
867          * MIPI0_PRE_RATIO      [23:20]
868          * set fimd ratio
869          */
870         cfg &= ~(0xf);
871         cfg |= 0x0;
872         writel(cfg, &clk->div_disp1_0);
873 }
874
875 void exynos4_set_mipi_clk(void)
876 {
877         struct exynos4_clock *clk =
878             (struct exynos4_clock *)samsung_get_base_clock();
879         unsigned int cfg = 0;
880
881         /*
882          * CLK_SRC_LCD0
883          * FIMD0_SEL            [3:0]
884          * MDNIE0_SEL           [7:4]
885          * MDNIE_PWM0_SEL       [8:11]
886          * MIPI0_SEL            [12:15]
887          * set mipi0 src clock 0x6: SCLK_MPLL
888          */
889         cfg = readl(&clk->src_lcd0);
890         cfg &= ~(0xf << 12);
891         cfg |= (0x6 << 12);
892         writel(cfg, &clk->src_lcd0);
893
894         /*
895          * CLK_SRC_MASK_LCD0
896          * FIMD0_MASK           [0]
897          * MDNIE0_MASK          [4]
898          * MDNIE_PWM0_MASK      [8]
899          * MIPI0_MASK           [12]
900          * set src mask mipi0 0x1: Unmask
901          */
902         cfg = readl(&clk->src_mask_lcd0);
903         cfg |= (0x1 << 12);
904         writel(cfg, &clk->src_mask_lcd0);
905
906         /*
907          * CLK_GATE_IP_LCD0
908          * CLK_FIMD0            [0]
909          * CLK_MIE0             [1]
910          * CLK_MDNIE0           [2]
911          * CLK_DSIM0            [3]
912          * CLK_SMMUFIMD0        [4]
913          * CLK_PPMULCD0         [5]
914          * Gating all clocks for MIPI0
915          */
916         cfg = readl(&clk->gate_ip_lcd0);
917         cfg |= 1 << 3;
918         writel(cfg, &clk->gate_ip_lcd0);
919
920         /*
921          * CLK_DIV_LCD0
922          * FIMD0_RATIO          [3:0]
923          * MDNIE0_RATIO         [7:4]
924          * MDNIE_PWM0_RATIO     [11:8]
925          * MDNIE_PWM_PRE_RATIO  [15:12]
926          * MIPI0_RATIO          [19:16]
927          * MIPI0_PRE_RATIO      [23:20]
928          * set mipi ratio
929          */
930         cfg &= ~(0xf << 16);
931         cfg |= (0x1 << 16);
932         writel(cfg, &clk->div_lcd0);
933 }
934
935 /*
936  * I2C
937  *
938  * exynos5: obtaining the I2C clock
939  */
940 static unsigned long exynos5_get_i2c_clk(void)
941 {
942         struct exynos5_clock *clk =
943                 (struct exynos5_clock *)samsung_get_base_clock();
944         unsigned long aclk_66, aclk_66_pre, sclk;
945         unsigned int ratio;
946
947         sclk = get_pll_clk(MPLL);
948
949         ratio = (readl(&clk->div_top1)) >> 24;
950         ratio &= 0x7;
951         aclk_66_pre = sclk / (ratio + 1);
952         ratio = readl(&clk->div_top0);
953         ratio &= 0x7;
954         aclk_66 = aclk_66_pre / (ratio + 1);
955         return aclk_66;
956 }
957
958 int exynos5_set_epll_clk(unsigned long rate)
959 {
960         unsigned int epll_con, epll_con_k;
961         unsigned int i;
962         unsigned int lockcnt;
963         unsigned int start;
964         struct exynos5_clock *clk =
965                 (struct exynos5_clock *)samsung_get_base_clock();
966
967         epll_con = readl(&clk->epll_con0);
968         epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
969                         EPLL_CON0_LOCK_DET_EN_SHIFT) |
970                 EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
971                 EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
972                 EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
973
974         for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) {
975                 if (exynos5_epll_div[i].freq_out == rate)
976                         break;
977         }
978
979         if (i == ARRAY_SIZE(exynos5_epll_div))
980                 return -1;
981
982         epll_con_k = exynos5_epll_div[i].k_dsm << 0;
983         epll_con |= exynos5_epll_div[i].en_lock_det <<
984                                 EPLL_CON0_LOCK_DET_EN_SHIFT;
985         epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
986         epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
987         epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
988
989         /*
990          * Required period ( in cycles) to genarate a stable clock output.
991          * The maximum clock time can be up to 3000 * PDIV cycles of PLLs
992          * frequency input (as per spec)
993          */
994         lockcnt = 3000 * exynos5_epll_div[i].p_div;
995
996         writel(lockcnt, &clk->epll_lock);
997         writel(epll_con, &clk->epll_con0);
998         writel(epll_con_k, &clk->epll_con1);
999
1000         start = get_timer(0);
1001
1002          while (!(readl(&clk->epll_con0) &
1003                         (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
1004                 if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
1005                         debug("%s: Timeout waiting for EPLL lock\n", __func__);
1006                         return -1;
1007                 }
1008         }
1009         return 0;
1010 }
1011
1012 void exynos5_set_i2s_clk_source(void)
1013 {
1014         struct exynos5_clock *clk =
1015                 (struct exynos5_clock *)samsung_get_base_clock();
1016
1017         clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
1018                         (CLK_SRC_SCLK_EPLL));
1019 }
1020
1021 int exynos5_set_i2s_clk_prescaler(unsigned int src_frq,
1022                                         unsigned int dst_frq)
1023 {
1024         struct exynos5_clock *clk =
1025                 (struct exynos5_clock *)samsung_get_base_clock();
1026         unsigned int div;
1027
1028         if ((dst_frq == 0) || (src_frq == 0)) {
1029                 debug("%s: Invalid requency input for prescaler\n", __func__);
1030                 debug("src frq = %d des frq = %d ", src_frq, dst_frq);
1031                 return -1;
1032         }
1033
1034         div = (src_frq / dst_frq);
1035         if (div > AUDIO_1_RATIO_MASK) {
1036                 debug("%s: Frequency ratio is out of range\n", __func__);
1037                 debug("src frq = %d des frq = %d ", src_frq, dst_frq);
1038                 return -1;
1039         }
1040         clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
1041                                 (div & AUDIO_1_RATIO_MASK));
1042         return 0;
1043 }
1044
1045 /**
1046  * Linearly searches for the most accurate main and fine stage clock scalars
1047  * (divisors) for a specified target frequency and scalar bit sizes by checking
1048  * all multiples of main_scalar_bits values. Will always return scalars up to or
1049  * slower than target.
1050  *
1051  * @param main_scalar_bits      Number of main scalar bits, must be > 0 and < 32
1052  * @param fine_scalar_bits      Number of fine scalar bits, must be > 0 and < 32
1053  * @param input_freq            Clock frequency to be scaled in Hz
1054  * @param target_freq           Desired clock frequency in Hz
1055  * @param best_fine_scalar      Pointer to store the fine stage divisor
1056  *
1057  * @return best_main_scalar     Main scalar for desired frequency or -1 if none
1058  * found
1059  */
1060 static int clock_calc_best_scalar(unsigned int main_scaler_bits,
1061         unsigned int fine_scalar_bits, unsigned int input_rate,
1062         unsigned int target_rate, unsigned int *best_fine_scalar)
1063 {
1064         int i;
1065         int best_main_scalar = -1;
1066         unsigned int best_error = target_rate;
1067         const unsigned int cap = (1 << fine_scalar_bits) - 1;
1068         const unsigned int loops = 1 << main_scaler_bits;
1069
1070         debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate,
1071                         target_rate, cap);
1072
1073         assert(best_fine_scalar != NULL);
1074         assert(main_scaler_bits <= fine_scalar_bits);
1075
1076         *best_fine_scalar = 1;
1077
1078         if (input_rate == 0 || target_rate == 0)
1079                 return -1;
1080
1081         if (target_rate >= input_rate)
1082                 return 1;
1083
1084         for (i = 1; i <= loops; i++) {
1085                 const unsigned int effective_div = max(min(input_rate / i /
1086                                                         target_rate, cap), 1);
1087                 const unsigned int effective_rate = input_rate / i /
1088                                                         effective_div;
1089                 const int error = target_rate - effective_rate;
1090
1091                 debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div,
1092                                 effective_rate, error);
1093
1094                 if (error >= 0 && error <= best_error) {
1095                         best_error = error;
1096                         best_main_scalar = i;
1097                         *best_fine_scalar = effective_div;
1098                 }
1099         }
1100
1101         return best_main_scalar;
1102 }
1103
1104 static int exynos5_set_spi_clk(enum periph_id periph_id,
1105                                         unsigned int rate)
1106 {
1107         struct exynos5_clock *clk =
1108                 (struct exynos5_clock *)samsung_get_base_clock();
1109         int main;
1110         unsigned int fine;
1111         unsigned shift, pre_shift;
1112         unsigned mask = 0xff;
1113         u32 *reg;
1114
1115         main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
1116         if (main < 0) {
1117                 debug("%s: Cannot set clock rate for periph %d",
1118                                 __func__, periph_id);
1119                 return -1;
1120         }
1121         main = main - 1;
1122         fine = fine - 1;
1123
1124         switch (periph_id) {
1125         case PERIPH_ID_SPI0:
1126                 reg = &clk->div_peric1;
1127                 shift = 0;
1128                 pre_shift = 8;
1129                 break;
1130         case PERIPH_ID_SPI1:
1131                 reg = &clk->div_peric1;
1132                 shift = 16;
1133                 pre_shift = 24;
1134                 break;
1135         case PERIPH_ID_SPI2:
1136                 reg = &clk->div_peric2;
1137                 shift = 0;
1138                 pre_shift = 8;
1139                 break;
1140         case PERIPH_ID_SPI3:
1141                 reg = &clk->sclk_div_isp;
1142                 shift = 0;
1143                 pre_shift = 4;
1144                 break;
1145         case PERIPH_ID_SPI4:
1146                 reg = &clk->sclk_div_isp;
1147                 shift = 12;
1148                 pre_shift = 16;
1149                 break;
1150         default:
1151                 debug("%s: Unsupported peripheral ID %d\n", __func__,
1152                       periph_id);
1153                 return -1;
1154         }
1155         clrsetbits_le32(reg, mask << shift, (main & mask) << shift);
1156         clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift);
1157
1158         return 0;
1159 }
1160
1161 static unsigned long exynos4_get_i2c_clk(void)
1162 {
1163         struct exynos4_clock *clk =
1164                 (struct exynos4_clock *)samsung_get_base_clock();
1165         unsigned long sclk, aclk_100;
1166         unsigned int ratio;
1167
1168         sclk = get_pll_clk(APLL);
1169
1170         ratio = (readl(&clk->div_top)) >> 4;
1171         ratio &= 0xf;
1172         aclk_100 = sclk / (ratio + 1);
1173         return aclk_100;
1174 }
1175
1176 unsigned long get_pll_clk(int pllreg)
1177 {
1178         if (cpu_is_exynos5())
1179                 return exynos5_get_pll_clk(pllreg);
1180         else {
1181                 if (proid_is_exynos4412())
1182                         return exynos4x12_get_pll_clk(pllreg);
1183                 return exynos4_get_pll_clk(pllreg);
1184         }
1185 }
1186
1187 unsigned long get_arm_clk(void)
1188 {
1189         if (cpu_is_exynos5())
1190                 return exynos5_get_arm_clk();
1191         else {
1192                 if (proid_is_exynos4412())
1193                         return exynos4x12_get_arm_clk();
1194                 return exynos4_get_arm_clk();
1195         }
1196 }
1197
1198 unsigned long get_i2c_clk(void)
1199 {
1200         if (cpu_is_exynos5()) {
1201                 return exynos5_get_i2c_clk();
1202         } else if (cpu_is_exynos4()) {
1203                 return exynos4_get_i2c_clk();
1204         } else {
1205                 debug("I2C clock is not set for this CPU\n");
1206                 return 0;
1207         }
1208 }
1209
1210 unsigned long get_pwm_clk(void)
1211 {
1212         if (cpu_is_exynos5())
1213                 return exynos5_get_pwm_clk();
1214         else {
1215                 if (proid_is_exynos4412())
1216                         return exynos4x12_get_pwm_clk();
1217                 return exynos4_get_pwm_clk();
1218         }
1219 }
1220
1221 unsigned long get_uart_clk(int dev_index)
1222 {
1223         if (cpu_is_exynos5())
1224                 return exynos5_get_uart_clk(dev_index);
1225         else {
1226                 if (proid_is_exynos4412())
1227                         return exynos4x12_get_uart_clk(dev_index);
1228                 return exynos4_get_uart_clk(dev_index);
1229         }
1230 }
1231
1232 unsigned long get_mmc_clk(int dev_index)
1233 {
1234         if (cpu_is_exynos5())
1235                 return exynos5_get_mmc_clk(dev_index);
1236         else
1237                 return exynos4_get_mmc_clk(dev_index);
1238 }
1239
1240 void set_mmc_clk(int dev_index, unsigned int div)
1241 {
1242         if (cpu_is_exynos5())
1243                 exynos5_set_mmc_clk(dev_index, div);
1244         else {
1245                 if (proid_is_exynos4412())
1246                         exynos4x12_set_mmc_clk(dev_index, div);
1247                 exynos4_set_mmc_clk(dev_index, div);
1248         }
1249 }
1250
1251 unsigned long get_lcd_clk(void)
1252 {
1253         if (cpu_is_exynos4())
1254                 return exynos4_get_lcd_clk();
1255         else
1256                 return exynos5_get_lcd_clk();
1257 }
1258
1259 void set_lcd_clk(void)
1260 {
1261         if (cpu_is_exynos4())
1262                 exynos4_set_lcd_clk();
1263         else
1264                 exynos5_set_lcd_clk();
1265 }
1266
1267 void set_mipi_clk(void)
1268 {
1269         if (cpu_is_exynos4())
1270                 exynos4_set_mipi_clk();
1271 }
1272
1273 int set_spi_clk(int periph_id, unsigned int rate)
1274 {
1275         if (cpu_is_exynos5())
1276                 return exynos5_set_spi_clk(periph_id, rate);
1277         else
1278                 return 0;
1279 }
1280
1281 int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
1282 {
1283
1284         if (cpu_is_exynos5())
1285                 return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq);
1286         else
1287                 return 0;
1288 }
1289
1290 void set_i2s_clk_source(void)
1291 {
1292         if (cpu_is_exynos5())
1293                 exynos5_set_i2s_clk_source();
1294 }
1295
1296 int set_epll_clk(unsigned long rate)
1297 {
1298         if (cpu_is_exynos5())
1299                 return exynos5_set_epll_clk(rate);
1300         else
1301                 return 0;
1302 }