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