2 * Copyright (C) 2010 Samsung Electronics
3 * Minkyu Kang <mk7.kang@samsung.com>
5 * See file CREDITS for list of people who contributed to this
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.
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.
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,
26 #include <asm/arch/clock.h>
27 #include <asm/arch/clk.h>
29 /* exynos4: return pll clock frequency */
30 static unsigned long exynos4_get_pll_clk(int pllreg)
32 struct exynos4_clock *clk =
33 (struct exynos4_clock *)samsung_get_base_clock();
34 unsigned long r, m, p, s, k = 0, mask, fout;
39 r = readl(&clk->apll_con0);
42 r = readl(&clk->mpll_con0);
45 r = readl(&clk->epll_con0);
46 k = readl(&clk->epll_con1);
49 r = readl(&clk->vpll_con0);
50 k = readl(&clk->vpll_con1);
53 printf("Unsupported PLL (%d)\n", pllreg);
58 * APLL_CON: MIDV [25:16]
59 * MPLL_CON: MIDV [25:16]
60 * EPLL_CON: MIDV [24:16]
61 * VPLL_CON: MIDV [24:16]
63 if (pllreg == APLL || pllreg == MPLL)
75 freq = CONFIG_SYS_CLK_FREQ;
79 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
80 fout = (m + k / 65536) * (freq / (p * (1 << s)));
81 } else if (pllreg == VPLL) {
83 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
84 fout = (m + k / 1024) * (freq / (p * (1 << s)));
88 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
89 fout = m * (freq / (p * (1 << (s - 1))));
95 /* exynos5: return pll clock frequency */
96 static unsigned long exynos5_get_pll_clk(int pllreg)
98 struct exynos5_clock *clk =
99 (struct exynos5_clock *)samsung_get_base_clock();
100 unsigned long r, m, p, s, k = 0, mask, fout;
101 unsigned int freq, pll_div2_sel, fout_sel;
105 r = readl(&clk->apll_con0);
108 r = readl(&clk->mpll_con0);
111 r = readl(&clk->epll_con0);
112 k = readl(&clk->epll_con1);
115 r = readl(&clk->vpll_con0);
116 k = readl(&clk->vpll_con1);
119 r = readl(&clk->bpll_con0);
122 printf("Unsupported PLL (%d)\n", pllreg);
127 * APLL_CON: MIDV [25:16]
128 * MPLL_CON: MIDV [25:16]
129 * EPLL_CON: MIDV [24:16]
130 * VPLL_CON: MIDV [24:16]
131 * BPLL_CON: MIDV [25:16]
133 if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL)
138 m = (r >> 16) & mask;
145 freq = CONFIG_SYS_CLK_FREQ;
147 if (pllreg == EPLL) {
149 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
150 fout = (m + k / 65536) * (freq / (p * (1 << s)));
151 } else if (pllreg == VPLL) {
153 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
154 fout = (m + k / 1024) * (freq / (p * (1 << s)));
158 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
159 fout = m * (freq / (p * (1 << (s - 1))));
162 /* According to the user manual, in EVT1 MPLL and BPLL always gives
163 * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/
164 if (pllreg == MPLL || pllreg == BPLL) {
165 pll_div2_sel = readl(&clk->pll_div2_sel);
169 fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
170 & MPLL_FOUT_SEL_MASK;
173 fout_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT)
174 & BPLL_FOUT_SEL_MASK;
185 /* exynos4: return ARM clock frequency */
186 static unsigned long exynos4_get_arm_clk(void)
188 struct exynos4_clock *clk =
189 (struct exynos4_clock *)samsung_get_base_clock();
191 unsigned long armclk;
192 unsigned int core_ratio;
193 unsigned int core2_ratio;
195 div = readl(&clk->div_cpu0);
197 /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
198 core_ratio = (div >> 0) & 0x7;
199 core2_ratio = (div >> 28) & 0x7;
201 armclk = get_pll_clk(APLL) / (core_ratio + 1);
202 armclk /= (core2_ratio + 1);
207 /* exynos5: return ARM clock frequency */
208 static unsigned long exynos5_get_arm_clk(void)
210 struct exynos5_clock *clk =
211 (struct exynos5_clock *)samsung_get_base_clock();
213 unsigned long armclk;
214 unsigned int arm_ratio;
215 unsigned int arm2_ratio;
217 div = readl(&clk->div_cpu0);
219 /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
220 arm_ratio = (div >> 0) & 0x7;
221 arm2_ratio = (div >> 28) & 0x7;
223 armclk = get_pll_clk(APLL) / (arm_ratio + 1);
224 armclk /= (arm2_ratio + 1);
229 /* exynos4: return pwm clock frequency */
230 static unsigned long exynos4_get_pwm_clk(void)
232 struct exynos4_clock *clk =
233 (struct exynos4_clock *)samsung_get_base_clock();
234 unsigned long pclk, sclk;
238 if (s5p_get_cpu_rev() == 0) {
243 sel = readl(&clk->src_peril0);
244 sel = (sel >> 24) & 0xf;
247 sclk = get_pll_clk(MPLL);
249 sclk = get_pll_clk(EPLL);
251 sclk = get_pll_clk(VPLL);
259 ratio = readl(&clk->div_peril3);
261 } else if (s5p_get_cpu_rev() == 1) {
262 sclk = get_pll_clk(MPLL);
267 pclk = sclk / (ratio + 1);
272 /* exynos5: return pwm clock frequency */
273 static unsigned long exynos5_get_pwm_clk(void)
275 struct exynos5_clock *clk =
276 (struct exynos5_clock *)samsung_get_base_clock();
277 unsigned long pclk, sclk;
284 ratio = readl(&clk->div_peric3);
286 sclk = get_pll_clk(MPLL);
288 pclk = sclk / (ratio + 1);
293 /* exynos4: return uart clock frequency */
294 static unsigned long exynos4_get_uart_clk(int dev_index)
296 struct exynos4_clock *clk =
297 (struct exynos4_clock *)samsung_get_base_clock();
298 unsigned long uclk, sclk;
311 sel = readl(&clk->src_peril0);
312 sel = (sel >> (dev_index << 2)) & 0xf;
315 sclk = get_pll_clk(MPLL);
317 sclk = get_pll_clk(EPLL);
319 sclk = get_pll_clk(VPLL);
328 * UART3_RATIO [12:15]
329 * UART4_RATIO [16:19]
330 * UART5_RATIO [23:20]
332 ratio = readl(&clk->div_peril0);
333 ratio = (ratio >> (dev_index << 2)) & 0xf;
335 uclk = sclk / (ratio + 1);
340 /* exynos5: return uart clock frequency */
341 static unsigned long exynos5_get_uart_clk(int dev_index)
343 struct exynos5_clock *clk =
344 (struct exynos5_clock *)samsung_get_base_clock();
345 unsigned long uclk, sclk;
358 sel = readl(&clk->src_peric0);
359 sel = (sel >> (dev_index << 2)) & 0xf;
362 sclk = get_pll_clk(MPLL);
364 sclk = get_pll_clk(EPLL);
366 sclk = get_pll_clk(VPLL);
375 * UART3_RATIO [12:15]
376 * UART4_RATIO [16:19]
377 * UART5_RATIO [23:20]
379 ratio = readl(&clk->div_peric0);
380 ratio = (ratio >> (dev_index << 2)) & 0xf;
382 uclk = sclk / (ratio + 1);
387 /* exynos4: set the mmc clock */
388 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
390 struct exynos4_clock *clk =
391 (struct exynos4_clock *)samsung_get_base_clock();
397 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
399 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
402 addr = (unsigned int)&clk->div_fsys1;
404 addr = (unsigned int)&clk->div_fsys2;
409 val &= ~(0xff << ((dev_index << 4) + 8));
410 val |= (div & 0xff) << ((dev_index << 4) + 8);
414 /* exynos5: set the mmc clock */
415 static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
417 struct exynos5_clock *clk =
418 (struct exynos5_clock *)samsung_get_base_clock();
424 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
426 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
429 addr = (unsigned int)&clk->div_fsys1;
431 addr = (unsigned int)&clk->div_fsys2;
436 val &= ~(0xff << ((dev_index << 4) + 8));
437 val |= (div & 0xff) << ((dev_index << 4) + 8);
441 /* get_lcd_clk: return lcd clock frequency */
442 static unsigned long exynos4_get_lcd_clk(void)
444 struct exynos4_clock *clk =
445 (struct exynos4_clock *)samsung_get_base_clock();
446 unsigned long pclk, sclk;
454 sel = readl(&clk->src_lcd0);
463 sclk = get_pll_clk(MPLL);
465 sclk = get_pll_clk(EPLL);
467 sclk = get_pll_clk(VPLL);
475 ratio = readl(&clk->div_lcd0);
478 pclk = sclk / (ratio + 1);
483 void exynos4_set_lcd_clk(void)
485 struct exynos4_clock *clk =
486 (struct exynos4_clock *)samsung_get_base_clock();
487 unsigned int cfg = 0;
499 cfg = readl(&clk->gate_block);
501 writel(cfg, &clk->gate_block);
507 * MDNIE_PWM0_SEL [8:11]
509 * set lcd0 src clock 0x6: SCLK_MPLL
511 cfg = readl(&clk->src_lcd0);
514 writel(cfg, &clk->src_lcd0);
524 * Gating all clocks for FIMD0
526 cfg = readl(&clk->gate_ip_lcd0);
528 writel(cfg, &clk->gate_ip_lcd0);
534 * MDNIE_PWM0_RATIO [11:8]
535 * MDNIE_PWM_PRE_RATIO [15:12]
536 * MIPI0_RATIO [19:16]
537 * MIPI0_PRE_RATIO [23:20]
542 writel(cfg, &clk->div_lcd0);
545 void exynos4_set_mipi_clk(void)
547 struct exynos4_clock *clk =
548 (struct exynos4_clock *)samsung_get_base_clock();
549 unsigned int cfg = 0;
555 * MDNIE_PWM0_SEL [8:11]
557 * set mipi0 src clock 0x6: SCLK_MPLL
559 cfg = readl(&clk->src_lcd0);
562 writel(cfg, &clk->src_lcd0);
568 * MDNIE_PWM0_MASK [8]
570 * set src mask mipi0 0x1: Unmask
572 cfg = readl(&clk->src_mask_lcd0);
574 writel(cfg, &clk->src_mask_lcd0);
584 * Gating all clocks for MIPI0
586 cfg = readl(&clk->gate_ip_lcd0);
588 writel(cfg, &clk->gate_ip_lcd0);
594 * MDNIE_PWM0_RATIO [11:8]
595 * MDNIE_PWM_PRE_RATIO [15:12]
596 * MIPI0_RATIO [19:16]
597 * MIPI0_PRE_RATIO [23:20]
602 writel(cfg, &clk->div_lcd0);
608 * exynos5: obtaining the I2C clock
610 static unsigned long exynos5_get_i2c_clk(void)
612 struct exynos5_clock *clk =
613 (struct exynos5_clock *)samsung_get_base_clock();
614 unsigned long aclk_66, aclk_66_pre, sclk;
617 sclk = get_pll_clk(MPLL);
619 ratio = (readl(&clk->div_top1)) >> 24;
621 aclk_66_pre = sclk / (ratio + 1);
622 ratio = readl(&clk->div_top0);
624 aclk_66 = aclk_66_pre / (ratio + 1);
628 unsigned long get_pll_clk(int pllreg)
630 if (cpu_is_exynos5())
631 return exynos5_get_pll_clk(pllreg);
633 return exynos4_get_pll_clk(pllreg);
636 unsigned long get_arm_clk(void)
638 if (cpu_is_exynos5())
639 return exynos5_get_arm_clk();
641 return exynos4_get_arm_clk();
644 unsigned long get_i2c_clk(void)
646 if (cpu_is_exynos5()) {
647 return exynos5_get_i2c_clk();
649 debug("I2C clock is not set for this CPU\n");
654 unsigned long get_pwm_clk(void)
656 if (cpu_is_exynos5())
657 return exynos5_get_pwm_clk();
659 return exynos4_get_pwm_clk();
662 unsigned long get_uart_clk(int dev_index)
664 if (cpu_is_exynos5())
665 return exynos5_get_uart_clk(dev_index);
667 return exynos4_get_uart_clk(dev_index);
670 void set_mmc_clk(int dev_index, unsigned int div)
672 if (cpu_is_exynos5())
673 exynos5_set_mmc_clk(dev_index, div);
675 exynos4_set_mmc_clk(dev_index, div);
678 unsigned long get_lcd_clk(void)
680 if (cpu_is_exynos4())
681 return exynos4_get_lcd_clk();
686 void set_lcd_clk(void)
688 if (cpu_is_exynos4())
689 exynos4_set_lcd_clk();
692 void set_mipi_clk(void)
694 if (cpu_is_exynos4())
695 exynos4_set_mipi_clk();