ARMV7: S5P: rename from s5pc1xx to s5p
[oweals/u-boot.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 unsigned long (*get_pclk)(void);
42 unsigned long (*get_arm_clk)(void);
43 unsigned long (*get_pll_clk)(int);
44
45 /* s5pc110: return pll clock frequency */
46 static unsigned long s5pc100_get_pll_clk(int pllreg)
47 {
48         struct s5pc100_clock *clk =
49                 (struct s5pc100_clock *)samsung_get_base_clock();
50         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 */
97 static unsigned long s5pc110_get_pll_clk(int pllreg)
98 {
99         struct s5pc110_clock *clk =
100                 (struct s5pc110_clock *)samsung_get_base_clock();
101         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 */
154 static unsigned long s5pc110_get_arm_clk(void)
155 {
156         struct s5pc110_clock *clk =
157                 (struct s5pc110_clock *)samsung_get_base_clock();
158         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 */
174 static unsigned long s5pc100_get_arm_clk(void)
175 {
176         struct s5pc100_clock *clk =
177                 (struct s5pc100_clock *)samsung_get_base_clock();
178         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 */
196 static unsigned long get_hclk(void)
197 {
198         struct s5pc100_clock *clk =
199                 (struct s5pc100_clock *)samsung_get_base_clock();
200         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 */
213 static unsigned long get_pclkd1(void)
214 {
215         struct s5pc100_clock *clk =
216                 (struct s5pc100_clock *)samsung_get_base_clock();
217         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 */
234 static unsigned long get_hclk_sys(int dom)
235 {
236         struct s5pc110_clock *clk =
237                 (struct s5pc110_clock *)samsung_get_base_clock();
238         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 */
263 static unsigned long get_pclk_sys(int dom)
264 {
265         struct s5pc110_clock *clk =
266                 (struct s5pc110_clock *)samsung_get_base_clock();
267         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 */
289 static unsigned long s5pc110_get_pclk(void)
290 {
291         return get_pclk_sys(CLK_P);
292 }
293
294 /* s5pc100: return peripheral clock frequency */
295 static unsigned long s5pc100_get_pclk(void)
296 {
297         return get_pclkd1();
298 }
299
300 void s5p_clock_init(void)
301 {
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 }