]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/s5pc1xx/clock.c
TX6 Release 2013-04-22
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / s5pc1xx / clock.c
1 /*
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>
28 #include <asm/arch/clk.h>
29
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
41 /* s5pc110: return pll clock frequency */
42 static unsigned long s5pc100_get_pll_clk(int pllreg)
43 {
44         struct s5pc100_clock *clk =
45                 (struct s5pc100_clock *)samsung_get_base_clock();
46         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 */
93 static unsigned long s5pc110_get_pll_clk(int pllreg)
94 {
95         struct s5pc110_clock *clk =
96                 (struct s5pc110_clock *)samsung_get_base_clock();
97         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 */
150 static unsigned long s5pc110_get_arm_clk(void)
151 {
152         struct s5pc110_clock *clk =
153                 (struct s5pc110_clock *)samsung_get_base_clock();
154         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 */
170 static unsigned long s5pc100_get_arm_clk(void)
171 {
172         struct s5pc100_clock *clk =
173                 (struct s5pc100_clock *)samsung_get_base_clock();
174         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 */
192 static unsigned long get_hclk(void)
193 {
194         struct s5pc100_clock *clk =
195                 (struct s5pc100_clock *)samsung_get_base_clock();
196         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 */
209 static unsigned long get_pclkd1(void)
210 {
211         struct s5pc100_clock *clk =
212                 (struct s5pc100_clock *)samsung_get_base_clock();
213         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 */
230 static unsigned long get_hclk_sys(int dom)
231 {
232         struct s5pc110_clock *clk =
233                 (struct s5pc110_clock *)samsung_get_base_clock();
234         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 */
259 static unsigned long get_pclk_sys(int dom)
260 {
261         struct s5pc110_clock *clk =
262                 (struct s5pc110_clock *)samsung_get_base_clock();
263         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 */
285 static unsigned long s5pc110_get_pclk(void)
286 {
287         return get_pclk_sys(CLK_P);
288 }
289
290 /* s5pc100: return peripheral clock frequency */
291 static unsigned long s5pc100_get_pclk(void)
292 {
293         return get_pclkd1();
294 }
295
296 /* s5pc1xx: return uart clock frequency */
297 static 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 */
306 static 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
314 unsigned long get_pll_clk(int pllreg)
315 {
316         if (cpu_is_s5pc110())
317                 return s5pc110_get_pll_clk(pllreg);
318         else
319                 return s5pc100_get_pll_clk(pllreg);
320 }
321
322 unsigned 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
330 unsigned long get_pwm_clk(void)
331 {
332         return s5pc1xx_get_pwm_clk();
333 }
334
335 unsigned long get_uart_clk(int dev_index)
336 {
337         return s5pc1xx_get_uart_clk(dev_index);
338 }
339
340 void set_mmc_clk(int dev_index, unsigned int div)
341 {
342         /* Do NOTHING */
343 }