]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/s5pc1xx/clock.c
Add GPL-2.0+ SPDX-License-Identifier to source files
[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  * SPDX-License-Identifier:     GPL-2.0+
7  */
8
9 #include <common.h>
10 #include <asm/io.h>
11 #include <asm/arch/clock.h>
12 #include <asm/arch/clk.h>
13
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
25 /* s5pc110: return pll clock frequency */
26 static unsigned long s5pc100_get_pll_clk(int pllreg)
27 {
28         struct s5pc100_clock *clk =
29                 (struct s5pc100_clock *)samsung_get_base_clock();
30         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 */
77 static unsigned long s5pc110_get_pll_clk(int pllreg)
78 {
79         struct s5pc110_clock *clk =
80                 (struct s5pc110_clock *)samsung_get_base_clock();
81         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 */
134 static unsigned long s5pc110_get_arm_clk(void)
135 {
136         struct s5pc110_clock *clk =
137                 (struct s5pc110_clock *)samsung_get_base_clock();
138         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 */
154 static unsigned long s5pc100_get_arm_clk(void)
155 {
156         struct s5pc100_clock *clk =
157                 (struct s5pc100_clock *)samsung_get_base_clock();
158         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 */
176 static unsigned long get_hclk(void)
177 {
178         struct s5pc100_clock *clk =
179                 (struct s5pc100_clock *)samsung_get_base_clock();
180         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 */
193 static unsigned long get_pclkd1(void)
194 {
195         struct s5pc100_clock *clk =
196                 (struct s5pc100_clock *)samsung_get_base_clock();
197         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 */
214 static unsigned long get_hclk_sys(int dom)
215 {
216         struct s5pc110_clock *clk =
217                 (struct s5pc110_clock *)samsung_get_base_clock();
218         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 */
243 static unsigned long get_pclk_sys(int dom)
244 {
245         struct s5pc110_clock *clk =
246                 (struct s5pc110_clock *)samsung_get_base_clock();
247         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 */
269 static unsigned long s5pc110_get_pclk(void)
270 {
271         return get_pclk_sys(CLK_P);
272 }
273
274 /* s5pc100: return peripheral clock frequency */
275 static unsigned long s5pc100_get_pclk(void)
276 {
277         return get_pclkd1();
278 }
279
280 /* s5pc1xx: return uart clock frequency */
281 static 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 */
290 static 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
298 unsigned long get_pll_clk(int pllreg)
299 {
300         if (cpu_is_s5pc110())
301                 return s5pc110_get_pll_clk(pllreg);
302         else
303                 return s5pc100_get_pll_clk(pllreg);
304 }
305
306 unsigned 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
314 unsigned long get_pwm_clk(void)
315 {
316         return s5pc1xx_get_pwm_clk();
317 }
318
319 unsigned long get_uart_clk(int dev_index)
320 {
321         return s5pc1xx_get_uart_clk(dev_index);
322 }
323
324 void set_mmc_clk(int dev_index, unsigned int div)
325 {
326         /* Do NOTHING */
327 }