]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/exynos/clock.c
EXYNOS5: Change parent clock of FIMD to MPLL
[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 /* exynos4: set the mmc clock */
488 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
489 {
490         struct exynos4_clock *clk =
491                 (struct exynos4_clock *)samsung_get_base_clock();
492         unsigned int addr;
493         unsigned int val;
494
495         /*
496          * CLK_DIV_FSYS1
497          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
498          * CLK_DIV_FSYS2
499          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
500          */
501         if (dev_index < 2) {
502                 addr = (unsigned int)&clk->div_fsys1;
503         } else {
504                 addr = (unsigned int)&clk->div_fsys2;
505                 dev_index -= 2;
506         }
507
508         val = readl(addr);
509         val &= ~(0xff << ((dev_index << 4) + 8));
510         val |= (div & 0xff) << ((dev_index << 4) + 8);
511         writel(val, addr);
512 }
513
514 /* exynos4x12: set the mmc clock */
515 static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div)
516 {
517         struct exynos4x12_clock *clk =
518                 (struct exynos4x12_clock *)samsung_get_base_clock();
519         unsigned int addr;
520         unsigned int val;
521
522         /*
523          * CLK_DIV_FSYS1
524          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
525          * CLK_DIV_FSYS2
526          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
527          */
528         if (dev_index < 2) {
529                 addr = (unsigned int)&clk->div_fsys1;
530         } else {
531                 addr = (unsigned int)&clk->div_fsys2;
532                 dev_index -= 2;
533         }
534
535         val = readl(addr);
536         val &= ~(0xff << ((dev_index << 4) + 8));
537         val |= (div & 0xff) << ((dev_index << 4) + 8);
538         writel(val, addr);
539 }
540
541 /* exynos5: set the mmc clock */
542 static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
543 {
544         struct exynos5_clock *clk =
545                 (struct exynos5_clock *)samsung_get_base_clock();
546         unsigned int addr;
547         unsigned int val;
548
549         /*
550          * CLK_DIV_FSYS1
551          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
552          * CLK_DIV_FSYS2
553          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
554          */
555         if (dev_index < 2) {
556                 addr = (unsigned int)&clk->div_fsys1;
557         } else {
558                 addr = (unsigned int)&clk->div_fsys2;
559                 dev_index -= 2;
560         }
561
562         val = readl(addr);
563         val &= ~(0xff << ((dev_index << 4) + 8));
564         val |= (div & 0xff) << ((dev_index << 4) + 8);
565         writel(val, addr);
566 }
567
568 /* get_lcd_clk: return lcd clock frequency */
569 static unsigned long exynos4_get_lcd_clk(void)
570 {
571         struct exynos4_clock *clk =
572                 (struct exynos4_clock *)samsung_get_base_clock();
573         unsigned long pclk, sclk;
574         unsigned int sel;
575         unsigned int ratio;
576
577         /*
578          * CLK_SRC_LCD0
579          * FIMD0_SEL [3:0]
580          */
581         sel = readl(&clk->src_lcd0);
582         sel = sel & 0xf;
583
584         /*
585          * 0x6: SCLK_MPLL
586          * 0x7: SCLK_EPLL
587          * 0x8: SCLK_VPLL
588          */
589         if (sel == 0x6)
590                 sclk = get_pll_clk(MPLL);
591         else if (sel == 0x7)
592                 sclk = get_pll_clk(EPLL);
593         else if (sel == 0x8)
594                 sclk = get_pll_clk(VPLL);
595         else
596                 return 0;
597
598         /*
599          * CLK_DIV_LCD0
600          * FIMD0_RATIO [3:0]
601          */
602         ratio = readl(&clk->div_lcd0);
603         ratio = ratio & 0xf;
604
605         pclk = sclk / (ratio + 1);
606
607         return pclk;
608 }
609
610 /* get_lcd_clk: return lcd clock frequency */
611 static unsigned long exynos5_get_lcd_clk(void)
612 {
613         struct exynos5_clock *clk =
614                 (struct exynos5_clock *)samsung_get_base_clock();
615         unsigned long pclk, sclk;
616         unsigned int sel;
617         unsigned int ratio;
618
619         /*
620          * CLK_SRC_LCD0
621          * FIMD0_SEL [3:0]
622          */
623         sel = readl(&clk->src_disp1_0);
624         sel = sel & 0xf;
625
626         /*
627          * 0x6: SCLK_MPLL
628          * 0x7: SCLK_EPLL
629          * 0x8: SCLK_VPLL
630          */
631         if (sel == 0x6)
632                 sclk = get_pll_clk(MPLL);
633         else if (sel == 0x7)
634                 sclk = get_pll_clk(EPLL);
635         else if (sel == 0x8)
636                 sclk = get_pll_clk(VPLL);
637         else
638                 return 0;
639
640         /*
641          * CLK_DIV_LCD0
642          * FIMD0_RATIO [3:0]
643          */
644         ratio = readl(&clk->div_disp1_0);
645         ratio = ratio & 0xf;
646
647         pclk = sclk / (ratio + 1);
648
649         return pclk;
650 }
651
652 void exynos4_set_lcd_clk(void)
653 {
654         struct exynos4_clock *clk =
655             (struct exynos4_clock *)samsung_get_base_clock();
656         unsigned int cfg = 0;
657
658         /*
659          * CLK_GATE_BLOCK
660          * CLK_CAM      [0]
661          * CLK_TV       [1]
662          * CLK_MFC      [2]
663          * CLK_G3D      [3]
664          * CLK_LCD0     [4]
665          * CLK_LCD1     [5]
666          * CLK_GPS      [7]
667          */
668         cfg = readl(&clk->gate_block);
669         cfg |= 1 << 4;
670         writel(cfg, &clk->gate_block);
671
672         /*
673          * CLK_SRC_LCD0
674          * FIMD0_SEL            [3:0]
675          * MDNIE0_SEL           [7:4]
676          * MDNIE_PWM0_SEL       [8:11]
677          * MIPI0_SEL            [12:15]
678          * set lcd0 src clock 0x6: SCLK_MPLL
679          */
680         cfg = readl(&clk->src_lcd0);
681         cfg &= ~(0xf);
682         cfg |= 0x6;
683         writel(cfg, &clk->src_lcd0);
684
685         /*
686          * CLK_GATE_IP_LCD0
687          * CLK_FIMD0            [0]
688          * CLK_MIE0             [1]
689          * CLK_MDNIE0           [2]
690          * CLK_DSIM0            [3]
691          * CLK_SMMUFIMD0        [4]
692          * CLK_PPMULCD0         [5]
693          * Gating all clocks for FIMD0
694          */
695         cfg = readl(&clk->gate_ip_lcd0);
696         cfg |= 1 << 0;
697         writel(cfg, &clk->gate_ip_lcd0);
698
699         /*
700          * CLK_DIV_LCD0
701          * FIMD0_RATIO          [3:0]
702          * MDNIE0_RATIO         [7:4]
703          * MDNIE_PWM0_RATIO     [11:8]
704          * MDNIE_PWM_PRE_RATIO  [15:12]
705          * MIPI0_RATIO          [19:16]
706          * MIPI0_PRE_RATIO      [23:20]
707          * set fimd ratio
708          */
709         cfg &= ~(0xf);
710         cfg |= 0x1;
711         writel(cfg, &clk->div_lcd0);
712 }
713
714 void exynos5_set_lcd_clk(void)
715 {
716         struct exynos5_clock *clk =
717             (struct exynos5_clock *)samsung_get_base_clock();
718         unsigned int cfg = 0;
719
720         /*
721          * CLK_GATE_BLOCK
722          * CLK_CAM      [0]
723          * CLK_TV       [1]
724          * CLK_MFC      [2]
725          * CLK_G3D      [3]
726          * CLK_LCD0     [4]
727          * CLK_LCD1     [5]
728          * CLK_GPS      [7]
729          */
730         cfg = readl(&clk->gate_block);
731         cfg |= 1 << 4;
732         writel(cfg, &clk->gate_block);
733
734         /*
735          * CLK_SRC_LCD0
736          * FIMD0_SEL            [3:0]
737          * MDNIE0_SEL           [7:4]
738          * MDNIE_PWM0_SEL       [8:11]
739          * MIPI0_SEL            [12:15]
740          * set lcd0 src clock 0x6: SCLK_MPLL
741          */
742         cfg = readl(&clk->src_disp1_0);
743         cfg &= ~(0xf);
744         cfg |= 0x6;
745         writel(cfg, &clk->src_disp1_0);
746
747         /*
748          * CLK_GATE_IP_LCD0
749          * CLK_FIMD0            [0]
750          * CLK_MIE0             [1]
751          * CLK_MDNIE0           [2]
752          * CLK_DSIM0            [3]
753          * CLK_SMMUFIMD0        [4]
754          * CLK_PPMULCD0         [5]
755          * Gating all clocks for FIMD0
756          */
757         cfg = readl(&clk->gate_ip_disp1);
758         cfg |= 1 << 0;
759         writel(cfg, &clk->gate_ip_disp1);
760
761         /*
762          * CLK_DIV_LCD0
763          * FIMD0_RATIO          [3:0]
764          * MDNIE0_RATIO         [7:4]
765          * MDNIE_PWM0_RATIO     [11:8]
766          * MDNIE_PWM_PRE_RATIO  [15:12]
767          * MIPI0_RATIO          [19:16]
768          * MIPI0_PRE_RATIO      [23:20]
769          * set fimd ratio
770          */
771         cfg &= ~(0xf);
772         cfg |= 0x0;
773         writel(cfg, &clk->div_disp1_0);
774 }
775
776 void exynos4_set_mipi_clk(void)
777 {
778         struct exynos4_clock *clk =
779             (struct exynos4_clock *)samsung_get_base_clock();
780         unsigned int cfg = 0;
781
782         /*
783          * CLK_SRC_LCD0
784          * FIMD0_SEL            [3:0]
785          * MDNIE0_SEL           [7:4]
786          * MDNIE_PWM0_SEL       [8:11]
787          * MIPI0_SEL            [12:15]
788          * set mipi0 src clock 0x6: SCLK_MPLL
789          */
790         cfg = readl(&clk->src_lcd0);
791         cfg &= ~(0xf << 12);
792         cfg |= (0x6 << 12);
793         writel(cfg, &clk->src_lcd0);
794
795         /*
796          * CLK_SRC_MASK_LCD0
797          * FIMD0_MASK           [0]
798          * MDNIE0_MASK          [4]
799          * MDNIE_PWM0_MASK      [8]
800          * MIPI0_MASK           [12]
801          * set src mask mipi0 0x1: Unmask
802          */
803         cfg = readl(&clk->src_mask_lcd0);
804         cfg |= (0x1 << 12);
805         writel(cfg, &clk->src_mask_lcd0);
806
807         /*
808          * CLK_GATE_IP_LCD0
809          * CLK_FIMD0            [0]
810          * CLK_MIE0             [1]
811          * CLK_MDNIE0           [2]
812          * CLK_DSIM0            [3]
813          * CLK_SMMUFIMD0        [4]
814          * CLK_PPMULCD0         [5]
815          * Gating all clocks for MIPI0
816          */
817         cfg = readl(&clk->gate_ip_lcd0);
818         cfg |= 1 << 3;
819         writel(cfg, &clk->gate_ip_lcd0);
820
821         /*
822          * CLK_DIV_LCD0
823          * FIMD0_RATIO          [3:0]
824          * MDNIE0_RATIO         [7:4]
825          * MDNIE_PWM0_RATIO     [11:8]
826          * MDNIE_PWM_PRE_RATIO  [15:12]
827          * MIPI0_RATIO          [19:16]
828          * MIPI0_PRE_RATIO      [23:20]
829          * set mipi ratio
830          */
831         cfg &= ~(0xf << 16);
832         cfg |= (0x1 << 16);
833         writel(cfg, &clk->div_lcd0);
834 }
835
836 /*
837  * I2C
838  *
839  * exynos5: obtaining the I2C clock
840  */
841 static unsigned long exynos5_get_i2c_clk(void)
842 {
843         struct exynos5_clock *clk =
844                 (struct exynos5_clock *)samsung_get_base_clock();
845         unsigned long aclk_66, aclk_66_pre, sclk;
846         unsigned int ratio;
847
848         sclk = get_pll_clk(MPLL);
849
850         ratio = (readl(&clk->div_top1)) >> 24;
851         ratio &= 0x7;
852         aclk_66_pre = sclk / (ratio + 1);
853         ratio = readl(&clk->div_top0);
854         ratio &= 0x7;
855         aclk_66 = aclk_66_pre / (ratio + 1);
856         return aclk_66;
857 }
858
859 int exynos5_set_epll_clk(unsigned long rate)
860 {
861         unsigned int epll_con, epll_con_k;
862         unsigned int i;
863         unsigned int lockcnt;
864         unsigned int start;
865         struct exynos5_clock *clk =
866                 (struct exynos5_clock *)samsung_get_base_clock();
867
868         epll_con = readl(&clk->epll_con0);
869         epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
870                         EPLL_CON0_LOCK_DET_EN_SHIFT) |
871                 EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
872                 EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
873                 EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
874
875         for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) {
876                 if (exynos5_epll_div[i].freq_out == rate)
877                         break;
878         }
879
880         if (i == ARRAY_SIZE(exynos5_epll_div))
881                 return -1;
882
883         epll_con_k = exynos5_epll_div[i].k_dsm << 0;
884         epll_con |= exynos5_epll_div[i].en_lock_det <<
885                                 EPLL_CON0_LOCK_DET_EN_SHIFT;
886         epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
887         epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
888         epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
889
890         /*
891          * Required period ( in cycles) to genarate a stable clock output.
892          * The maximum clock time can be up to 3000 * PDIV cycles of PLLs
893          * frequency input (as per spec)
894          */
895         lockcnt = 3000 * exynos5_epll_div[i].p_div;
896
897         writel(lockcnt, &clk->epll_lock);
898         writel(epll_con, &clk->epll_con0);
899         writel(epll_con_k, &clk->epll_con1);
900
901         start = get_timer(0);
902
903          while (!(readl(&clk->epll_con0) &
904                         (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
905                 if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
906                         debug("%s: Timeout waiting for EPLL lock\n", __func__);
907                         return -1;
908                 }
909         }
910         return 0;
911 }
912
913 void exynos5_set_i2s_clk_source(void)
914 {
915         struct exynos5_clock *clk =
916                 (struct exynos5_clock *)samsung_get_base_clock();
917
918         clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
919                         (CLK_SRC_SCLK_EPLL));
920 }
921
922 int exynos5_set_i2s_clk_prescaler(unsigned int src_frq,
923                                         unsigned int dst_frq)
924 {
925         struct exynos5_clock *clk =
926                 (struct exynos5_clock *)samsung_get_base_clock();
927         unsigned int div;
928
929         if ((dst_frq == 0) || (src_frq == 0)) {
930                 debug("%s: Invalid requency input for prescaler\n", __func__);
931                 debug("src frq = %d des frq = %d ", src_frq, dst_frq);
932                 return -1;
933         }
934
935         div = (src_frq / dst_frq);
936         if (div > AUDIO_1_RATIO_MASK) {
937                 debug("%s: Frequency ratio is out of range\n", __func__);
938                 debug("src frq = %d des frq = %d ", src_frq, dst_frq);
939                 return -1;
940         }
941         clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
942                                 (div & AUDIO_1_RATIO_MASK));
943         return 0;
944 }
945
946 /**
947  * Linearly searches for the most accurate main and fine stage clock scalars
948  * (divisors) for a specified target frequency and scalar bit sizes by checking
949  * all multiples of main_scalar_bits values. Will always return scalars up to or
950  * slower than target.
951  *
952  * @param main_scalar_bits      Number of main scalar bits, must be > 0 and < 32
953  * @param fine_scalar_bits      Number of fine scalar bits, must be > 0 and < 32
954  * @param input_freq            Clock frequency to be scaled in Hz
955  * @param target_freq           Desired clock frequency in Hz
956  * @param best_fine_scalar      Pointer to store the fine stage divisor
957  *
958  * @return best_main_scalar     Main scalar for desired frequency or -1 if none
959  * found
960  */
961 static int clock_calc_best_scalar(unsigned int main_scaler_bits,
962         unsigned int fine_scalar_bits, unsigned int input_rate,
963         unsigned int target_rate, unsigned int *best_fine_scalar)
964 {
965         int i;
966         int best_main_scalar = -1;
967         unsigned int best_error = target_rate;
968         const unsigned int cap = (1 << fine_scalar_bits) - 1;
969         const unsigned int loops = 1 << main_scaler_bits;
970
971         debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate,
972                         target_rate, cap);
973
974         assert(best_fine_scalar != NULL);
975         assert(main_scaler_bits <= fine_scalar_bits);
976
977         *best_fine_scalar = 1;
978
979         if (input_rate == 0 || target_rate == 0)
980                 return -1;
981
982         if (target_rate >= input_rate)
983                 return 1;
984
985         for (i = 1; i <= loops; i++) {
986                 const unsigned int effective_div = max(min(input_rate / i /
987                                                         target_rate, cap), 1);
988                 const unsigned int effective_rate = input_rate / i /
989                                                         effective_div;
990                 const int error = target_rate - effective_rate;
991
992                 debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div,
993                                 effective_rate, error);
994
995                 if (error >= 0 && error <= best_error) {
996                         best_error = error;
997                         best_main_scalar = i;
998                         *best_fine_scalar = effective_div;
999                 }
1000         }
1001
1002         return best_main_scalar;
1003 }
1004
1005 static int exynos5_set_spi_clk(enum periph_id periph_id,
1006                                         unsigned int rate)
1007 {
1008         struct exynos5_clock *clk =
1009                 (struct exynos5_clock *)samsung_get_base_clock();
1010         int main;
1011         unsigned int fine;
1012         unsigned shift, pre_shift;
1013         unsigned mask = 0xff;
1014         u32 *reg;
1015
1016         main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
1017         if (main < 0) {
1018                 debug("%s: Cannot set clock rate for periph %d",
1019                                 __func__, periph_id);
1020                 return -1;
1021         }
1022         main = main - 1;
1023         fine = fine - 1;
1024
1025         switch (periph_id) {
1026         case PERIPH_ID_SPI0:
1027                 reg = &clk->div_peric1;
1028                 shift = 0;
1029                 pre_shift = 8;
1030                 break;
1031         case PERIPH_ID_SPI1:
1032                 reg = &clk->div_peric1;
1033                 shift = 16;
1034                 pre_shift = 24;
1035                 break;
1036         case PERIPH_ID_SPI2:
1037                 reg = &clk->div_peric2;
1038                 shift = 0;
1039                 pre_shift = 8;
1040                 break;
1041         case PERIPH_ID_SPI3:
1042                 reg = &clk->sclk_div_isp;
1043                 shift = 0;
1044                 pre_shift = 4;
1045                 break;
1046         case PERIPH_ID_SPI4:
1047                 reg = &clk->sclk_div_isp;
1048                 shift = 12;
1049                 pre_shift = 16;
1050                 break;
1051         default:
1052                 debug("%s: Unsupported peripheral ID %d\n", __func__,
1053                       periph_id);
1054                 return -1;
1055         }
1056         clrsetbits_le32(reg, mask << shift, (main & mask) << shift);
1057         clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift);
1058
1059         return 0;
1060 }
1061
1062 static unsigned long exynos4_get_i2c_clk(void)
1063 {
1064         struct exynos4_clock *clk =
1065                 (struct exynos4_clock *)samsung_get_base_clock();
1066         unsigned long sclk, aclk_100;
1067         unsigned int ratio;
1068
1069         sclk = get_pll_clk(APLL);
1070
1071         ratio = (readl(&clk->div_top)) >> 4;
1072         ratio &= 0xf;
1073         aclk_100 = sclk / (ratio + 1);
1074         return aclk_100;
1075 }
1076
1077 unsigned long get_pll_clk(int pllreg)
1078 {
1079         if (cpu_is_exynos5())
1080                 return exynos5_get_pll_clk(pllreg);
1081         else {
1082                 if (proid_is_exynos4412())
1083                         return exynos4x12_get_pll_clk(pllreg);
1084                 return exynos4_get_pll_clk(pllreg);
1085         }
1086 }
1087
1088 unsigned long get_arm_clk(void)
1089 {
1090         if (cpu_is_exynos5())
1091                 return exynos5_get_arm_clk();
1092         else {
1093                 if (proid_is_exynos4412())
1094                         return exynos4x12_get_arm_clk();
1095                 return exynos4_get_arm_clk();
1096         }
1097 }
1098
1099 unsigned long get_i2c_clk(void)
1100 {
1101         if (cpu_is_exynos5()) {
1102                 return exynos5_get_i2c_clk();
1103         } else if (cpu_is_exynos4()) {
1104                 return exynos4_get_i2c_clk();
1105         } else {
1106                 debug("I2C clock is not set for this CPU\n");
1107                 return 0;
1108         }
1109 }
1110
1111 unsigned long get_pwm_clk(void)
1112 {
1113         if (cpu_is_exynos5())
1114                 return exynos5_get_pwm_clk();
1115         else {
1116                 if (proid_is_exynos4412())
1117                         return exynos4x12_get_pwm_clk();
1118                 return exynos4_get_pwm_clk();
1119         }
1120 }
1121
1122 unsigned long get_uart_clk(int dev_index)
1123 {
1124         if (cpu_is_exynos5())
1125                 return exynos5_get_uart_clk(dev_index);
1126         else {
1127                 if (proid_is_exynos4412())
1128                         return exynos4x12_get_uart_clk(dev_index);
1129                 return exynos4_get_uart_clk(dev_index);
1130         }
1131 }
1132
1133 void set_mmc_clk(int dev_index, unsigned int div)
1134 {
1135         if (cpu_is_exynos5())
1136                 exynos5_set_mmc_clk(dev_index, div);
1137         else {
1138                 if (proid_is_exynos4412())
1139                         exynos4x12_set_mmc_clk(dev_index, div);
1140                 exynos4_set_mmc_clk(dev_index, div);
1141         }
1142 }
1143
1144 unsigned long get_lcd_clk(void)
1145 {
1146         if (cpu_is_exynos4())
1147                 return exynos4_get_lcd_clk();
1148         else
1149                 return exynos5_get_lcd_clk();
1150 }
1151
1152 void set_lcd_clk(void)
1153 {
1154         if (cpu_is_exynos4())
1155                 exynos4_set_lcd_clk();
1156         else
1157                 exynos5_set_lcd_clk();
1158 }
1159
1160 void set_mipi_clk(void)
1161 {
1162         if (cpu_is_exynos4())
1163                 exynos4_set_mipi_clk();
1164 }
1165
1166 int set_spi_clk(int periph_id, unsigned int rate)
1167 {
1168         if (cpu_is_exynos5())
1169                 return exynos5_set_spi_clk(periph_id, rate);
1170         else
1171                 return 0;
1172 }
1173
1174 int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
1175 {
1176
1177         if (cpu_is_exynos5())
1178                 return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq);
1179         else
1180                 return 0;
1181 }
1182
1183 void set_i2s_clk_source(void)
1184 {
1185         if (cpu_is_exynos5())
1186                 exynos5_set_i2s_clk_source();
1187 }
1188
1189 int set_epll_clk(unsigned long rate)
1190 {
1191         if (cpu_is_exynos5())
1192                 return exynos5_set_epll_clk(rate);
1193         else
1194                 return 0;
1195 }