blob: 0c199cdab3d7771ac20f7b3467fc286dde4fb489 [file] [log] [blame]
Minkyu Kang008a3512011-01-24 15:22:23 +09001/*
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
29#ifndef CONFIG_SYS_CLK_FREQ_C210
30#define CONFIG_SYS_CLK_FREQ_C210 24000000
31#endif
32
Chander Kashyap393cb362011-12-06 23:34:12 +000033/* exynos4: return pll clock frequency */
34static unsigned long exynos4_get_pll_clk(int pllreg)
Minkyu Kang008a3512011-01-24 15:22:23 +090035{
Chander Kashyap393cb362011-12-06 23:34:12 +000036 struct exynos4_clock *clk =
37 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kang008a3512011-01-24 15:22:23 +090038 unsigned long r, m, p, s, k = 0, mask, fout;
39 unsigned int freq;
40
41 switch (pllreg) {
42 case APLL:
43 r = readl(&clk->apll_con0);
44 break;
45 case MPLL:
46 r = readl(&clk->mpll_con0);
47 break;
48 case EPLL:
49 r = readl(&clk->epll_con0);
50 k = readl(&clk->epll_con1);
51 break;
52 case VPLL:
53 r = readl(&clk->vpll_con0);
54 k = readl(&clk->vpll_con1);
55 break;
56 default:
57 printf("Unsupported PLL (%d)\n", pllreg);
58 return 0;
59 }
60
61 /*
62 * APLL_CON: MIDV [25:16]
63 * MPLL_CON: MIDV [25:16]
64 * EPLL_CON: MIDV [24:16]
65 * VPLL_CON: MIDV [24:16]
66 */
67 if (pllreg == APLL || pllreg == MPLL)
68 mask = 0x3ff;
69 else
70 mask = 0x1ff;
71
72 m = (r >> 16) & mask;
73
74 /* PDIV [13:8] */
75 p = (r >> 8) & 0x3f;
76 /* SDIV [2:0] */
77 s = r & 0x7;
78
79 freq = CONFIG_SYS_CLK_FREQ_C210;
80
81 if (pllreg == EPLL) {
82 k = k & 0xffff;
83 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
84 fout = (m + k / 65536) * (freq / (p * (1 << s)));
85 } else if (pllreg == VPLL) {
86 k = k & 0xfff;
87 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
88 fout = (m + k / 1024) * (freq / (p * (1 << s)));
89 } else {
90 if (s < 1)
91 s = 1;
92 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
93 fout = m * (freq / (p * (1 << (s - 1))));
94 }
95
96 return fout;
97}
98
Chander Kashyap393cb362011-12-06 23:34:12 +000099/* exynos4: return ARM clock frequency */
100static unsigned long exynos4_get_arm_clk(void)
Minkyu Kang008a3512011-01-24 15:22:23 +0900101{
Chander Kashyap393cb362011-12-06 23:34:12 +0000102 struct exynos4_clock *clk =
103 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kang008a3512011-01-24 15:22:23 +0900104 unsigned long div;
Chander Kashyapdb68bc22011-12-18 22:56:44 +0000105 unsigned long armclk;
106 unsigned int core_ratio;
107 unsigned int core2_ratio;
Minkyu Kang008a3512011-01-24 15:22:23 +0900108
109 div = readl(&clk->div_cpu0);
110
Chander Kashyapdb68bc22011-12-18 22:56:44 +0000111 /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
112 core_ratio = (div >> 0) & 0x7;
113 core2_ratio = (div >> 28) & 0x7;
Minkyu Kang008a3512011-01-24 15:22:23 +0900114
Chander Kashyapdb68bc22011-12-18 22:56:44 +0000115 armclk = get_pll_clk(APLL) / (core_ratio + 1);
116 armclk /= (core2_ratio + 1);
Minkyu Kang008a3512011-01-24 15:22:23 +0900117
Chander Kashyapdb68bc22011-12-18 22:56:44 +0000118 return armclk;
Minkyu Kang008a3512011-01-24 15:22:23 +0900119}
120
Chander Kashyap393cb362011-12-06 23:34:12 +0000121/* exynos4: return pwm clock frequency */
122static unsigned long exynos4_get_pwm_clk(void)
Minkyu Kang008a3512011-01-24 15:22:23 +0900123{
Chander Kashyap393cb362011-12-06 23:34:12 +0000124 struct exynos4_clock *clk =
125 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kang008a3512011-01-24 15:22:23 +0900126 unsigned long pclk, sclk;
127 unsigned int sel;
128 unsigned int ratio;
129
Minkyu Kangb4f73912011-05-18 16:57:55 +0900130 if (s5p_get_cpu_rev() == 0) {
131 /*
132 * CLK_SRC_PERIL0
133 * PWM_SEL [27:24]
134 */
135 sel = readl(&clk->src_peril0);
136 sel = (sel >> 24) & 0xf;
Minkyu Kang008a3512011-01-24 15:22:23 +0900137
Minkyu Kangb4f73912011-05-18 16:57:55 +0900138 if (sel == 0x6)
139 sclk = get_pll_clk(MPLL);
140 else if (sel == 0x7)
141 sclk = get_pll_clk(EPLL);
142 else if (sel == 0x8)
143 sclk = get_pll_clk(VPLL);
144 else
145 return 0;
146
147 /*
148 * CLK_DIV_PERIL3
149 * PWM_RATIO [3:0]
150 */
151 ratio = readl(&clk->div_peril3);
152 ratio = ratio & 0xf;
153 } else if (s5p_get_cpu_rev() == 1) {
Minkyu Kang008a3512011-01-24 15:22:23 +0900154 sclk = get_pll_clk(MPLL);
Minkyu Kangb4f73912011-05-18 16:57:55 +0900155 ratio = 8;
156 } else
Minkyu Kang008a3512011-01-24 15:22:23 +0900157 return 0;
158
Minkyu Kang008a3512011-01-24 15:22:23 +0900159 pclk = sclk / (ratio + 1);
160
161 return pclk;
162}
163
Chander Kashyap393cb362011-12-06 23:34:12 +0000164/* exynos4: return uart clock frequency */
165static unsigned long exynos4_get_uart_clk(int dev_index)
Minkyu Kang008a3512011-01-24 15:22:23 +0900166{
Chander Kashyap393cb362011-12-06 23:34:12 +0000167 struct exynos4_clock *clk =
168 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kang008a3512011-01-24 15:22:23 +0900169 unsigned long uclk, sclk;
170 unsigned int sel;
171 unsigned int ratio;
172
173 /*
174 * CLK_SRC_PERIL0
175 * UART0_SEL [3:0]
176 * UART1_SEL [7:4]
177 * UART2_SEL [8:11]
178 * UART3_SEL [12:15]
179 * UART4_SEL [16:19]
180 * UART5_SEL [23:20]
181 */
182 sel = readl(&clk->src_peril0);
183 sel = (sel >> (dev_index << 2)) & 0xf;
184
185 if (sel == 0x6)
186 sclk = get_pll_clk(MPLL);
187 else if (sel == 0x7)
188 sclk = get_pll_clk(EPLL);
189 else if (sel == 0x8)
190 sclk = get_pll_clk(VPLL);
191 else
192 return 0;
193
194 /*
195 * CLK_DIV_PERIL0
196 * UART0_RATIO [3:0]
197 * UART1_RATIO [7:4]
198 * UART2_RATIO [8:11]
199 * UART3_RATIO [12:15]
200 * UART4_RATIO [16:19]
201 * UART5_RATIO [23:20]
202 */
203 ratio = readl(&clk->div_peril0);
204 ratio = (ratio >> (dev_index << 2)) & 0xf;
205
206 uclk = sclk / (ratio + 1);
207
208 return uclk;
209}
210
Chander Kashyap393cb362011-12-06 23:34:12 +0000211/* exynos4: set the mmc clock */
212static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
Jaehoon Chung68a8cbf2011-05-17 21:19:17 +0000213{
Chander Kashyap393cb362011-12-06 23:34:12 +0000214 struct exynos4_clock *clk =
215 (struct exynos4_clock *)samsung_get_base_clock();
Jaehoon Chung68a8cbf2011-05-17 21:19:17 +0000216 unsigned int addr;
217 unsigned int val;
218
219 /*
220 * CLK_DIV_FSYS1
221 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
222 * CLK_DIV_FSYS2
223 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
224 */
225 if (dev_index < 2) {
226 addr = (unsigned int)&clk->div_fsys1;
227 } else {
228 addr = (unsigned int)&clk->div_fsys2;
229 dev_index -= 2;
230 }
231
232 val = readl(addr);
233 val &= ~(0xff << ((dev_index << 4) + 8));
234 val |= (div & 0xff) << ((dev_index << 4) + 8);
235 writel(val, addr);
236}
237
Minkyu Kang008a3512011-01-24 15:22:23 +0900238unsigned long get_pll_clk(int pllreg)
239{
Chander Kashyap393cb362011-12-06 23:34:12 +0000240 return exynos4_get_pll_clk(pllreg);
Minkyu Kang008a3512011-01-24 15:22:23 +0900241}
242
243unsigned long get_arm_clk(void)
244{
Chander Kashyap393cb362011-12-06 23:34:12 +0000245 return exynos4_get_arm_clk();
Minkyu Kang008a3512011-01-24 15:22:23 +0900246}
247
248unsigned long get_pwm_clk(void)
249{
Chander Kashyap393cb362011-12-06 23:34:12 +0000250 return exynos4_get_pwm_clk();
Minkyu Kang008a3512011-01-24 15:22:23 +0900251}
252
253unsigned long get_uart_clk(int dev_index)
254{
Chander Kashyap393cb362011-12-06 23:34:12 +0000255 return exynos4_get_uart_clk(dev_index);
Minkyu Kang008a3512011-01-24 15:22:23 +0900256}
Jaehoon Chung68a8cbf2011-05-17 21:19:17 +0000257
258void set_mmc_clk(int dev_index, unsigned int div)
259{
Chander Kashyap393cb362011-12-06 23:34:12 +0000260 exynos4_set_mmc_clk(dev_index, div);
Jaehoon Chung68a8cbf2011-05-17 21:19:17 +0000261}