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;
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))));
161 /* exynos4: return ARM clock frequency */
162 static unsigned long exynos4_get_arm_clk(void)
164 struct exynos4_clock *clk =
165 (struct exynos4_clock *)samsung_get_base_clock();
167 unsigned long armclk;
168 unsigned int core_ratio;
169 unsigned int core2_ratio;
171 div = readl(&clk->div_cpu0);
173 /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
174 core_ratio = (div >> 0) & 0x7;
175 core2_ratio = (div >> 28) & 0x7;
177 armclk = get_pll_clk(APLL) / (core_ratio + 1);
178 armclk /= (core2_ratio + 1);
183 /* exynos5: return ARM clock frequency */
184 static unsigned long exynos5_get_arm_clk(void)
186 struct exynos5_clock *clk =
187 (struct exynos5_clock *)samsung_get_base_clock();
189 unsigned long armclk;
190 unsigned int arm_ratio;
191 unsigned int arm2_ratio;
193 div = readl(&clk->div_cpu0);
195 /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
196 arm_ratio = (div >> 0) & 0x7;
197 arm2_ratio = (div >> 28) & 0x7;
199 armclk = get_pll_clk(APLL) / (arm_ratio + 1);
200 armclk /= (arm2_ratio + 1);
205 /* exynos4: return pwm clock frequency */
206 static unsigned long exynos4_get_pwm_clk(void)
208 struct exynos4_clock *clk =
209 (struct exynos4_clock *)samsung_get_base_clock();
210 unsigned long pclk, sclk;
214 if (s5p_get_cpu_rev() == 0) {
219 sel = readl(&clk->src_peril0);
220 sel = (sel >> 24) & 0xf;
223 sclk = get_pll_clk(MPLL);
225 sclk = get_pll_clk(EPLL);
227 sclk = get_pll_clk(VPLL);
235 ratio = readl(&clk->div_peril3);
237 } else if (s5p_get_cpu_rev() == 1) {
238 sclk = get_pll_clk(MPLL);
243 pclk = sclk / (ratio + 1);
248 /* exynos5: return pwm clock frequency */
249 static unsigned long exynos5_get_pwm_clk(void)
251 struct exynos5_clock *clk =
252 (struct exynos5_clock *)samsung_get_base_clock();
253 unsigned long pclk, sclk;
260 ratio = readl(&clk->div_peric3);
262 sclk = get_pll_clk(MPLL);
264 pclk = sclk / (ratio + 1);
269 /* exynos4: return uart clock frequency */
270 static unsigned long exynos4_get_uart_clk(int dev_index)
272 struct exynos4_clock *clk =
273 (struct exynos4_clock *)samsung_get_base_clock();
274 unsigned long uclk, sclk;
287 sel = readl(&clk->src_peril0);
288 sel = (sel >> (dev_index << 2)) & 0xf;
291 sclk = get_pll_clk(MPLL);
293 sclk = get_pll_clk(EPLL);
295 sclk = get_pll_clk(VPLL);
304 * UART3_RATIO [12:15]
305 * UART4_RATIO [16:19]
306 * UART5_RATIO [23:20]
308 ratio = readl(&clk->div_peril0);
309 ratio = (ratio >> (dev_index << 2)) & 0xf;
311 uclk = sclk / (ratio + 1);
316 /* exynos5: return uart clock frequency */
317 static unsigned long exynos5_get_uart_clk(int dev_index)
319 struct exynos5_clock *clk =
320 (struct exynos5_clock *)samsung_get_base_clock();
321 unsigned long uclk, sclk;
334 sel = readl(&clk->src_peric0);
335 sel = (sel >> (dev_index << 2)) & 0xf;
338 sclk = get_pll_clk(MPLL);
340 sclk = get_pll_clk(EPLL);
342 sclk = get_pll_clk(VPLL);
351 * UART3_RATIO [12:15]
352 * UART4_RATIO [16:19]
353 * UART5_RATIO [23:20]
355 ratio = readl(&clk->div_peric0);
356 ratio = (ratio >> (dev_index << 2)) & 0xf;
358 uclk = sclk / (ratio + 1);
363 /* exynos4: set the mmc clock */
364 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
366 struct exynos4_clock *clk =
367 (struct exynos4_clock *)samsung_get_base_clock();
373 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
375 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
378 addr = (unsigned int)&clk->div_fsys1;
380 addr = (unsigned int)&clk->div_fsys2;
385 val &= ~(0xff << ((dev_index << 4) + 8));
386 val |= (div & 0xff) << ((dev_index << 4) + 8);
390 /* exynos5: set the mmc clock */
391 static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
393 struct exynos5_clock *clk =
394 (struct exynos5_clock *)samsung_get_base_clock();
400 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
402 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
405 addr = (unsigned int)&clk->div_fsys1;
407 addr = (unsigned int)&clk->div_fsys2;
412 val &= ~(0xff << ((dev_index << 4) + 8));
413 val |= (div & 0xff) << ((dev_index << 4) + 8);
417 unsigned long get_pll_clk(int pllreg)
419 if (cpu_is_exynos5())
420 return exynos5_get_pll_clk(pllreg);
422 return exynos4_get_pll_clk(pllreg);
425 unsigned long get_arm_clk(void)
427 if (cpu_is_exynos5())
428 return exynos5_get_arm_clk();
430 return exynos4_get_arm_clk();
433 unsigned long get_pwm_clk(void)
435 if (cpu_is_exynos5())
436 return exynos5_get_pwm_clk();
438 return exynos4_get_pwm_clk();
441 unsigned long get_uart_clk(int dev_index)
443 if (cpu_is_exynos5())
444 return exynos5_get_uart_clk(dev_index);
446 return exynos4_get_uart_clk(dev_index);
449 void set_mmc_clk(int dev_index, unsigned int div)
451 if (cpu_is_exynos5())
452 exynos5_set_mmc_clk(dev_index, div);
454 exynos4_set_mmc_clk(dev_index, div);