blob: e92647cdfc0d22efd36e2f98ce900098ba035e7f [file] [log] [blame]
Minkyu Kang399e5ae2009-10-01 17:20:01 +09001/*
2 * Copyright (C) 2009 Samsung Electronics
3 * Minkyu Kang <mk7.kang@samsung.com>
4 * Heungjun Kim <riverful.kim@samsung.com>
5 *
6 * See file CREDITS for list of people who contributed to this
7 * project.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 */
24
25#include <common.h>
26#include <asm/io.h>
27#include <asm/arch/clock.h>
Naveen Krishna CH6c71a8f2010-02-04 14:17:38 +090028#include <asm/arch/clk.h>
Minkyu Kang399e5ae2009-10-01 17:20:01 +090029
30#define CLK_M 0
31#define CLK_D 1
32#define CLK_P 2
33
34#ifndef CONFIG_SYS_CLK_FREQ_C100
35#define CONFIG_SYS_CLK_FREQ_C100 12000000
36#endif
37#ifndef CONFIG_SYS_CLK_FREQ_C110
38#define CONFIG_SYS_CLK_FREQ_C110 24000000
39#endif
40
Minkyu Kang399e5ae2009-10-01 17:20:01 +090041/* s5pc110: return pll clock frequency */
42static unsigned long s5pc100_get_pll_clk(int pllreg)
43{
Minkyu Kangd93d0f02010-08-13 16:07:35 +090044 struct s5pc100_clock *clk =
45 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang399e5ae2009-10-01 17:20:01 +090046 unsigned long r, m, p, s, mask, fout;
47 unsigned int freq;
48
49 switch (pllreg) {
50 case APLL:
51 r = readl(&clk->apll_con);
52 break;
53 case MPLL:
54 r = readl(&clk->mpll_con);
55 break;
56 case EPLL:
57 r = readl(&clk->epll_con);
58 break;
59 case HPLL:
60 r = readl(&clk->hpll_con);
61 break;
62 default:
63 printf("Unsupported PLL (%d)\n", pllreg);
64 return 0;
65 }
66
67 /*
68 * APLL_CON: MIDV [25:16]
69 * MPLL_CON: MIDV [23:16]
70 * EPLL_CON: MIDV [23:16]
71 * HPLL_CON: MIDV [23:16]
72 */
73 if (pllreg == APLL)
74 mask = 0x3ff;
75 else
76 mask = 0x0ff;
77
78 m = (r >> 16) & mask;
79
80 /* PDIV [13:8] */
81 p = (r >> 8) & 0x3f;
82 /* SDIV [2:0] */
83 s = r & 0x7;
84
85 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
86 freq = CONFIG_SYS_CLK_FREQ_C100;
87 fout = m * (freq / (p * (1 << s)));
88
89 return fout;
90}
91
92/* s5pc100: return pll clock frequency */
93static unsigned long s5pc110_get_pll_clk(int pllreg)
94{
Minkyu Kangd93d0f02010-08-13 16:07:35 +090095 struct s5pc110_clock *clk =
96 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang399e5ae2009-10-01 17:20:01 +090097 unsigned long r, m, p, s, mask, fout;
98 unsigned int freq;
99
100 switch (pllreg) {
101 case APLL:
102 r = readl(&clk->apll_con);
103 break;
104 case MPLL:
105 r = readl(&clk->mpll_con);
106 break;
107 case EPLL:
108 r = readl(&clk->epll_con);
109 break;
110 case VPLL:
111 r = readl(&clk->vpll_con);
112 break;
113 default:
114 printf("Unsupported PLL (%d)\n", pllreg);
115 return 0;
116 }
117
118 /*
119 * APLL_CON: MIDV [25:16]
120 * MPLL_CON: MIDV [25:16]
121 * EPLL_CON: MIDV [24:16]
122 * VPLL_CON: MIDV [24:16]
123 */
124 if (pllreg == APLL || pllreg == MPLL)
125 mask = 0x3ff;
126 else
127 mask = 0x1ff;
128
129 m = (r >> 16) & mask;
130
131 /* PDIV [13:8] */
132 p = (r >> 8) & 0x3f;
133 /* SDIV [2:0] */
134 s = r & 0x7;
135
136 freq = CONFIG_SYS_CLK_FREQ_C110;
137 if (pllreg == APLL) {
138 if (s < 1)
139 s = 1;
140 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
141 fout = m * (freq / (p * (1 << (s - 1))));
142 } else
143 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
144 fout = m * (freq / (p * (1 << s)));
145
146 return fout;
147}
148
149/* s5pc110: return ARM clock frequency */
150static unsigned long s5pc110_get_arm_clk(void)
151{
Minkyu Kangd93d0f02010-08-13 16:07:35 +0900152 struct s5pc110_clock *clk =
153 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang399e5ae2009-10-01 17:20:01 +0900154 unsigned long div;
155 unsigned long dout_apll, armclk;
156 unsigned int apll_ratio;
157
158 div = readl(&clk->div0);
159
160 /* APLL_RATIO: [2:0] */
161 apll_ratio = div & 0x7;
162
163 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
164 armclk = dout_apll;
165
166 return armclk;
167}
168
169/* s5pc100: return ARM clock frequency */
170static unsigned long s5pc100_get_arm_clk(void)
171{
Minkyu Kangd93d0f02010-08-13 16:07:35 +0900172 struct s5pc100_clock *clk =
173 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang399e5ae2009-10-01 17:20:01 +0900174 unsigned long div;
175 unsigned long dout_apll, armclk;
176 unsigned int apll_ratio, arm_ratio;
177
178 div = readl(&clk->div0);
179
180 /* ARM_RATIO: [6:4] */
181 arm_ratio = (div >> 4) & 0x7;
182 /* APLL_RATIO: [0] */
183 apll_ratio = div & 0x1;
184
185 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
186 armclk = dout_apll / (arm_ratio + 1);
187
188 return armclk;
189}
190
191/* s5pc100: return HCLKD0 frequency */
192static unsigned long get_hclk(void)
193{
Minkyu Kangd93d0f02010-08-13 16:07:35 +0900194 struct s5pc100_clock *clk =
195 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang399e5ae2009-10-01 17:20:01 +0900196 unsigned long hclkd0;
197 uint div, d0_bus_ratio;
198
199 div = readl(&clk->div0);
200 /* D0_BUS_RATIO: [10:8] */
201 d0_bus_ratio = (div >> 8) & 0x7;
202
203 hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
204
205 return hclkd0;
206}
207
208/* s5pc100: return PCLKD1 frequency */
209static unsigned long get_pclkd1(void)
210{
Minkyu Kangd93d0f02010-08-13 16:07:35 +0900211 struct s5pc100_clock *clk =
212 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang399e5ae2009-10-01 17:20:01 +0900213 unsigned long d1_bus, pclkd1;
214 uint div, d1_bus_ratio, pclkd1_ratio;
215
216 div = readl(&clk->div0);
217 /* D1_BUS_RATIO: [14:12] */
218 d1_bus_ratio = (div >> 12) & 0x7;
219 /* PCLKD1_RATIO: [18:16] */
220 pclkd1_ratio = (div >> 16) & 0x7;
221
222 /* ASYNC Mode */
223 d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
224 pclkd1 = d1_bus / (pclkd1_ratio + 1);
225
226 return pclkd1;
227}
228
229/* s5pc110: return HCLKs frequency */
230static unsigned long get_hclk_sys(int dom)
231{
Minkyu Kangd93d0f02010-08-13 16:07:35 +0900232 struct s5pc110_clock *clk =
233 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang399e5ae2009-10-01 17:20:01 +0900234 unsigned long hclk;
235 unsigned int div;
236 unsigned int offset;
237 unsigned int hclk_sys_ratio;
238
239 if (dom == CLK_M)
240 return get_hclk();
241
242 div = readl(&clk->div0);
243
244 /*
245 * HCLK_MSYS_RATIO: [10:8]
246 * HCLK_DSYS_RATIO: [19:16]
247 * HCLK_PSYS_RATIO: [27:24]
248 */
249 offset = 8 + (dom << 0x3);
250
251 hclk_sys_ratio = (div >> offset) & 0xf;
252
253 hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1);
254
255 return hclk;
256}
257
258/* s5pc110: return PCLKs frequency */
259static unsigned long get_pclk_sys(int dom)
260{
Minkyu Kangd93d0f02010-08-13 16:07:35 +0900261 struct s5pc110_clock *clk =
262 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang399e5ae2009-10-01 17:20:01 +0900263 unsigned long pclk;
264 unsigned int div;
265 unsigned int offset;
266 unsigned int pclk_sys_ratio;
267
268 div = readl(&clk->div0);
269
270 /*
271 * PCLK_MSYS_RATIO: [14:12]
272 * PCLK_DSYS_RATIO: [22:20]
273 * PCLK_PSYS_RATIO: [30:28]
274 */
275 offset = 12 + (dom << 0x3);
276
277 pclk_sys_ratio = (div >> offset) & 0x7;
278
279 pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
280
281 return pclk;
282}
283
284/* s5pc110: return peripheral clock frequency */
285static unsigned long s5pc110_get_pclk(void)
286{
287 return get_pclk_sys(CLK_P);
288}
289
290/* s5pc100: return peripheral clock frequency */
291static unsigned long s5pc100_get_pclk(void)
292{
293 return get_pclkd1();
294}
295
Minkyu Kangf70409a2010-08-24 15:51:55 +0900296/* s5pc1xx: return uart clock frequency */
297static unsigned long s5pc1xx_get_uart_clk(int dev_index)
298{
299 if (cpu_is_s5pc110())
300 return s5pc110_get_pclk();
301 else
302 return s5pc100_get_pclk();
303}
304
305/* s5pc1xx: return pwm clock frequency */
306static unsigned long s5pc1xx_get_pwm_clk(void)
307{
308 if (cpu_is_s5pc110())
309 return s5pc110_get_pclk();
310 else
311 return s5pc100_get_pclk();
312}
313
Minkyu Kang3c152162010-12-27 15:55:48 +0900314unsigned long get_pll_clk(int pllreg)
Minkyu Kang399e5ae2009-10-01 17:20:01 +0900315{
Minkyu Kang3c152162010-12-27 15:55:48 +0900316 if (cpu_is_s5pc110())
317 return s5pc110_get_pll_clk(pllreg);
318 else
319 return s5pc100_get_pll_clk(pllreg);
320}
321
322unsigned long get_arm_clk(void)
323{
324 if (cpu_is_s5pc110())
325 return s5pc110_get_arm_clk();
326 else
327 return s5pc100_get_arm_clk();
328}
329
330unsigned long get_pwm_clk(void)
331{
332 return s5pc1xx_get_pwm_clk();
333}
334
335unsigned long get_uart_clk(int dev_index)
336{
337 return s5pc1xx_get_uart_clk(dev_index);
Minkyu Kang399e5ae2009-10-01 17:20:01 +0900338}