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, mpll_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 printf("Unsupported PLL (%d)\n", pllreg);
124 * APLL_CON: MIDV [25:16]
125 * MPLL_CON: MIDV [25:16]
126 * EPLL_CON: MIDV [24:16]
127 * VPLL_CON: MIDV [24:16]
129 if (pllreg == APLL || pllreg == MPLL)
134 m = (r >> 16) & mask;
141 freq = CONFIG_SYS_CLK_FREQ;
143 if (pllreg == EPLL) {
145 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
146 fout = (m + k / 65536) * (freq / (p * (1 << s)));
147 } else if (pllreg == VPLL) {
149 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
150 fout = (m + k / 1024) * (freq / (p * (1 << s)));
154 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
155 fout = m * (freq / (p * (1 << (s - 1))));
158 /* According to the user manual, in EVT1 MPLL always gives
159 * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/
160 if (pllreg == MPLL) {
161 pll_div2_sel = readl(&clk->pll_div2_sel);
162 mpll_fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
163 & MPLL_FOUT_SEL_MASK;
164 if (mpll_fout_sel == 0)
171 /* exynos4: return ARM clock frequency */
172 static unsigned long exynos4_get_arm_clk(void)
174 struct exynos4_clock *clk =
175 (struct exynos4_clock *)samsung_get_base_clock();
177 unsigned long armclk;
178 unsigned int core_ratio;
179 unsigned int core2_ratio;
181 div = readl(&clk->div_cpu0);
183 /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
184 core_ratio = (div >> 0) & 0x7;
185 core2_ratio = (div >> 28) & 0x7;
187 armclk = get_pll_clk(APLL) / (core_ratio + 1);
188 armclk /= (core2_ratio + 1);
193 /* exynos5: return ARM clock frequency */
194 static unsigned long exynos5_get_arm_clk(void)
196 struct exynos5_clock *clk =
197 (struct exynos5_clock *)samsung_get_base_clock();
199 unsigned long armclk;
200 unsigned int arm_ratio;
201 unsigned int arm2_ratio;
203 div = readl(&clk->div_cpu0);
205 /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
206 arm_ratio = (div >> 0) & 0x7;
207 arm2_ratio = (div >> 28) & 0x7;
209 armclk = get_pll_clk(APLL) / (arm_ratio + 1);
210 armclk /= (arm2_ratio + 1);
215 /* exynos4: return pwm clock frequency */
216 static unsigned long exynos4_get_pwm_clk(void)
218 struct exynos4_clock *clk =
219 (struct exynos4_clock *)samsung_get_base_clock();
220 unsigned long pclk, sclk;
224 if (s5p_get_cpu_rev() == 0) {
229 sel = readl(&clk->src_peril0);
230 sel = (sel >> 24) & 0xf;
233 sclk = get_pll_clk(MPLL);
235 sclk = get_pll_clk(EPLL);
237 sclk = get_pll_clk(VPLL);
245 ratio = readl(&clk->div_peril3);
247 } else if (s5p_get_cpu_rev() == 1) {
248 sclk = get_pll_clk(MPLL);
253 pclk = sclk / (ratio + 1);
258 /* exynos5: return pwm clock frequency */
259 static unsigned long exynos5_get_pwm_clk(void)
261 struct exynos5_clock *clk =
262 (struct exynos5_clock *)samsung_get_base_clock();
263 unsigned long pclk, sclk;
270 ratio = readl(&clk->div_peric3);
272 sclk = get_pll_clk(MPLL);
274 pclk = sclk / (ratio + 1);
279 /* exynos4: return uart clock frequency */
280 static unsigned long exynos4_get_uart_clk(int dev_index)
282 struct exynos4_clock *clk =
283 (struct exynos4_clock *)samsung_get_base_clock();
284 unsigned long uclk, sclk;
297 sel = readl(&clk->src_peril0);
298 sel = (sel >> (dev_index << 2)) & 0xf;
301 sclk = get_pll_clk(MPLL);
303 sclk = get_pll_clk(EPLL);
305 sclk = get_pll_clk(VPLL);
314 * UART3_RATIO [12:15]
315 * UART4_RATIO [16:19]
316 * UART5_RATIO [23:20]
318 ratio = readl(&clk->div_peril0);
319 ratio = (ratio >> (dev_index << 2)) & 0xf;
321 uclk = sclk / (ratio + 1);
326 /* exynos5: return uart clock frequency */
327 static unsigned long exynos5_get_uart_clk(int dev_index)
329 struct exynos5_clock *clk =
330 (struct exynos5_clock *)samsung_get_base_clock();
331 unsigned long uclk, sclk;
344 sel = readl(&clk->src_peric0);
345 sel = (sel >> (dev_index << 2)) & 0xf;
348 sclk = get_pll_clk(MPLL);
350 sclk = get_pll_clk(EPLL);
352 sclk = get_pll_clk(VPLL);
361 * UART3_RATIO [12:15]
362 * UART4_RATIO [16:19]
363 * UART5_RATIO [23:20]
365 ratio = readl(&clk->div_peric0);
366 ratio = (ratio >> (dev_index << 2)) & 0xf;
368 uclk = sclk / (ratio + 1);
373 /* exynos4: set the mmc clock */
374 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
376 struct exynos4_clock *clk =
377 (struct exynos4_clock *)samsung_get_base_clock();
383 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
385 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
388 addr = (unsigned int)&clk->div_fsys1;
390 addr = (unsigned int)&clk->div_fsys2;
395 val &= ~(0xff << ((dev_index << 4) + 8));
396 val |= (div & 0xff) << ((dev_index << 4) + 8);
400 /* exynos5: set the mmc clock */
401 static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
403 struct exynos5_clock *clk =
404 (struct exynos5_clock *)samsung_get_base_clock();
410 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
412 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
415 addr = (unsigned int)&clk->div_fsys1;
417 addr = (unsigned int)&clk->div_fsys2;
422 val &= ~(0xff << ((dev_index << 4) + 8));
423 val |= (div & 0xff) << ((dev_index << 4) + 8);
427 /* get_lcd_clk: return lcd clock frequency */
428 static unsigned long exynos4_get_lcd_clk(void)
430 struct exynos4_clock *clk =
431 (struct exynos4_clock *)samsung_get_base_clock();
432 unsigned long pclk, sclk;
440 sel = readl(&clk->src_lcd0);
449 sclk = get_pll_clk(MPLL);
451 sclk = get_pll_clk(EPLL);
453 sclk = get_pll_clk(VPLL);
461 ratio = readl(&clk->div_lcd0);
464 pclk = sclk / (ratio + 1);
469 void exynos4_set_lcd_clk(void)
471 struct exynos4_clock *clk =
472 (struct exynos4_clock *)samsung_get_base_clock();
473 unsigned int cfg = 0;
485 cfg = readl(&clk->gate_block);
487 writel(cfg, &clk->gate_block);
493 * MDNIE_PWM0_SEL [8:11]
495 * set lcd0 src clock 0x6: SCLK_MPLL
497 cfg = readl(&clk->src_lcd0);
500 writel(cfg, &clk->src_lcd0);
510 * Gating all clocks for FIMD0
512 cfg = readl(&clk->gate_ip_lcd0);
514 writel(cfg, &clk->gate_ip_lcd0);
520 * MDNIE_PWM0_RATIO [11:8]
521 * MDNIE_PWM_PRE_RATIO [15:12]
522 * MIPI0_RATIO [19:16]
523 * MIPI0_PRE_RATIO [23:20]
528 writel(cfg, &clk->div_lcd0);
531 void exynos4_set_mipi_clk(void)
533 struct exynos4_clock *clk =
534 (struct exynos4_clock *)samsung_get_base_clock();
535 unsigned int cfg = 0;
541 * MDNIE_PWM0_SEL [8:11]
543 * set mipi0 src clock 0x6: SCLK_MPLL
545 cfg = readl(&clk->src_lcd0);
548 writel(cfg, &clk->src_lcd0);
554 * MDNIE_PWM0_MASK [8]
556 * set src mask mipi0 0x1: Unmask
558 cfg = readl(&clk->src_mask_lcd0);
560 writel(cfg, &clk->src_mask_lcd0);
570 * Gating all clocks for MIPI0
572 cfg = readl(&clk->gate_ip_lcd0);
574 writel(cfg, &clk->gate_ip_lcd0);
580 * MDNIE_PWM0_RATIO [11:8]
581 * MDNIE_PWM_PRE_RATIO [15:12]
582 * MIPI0_RATIO [19:16]
583 * MIPI0_PRE_RATIO [23:20]
588 writel(cfg, &clk->div_lcd0);
594 * exynos5: obtaining the I2C clock
596 static unsigned long exynos5_get_i2c_clk(void)
598 struct exynos5_clock *clk =
599 (struct exynos5_clock *)samsung_get_base_clock();
600 unsigned long aclk_66, aclk_66_pre, sclk;
603 sclk = get_pll_clk(MPLL);
605 ratio = (readl(&clk->div_top1)) >> 24;
607 aclk_66_pre = sclk / (ratio + 1);
608 ratio = readl(&clk->div_top0);
610 aclk_66 = aclk_66_pre / (ratio + 1);
614 unsigned long get_pll_clk(int pllreg)
616 if (cpu_is_exynos5())
617 return exynos5_get_pll_clk(pllreg);
619 return exynos4_get_pll_clk(pllreg);
622 unsigned long get_arm_clk(void)
624 if (cpu_is_exynos5())
625 return exynos5_get_arm_clk();
627 return exynos4_get_arm_clk();
630 unsigned long get_i2c_clk(void)
632 if (cpu_is_exynos5()) {
633 return exynos5_get_i2c_clk();
635 debug("I2C clock is not set for this CPU\n");
640 unsigned long get_pwm_clk(void)
642 if (cpu_is_exynos5())
643 return exynos5_get_pwm_clk();
645 return exynos4_get_pwm_clk();
648 unsigned long get_uart_clk(int dev_index)
650 if (cpu_is_exynos5())
651 return exynos5_get_uart_clk(dev_index);
653 return exynos4_get_uart_clk(dev_index);
656 void set_mmc_clk(int dev_index, unsigned int div)
658 if (cpu_is_exynos5())
659 exynos5_set_mmc_clk(dev_index, div);
661 exynos4_set_mmc_clk(dev_index, div);
664 unsigned long get_lcd_clk(void)
666 if (cpu_is_exynos4())
667 return exynos4_get_lcd_clk();
672 void set_lcd_clk(void)
674 if (cpu_is_exynos4())
675 exynos4_set_lcd_clk();
678 void set_mipi_clk(void)
680 if (cpu_is_exynos4())
681 exynos4_set_mipi_clk();