blob: 3da00717f44762c370aaba1acc63fc3d17eafc3d [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 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
Minkyu Kang87649982009-10-01 17:20:01 +09007 */
8
9#include <common.h>
10#include <asm/io.h>
11#include <asm/arch/clock.h>
Naveen Krishna CH35c1f672010-02-04 14:17:38 +090012#include <asm/arch/clk.h>
Minkyu Kang87649982009-10-01 17:20:01 +090013
14#define CLK_M 0
15#define CLK_D 1
16#define CLK_P 2
17
18#ifndef CONFIG_SYS_CLK_FREQ_C100
19#define CONFIG_SYS_CLK_FREQ_C100 12000000
20#endif
21#ifndef CONFIG_SYS_CLK_FREQ_C110
22#define CONFIG_SYS_CLK_FREQ_C110 24000000
23#endif
24
Minkyu Kang87649982009-10-01 17:20:01 +090025/* s5pc110: return pll clock frequency */
26static unsigned long s5pc100_get_pll_clk(int pllreg)
27{
Minkyu Kangc8189842010-08-13 16:07:35 +090028 struct s5pc100_clock *clk =
29 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +090030 unsigned long r, m, p, s, mask, fout;
31 unsigned int freq;
32
33 switch (pllreg) {
34 case APLL:
35 r = readl(&clk->apll_con);
36 break;
37 case MPLL:
38 r = readl(&clk->mpll_con);
39 break;
40 case EPLL:
41 r = readl(&clk->epll_con);
42 break;
43 case HPLL:
44 r = readl(&clk->hpll_con);
45 break;
46 default:
47 printf("Unsupported PLL (%d)\n", pllreg);
48 return 0;
49 }
50
51 /*
52 * APLL_CON: MIDV [25:16]
53 * MPLL_CON: MIDV [23:16]
54 * EPLL_CON: MIDV [23:16]
55 * HPLL_CON: MIDV [23:16]
56 */
57 if (pllreg == APLL)
58 mask = 0x3ff;
59 else
60 mask = 0x0ff;
61
62 m = (r >> 16) & mask;
63
64 /* PDIV [13:8] */
65 p = (r >> 8) & 0x3f;
66 /* SDIV [2:0] */
67 s = r & 0x7;
68
69 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
70 freq = CONFIG_SYS_CLK_FREQ_C100;
71 fout = m * (freq / (p * (1 << s)));
72
73 return fout;
74}
75
76/* s5pc100: return pll clock frequency */
77static unsigned long s5pc110_get_pll_clk(int pllreg)
78{
Minkyu Kangc8189842010-08-13 16:07:35 +090079 struct s5pc110_clock *clk =
80 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +090081 unsigned long r, m, p, s, mask, fout;
82 unsigned int freq;
83
84 switch (pllreg) {
85 case APLL:
86 r = readl(&clk->apll_con);
87 break;
88 case MPLL:
89 r = readl(&clk->mpll_con);
90 break;
91 case EPLL:
92 r = readl(&clk->epll_con);
93 break;
94 case VPLL:
95 r = readl(&clk->vpll_con);
96 break;
97 default:
98 printf("Unsupported PLL (%d)\n", pllreg);
99 return 0;
100 }
101
102 /*
103 * APLL_CON: MIDV [25:16]
104 * MPLL_CON: MIDV [25:16]
105 * EPLL_CON: MIDV [24:16]
106 * VPLL_CON: MIDV [24:16]
107 */
108 if (pllreg == APLL || pllreg == MPLL)
109 mask = 0x3ff;
110 else
111 mask = 0x1ff;
112
113 m = (r >> 16) & mask;
114
115 /* PDIV [13:8] */
116 p = (r >> 8) & 0x3f;
117 /* SDIV [2:0] */
118 s = r & 0x7;
119
120 freq = CONFIG_SYS_CLK_FREQ_C110;
121 if (pllreg == APLL) {
122 if (s < 1)
123 s = 1;
124 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
125 fout = m * (freq / (p * (1 << (s - 1))));
126 } else
127 /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
128 fout = m * (freq / (p * (1 << s)));
129
130 return fout;
131}
132
133/* s5pc110: return ARM clock frequency */
134static unsigned long s5pc110_get_arm_clk(void)
135{
Minkyu Kangc8189842010-08-13 16:07:35 +0900136 struct s5pc110_clock *clk =
137 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900138 unsigned long div;
139 unsigned long dout_apll, armclk;
140 unsigned int apll_ratio;
141
142 div = readl(&clk->div0);
143
144 /* APLL_RATIO: [2:0] */
145 apll_ratio = div & 0x7;
146
147 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
148 armclk = dout_apll;
149
150 return armclk;
151}
152
153/* s5pc100: return ARM clock frequency */
154static unsigned long s5pc100_get_arm_clk(void)
155{
Minkyu Kangc8189842010-08-13 16:07:35 +0900156 struct s5pc100_clock *clk =
157 (struct s5pc100_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, arm_ratio;
161
162 div = readl(&clk->div0);
163
164 /* ARM_RATIO: [6:4] */
165 arm_ratio = (div >> 4) & 0x7;
166 /* APLL_RATIO: [0] */
167 apll_ratio = div & 0x1;
168
169 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
170 armclk = dout_apll / (arm_ratio + 1);
171
172 return armclk;
173}
174
175/* s5pc100: return HCLKD0 frequency */
176static unsigned long get_hclk(void)
177{
Minkyu Kangc8189842010-08-13 16:07:35 +0900178 struct s5pc100_clock *clk =
179 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900180 unsigned long hclkd0;
181 uint div, d0_bus_ratio;
182
183 div = readl(&clk->div0);
184 /* D0_BUS_RATIO: [10:8] */
185 d0_bus_ratio = (div >> 8) & 0x7;
186
187 hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
188
189 return hclkd0;
190}
191
192/* s5pc100: return PCLKD1 frequency */
193static unsigned long get_pclkd1(void)
194{
Minkyu Kangc8189842010-08-13 16:07:35 +0900195 struct s5pc100_clock *clk =
196 (struct s5pc100_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900197 unsigned long d1_bus, pclkd1;
198 uint div, d1_bus_ratio, pclkd1_ratio;
199
200 div = readl(&clk->div0);
201 /* D1_BUS_RATIO: [14:12] */
202 d1_bus_ratio = (div >> 12) & 0x7;
203 /* PCLKD1_RATIO: [18:16] */
204 pclkd1_ratio = (div >> 16) & 0x7;
205
206 /* ASYNC Mode */
207 d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
208 pclkd1 = d1_bus / (pclkd1_ratio + 1);
209
210 return pclkd1;
211}
212
213/* s5pc110: return HCLKs frequency */
214static unsigned long get_hclk_sys(int dom)
215{
Minkyu Kangc8189842010-08-13 16:07:35 +0900216 struct s5pc110_clock *clk =
217 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900218 unsigned long hclk;
219 unsigned int div;
220 unsigned int offset;
221 unsigned int hclk_sys_ratio;
222
223 if (dom == CLK_M)
224 return get_hclk();
225
226 div = readl(&clk->div0);
227
228 /*
229 * HCLK_MSYS_RATIO: [10:8]
230 * HCLK_DSYS_RATIO: [19:16]
231 * HCLK_PSYS_RATIO: [27:24]
232 */
233 offset = 8 + (dom << 0x3);
234
235 hclk_sys_ratio = (div >> offset) & 0xf;
236
237 hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1);
238
239 return hclk;
240}
241
242/* s5pc110: return PCLKs frequency */
243static unsigned long get_pclk_sys(int dom)
244{
Minkyu Kangc8189842010-08-13 16:07:35 +0900245 struct s5pc110_clock *clk =
246 (struct s5pc110_clock *)samsung_get_base_clock();
Minkyu Kang87649982009-10-01 17:20:01 +0900247 unsigned long pclk;
248 unsigned int div;
249 unsigned int offset;
250 unsigned int pclk_sys_ratio;
251
252 div = readl(&clk->div0);
253
254 /*
255 * PCLK_MSYS_RATIO: [14:12]
256 * PCLK_DSYS_RATIO: [22:20]
257 * PCLK_PSYS_RATIO: [30:28]
258 */
259 offset = 12 + (dom << 0x3);
260
261 pclk_sys_ratio = (div >> offset) & 0x7;
262
263 pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
264
265 return pclk;
266}
267
268/* s5pc110: return peripheral clock frequency */
269static unsigned long s5pc110_get_pclk(void)
270{
271 return get_pclk_sys(CLK_P);
272}
273
274/* s5pc100: return peripheral clock frequency */
275static unsigned long s5pc100_get_pclk(void)
276{
277 return get_pclkd1();
278}
279
Minkyu Kang36f25cf2010-08-24 15:51:55 +0900280/* s5pc1xx: return uart clock frequency */
281static unsigned long s5pc1xx_get_uart_clk(int dev_index)
282{
283 if (cpu_is_s5pc110())
284 return s5pc110_get_pclk();
285 else
286 return s5pc100_get_pclk();
287}
288
289/* s5pc1xx: return pwm clock frequency */
290static unsigned long s5pc1xx_get_pwm_clk(void)
291{
292 if (cpu_is_s5pc110())
293 return s5pc110_get_pclk();
294 else
295 return s5pc100_get_pclk();
296}
297
Minkyu Kang8bd7dad2010-12-27 15:55:48 +0900298unsigned long get_pll_clk(int pllreg)
Minkyu Kang87649982009-10-01 17:20:01 +0900299{
Minkyu Kang8bd7dad2010-12-27 15:55:48 +0900300 if (cpu_is_s5pc110())
301 return s5pc110_get_pll_clk(pllreg);
302 else
303 return s5pc100_get_pll_clk(pllreg);
304}
305
306unsigned long get_arm_clk(void)
307{
308 if (cpu_is_s5pc110())
309 return s5pc110_get_arm_clk();
310 else
311 return s5pc100_get_arm_clk();
312}
313
314unsigned long get_pwm_clk(void)
315{
316 return s5pc1xx_get_pwm_clk();
317}
318
319unsigned long get_uart_clk(int dev_index)
320{
321 return s5pc1xx_get_uart_clk(dev_index);
Minkyu Kang87649982009-10-01 17:20:01 +0900322}
Jaehoon Chung9a772212011-05-17 21:19:17 +0000323
324void set_mmc_clk(int dev_index, unsigned int div)
325{
326 /* Do NOTHING */
327}