blob: c9b54856e3aac74ed71f6444f45354bbf6a2224c [file] [log] [blame]
Minkyu Kang87649982009-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 CH35c1f672010-02-04 14:17:38 +090028#include <asm/arch/clk.h>
Minkyu Kang87649982009-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
41unsigned long (*get_pclk)(void);
42unsigned long (*get_arm_clk)(void);
43unsigned long (*get_pll_clk)(int);
44
45/* s5pc110: return pll clock frequency */
46static unsigned long s5pc100_get_pll_clk(int pllreg)
47{
Minkyu Kangc8189842010-08-13 16:07:35 +090048 struct s5pc100_clock *clk =
49 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +090050 unsigned long r, m, p, s, mask, fout;
51 unsigned int freq;
52
53 switch (pllreg) {
54 case APLL:
55 r = readl(&clk->apll_con);
56 break;
57 case MPLL:
58 r = readl(&clk->mpll_con);
59 break;
60 case EPLL:
61 r = readl(&clk->epll_con);
62 break;
63 case HPLL:
64 r = readl(&clk->hpll_con);
65 break;
66 default:
67 printf("Unsupported PLL (%d)\n", pllreg);
68 return 0;
69 }
70
71 /*
72 * APLL_CON: MIDV [25:16]
73 * MPLL_CON: MIDV [23:16]
74 * EPLL_CON: MIDV [23:16]
75 * HPLL_CON: MIDV [23:16]
76 */
77 if (pllreg == APLL)
78 mask = 0x3ff;
79 else
80 mask = 0x0ff;
81
82 m = (r >> 16) & mask;
83
84 /* PDIV [13:8] */
85 p = (r >> 8) & 0x3f;
86 /* SDIV [2:0] */
87 s = r & 0x7;
88
89 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
90 freq = CONFIG_SYS_CLK_FREQ_C100;
91 fout = m * (freq / (p * (1 << s)));
92
93 return fout;
94}
95
96/* s5pc100: return pll clock frequency */
97static unsigned long s5pc110_get_pll_clk(int pllreg)
98{
Minkyu Kangc8189842010-08-13 16:07:35 +090099 struct s5pc110_clock *clk =
100 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900101 unsigned long r, m, p, s, mask, fout;
102 unsigned int freq;
103
104 switch (pllreg) {
105 case APLL:
106 r = readl(&clk->apll_con);
107 break;
108 case MPLL:
109 r = readl(&clk->mpll_con);
110 break;
111 case EPLL:
112 r = readl(&clk->epll_con);
113 break;
114 case VPLL:
115 r = readl(&clk->vpll_con);
116 break;
117 default:
118 printf("Unsupported PLL (%d)\n", pllreg);
119 return 0;
120 }
121
122 /*
123 * APLL_CON: MIDV [25:16]
124 * MPLL_CON: MIDV [25:16]
125 * EPLL_CON: MIDV [24:16]
126 * VPLL_CON: MIDV [24:16]
127 */
128 if (pllreg == APLL || pllreg == MPLL)
129 mask = 0x3ff;
130 else
131 mask = 0x1ff;
132
133 m = (r >> 16) & mask;
134
135 /* PDIV [13:8] */
136 p = (r >> 8) & 0x3f;
137 /* SDIV [2:0] */
138 s = r & 0x7;
139
140 freq = CONFIG_SYS_CLK_FREQ_C110;
141 if (pllreg == APLL) {
142 if (s < 1)
143 s = 1;
144 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
145 fout = m * (freq / (p * (1 << (s - 1))));
146 } else
147 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
148 fout = m * (freq / (p * (1 << s)));
149
150 return fout;
151}
152
153/* s5pc110: return ARM clock frequency */
154static unsigned long s5pc110_get_arm_clk(void)
155{
Minkyu Kangc8189842010-08-13 16:07:35 +0900156 struct s5pc110_clock *clk =
157 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900158 unsigned long div;
159 unsigned long dout_apll, armclk;
160 unsigned int apll_ratio;
161
162 div = readl(&clk->div0);
163
164 /* APLL_RATIO: [2:0] */
165 apll_ratio = div & 0x7;
166
167 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
168 armclk = dout_apll;
169
170 return armclk;
171}
172
173/* s5pc100: return ARM clock frequency */
174static unsigned long s5pc100_get_arm_clk(void)
175{
Minkyu Kangc8189842010-08-13 16:07:35 +0900176 struct s5pc100_clock *clk =
177 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900178 unsigned long div;
179 unsigned long dout_apll, armclk;
180 unsigned int apll_ratio, arm_ratio;
181
182 div = readl(&clk->div0);
183
184 /* ARM_RATIO: [6:4] */
185 arm_ratio = (div >> 4) & 0x7;
186 /* APLL_RATIO: [0] */
187 apll_ratio = div & 0x1;
188
189 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
190 armclk = dout_apll / (arm_ratio + 1);
191
192 return armclk;
193}
194
195/* s5pc100: return HCLKD0 frequency */
196static unsigned long get_hclk(void)
197{
Minkyu Kangc8189842010-08-13 16:07:35 +0900198 struct s5pc100_clock *clk =
199 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900200 unsigned long hclkd0;
201 uint div, d0_bus_ratio;
202
203 div = readl(&clk->div0);
204 /* D0_BUS_RATIO: [10:8] */
205 d0_bus_ratio = (div >> 8) & 0x7;
206
207 hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
208
209 return hclkd0;
210}
211
212/* s5pc100: return PCLKD1 frequency */
213static unsigned long get_pclkd1(void)
214{
Minkyu Kangc8189842010-08-13 16:07:35 +0900215 struct s5pc100_clock *clk =
216 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900217 unsigned long d1_bus, pclkd1;
218 uint div, d1_bus_ratio, pclkd1_ratio;
219
220 div = readl(&clk->div0);
221 /* D1_BUS_RATIO: [14:12] */
222 d1_bus_ratio = (div >> 12) & 0x7;
223 /* PCLKD1_RATIO: [18:16] */
224 pclkd1_ratio = (div >> 16) & 0x7;
225
226 /* ASYNC Mode */
227 d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
228 pclkd1 = d1_bus / (pclkd1_ratio + 1);
229
230 return pclkd1;
231}
232
233/* s5pc110: return HCLKs frequency */
234static unsigned long get_hclk_sys(int dom)
235{
Minkyu Kangc8189842010-08-13 16:07:35 +0900236 struct s5pc110_clock *clk =
237 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900238 unsigned long hclk;
239 unsigned int div;
240 unsigned int offset;
241 unsigned int hclk_sys_ratio;
242
243 if (dom == CLK_M)
244 return get_hclk();
245
246 div = readl(&clk->div0);
247
248 /*
249 * HCLK_MSYS_RATIO: [10:8]
250 * HCLK_DSYS_RATIO: [19:16]
251 * HCLK_PSYS_RATIO: [27:24]
252 */
253 offset = 8 + (dom << 0x3);
254
255 hclk_sys_ratio = (div >> offset) & 0xf;
256
257 hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1);
258
259 return hclk;
260}
261
262/* s5pc110: return PCLKs frequency */
263static unsigned long get_pclk_sys(int dom)
264{
Minkyu Kangc8189842010-08-13 16:07:35 +0900265 struct s5pc110_clock *clk =
266 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900267 unsigned long pclk;
268 unsigned int div;
269 unsigned int offset;
270 unsigned int pclk_sys_ratio;
271
272 div = readl(&clk->div0);
273
274 /*
275 * PCLK_MSYS_RATIO: [14:12]
276 * PCLK_DSYS_RATIO: [22:20]
277 * PCLK_PSYS_RATIO: [30:28]
278 */
279 offset = 12 + (dom << 0x3);
280
281 pclk_sys_ratio = (div >> offset) & 0x7;
282
283 pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
284
285 return pclk;
286}
287
288/* s5pc110: return peripheral clock frequency */
289static unsigned long s5pc110_get_pclk(void)
290{
291 return get_pclk_sys(CLK_P);
292}
293
294/* s5pc100: return peripheral clock frequency */
295static unsigned long s5pc100_get_pclk(void)
296{
297 return get_pclkd1();
298}
299
Minkyu Kang2917c0a2010-08-19 20:41:50 +0900300void s5p_clock_init(void)
Minkyu Kang87649982009-10-01 17:20:01 +0900301{
302 if (cpu_is_s5pc110()) {
303 get_pll_clk = s5pc110_get_pll_clk;
304 get_arm_clk = s5pc110_get_arm_clk;
305 get_pclk = s5pc110_get_pclk;
306 } else {
307 get_pll_clk = s5pc100_get_pll_clk;
308 get_arm_clk = s5pc100_get_arm_clk;
309 get_pclk = s5pc100_get_pclk;
310 }
311}