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