2 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
3 * Minkyu Kang <mk7.kang@samsung.com>
4 * Sanghee Kim <sh0130.kim@samsung.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of
9 * the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24 #include <asm/arch/clock.h>
25 #include <asm/arch/clk.h>
27 #ifndef CONFIG_SYS_CLK_FREQ
28 #define CONFIG_SYS_CLK_FREQ 24000000
31 /* get_pll_clk: return pll clock frequency */
32 static unsigned long exynos4_get_pll_clk(int pllreg)
34 struct exynos4_clock *clk =
35 (struct exynos4_clock *)samsung_get_base_clock();
36 unsigned long r, m, p, s, k = 0, mask, fout;
41 r = readl(&clk->apll_con0);
44 r = readl(&clk->mpll_con0);
47 r = readl(&clk->epll_con0);
48 k = readl(&clk->epll_con1);
51 r = readl(&clk->vpll_con0);
52 k = readl(&clk->vpll_con1);
55 printf("Unsupported PLL (%d)\n", pllreg);
60 * APLL_CON: MIDV [25:16]
61 * MPLL_CON: MIDV [25:16]
62 * EPLL_CON: MIDV [24:16]
63 * VPLL_CON: MIDV [24:16]
65 if (pllreg == APLL || pllreg == MPLL)
77 freq = CONFIG_SYS_CLK_FREQ;
81 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
82 fout = (m + k / 65536) * (freq / (p * (1 << s)));
83 } else if (pllreg == VPLL) {
85 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
86 fout = (m + k / 1024) * (freq / (p * (1 << s)));
90 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
91 fout = m * (freq / (p * (1 << (s - 1))));
97 /* get_arm_clk: return ARM clock frequency */
98 static unsigned long exynos4_get_arm_clk(void)
100 struct exynos4_clock *clk =
101 (struct exynos4_clock *)samsung_get_base_clock();
103 unsigned long dout_apll;
104 unsigned int apll_ratio;
106 div = readl(&clk->div_cpu0);
108 /* APLL_RATIO: [26:24] */
109 apll_ratio = (div >> 24) & 0x7;
111 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
116 /* get_pwm_clk: return pwm clock frequency */
117 static unsigned long exynos4_get_pwm_clk(void)
119 unsigned long pclk, sclk;
122 sclk = get_pll_clk(MPLL);
125 pclk = sclk / (ratio + 1);
130 /* get_uart_clk: return uart clock frequency */
131 static unsigned long exynos4_get_uart_clk(int dev_index)
133 struct exynos4_clock *clk =
134 (struct exynos4_clock *)samsung_get_base_clock();
135 unsigned long uclk, sclk;
148 sel = readl(&clk->src_peril0);
149 sel = (sel >> (dev_index << 2)) & 0xf;
152 sclk = get_pll_clk(MPLL);
154 sclk = get_pll_clk(EPLL);
156 sclk = get_pll_clk(VPLL);
165 * UART3_RATIO [12:15]
166 * UART4_RATIO [16:19]
167 * UART5_RATIO [23:20]
169 ratio = readl(&clk->div_peril0);
170 ratio = (ratio >> (dev_index << 2)) & 0xf;
172 uclk = sclk / (ratio + 1);
178 * set_lcd_clk: set parent clock and ratio for fimdx.
179 * @dev_index: index of fimd using bus0 or bus1.
180 * @div: ratio value for sclk_fimd.
182 static int exynos4_set_lcd_clk(const unsigned int dev_index,
183 const unsigned int pclk_name, const unsigned int div)
185 struct exynos4_clock *clk =
186 (struct exynos4_clock *)samsung_get_base_clock();
187 unsigned int sel, ratio;
188 unsigned int parent_sel;
189 unsigned int src_addr, div_addr;
191 #if defined(CONFIG_EXYNOS4210)
192 if (dev_index == 0) {
193 src_addr = (unsigned int)&clk->src_lcd0;
194 div_addr = (unsigned int)&clk->div_lcd0;
195 } else if (dev_index == 1) {
196 src_addr = (unsigned int)&clk->src_lcd1;
197 div_addr = (unsigned int)&clk->div_lcd1;
202 printf("%s: not supported for %d\n", __func__, dev_index);
206 src_addr = (unsigned int)&clk->src_lcd;
207 div_addr = (unsigned int)&clk->div_lcd;
214 sel = readl(src_addr);
232 sel |= (parent_sel & 0xf);
233 writel(sel, src_addr);
239 ratio = readl(div_addr);
242 writel(ratio, div_addr);
247 /* get_lcd_clk: return lcd clock frequency */
248 static unsigned long exynos4_get_lcd_clk(void)
250 struct exynos4_clock *clk =
251 (struct exynos4_clock *)samsung_get_base_clock();
252 unsigned long pclk, sclk;
260 #if defined(CONFIG_EXYNOS4210)
261 sel = readl(&clk->src_lcd0);
263 sel = readl(&clk->src_lcd);
268 sclk = get_pll_clk(MPLL);
270 sclk = get_pll_clk(EPLL);
272 sclk = get_pll_clk(VPLL);
280 #if defined(CONFIG_EXYNOS4210)
281 ratio = readl(&clk->div_lcd0);
283 ratio = readl(&clk->div_lcd);
287 pclk = sclk / (ratio + 1);
292 /* set_mmc_clk: set the mmc clock */
293 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
295 struct exynos4_clock *clk =
296 (struct exynos4_clock *)samsung_get_base_clock();
302 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
304 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
307 addr = (unsigned int)&clk->div_fsys1;
309 addr = (unsigned int)&clk->div_fsys2;
314 val &= ~(0xff << ((dev_index << 4) + 8));
315 val |= (div & 0xff) << ((dev_index << 4) + 8);
319 unsigned long get_pll_clk(int pllreg)
321 return exynos4_get_pll_clk(pllreg);
324 unsigned long get_arm_clk(void)
326 return exynos4_get_arm_clk();
329 unsigned long get_pwm_clk(void)
331 return exynos4_get_pwm_clk();
334 unsigned long get_uart_clk(int dev_index)
336 return exynos4_get_uart_clk(dev_index);
339 unsigned long get_lcd_clk(void)
341 return exynos4_get_lcd_clk();
344 unsigned long get_systimer_clk(void)
346 return (24 * 1000 * 1000); /* XusbXTI */
349 void set_mmc_clk(int dev_index, unsigned int div)
351 exynos4_set_mmc_clk(dev_index, div);
354 int set_lcd_clk(const unsigned int dev_index,
355 const unsigned int pclk_name, const unsigned int div)
357 return exynos4_set_lcd_clk(dev_index, pclk_name, div);