]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
008a351a MK |
2 | /* |
3 | * Copyright (C) 2010 Samsung Electronics | |
4 | * Minkyu Kang <mk7.kang@samsung.com> | |
008a351a MK |
5 | */ |
6 | ||
7 | #include <common.h> | |
8 | #include <asm/io.h> | |
9 | #include <asm/arch/clock.h> | |
10 | #include <asm/arch/clk.h> | |
b56b3042 | 11 | #include <asm/arch/periph.h> |
008a351a | 12 | |
e161f60f MK |
13 | #define PLL_DIV_1024 1024 |
14 | #define PLL_DIV_65535 65535 | |
15 | #define PLL_DIV_65536 65536 | |
12a46a38 PV |
16 | /* * |
17 | * This structure is to store the src bit, div bit and prediv bit | |
18 | * positions of the peripheral clocks of the src and div registers | |
19 | */ | |
20 | struct clk_bit_info { | |
d606ded1 | 21 | enum periph_id id; |
c5d32170 AS |
22 | int32_t src_mask; |
23 | int32_t div_mask; | |
24 | int32_t prediv_mask; | |
12a46a38 PV |
25 | int8_t src_bit; |
26 | int8_t div_bit; | |
27 | int8_t prediv_bit; | |
28 | }; | |
29 | ||
ecdfb4e9 | 30 | static struct clk_bit_info exynos5_bit_info[] = { |
c5d32170 AS |
31 | /* periph id s_mask d_mask p_mask s_bit d_bit p_bit */ |
32 | {PERIPH_ID_UART0, 0xf, 0xf, -1, 0, 0, -1}, | |
33 | {PERIPH_ID_UART1, 0xf, 0xf, -1, 4, 4, -1}, | |
34 | {PERIPH_ID_UART2, 0xf, 0xf, -1, 8, 8, -1}, | |
35 | {PERIPH_ID_UART3, 0xf, 0xf, -1, 12, 12, -1}, | |
36 | {PERIPH_ID_I2C0, -1, 0x7, 0x7, -1, 24, 0}, | |
37 | {PERIPH_ID_I2C1, -1, 0x7, 0x7, -1, 24, 0}, | |
38 | {PERIPH_ID_I2C2, -1, 0x7, 0x7, -1, 24, 0}, | |
39 | {PERIPH_ID_I2C3, -1, 0x7, 0x7, -1, 24, 0}, | |
40 | {PERIPH_ID_I2C4, -1, 0x7, 0x7, -1, 24, 0}, | |
41 | {PERIPH_ID_I2C5, -1, 0x7, 0x7, -1, 24, 0}, | |
42 | {PERIPH_ID_I2C6, -1, 0x7, 0x7, -1, 24, 0}, | |
43 | {PERIPH_ID_I2C7, -1, 0x7, 0x7, -1, 24, 0}, | |
44 | {PERIPH_ID_SPI0, 0xf, 0xf, 0xff, 16, 0, 8}, | |
45 | {PERIPH_ID_SPI1, 0xf, 0xf, 0xff, 20, 16, 24}, | |
46 | {PERIPH_ID_SPI2, 0xf, 0xf, 0xff, 24, 0, 8}, | |
47 | {PERIPH_ID_SDMMC0, 0xf, 0xf, 0xff, 0, 0, 8}, | |
48 | {PERIPH_ID_SDMMC1, 0xf, 0xf, 0xff, 4, 16, 24}, | |
49 | {PERIPH_ID_SDMMC2, 0xf, 0xf, 0xff, 8, 0, 8}, | |
50 | {PERIPH_ID_SDMMC3, 0xf, 0xf, 0xff, 12, 16, 24}, | |
51 | {PERIPH_ID_I2S0, 0xf, 0xf, 0xff, 0, 0, 4}, | |
52 | {PERIPH_ID_I2S1, 0xf, 0xf, 0xff, 4, 12, 16}, | |
53 | {PERIPH_ID_SPI3, 0xf, 0xf, 0xff, 0, 0, 4}, | |
54 | {PERIPH_ID_SPI4, 0xf, 0xf, 0xff, 4, 12, 16}, | |
55 | {PERIPH_ID_SDMMC4, 0xf, 0xf, 0xff, 16, 0, 8}, | |
56 | {PERIPH_ID_PWM0, 0xf, 0xf, -1, 24, 0, -1}, | |
57 | {PERIPH_ID_PWM1, 0xf, 0xf, -1, 24, 0, -1}, | |
58 | {PERIPH_ID_PWM2, 0xf, 0xf, -1, 24, 0, -1}, | |
59 | {PERIPH_ID_PWM3, 0xf, 0xf, -1, 24, 0, -1}, | |
60 | {PERIPH_ID_PWM4, 0xf, 0xf, -1, 24, 0, -1}, | |
61 | ||
62 | {PERIPH_ID_NONE, -1, -1, -1, -1, -1, -1}, | |
12a46a38 PV |
63 | }; |
64 | ||
ecdfb4e9 | 65 | static struct clk_bit_info exynos542x_bit_info[] = { |
c5d32170 AS |
66 | /* periph id s_mask d_mask p_mask s_bit d_bit p_bit */ |
67 | {PERIPH_ID_UART0, 0xf, 0xf, -1, 4, 8, -1}, | |
68 | {PERIPH_ID_UART1, 0xf, 0xf, -1, 8, 12, -1}, | |
69 | {PERIPH_ID_UART2, 0xf, 0xf, -1, 12, 16, -1}, | |
70 | {PERIPH_ID_UART3, 0xf, 0xf, -1, 16, 20, -1}, | |
71 | {PERIPH_ID_I2C0, -1, 0x3f, -1, -1, 8, -1}, | |
72 | {PERIPH_ID_I2C1, -1, 0x3f, -1, -1, 8, -1}, | |
73 | {PERIPH_ID_I2C2, -1, 0x3f, -1, -1, 8, -1}, | |
74 | {PERIPH_ID_I2C3, -1, 0x3f, -1, -1, 8, -1}, | |
75 | {PERIPH_ID_I2C4, -1, 0x3f, -1, -1, 8, -1}, | |
76 | {PERIPH_ID_I2C5, -1, 0x3f, -1, -1, 8, -1}, | |
77 | {PERIPH_ID_I2C6, -1, 0x3f, -1, -1, 8, -1}, | |
78 | {PERIPH_ID_I2C7, -1, 0x3f, -1, -1, 8, -1}, | |
79 | {PERIPH_ID_SPI0, 0xf, 0xf, 0xff, 20, 20, 8}, | |
80 | {PERIPH_ID_SPI1, 0xf, 0xf, 0xff, 24, 24, 16}, | |
81 | {PERIPH_ID_SPI2, 0xf, 0xf, 0xff, 28, 28, 24}, | |
82 | {PERIPH_ID_SDMMC0, 0x7, 0x3ff, -1, 8, 0, -1}, | |
83 | {PERIPH_ID_SDMMC1, 0x7, 0x3ff, -1, 12, 10, -1}, | |
84 | {PERIPH_ID_SDMMC2, 0x7, 0x3ff, -1, 16, 20, -1}, | |
85 | {PERIPH_ID_I2C8, -1, 0x3f, -1, -1, 8, -1}, | |
86 | {PERIPH_ID_I2C9, -1, 0x3f, -1, -1, 8, -1}, | |
87 | {PERIPH_ID_I2S0, 0xf, 0xf, 0xff, 0, 0, 4}, | |
88 | {PERIPH_ID_I2S1, 0xf, 0xf, 0xff, 4, 12, 16}, | |
89 | {PERIPH_ID_SPI3, 0xf, 0xf, 0xff, 12, 16, 0}, | |
90 | {PERIPH_ID_SPI4, 0xf, 0xf, 0xff, 16, 20, 8}, | |
91 | {PERIPH_ID_PWM0, 0xf, 0xf, -1, 24, 28, -1}, | |
92 | {PERIPH_ID_PWM1, 0xf, 0xf, -1, 24, 28, -1}, | |
93 | {PERIPH_ID_PWM2, 0xf, 0xf, -1, 24, 28, -1}, | |
94 | {PERIPH_ID_PWM3, 0xf, 0xf, -1, 24, 28, -1}, | |
95 | {PERIPH_ID_PWM4, 0xf, 0xf, -1, 24, 28, -1}, | |
96 | {PERIPH_ID_I2C10, -1, 0x3f, -1, -1, 8, -1}, | |
97 | ||
98 | {PERIPH_ID_NONE, -1, -1, -1, -1, -1, -1}, | |
ecdfb4e9 AS |
99 | }; |
100 | ||
2e206caa RS |
101 | /* Epll Clock division values to achive different frequency output */ |
102 | static struct set_epll_con_val exynos5_epll_div[] = { | |
103 | { 192000000, 0, 48, 3, 1, 0 }, | |
104 | { 180000000, 0, 45, 3, 1, 0 }, | |
105 | { 73728000, 1, 73, 3, 3, 47710 }, | |
106 | { 67737600, 1, 90, 4, 3, 20762 }, | |
107 | { 49152000, 0, 49, 3, 3, 9961 }, | |
108 | { 45158400, 0, 45, 3, 3, 10381 }, | |
109 | { 180633600, 0, 45, 3, 1, 10381 } | |
110 | }; | |
111 | ||
bb6527bc MK |
112 | /* exynos: return pll clock frequency */ |
113 | static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k) | |
008a351a | 114 | { |
bb6527bc | 115 | unsigned long m, p, s = 0, mask, fout; |
e161f60f | 116 | unsigned int div; |
008a351a | 117 | unsigned int freq; |
008a351a MK |
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] | |
bb6527bc | 123 | * BPLL_CON: MIDV [25:16]: Exynos5 |
008a351a | 124 | */ |
496f0e47 AK |
125 | if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL || |
126 | pllreg == SPLL) | |
008a351a MK |
127 | mask = 0x3ff; |
128 | else | |
129 | mask = 0x1ff; | |
130 | ||
131 | m = (r >> 16) & mask; | |
132 | ||
133 | /* PDIV [13:8] */ | |
134 | p = (r >> 8) & 0x3f; | |
135 | /* SDIV [2:0] */ | |
136 | s = r & 0x7; | |
137 | ||
5e46f83c | 138 | freq = CONFIG_SYS_CLK_FREQ; |
008a351a | 139 | |
060c227a | 140 | if (pllreg == EPLL || pllreg == RPLL) { |
008a351a MK |
141 | k = k & 0xffff; |
142 | /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */ | |
e161f60f | 143 | fout = (m + k / PLL_DIV_65536) * (freq / (p * (1 << s))); |
008a351a MK |
144 | } else if (pllreg == VPLL) { |
145 | k = k & 0xfff; | |
e161f60f MK |
146 | |
147 | /* | |
148 | * Exynos4210 | |
149 | * FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) | |
150 | * | |
151 | * Exynos4412 | |
152 | * FOUT = (MDIV + K / 65535) * FIN / (PDIV * 2^SDIV) | |
153 | * | |
154 | * Exynos5250 | |
155 | * FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) | |
156 | */ | |
157 | if (proid_is_exynos4210()) | |
158 | div = PLL_DIV_1024; | |
159 | else if (proid_is_exynos4412()) | |
160 | div = PLL_DIV_65535; | |
d64c8ade PM |
161 | else if (proid_is_exynos5250() || proid_is_exynos5420() || |
162 | proid_is_exynos5422()) | |
e161f60f MK |
163 | div = PLL_DIV_65536; |
164 | else | |
165 | return 0; | |
166 | ||
167 | fout = (m + k / div) * (freq / (p * (1 << s))); | |
008a351a | 168 | } else { |
e161f60f | 169 | /* |
f4eaf88e | 170 | * Exynos4412 / Exynos5250 |
e161f60f MK |
171 | * FOUT = MDIV * FIN / (PDIV * 2^SDIV) |
172 | * | |
f4eaf88e | 173 | * Exynos4210 |
e161f60f MK |
174 | * FOUT = MDIV * FIN / (PDIV * 2^(SDIV-1)) |
175 | */ | |
176 | if (proid_is_exynos4210()) | |
e161f60f | 177 | fout = m * (freq / (p * (1 << (s - 1)))); |
f4eaf88e ŁM |
178 | else |
179 | fout = m * (freq / (p * (1 << s))); | |
008a351a | 180 | } |
008a351a MK |
181 | return fout; |
182 | } | |
183 | ||
bb6527bc MK |
184 | /* exynos4: return pll clock frequency */ |
185 | static unsigned long exynos4_get_pll_clk(int pllreg) | |
186 | { | |
187 | struct exynos4_clock *clk = | |
188 | (struct exynos4_clock *)samsung_get_base_clock(); | |
189 | unsigned long r, k = 0; | |
190 | ||
191 | switch (pllreg) { | |
192 | case APLL: | |
193 | r = readl(&clk->apll_con0); | |
194 | break; | |
195 | case MPLL: | |
196 | r = readl(&clk->mpll_con0); | |
197 | break; | |
198 | case EPLL: | |
199 | r = readl(&clk->epll_con0); | |
200 | k = readl(&clk->epll_con1); | |
201 | break; | |
202 | case VPLL: | |
203 | r = readl(&clk->vpll_con0); | |
204 | k = readl(&clk->vpll_con1); | |
205 | break; | |
206 | default: | |
207 | printf("Unsupported PLL (%d)\n", pllreg); | |
208 | return 0; | |
209 | } | |
210 | ||
211 | return exynos_get_pll_clk(pllreg, r, k); | |
212 | } | |
213 | ||
a5277573 CK |
214 | /* exynos4x12: return pll clock frequency */ |
215 | static unsigned long exynos4x12_get_pll_clk(int pllreg) | |
216 | { | |
217 | struct exynos4x12_clock *clk = | |
218 | (struct exynos4x12_clock *)samsung_get_base_clock(); | |
219 | unsigned long r, k = 0; | |
220 | ||
221 | switch (pllreg) { | |
222 | case APLL: | |
223 | r = readl(&clk->apll_con0); | |
224 | break; | |
225 | case MPLL: | |
226 | r = readl(&clk->mpll_con0); | |
227 | break; | |
228 | case EPLL: | |
229 | r = readl(&clk->epll_con0); | |
230 | k = readl(&clk->epll_con1); | |
231 | break; | |
232 | case VPLL: | |
233 | r = readl(&clk->vpll_con0); | |
234 | k = readl(&clk->vpll_con1); | |
235 | break; | |
236 | default: | |
237 | printf("Unsupported PLL (%d)\n", pllreg); | |
238 | return 0; | |
239 | } | |
240 | ||
241 | return exynos_get_pll_clk(pllreg, r, k); | |
242 | } | |
243 | ||
37bb6d89 CK |
244 | /* exynos5: return pll clock frequency */ |
245 | static unsigned long exynos5_get_pll_clk(int pllreg) | |
246 | { | |
247 | struct exynos5_clock *clk = | |
248 | (struct exynos5_clock *)samsung_get_base_clock(); | |
bb6527bc MK |
249 | unsigned long r, k = 0, fout; |
250 | unsigned int pll_div2_sel, fout_sel; | |
37bb6d89 CK |
251 | |
252 | switch (pllreg) { | |
253 | case APLL: | |
254 | r = readl(&clk->apll_con0); | |
255 | break; | |
256 | case MPLL: | |
257 | r = readl(&clk->mpll_con0); | |
258 | break; | |
259 | case EPLL: | |
260 | r = readl(&clk->epll_con0); | |
261 | k = readl(&clk->epll_con1); | |
262 | break; | |
263 | case VPLL: | |
264 | r = readl(&clk->vpll_con0); | |
265 | k = readl(&clk->vpll_con1); | |
266 | break; | |
10bc1a7f RS |
267 | case BPLL: |
268 | r = readl(&clk->bpll_con0); | |
269 | break; | |
37bb6d89 CK |
270 | default: |
271 | printf("Unsupported PLL (%d)\n", pllreg); | |
272 | return 0; | |
273 | } | |
274 | ||
bb6527bc | 275 | fout = exynos_get_pll_clk(pllreg, r, k); |
37bb6d89 | 276 | |
10bc1a7f | 277 | /* According to the user manual, in EVT1 MPLL and BPLL always gives |
6071bcae | 278 | * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/ |
10bc1a7f | 279 | if (pllreg == MPLL || pllreg == BPLL) { |
6071bcae | 280 | pll_div2_sel = readl(&clk->pll_div2_sel); |
10bc1a7f RS |
281 | |
282 | switch (pllreg) { | |
283 | case MPLL: | |
284 | fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT) | |
285 | & MPLL_FOUT_SEL_MASK; | |
286 | break; | |
287 | case BPLL: | |
288 | fout_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT) | |
289 | & BPLL_FOUT_SEL_MASK; | |
290 | break; | |
f8c5cfad JC |
291 | default: |
292 | fout_sel = -1; | |
293 | break; | |
10bc1a7f RS |
294 | } |
295 | ||
296 | if (fout_sel == 0) | |
6071bcae RS |
297 | fout /= 2; |
298 | } | |
299 | ||
37bb6d89 CK |
300 | return fout; |
301 | } | |
302 | ||
325eb18c AS |
303 | /* exynos542x: return pll clock frequency */ |
304 | static unsigned long exynos542x_get_pll_clk(int pllreg) | |
305 | { | |
306 | struct exynos5420_clock *clk = | |
307 | (struct exynos5420_clock *)samsung_get_base_clock(); | |
308 | unsigned long r, k = 0; | |
309 | ||
310 | switch (pllreg) { | |
311 | case APLL: | |
312 | r = readl(&clk->apll_con0); | |
313 | break; | |
314 | case MPLL: | |
315 | r = readl(&clk->mpll_con0); | |
316 | break; | |
317 | case EPLL: | |
318 | r = readl(&clk->epll_con0); | |
319 | k = readl(&clk->epll_con1); | |
320 | break; | |
321 | case VPLL: | |
322 | r = readl(&clk->vpll_con0); | |
323 | k = readl(&clk->vpll_con1); | |
324 | break; | |
325 | case BPLL: | |
326 | r = readl(&clk->bpll_con0); | |
327 | break; | |
328 | case RPLL: | |
329 | r = readl(&clk->rpll_con0); | |
330 | k = readl(&clk->rpll_con1); | |
331 | break; | |
332 | case SPLL: | |
333 | r = readl(&clk->spll_con0); | |
334 | break; | |
335 | default: | |
336 | printf("Unsupported PLL (%d)\n", pllreg); | |
337 | return 0; | |
338 | } | |
339 | ||
340 | return exynos_get_pll_clk(pllreg, r, k); | |
341 | } | |
342 | ||
d606ded1 AS |
343 | static struct clk_bit_info *get_clk_bit_info(int peripheral) |
344 | { | |
345 | int i; | |
ecdfb4e9 AS |
346 | struct clk_bit_info *info; |
347 | ||
d64c8ade | 348 | if (proid_is_exynos5420() || proid_is_exynos5422()) |
ecdfb4e9 AS |
349 | info = exynos542x_bit_info; |
350 | else | |
351 | info = exynos5_bit_info; | |
d606ded1 | 352 | |
ecdfb4e9 AS |
353 | for (i = 0; info[i].id != PERIPH_ID_NONE; i++) { |
354 | if (info[i].id == peripheral) | |
d606ded1 AS |
355 | break; |
356 | } | |
357 | ||
ecdfb4e9 | 358 | if (info[i].id == PERIPH_ID_NONE) |
d606ded1 AS |
359 | debug("ERROR: Peripheral ID %d not found\n", peripheral); |
360 | ||
ecdfb4e9 | 361 | return &info[i]; |
d606ded1 AS |
362 | } |
363 | ||
12a46a38 PV |
364 | static unsigned long exynos5_get_periph_rate(int peripheral) |
365 | { | |
d606ded1 | 366 | struct clk_bit_info *bit_info = get_clk_bit_info(peripheral); |
2e82e925 AS |
367 | unsigned long sclk = 0; |
368 | unsigned int src = 0, div = 0, sub_div = 0; | |
12a46a38 PV |
369 | struct exynos5_clock *clk = |
370 | (struct exynos5_clock *)samsung_get_base_clock(); | |
371 | ||
372 | switch (peripheral) { | |
373 | case PERIPH_ID_UART0: | |
374 | case PERIPH_ID_UART1: | |
375 | case PERIPH_ID_UART2: | |
376 | case PERIPH_ID_UART3: | |
377 | src = readl(&clk->src_peric0); | |
378 | div = readl(&clk->div_peric0); | |
379 | break; | |
380 | case PERIPH_ID_PWM0: | |
381 | case PERIPH_ID_PWM1: | |
382 | case PERIPH_ID_PWM2: | |
383 | case PERIPH_ID_PWM3: | |
384 | case PERIPH_ID_PWM4: | |
385 | src = readl(&clk->src_peric0); | |
386 | div = readl(&clk->div_peric3); | |
387 | break; | |
3dd22a37 DKM |
388 | case PERIPH_ID_I2S0: |
389 | src = readl(&clk->src_mau); | |
2e82e925 | 390 | div = sub_div = readl(&clk->div_mau); |
12a46a38 PV |
391 | case PERIPH_ID_SPI0: |
392 | case PERIPH_ID_SPI1: | |
393 | src = readl(&clk->src_peric1); | |
2e82e925 | 394 | div = sub_div = readl(&clk->div_peric1); |
12a46a38 PV |
395 | break; |
396 | case PERIPH_ID_SPI2: | |
397 | src = readl(&clk->src_peric1); | |
2e82e925 | 398 | div = sub_div = readl(&clk->div_peric2); |
12a46a38 PV |
399 | break; |
400 | case PERIPH_ID_SPI3: | |
401 | case PERIPH_ID_SPI4: | |
402 | src = readl(&clk->sclk_src_isp); | |
2e82e925 | 403 | div = sub_div = readl(&clk->sclk_div_isp); |
12a46a38 PV |
404 | break; |
405 | case PERIPH_ID_SDMMC0: | |
406 | case PERIPH_ID_SDMMC1: | |
9deff107 | 407 | src = readl(&clk->src_fsys); |
2e82e925 | 408 | div = sub_div = readl(&clk->div_fsys1); |
9deff107 | 409 | break; |
12a46a38 PV |
410 | case PERIPH_ID_SDMMC2: |
411 | case PERIPH_ID_SDMMC3: | |
412 | src = readl(&clk->src_fsys); | |
2e82e925 | 413 | div = sub_div = readl(&clk->div_fsys2); |
12a46a38 PV |
414 | break; |
415 | case PERIPH_ID_I2C0: | |
416 | case PERIPH_ID_I2C1: | |
417 | case PERIPH_ID_I2C2: | |
418 | case PERIPH_ID_I2C3: | |
419 | case PERIPH_ID_I2C4: | |
420 | case PERIPH_ID_I2C5: | |
421 | case PERIPH_ID_I2C6: | |
422 | case PERIPH_ID_I2C7: | |
2e82e925 | 423 | src = EXYNOS_SRC_MPLL; |
0467faf5 GG |
424 | div = readl(&clk->div_top1); |
425 | sub_div = readl(&clk->div_top0); | |
2e82e925 | 426 | break; |
12a46a38 PV |
427 | default: |
428 | debug("%s: invalid peripheral %d", __func__, peripheral); | |
429 | return -1; | |
430 | }; | |
431 | ||
9deff107 | 432 | if (bit_info->src_bit >= 0) |
c5d32170 | 433 | src = (src >> bit_info->src_bit) & bit_info->src_mask; |
12a46a38 PV |
434 | |
435 | switch (src) { | |
436 | case EXYNOS_SRC_MPLL: | |
437 | sclk = exynos5_get_pll_clk(MPLL); | |
438 | break; | |
439 | case EXYNOS_SRC_EPLL: | |
440 | sclk = exynos5_get_pll_clk(EPLL); | |
441 | break; | |
442 | case EXYNOS_SRC_VPLL: | |
443 | sclk = exynos5_get_pll_clk(VPLL); | |
444 | break; | |
445 | default: | |
2e82e925 | 446 | debug("%s: EXYNOS_SRC %d not supported\n", __func__, src); |
12a46a38 PV |
447 | return 0; |
448 | } | |
449 | ||
2e82e925 AS |
450 | /* Clock divider ratio for this peripheral */ |
451 | if (bit_info->div_bit >= 0) | |
452 | div = (div >> bit_info->div_bit) & bit_info->div_mask; | |
12a46a38 | 453 | |
2e82e925 AS |
454 | /* Clock pre-divider ratio for this peripheral */ |
455 | if (bit_info->prediv_bit >= 0) | |
456 | sub_div = (sub_div >> bit_info->prediv_bit) | |
457 | & bit_info->prediv_mask; | |
12a46a38 | 458 | |
2e82e925 AS |
459 | /* Calculate and return required clock rate */ |
460 | return (sclk / (div + 1)) / (sub_div + 1); | |
12a46a38 PV |
461 | } |
462 | ||
ecdfb4e9 AS |
463 | static unsigned long exynos542x_get_periph_rate(int peripheral) |
464 | { | |
465 | struct clk_bit_info *bit_info = get_clk_bit_info(peripheral); | |
2e82e925 AS |
466 | unsigned long sclk = 0; |
467 | unsigned int src = 0, div = 0, sub_div = 0; | |
ecdfb4e9 AS |
468 | struct exynos5420_clock *clk = |
469 | (struct exynos5420_clock *)samsung_get_base_clock(); | |
470 | ||
471 | switch (peripheral) { | |
472 | case PERIPH_ID_UART0: | |
473 | case PERIPH_ID_UART1: | |
474 | case PERIPH_ID_UART2: | |
475 | case PERIPH_ID_UART3: | |
476 | case PERIPH_ID_PWM0: | |
477 | case PERIPH_ID_PWM1: | |
478 | case PERIPH_ID_PWM2: | |
479 | case PERIPH_ID_PWM3: | |
480 | case PERIPH_ID_PWM4: | |
481 | src = readl(&clk->src_peric0); | |
482 | div = readl(&clk->div_peric0); | |
483 | break; | |
484 | case PERIPH_ID_SPI0: | |
485 | case PERIPH_ID_SPI1: | |
486 | case PERIPH_ID_SPI2: | |
487 | src = readl(&clk->src_peric1); | |
488 | div = readl(&clk->div_peric1); | |
489 | sub_div = readl(&clk->div_peric4); | |
490 | break; | |
491 | case PERIPH_ID_SPI3: | |
492 | case PERIPH_ID_SPI4: | |
493 | src = readl(&clk->src_isp); | |
494 | div = readl(&clk->div_isp1); | |
495 | sub_div = readl(&clk->div_isp1); | |
496 | break; | |
497 | case PERIPH_ID_SDMMC0: | |
498 | case PERIPH_ID_SDMMC1: | |
499 | case PERIPH_ID_SDMMC2: | |
500 | case PERIPH_ID_SDMMC3: | |
501 | src = readl(&clk->src_fsys); | |
502 | div = readl(&clk->div_fsys1); | |
503 | break; | |
504 | case PERIPH_ID_I2C0: | |
505 | case PERIPH_ID_I2C1: | |
506 | case PERIPH_ID_I2C2: | |
507 | case PERIPH_ID_I2C3: | |
508 | case PERIPH_ID_I2C4: | |
509 | case PERIPH_ID_I2C5: | |
510 | case PERIPH_ID_I2C6: | |
511 | case PERIPH_ID_I2C7: | |
512 | case PERIPH_ID_I2C8: | |
513 | case PERIPH_ID_I2C9: | |
514 | case PERIPH_ID_I2C10: | |
2e82e925 AS |
515 | src = EXYNOS542X_SRC_MPLL; |
516 | div = readl(&clk->div_top1); | |
517 | break; | |
ecdfb4e9 AS |
518 | default: |
519 | debug("%s: invalid peripheral %d", __func__, peripheral); | |
520 | return -1; | |
521 | }; | |
522 | ||
523 | if (bit_info->src_bit >= 0) | |
c5d32170 | 524 | src = (src >> bit_info->src_bit) & bit_info->src_mask; |
ecdfb4e9 AS |
525 | |
526 | switch (src) { | |
527 | case EXYNOS542X_SRC_MPLL: | |
528 | sclk = exynos542x_get_pll_clk(MPLL); | |
529 | break; | |
530 | case EXYNOS542X_SRC_SPLL: | |
531 | sclk = exynos542x_get_pll_clk(SPLL); | |
532 | break; | |
533 | case EXYNOS542X_SRC_EPLL: | |
534 | sclk = exynos542x_get_pll_clk(EPLL); | |
535 | break; | |
536 | case EXYNOS542X_SRC_RPLL: | |
537 | sclk = exynos542x_get_pll_clk(RPLL); | |
538 | break; | |
539 | default: | |
2e82e925 | 540 | debug("%s: EXYNOS542X_SRC %d not supported", __func__, src); |
ecdfb4e9 AS |
541 | return 0; |
542 | } | |
543 | ||
2e82e925 AS |
544 | /* Clock divider ratio for this peripheral */ |
545 | if (bit_info->div_bit >= 0) | |
c5d32170 | 546 | div = (div >> bit_info->div_bit) & bit_info->div_mask; |
ecdfb4e9 | 547 | |
2e82e925 AS |
548 | /* Clock pre-divider ratio for this peripheral */ |
549 | if (bit_info->prediv_bit >= 0) | |
c5d32170 | 550 | sub_div = (sub_div >> bit_info->prediv_bit) |
2e82e925 | 551 | & bit_info->prediv_mask; |
ecdfb4e9 | 552 | |
2e82e925 AS |
553 | /* Calculate and return required clock rate */ |
554 | return (sclk / (div + 1)) / (sub_div + 1); | |
ecdfb4e9 AS |
555 | } |
556 | ||
12a46a38 PV |
557 | unsigned long clock_get_periph_rate(int peripheral) |
558 | { | |
ecdfb4e9 | 559 | if (cpu_is_exynos5()) { |
d64c8ade | 560 | if (proid_is_exynos5420() || proid_is_exynos5422()) |
ecdfb4e9 | 561 | return exynos542x_get_periph_rate(peripheral); |
12a46a38 | 562 | return exynos5_get_periph_rate(peripheral); |
ecdfb4e9 | 563 | } else { |
12a46a38 | 564 | return 0; |
ecdfb4e9 | 565 | } |
12a46a38 PV |
566 | } |
567 | ||
393cb361 CK |
568 | /* exynos4: return ARM clock frequency */ |
569 | static unsigned long exynos4_get_arm_clk(void) | |
008a351a | 570 | { |
393cb361 CK |
571 | struct exynos4_clock *clk = |
572 | (struct exynos4_clock *)samsung_get_base_clock(); | |
008a351a | 573 | unsigned long div; |
db68bc2c CK |
574 | unsigned long armclk; |
575 | unsigned int core_ratio; | |
576 | unsigned int core2_ratio; | |
008a351a MK |
577 | |
578 | div = readl(&clk->div_cpu0); | |
579 | ||
db68bc2c CK |
580 | /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */ |
581 | core_ratio = (div >> 0) & 0x7; | |
582 | core2_ratio = (div >> 28) & 0x7; | |
008a351a | 583 | |
db68bc2c CK |
584 | armclk = get_pll_clk(APLL) / (core_ratio + 1); |
585 | armclk /= (core2_ratio + 1); | |
008a351a | 586 | |
db68bc2c | 587 | return armclk; |
008a351a MK |
588 | } |
589 | ||
a5277573 CK |
590 | /* exynos4x12: return ARM clock frequency */ |
591 | static unsigned long exynos4x12_get_arm_clk(void) | |
592 | { | |
593 | struct exynos4x12_clock *clk = | |
594 | (struct exynos4x12_clock *)samsung_get_base_clock(); | |
595 | unsigned long div; | |
596 | unsigned long armclk; | |
597 | unsigned int core_ratio; | |
598 | unsigned int core2_ratio; | |
599 | ||
600 | div = readl(&clk->div_cpu0); | |
601 | ||
602 | /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */ | |
603 | core_ratio = (div >> 0) & 0x7; | |
604 | core2_ratio = (div >> 28) & 0x7; | |
605 | ||
606 | armclk = get_pll_clk(APLL) / (core_ratio + 1); | |
607 | armclk /= (core2_ratio + 1); | |
608 | ||
609 | return armclk; | |
610 | } | |
611 | ||
37bb6d89 CK |
612 | /* exynos5: return ARM clock frequency */ |
613 | static unsigned long exynos5_get_arm_clk(void) | |
614 | { | |
615 | struct exynos5_clock *clk = | |
616 | (struct exynos5_clock *)samsung_get_base_clock(); | |
617 | unsigned long div; | |
618 | unsigned long armclk; | |
619 | unsigned int arm_ratio; | |
620 | unsigned int arm2_ratio; | |
621 | ||
622 | div = readl(&clk->div_cpu0); | |
623 | ||
624 | /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */ | |
625 | arm_ratio = (div >> 0) & 0x7; | |
626 | arm2_ratio = (div >> 28) & 0x7; | |
627 | ||
628 | armclk = get_pll_clk(APLL) / (arm_ratio + 1); | |
629 | armclk /= (arm2_ratio + 1); | |
630 | ||
631 | return armclk; | |
632 | } | |
633 | ||
393cb361 CK |
634 | /* exynos4: return pwm clock frequency */ |
635 | static unsigned long exynos4_get_pwm_clk(void) | |
008a351a | 636 | { |
393cb361 CK |
637 | struct exynos4_clock *clk = |
638 | (struct exynos4_clock *)samsung_get_base_clock(); | |
008a351a MK |
639 | unsigned long pclk, sclk; |
640 | unsigned int sel; | |
641 | unsigned int ratio; | |
642 | ||
b4f73910 MK |
643 | if (s5p_get_cpu_rev() == 0) { |
644 | /* | |
645 | * CLK_SRC_PERIL0 | |
646 | * PWM_SEL [27:24] | |
647 | */ | |
648 | sel = readl(&clk->src_peril0); | |
649 | sel = (sel >> 24) & 0xf; | |
650 | ||
651 | if (sel == 0x6) | |
652 | sclk = get_pll_clk(MPLL); | |
653 | else if (sel == 0x7) | |
654 | sclk = get_pll_clk(EPLL); | |
655 | else if (sel == 0x8) | |
656 | sclk = get_pll_clk(VPLL); | |
657 | else | |
658 | return 0; | |
659 | ||
660 | /* | |
661 | * CLK_DIV_PERIL3 | |
662 | * PWM_RATIO [3:0] | |
663 | */ | |
664 | ratio = readl(&clk->div_peril3); | |
665 | ratio = ratio & 0xf; | |
666 | } else if (s5p_get_cpu_rev() == 1) { | |
008a351a | 667 | sclk = get_pll_clk(MPLL); |
b4f73910 MK |
668 | ratio = 8; |
669 | } else | |
008a351a MK |
670 | return 0; |
671 | ||
008a351a MK |
672 | pclk = sclk / (ratio + 1); |
673 | ||
674 | return pclk; | |
675 | } | |
676 | ||
a5277573 CK |
677 | /* exynos4x12: return pwm clock frequency */ |
678 | static unsigned long exynos4x12_get_pwm_clk(void) | |
679 | { | |
680 | unsigned long pclk, sclk; | |
681 | unsigned int ratio; | |
682 | ||
683 | sclk = get_pll_clk(MPLL); | |
684 | ratio = 8; | |
685 | ||
686 | pclk = sclk / (ratio + 1); | |
687 | ||
688 | return pclk; | |
689 | } | |
690 | ||
393cb361 CK |
691 | /* exynos4: return uart clock frequency */ |
692 | static unsigned long exynos4_get_uart_clk(int dev_index) | |
008a351a | 693 | { |
393cb361 CK |
694 | struct exynos4_clock *clk = |
695 | (struct exynos4_clock *)samsung_get_base_clock(); | |
008a351a MK |
696 | unsigned long uclk, sclk; |
697 | unsigned int sel; | |
698 | unsigned int ratio; | |
699 | ||
700 | /* | |
701 | * CLK_SRC_PERIL0 | |
702 | * UART0_SEL [3:0] | |
703 | * UART1_SEL [7:4] | |
704 | * UART2_SEL [8:11] | |
705 | * UART3_SEL [12:15] | |
706 | * UART4_SEL [16:19] | |
707 | * UART5_SEL [23:20] | |
708 | */ | |
709 | sel = readl(&clk->src_peril0); | |
710 | sel = (sel >> (dev_index << 2)) & 0xf; | |
711 | ||
712 | if (sel == 0x6) | |
713 | sclk = get_pll_clk(MPLL); | |
714 | else if (sel == 0x7) | |
715 | sclk = get_pll_clk(EPLL); | |
716 | else if (sel == 0x8) | |
717 | sclk = get_pll_clk(VPLL); | |
718 | else | |
719 | return 0; | |
720 | ||
721 | /* | |
722 | * CLK_DIV_PERIL0 | |
723 | * UART0_RATIO [3:0] | |
724 | * UART1_RATIO [7:4] | |
725 | * UART2_RATIO [8:11] | |
726 | * UART3_RATIO [12:15] | |
727 | * UART4_RATIO [16:19] | |
728 | * UART5_RATIO [23:20] | |
729 | */ | |
730 | ratio = readl(&clk->div_peril0); | |
731 | ratio = (ratio >> (dev_index << 2)) & 0xf; | |
732 | ||
733 | uclk = sclk / (ratio + 1); | |
734 | ||
735 | return uclk; | |
736 | } | |
737 | ||
a5277573 CK |
738 | /* exynos4x12: return uart clock frequency */ |
739 | static unsigned long exynos4x12_get_uart_clk(int dev_index) | |
740 | { | |
741 | struct exynos4x12_clock *clk = | |
742 | (struct exynos4x12_clock *)samsung_get_base_clock(); | |
743 | unsigned long uclk, sclk; | |
744 | unsigned int sel; | |
745 | unsigned int ratio; | |
746 | ||
747 | /* | |
748 | * CLK_SRC_PERIL0 | |
749 | * UART0_SEL [3:0] | |
750 | * UART1_SEL [7:4] | |
751 | * UART2_SEL [8:11] | |
752 | * UART3_SEL [12:15] | |
753 | * UART4_SEL [16:19] | |
754 | */ | |
755 | sel = readl(&clk->src_peril0); | |
756 | sel = (sel >> (dev_index << 2)) & 0xf; | |
757 | ||
758 | if (sel == 0x6) | |
759 | sclk = get_pll_clk(MPLL); | |
760 | else if (sel == 0x7) | |
761 | sclk = get_pll_clk(EPLL); | |
762 | else if (sel == 0x8) | |
763 | sclk = get_pll_clk(VPLL); | |
764 | else | |
765 | return 0; | |
766 | ||
767 | /* | |
768 | * CLK_DIV_PERIL0 | |
769 | * UART0_RATIO [3:0] | |
770 | * UART1_RATIO [7:4] | |
771 | * UART2_RATIO [8:11] | |
772 | * UART3_RATIO [12:15] | |
773 | * UART4_RATIO [16:19] | |
774 | */ | |
775 | ratio = readl(&clk->div_peril0); | |
776 | ratio = (ratio >> (dev_index << 2)) & 0xf; | |
777 | ||
778 | uclk = sclk / (ratio + 1); | |
779 | ||
780 | return uclk; | |
781 | } | |
782 | ||
c39e969e JC |
783 | static unsigned long exynos4_get_mmc_clk(int dev_index) |
784 | { | |
785 | struct exynos4_clock *clk = | |
786 | (struct exynos4_clock *)samsung_get_base_clock(); | |
787 | unsigned long uclk, sclk; | |
788 | unsigned int sel, ratio, pre_ratio; | |
2b81c26b | 789 | int shift = 0; |
c39e969e JC |
790 | |
791 | sel = readl(&clk->src_fsys); | |
792 | sel = (sel >> (dev_index << 2)) & 0xf; | |
793 | ||
794 | if (sel == 0x6) | |
795 | sclk = get_pll_clk(MPLL); | |
796 | else if (sel == 0x7) | |
797 | sclk = get_pll_clk(EPLL); | |
798 | else if (sel == 0x8) | |
799 | sclk = get_pll_clk(VPLL); | |
800 | else | |
801 | return 0; | |
802 | ||
803 | switch (dev_index) { | |
804 | case 0: | |
805 | case 1: | |
806 | ratio = readl(&clk->div_fsys1); | |
807 | pre_ratio = readl(&clk->div_fsys1); | |
808 | break; | |
809 | case 2: | |
810 | case 3: | |
811 | ratio = readl(&clk->div_fsys2); | |
812 | pre_ratio = readl(&clk->div_fsys2); | |
813 | break; | |
814 | case 4: | |
815 | ratio = readl(&clk->div_fsys3); | |
816 | pre_ratio = readl(&clk->div_fsys3); | |
817 | break; | |
818 | default: | |
819 | return 0; | |
820 | } | |
821 | ||
822 | if (dev_index == 1 || dev_index == 3) | |
823 | shift = 16; | |
824 | ||
825 | ratio = (ratio >> shift) & 0xf; | |
826 | pre_ratio = (pre_ratio >> (shift + 8)) & 0xff; | |
827 | uclk = (sclk / (ratio + 1)) / (pre_ratio + 1); | |
828 | ||
829 | return uclk; | |
830 | } | |
831 | ||
393cb361 CK |
832 | /* exynos4: set the mmc clock */ |
833 | static void exynos4_set_mmc_clk(int dev_index, unsigned int div) | |
68a8cbfa | 834 | { |
393cb361 CK |
835 | struct exynos4_clock *clk = |
836 | (struct exynos4_clock *)samsung_get_base_clock(); | |
39c49756 | 837 | unsigned int addr, clear_bit, set_bit; |
68a8cbfa JC |
838 | |
839 | /* | |
840 | * CLK_DIV_FSYS1 | |
841 | * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24] | |
842 | * CLK_DIV_FSYS2 | |
843 | * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24] | |
5374d386 | 844 | * CLK_DIV_FSYS3 |
39c49756 | 845 | * MMC4_RATIO [3:0] |
68a8cbfa JC |
846 | */ |
847 | if (dev_index < 2) { | |
848 | addr = (unsigned int)&clk->div_fsys1; | |
39c49756 JC |
849 | clear_bit = MASK_PRE_RATIO(dev_index); |
850 | set_bit = SET_PRE_RATIO(dev_index, div); | |
851 | } else if (dev_index == 4) { | |
5374d386 JC |
852 | addr = (unsigned int)&clk->div_fsys3; |
853 | dev_index -= 4; | |
39c49756 JC |
854 | /* MMC4 is controlled with the MMC4_RATIO value */ |
855 | clear_bit = MASK_RATIO(dev_index); | |
856 | set_bit = SET_RATIO(dev_index, div); | |
68a8cbfa JC |
857 | } else { |
858 | addr = (unsigned int)&clk->div_fsys2; | |
859 | dev_index -= 2; | |
39c49756 JC |
860 | clear_bit = MASK_PRE_RATIO(dev_index); |
861 | set_bit = SET_PRE_RATIO(dev_index, div); | |
68a8cbfa JC |
862 | } |
863 | ||
39c49756 | 864 | clrsetbits_le32(addr, clear_bit, set_bit); |
68a8cbfa JC |
865 | } |
866 | ||
37bb6d89 CK |
867 | /* exynos5: set the mmc clock */ |
868 | static void exynos5_set_mmc_clk(int dev_index, unsigned int div) | |
869 | { | |
870 | struct exynos5_clock *clk = | |
871 | (struct exynos5_clock *)samsung_get_base_clock(); | |
872 | unsigned int addr; | |
37bb6d89 CK |
873 | |
874 | /* | |
875 | * CLK_DIV_FSYS1 | |
876 | * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24] | |
877 | * CLK_DIV_FSYS2 | |
878 | * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24] | |
879 | */ | |
880 | if (dev_index < 2) { | |
881 | addr = (unsigned int)&clk->div_fsys1; | |
882 | } else { | |
883 | addr = (unsigned int)&clk->div_fsys2; | |
884 | dev_index -= 2; | |
885 | } | |
886 | ||
e25bfecf IS |
887 | clrsetbits_le32(addr, 0xff << ((dev_index << 4) + 8), |
888 | (div & 0xff) << ((dev_index << 4) + 8)); | |
37bb6d89 CK |
889 | } |
890 | ||
060c227a RS |
891 | /* exynos5: set the mmc clock */ |
892 | static void exynos5420_set_mmc_clk(int dev_index, unsigned int div) | |
893 | { | |
894 | struct exynos5420_clock *clk = | |
895 | (struct exynos5420_clock *)samsung_get_base_clock(); | |
896 | unsigned int addr; | |
e25bfecf | 897 | unsigned int shift; |
060c227a RS |
898 | |
899 | /* | |
900 | * CLK_DIV_FSYS1 | |
901 | * MMC0_RATIO [9:0] | |
902 | * MMC1_RATIO [19:10] | |
903 | * MMC2_RATIO [29:20] | |
904 | */ | |
905 | addr = (unsigned int)&clk->div_fsys1; | |
906 | shift = dev_index * 10; | |
907 | ||
e25bfecf | 908 | clrsetbits_le32(addr, 0x3ff << shift, (div & 0x3ff) << shift); |
060c227a RS |
909 | } |
910 | ||
37835d4b DL |
911 | /* get_lcd_clk: return lcd clock frequency */ |
912 | static unsigned long exynos4_get_lcd_clk(void) | |
913 | { | |
914 | struct exynos4_clock *clk = | |
915 | (struct exynos4_clock *)samsung_get_base_clock(); | |
916 | unsigned long pclk, sclk; | |
917 | unsigned int sel; | |
918 | unsigned int ratio; | |
919 | ||
920 | /* | |
921 | * CLK_SRC_LCD0 | |
922 | * FIMD0_SEL [3:0] | |
923 | */ | |
924 | sel = readl(&clk->src_lcd0); | |
925 | sel = sel & 0xf; | |
926 | ||
927 | /* | |
928 | * 0x6: SCLK_MPLL | |
929 | * 0x7: SCLK_EPLL | |
930 | * 0x8: SCLK_VPLL | |
931 | */ | |
932 | if (sel == 0x6) | |
933 | sclk = get_pll_clk(MPLL); | |
934 | else if (sel == 0x7) | |
935 | sclk = get_pll_clk(EPLL); | |
936 | else if (sel == 0x8) | |
937 | sclk = get_pll_clk(VPLL); | |
938 | else | |
939 | return 0; | |
940 | ||
941 | /* | |
942 | * CLK_DIV_LCD0 | |
943 | * FIMD0_RATIO [3:0] | |
944 | */ | |
945 | ratio = readl(&clk->div_lcd0); | |
946 | ratio = ratio & 0xf; | |
947 | ||
948 | pclk = sclk / (ratio + 1); | |
949 | ||
950 | return pclk; | |
951 | } | |
952 | ||
2c5cd25c DL |
953 | /* get_lcd_clk: return lcd clock frequency */ |
954 | static unsigned long exynos5_get_lcd_clk(void) | |
955 | { | |
956 | struct exynos5_clock *clk = | |
957 | (struct exynos5_clock *)samsung_get_base_clock(); | |
958 | unsigned long pclk, sclk; | |
959 | unsigned int sel; | |
960 | unsigned int ratio; | |
961 | ||
962 | /* | |
963 | * CLK_SRC_LCD0 | |
964 | * FIMD0_SEL [3:0] | |
965 | */ | |
966 | sel = readl(&clk->src_disp1_0); | |
967 | sel = sel & 0xf; | |
968 | ||
969 | /* | |
970 | * 0x6: SCLK_MPLL | |
971 | * 0x7: SCLK_EPLL | |
972 | * 0x8: SCLK_VPLL | |
973 | */ | |
974 | if (sel == 0x6) | |
975 | sclk = get_pll_clk(MPLL); | |
976 | else if (sel == 0x7) | |
977 | sclk = get_pll_clk(EPLL); | |
978 | else if (sel == 0x8) | |
979 | sclk = get_pll_clk(VPLL); | |
980 | else | |
981 | return 0; | |
982 | ||
983 | /* | |
984 | * CLK_DIV_LCD0 | |
985 | * FIMD0_RATIO [3:0] | |
986 | */ | |
987 | ratio = readl(&clk->div_disp1_0); | |
988 | ratio = ratio & 0xf; | |
989 | ||
990 | pclk = sclk / (ratio + 1); | |
991 | ||
992 | return pclk; | |
993 | } | |
994 | ||
496f0e47 AK |
995 | static unsigned long exynos5420_get_lcd_clk(void) |
996 | { | |
997 | struct exynos5420_clock *clk = | |
998 | (struct exynos5420_clock *)samsung_get_base_clock(); | |
999 | unsigned long pclk, sclk; | |
1000 | unsigned int sel; | |
1001 | unsigned int ratio; | |
1002 | ||
1003 | /* | |
1004 | * CLK_SRC_DISP10 | |
1005 | * FIMD1_SEL [4] | |
1006 | * 0: SCLK_RPLL | |
1007 | * 1: SCLK_SPLL | |
1008 | */ | |
1009 | sel = readl(&clk->src_disp10); | |
1010 | sel &= (1 << 4); | |
1011 | ||
1012 | if (sel) | |
1013 | sclk = get_pll_clk(SPLL); | |
1014 | else | |
1015 | sclk = get_pll_clk(RPLL); | |
1016 | ||
1017 | /* | |
1018 | * CLK_DIV_DISP10 | |
1019 | * FIMD1_RATIO [3:0] | |
1020 | */ | |
1021 | ratio = readl(&clk->div_disp10); | |
1022 | ratio = ratio & 0xf; | |
1023 | ||
1024 | pclk = sclk / (ratio + 1); | |
1025 | ||
1026 | return pclk; | |
1027 | } | |
1028 | ||
70b4fb66 AK |
1029 | static unsigned long exynos5800_get_lcd_clk(void) |
1030 | { | |
1031 | struct exynos5420_clock *clk = | |
1032 | (struct exynos5420_clock *)samsung_get_base_clock(); | |
1033 | unsigned long sclk; | |
1034 | unsigned int sel; | |
1035 | unsigned int ratio; | |
1036 | ||
1037 | /* | |
1038 | * CLK_SRC_DISP10 | |
1039 | * CLKMUX_FIMD1 [6:4] | |
1040 | */ | |
1041 | sel = (readl(&clk->src_disp10) >> 4) & 0x7; | |
1042 | ||
1043 | if (sel) { | |
1044 | /* | |
1045 | * Mapping of CLK_SRC_DISP10 CLKMUX_FIMD1 [6:4] values into | |
1046 | * PLLs. The first element is a placeholder to bypass the | |
1047 | * default settig. | |
1048 | */ | |
1049 | const int reg_map[] = {0, CPLL, DPLL, MPLL, SPLL, IPLL, EPLL, | |
1050 | RPLL}; | |
1051 | sclk = get_pll_clk(reg_map[sel]); | |
1052 | } else | |
1053 | sclk = CONFIG_SYS_CLK_FREQ; | |
1054 | /* | |
1055 | * CLK_DIV_DISP10 | |
1056 | * FIMD1_RATIO [3:0] | |
1057 | */ | |
1058 | ratio = readl(&clk->div_disp10) & 0xf; | |
1059 | ||
1060 | return sclk / (ratio + 1); | |
1061 | } | |
1062 | ||
37835d4b DL |
1063 | void exynos4_set_lcd_clk(void) |
1064 | { | |
1065 | struct exynos4_clock *clk = | |
1066 | (struct exynos4_clock *)samsung_get_base_clock(); | |
37835d4b DL |
1067 | |
1068 | /* | |
1069 | * CLK_GATE_BLOCK | |
1070 | * CLK_CAM [0] | |
1071 | * CLK_TV [1] | |
1072 | * CLK_MFC [2] | |
1073 | * CLK_G3D [3] | |
1074 | * CLK_LCD0 [4] | |
1075 | * CLK_LCD1 [5] | |
1076 | * CLK_GPS [7] | |
1077 | */ | |
e25bfecf | 1078 | setbits_le32(&clk->gate_block, 1 << 4); |
37835d4b DL |
1079 | |
1080 | /* | |
1081 | * CLK_SRC_LCD0 | |
1082 | * FIMD0_SEL [3:0] | |
1083 | * MDNIE0_SEL [7:4] | |
1084 | * MDNIE_PWM0_SEL [8:11] | |
1085 | * MIPI0_SEL [12:15] | |
1086 | * set lcd0 src clock 0x6: SCLK_MPLL | |
1087 | */ | |
e25bfecf | 1088 | clrsetbits_le32(&clk->src_lcd0, 0xf, 0x6); |
37835d4b DL |
1089 | |
1090 | /* | |
1091 | * CLK_GATE_IP_LCD0 | |
1092 | * CLK_FIMD0 [0] | |
1093 | * CLK_MIE0 [1] | |
1094 | * CLK_MDNIE0 [2] | |
1095 | * CLK_DSIM0 [3] | |
1096 | * CLK_SMMUFIMD0 [4] | |
1097 | * CLK_PPMULCD0 [5] | |
1098 | * Gating all clocks for FIMD0 | |
1099 | */ | |
e25bfecf | 1100 | setbits_le32(&clk->gate_ip_lcd0, 1 << 0); |
37835d4b DL |
1101 | |
1102 | /* | |
1103 | * CLK_DIV_LCD0 | |
1104 | * FIMD0_RATIO [3:0] | |
1105 | * MDNIE0_RATIO [7:4] | |
1106 | * MDNIE_PWM0_RATIO [11:8] | |
1107 | * MDNIE_PWM_PRE_RATIO [15:12] | |
1108 | * MIPI0_RATIO [19:16] | |
1109 | * MIPI0_PRE_RATIO [23:20] | |
1110 | * set fimd ratio | |
1111 | */ | |
e25bfecf | 1112 | clrsetbits_le32(&clk->div_lcd0, 0xf, 0x1); |
37835d4b DL |
1113 | } |
1114 | ||
2c5cd25c DL |
1115 | void exynos5_set_lcd_clk(void) |
1116 | { | |
1117 | struct exynos5_clock *clk = | |
1118 | (struct exynos5_clock *)samsung_get_base_clock(); | |
2c5cd25c DL |
1119 | |
1120 | /* | |
1121 | * CLK_GATE_BLOCK | |
1122 | * CLK_CAM [0] | |
1123 | * CLK_TV [1] | |
1124 | * CLK_MFC [2] | |
1125 | * CLK_G3D [3] | |
1126 | * CLK_LCD0 [4] | |
1127 | * CLK_LCD1 [5] | |
1128 | * CLK_GPS [7] | |
1129 | */ | |
e25bfecf | 1130 | setbits_le32(&clk->gate_block, 1 << 4); |
2c5cd25c DL |
1131 | |
1132 | /* | |
1133 | * CLK_SRC_LCD0 | |
1134 | * FIMD0_SEL [3:0] | |
1135 | * MDNIE0_SEL [7:4] | |
1136 | * MDNIE_PWM0_SEL [8:11] | |
1137 | * MIPI0_SEL [12:15] | |
1138 | * set lcd0 src clock 0x6: SCLK_MPLL | |
1139 | */ | |
e25bfecf | 1140 | clrsetbits_le32(&clk->src_disp1_0, 0xf, 0x6); |
2c5cd25c DL |
1141 | |
1142 | /* | |
1143 | * CLK_GATE_IP_LCD0 | |
1144 | * CLK_FIMD0 [0] | |
1145 | * CLK_MIE0 [1] | |
1146 | * CLK_MDNIE0 [2] | |
1147 | * CLK_DSIM0 [3] | |
1148 | * CLK_SMMUFIMD0 [4] | |
1149 | * CLK_PPMULCD0 [5] | |
1150 | * Gating all clocks for FIMD0 | |
1151 | */ | |
e25bfecf | 1152 | setbits_le32(&clk->gate_ip_disp1, 1 << 0); |
2c5cd25c DL |
1153 | |
1154 | /* | |
1155 | * CLK_DIV_LCD0 | |
1156 | * FIMD0_RATIO [3:0] | |
1157 | * MDNIE0_RATIO [7:4] | |
1158 | * MDNIE_PWM0_RATIO [11:8] | |
1159 | * MDNIE_PWM_PRE_RATIO [15:12] | |
1160 | * MIPI0_RATIO [19:16] | |
1161 | * MIPI0_PRE_RATIO [23:20] | |
1162 | * set fimd ratio | |
1163 | */ | |
e25bfecf | 1164 | clrsetbits_le32(&clk->div_disp1_0, 0xf, 0x0); |
2c5cd25c DL |
1165 | } |
1166 | ||
496f0e47 AK |
1167 | void exynos5420_set_lcd_clk(void) |
1168 | { | |
1169 | struct exynos5420_clock *clk = | |
1170 | (struct exynos5420_clock *)samsung_get_base_clock(); | |
1171 | unsigned int cfg; | |
1172 | ||
1173 | /* | |
1174 | * CLK_SRC_DISP10 | |
1175 | * FIMD1_SEL [4] | |
1176 | * 0: SCLK_RPLL | |
1177 | * 1: SCLK_SPLL | |
1178 | */ | |
1179 | cfg = readl(&clk->src_disp10); | |
1180 | cfg &= ~(0x1 << 4); | |
1181 | cfg |= (0 << 4); | |
1182 | writel(cfg, &clk->src_disp10); | |
1183 | ||
1184 | /* | |
1185 | * CLK_DIV_DISP10 | |
1186 | * FIMD1_RATIO [3:0] | |
1187 | */ | |
1188 | cfg = readl(&clk->div_disp10); | |
1189 | cfg &= ~(0xf << 0); | |
1190 | cfg |= (0 << 0); | |
1191 | writel(cfg, &clk->div_disp10); | |
1192 | } | |
1193 | ||
70b4fb66 AK |
1194 | void exynos5800_set_lcd_clk(void) |
1195 | { | |
1196 | struct exynos5420_clock *clk = | |
1197 | (struct exynos5420_clock *)samsung_get_base_clock(); | |
1198 | unsigned int cfg; | |
1199 | ||
1200 | /* | |
1201 | * Use RPLL for pixel clock | |
1202 | * CLK_SRC_DISP10 CLKMUX_FIMD1 [6:4] | |
1203 | * ================== | |
1204 | * 111: SCLK_RPLL | |
1205 | */ | |
1206 | cfg = readl(&clk->src_disp10) | (0x7 << 4); | |
1207 | writel(cfg, &clk->src_disp10); | |
1208 | ||
1209 | /* | |
1210 | * CLK_DIV_DISP10 | |
1211 | * FIMD1_RATIO [3:0] | |
1212 | */ | |
1213 | clrsetbits_le32(&clk->div_disp10, 0xf << 0, 0x0 << 0); | |
1214 | } | |
1215 | ||
37835d4b DL |
1216 | void exynos4_set_mipi_clk(void) |
1217 | { | |
1218 | struct exynos4_clock *clk = | |
1219 | (struct exynos4_clock *)samsung_get_base_clock(); | |
37835d4b DL |
1220 | |
1221 | /* | |
1222 | * CLK_SRC_LCD0 | |
1223 | * FIMD0_SEL [3:0] | |
1224 | * MDNIE0_SEL [7:4] | |
1225 | * MDNIE_PWM0_SEL [8:11] | |
1226 | * MIPI0_SEL [12:15] | |
1227 | * set mipi0 src clock 0x6: SCLK_MPLL | |
1228 | */ | |
e25bfecf | 1229 | clrsetbits_le32(&clk->src_lcd0, 0xf << 12, 0x6 << 12); |
37835d4b DL |
1230 | |
1231 | /* | |
1232 | * CLK_SRC_MASK_LCD0 | |
1233 | * FIMD0_MASK [0] | |
1234 | * MDNIE0_MASK [4] | |
1235 | * MDNIE_PWM0_MASK [8] | |
1236 | * MIPI0_MASK [12] | |
1237 | * set src mask mipi0 0x1: Unmask | |
1238 | */ | |
e25bfecf | 1239 | setbits_le32(&clk->src_mask_lcd0, 0x1 << 12); |
37835d4b DL |
1240 | |
1241 | /* | |
1242 | * CLK_GATE_IP_LCD0 | |
1243 | * CLK_FIMD0 [0] | |
1244 | * CLK_MIE0 [1] | |
1245 | * CLK_MDNIE0 [2] | |
1246 | * CLK_DSIM0 [3] | |
1247 | * CLK_SMMUFIMD0 [4] | |
1248 | * CLK_PPMULCD0 [5] | |
1249 | * Gating all clocks for MIPI0 | |
1250 | */ | |
e25bfecf | 1251 | setbits_le32(&clk->gate_ip_lcd0, 1 << 3); |
37835d4b DL |
1252 | |
1253 | /* | |
1254 | * CLK_DIV_LCD0 | |
1255 | * FIMD0_RATIO [3:0] | |
1256 | * MDNIE0_RATIO [7:4] | |
1257 | * MDNIE_PWM0_RATIO [11:8] | |
1258 | * MDNIE_PWM_PRE_RATIO [15:12] | |
1259 | * MIPI0_RATIO [19:16] | |
1260 | * MIPI0_PRE_RATIO [23:20] | |
1261 | * set mipi ratio | |
1262 | */ | |
e25bfecf | 1263 | clrsetbits_le32(&clk->div_lcd0, 0xf << 16, 0x1 << 16); |
37835d4b DL |
1264 | } |
1265 | ||
2e206caa RS |
1266 | int exynos5_set_epll_clk(unsigned long rate) |
1267 | { | |
1268 | unsigned int epll_con, epll_con_k; | |
1269 | unsigned int i; | |
1270 | unsigned int lockcnt; | |
1271 | unsigned int start; | |
1272 | struct exynos5_clock *clk = | |
1273 | (struct exynos5_clock *)samsung_get_base_clock(); | |
1274 | ||
1275 | epll_con = readl(&clk->epll_con0); | |
1276 | epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK << | |
1277 | EPLL_CON0_LOCK_DET_EN_SHIFT) | | |
1278 | EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT | | |
1279 | EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT | | |
1280 | EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT); | |
1281 | ||
1282 | for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) { | |
1283 | if (exynos5_epll_div[i].freq_out == rate) | |
1284 | break; | |
1285 | } | |
1286 | ||
1287 | if (i == ARRAY_SIZE(exynos5_epll_div)) | |
1288 | return -1; | |
1289 | ||
1290 | epll_con_k = exynos5_epll_div[i].k_dsm << 0; | |
1291 | epll_con |= exynos5_epll_div[i].en_lock_det << | |
1292 | EPLL_CON0_LOCK_DET_EN_SHIFT; | |
1293 | epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT; | |
1294 | epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT; | |
1295 | epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT; | |
1296 | ||
1297 | /* | |
1298 | * Required period ( in cycles) to genarate a stable clock output. | |
1299 | * The maximum clock time can be up to 3000 * PDIV cycles of PLLs | |
1300 | * frequency input (as per spec) | |
1301 | */ | |
1302 | lockcnt = 3000 * exynos5_epll_div[i].p_div; | |
1303 | ||
1304 | writel(lockcnt, &clk->epll_lock); | |
1305 | writel(epll_con, &clk->epll_con0); | |
1306 | writel(epll_con_k, &clk->epll_con1); | |
1307 | ||
1308 | start = get_timer(0); | |
1309 | ||
1310 | while (!(readl(&clk->epll_con0) & | |
1311 | (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) { | |
1312 | if (get_timer(start) > TIMEOUT_EPLL_LOCK) { | |
1313 | debug("%s: Timeout waiting for EPLL lock\n", __func__); | |
1314 | return -1; | |
1315 | } | |
1316 | } | |
1317 | return 0; | |
1318 | } | |
1319 | ||
3dd22a37 | 1320 | int exynos5_set_i2s_clk_source(unsigned int i2s_id) |
2e206caa RS |
1321 | { |
1322 | struct exynos5_clock *clk = | |
1323 | (struct exynos5_clock *)samsung_get_base_clock(); | |
3dd22a37 DKM |
1324 | unsigned int *audio_ass = (unsigned int *)samsung_get_base_audio_ass(); |
1325 | ||
1326 | if (i2s_id == 0) { | |
1327 | setbits_le32(&clk->src_top2, CLK_SRC_MOUT_EPLL); | |
1328 | clrsetbits_le32(&clk->src_mau, AUDIO0_SEL_MASK, | |
1329 | (CLK_SRC_SCLK_EPLL)); | |
1330 | setbits_le32(audio_ass, AUDIO_CLKMUX_ASS); | |
1331 | } else if (i2s_id == 1) { | |
1332 | clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK, | |
1333 | (CLK_SRC_SCLK_EPLL)); | |
1334 | } else { | |
1335 | return -1; | |
1336 | } | |
1337 | return 0; | |
2e206caa RS |
1338 | } |
1339 | ||
1340 | int exynos5_set_i2s_clk_prescaler(unsigned int src_frq, | |
3dd22a37 DKM |
1341 | unsigned int dst_frq, |
1342 | unsigned int i2s_id) | |
2e206caa RS |
1343 | { |
1344 | struct exynos5_clock *clk = | |
1345 | (struct exynos5_clock *)samsung_get_base_clock(); | |
1346 | unsigned int div; | |
1347 | ||
1348 | if ((dst_frq == 0) || (src_frq == 0)) { | |
1349 | debug("%s: Invalid requency input for prescaler\n", __func__); | |
1350 | debug("src frq = %d des frq = %d ", src_frq, dst_frq); | |
1351 | return -1; | |
1352 | } | |
1353 | ||
1354 | div = (src_frq / dst_frq); | |
3dd22a37 DKM |
1355 | if (i2s_id == 0) { |
1356 | if (div > AUDIO_0_RATIO_MASK) { | |
1357 | debug("%s: Frequency ratio is out of range\n", | |
1358 | __func__); | |
1359 | debug("src frq = %d des frq = %d ", src_frq, dst_frq); | |
1360 | return -1; | |
1361 | } | |
1362 | clrsetbits_le32(&clk->div_mau, AUDIO_0_RATIO_MASK, | |
1363 | (div & AUDIO_0_RATIO_MASK)); | |
cf852027 | 1364 | } else if (i2s_id == 1) { |
3dd22a37 DKM |
1365 | if (div > AUDIO_1_RATIO_MASK) { |
1366 | debug("%s: Frequency ratio is out of range\n", | |
1367 | __func__); | |
1368 | debug("src frq = %d des frq = %d ", src_frq, dst_frq); | |
1369 | return -1; | |
1370 | } | |
1371 | clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, | |
1372 | (div & AUDIO_1_RATIO_MASK)); | |
1373 | } else { | |
2e206caa RS |
1374 | return -1; |
1375 | } | |
2e206caa RS |
1376 | return 0; |
1377 | } | |
1378 | ||
b56b3042 HR |
1379 | /** |
1380 | * Linearly searches for the most accurate main and fine stage clock scalars | |
1381 | * (divisors) for a specified target frequency and scalar bit sizes by checking | |
1382 | * all multiples of main_scalar_bits values. Will always return scalars up to or | |
1383 | * slower than target. | |
1384 | * | |
1385 | * @param main_scalar_bits Number of main scalar bits, must be > 0 and < 32 | |
1386 | * @param fine_scalar_bits Number of fine scalar bits, must be > 0 and < 32 | |
1387 | * @param input_freq Clock frequency to be scaled in Hz | |
1388 | * @param target_freq Desired clock frequency in Hz | |
1389 | * @param best_fine_scalar Pointer to store the fine stage divisor | |
1390 | * | |
1391 | * @return best_main_scalar Main scalar for desired frequency or -1 if none | |
1392 | * found | |
1393 | */ | |
1394 | static int clock_calc_best_scalar(unsigned int main_scaler_bits, | |
1395 | unsigned int fine_scalar_bits, unsigned int input_rate, | |
1396 | unsigned int target_rate, unsigned int *best_fine_scalar) | |
1397 | { | |
1398 | int i; | |
1399 | int best_main_scalar = -1; | |
1400 | unsigned int best_error = target_rate; | |
1401 | const unsigned int cap = (1 << fine_scalar_bits) - 1; | |
1402 | const unsigned int loops = 1 << main_scaler_bits; | |
1403 | ||
1404 | debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate, | |
1405 | target_rate, cap); | |
1406 | ||
1407 | assert(best_fine_scalar != NULL); | |
1408 | assert(main_scaler_bits <= fine_scalar_bits); | |
1409 | ||
1410 | *best_fine_scalar = 1; | |
1411 | ||
1412 | if (input_rate == 0 || target_rate == 0) | |
1413 | return -1; | |
1414 | ||
1415 | if (target_rate >= input_rate) | |
1416 | return 1; | |
1417 | ||
1418 | for (i = 1; i <= loops; i++) { | |
b4141195 MY |
1419 | const unsigned int effective_div = |
1420 | max(min(input_rate / i / target_rate, cap), 1U); | |
b56b3042 HR |
1421 | const unsigned int effective_rate = input_rate / i / |
1422 | effective_div; | |
1423 | const int error = target_rate - effective_rate; | |
1424 | ||
1425 | debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div, | |
1426 | effective_rate, error); | |
1427 | ||
1428 | if (error >= 0 && error <= best_error) { | |
1429 | best_error = error; | |
1430 | best_main_scalar = i; | |
1431 | *best_fine_scalar = effective_div; | |
1432 | } | |
1433 | } | |
1434 | ||
1435 | return best_main_scalar; | |
1436 | } | |
1437 | ||
1438 | static int exynos5_set_spi_clk(enum periph_id periph_id, | |
1439 | unsigned int rate) | |
1440 | { | |
1441 | struct exynos5_clock *clk = | |
1442 | (struct exynos5_clock *)samsung_get_base_clock(); | |
1443 | int main; | |
1444 | unsigned int fine; | |
1445 | unsigned shift, pre_shift; | |
1446 | unsigned mask = 0xff; | |
1447 | u32 *reg; | |
1448 | ||
1449 | main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); | |
1450 | if (main < 0) { | |
1451 | debug("%s: Cannot set clock rate for periph %d", | |
1452 | __func__, periph_id); | |
1453 | return -1; | |
1454 | } | |
1455 | main = main - 1; | |
1456 | fine = fine - 1; | |
1457 | ||
1458 | switch (periph_id) { | |
1459 | case PERIPH_ID_SPI0: | |
1460 | reg = &clk->div_peric1; | |
1461 | shift = 0; | |
1462 | pre_shift = 8; | |
1463 | break; | |
1464 | case PERIPH_ID_SPI1: | |
1465 | reg = &clk->div_peric1; | |
1466 | shift = 16; | |
1467 | pre_shift = 24; | |
1468 | break; | |
1469 | case PERIPH_ID_SPI2: | |
1470 | reg = &clk->div_peric2; | |
1471 | shift = 0; | |
1472 | pre_shift = 8; | |
1473 | break; | |
1474 | case PERIPH_ID_SPI3: | |
1475 | reg = &clk->sclk_div_isp; | |
1476 | shift = 0; | |
1477 | pre_shift = 4; | |
1478 | break; | |
1479 | case PERIPH_ID_SPI4: | |
1480 | reg = &clk->sclk_div_isp; | |
1481 | shift = 12; | |
1482 | pre_shift = 16; | |
1483 | break; | |
1484 | default: | |
1485 | debug("%s: Unsupported peripheral ID %d\n", __func__, | |
1486 | periph_id); | |
1487 | return -1; | |
1488 | } | |
1489 | clrsetbits_le32(reg, mask << shift, (main & mask) << shift); | |
1490 | clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift); | |
1491 | ||
1492 | return 0; | |
1493 | } | |
1494 | ||
060c227a RS |
1495 | static int exynos5420_set_spi_clk(enum periph_id periph_id, |
1496 | unsigned int rate) | |
1497 | { | |
1498 | struct exynos5420_clock *clk = | |
1499 | (struct exynos5420_clock *)samsung_get_base_clock(); | |
1500 | int main; | |
1501 | unsigned int fine; | |
1502 | unsigned shift, pre_shift; | |
1503 | unsigned div_mask = 0xf, pre_div_mask = 0xff; | |
1504 | u32 *reg; | |
1505 | u32 *pre_reg; | |
1506 | ||
1507 | main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); | |
1508 | if (main < 0) { | |
1509 | debug("%s: Cannot set clock rate for periph %d", | |
1510 | __func__, periph_id); | |
1511 | return -1; | |
1512 | } | |
1513 | main = main - 1; | |
1514 | fine = fine - 1; | |
1515 | ||
1516 | switch (periph_id) { | |
1517 | case PERIPH_ID_SPI0: | |
1518 | reg = &clk->div_peric1; | |
1519 | shift = 20; | |
1520 | pre_reg = &clk->div_peric4; | |
1521 | pre_shift = 8; | |
1522 | break; | |
1523 | case PERIPH_ID_SPI1: | |
1524 | reg = &clk->div_peric1; | |
1525 | shift = 24; | |
1526 | pre_reg = &clk->div_peric4; | |
1527 | pre_shift = 16; | |
1528 | break; | |
1529 | case PERIPH_ID_SPI2: | |
1530 | reg = &clk->div_peric1; | |
1531 | shift = 28; | |
1532 | pre_reg = &clk->div_peric4; | |
1533 | pre_shift = 24; | |
1534 | break; | |
1535 | case PERIPH_ID_SPI3: | |
1536 | reg = &clk->div_isp1; | |
1537 | shift = 16; | |
1538 | pre_reg = &clk->div_isp1; | |
1539 | pre_shift = 0; | |
1540 | break; | |
1541 | case PERIPH_ID_SPI4: | |
1542 | reg = &clk->div_isp1; | |
1543 | shift = 20; | |
1544 | pre_reg = &clk->div_isp1; | |
1545 | pre_shift = 8; | |
1546 | break; | |
1547 | default: | |
1548 | debug("%s: Unsupported peripheral ID %d\n", __func__, | |
1549 | periph_id); | |
1550 | return -1; | |
1551 | } | |
1552 | ||
1553 | clrsetbits_le32(reg, div_mask << shift, (main & div_mask) << shift); | |
1554 | clrsetbits_le32(pre_reg, pre_div_mask << pre_shift, | |
1555 | (fine & pre_div_mask) << pre_shift); | |
1556 | ||
1557 | return 0; | |
1558 | } | |
1559 | ||
83d745dd PW |
1560 | static unsigned long exynos4_get_i2c_clk(void) |
1561 | { | |
1562 | struct exynos4_clock *clk = | |
1563 | (struct exynos4_clock *)samsung_get_base_clock(); | |
1564 | unsigned long sclk, aclk_100; | |
1565 | unsigned int ratio; | |
1566 | ||
1567 | sclk = get_pll_clk(APLL); | |
1568 | ||
1569 | ratio = (readl(&clk->div_top)) >> 4; | |
1570 | ratio &= 0xf; | |
1571 | aclk_100 = sclk / (ratio + 1); | |
1572 | return aclk_100; | |
b56b3042 HR |
1573 | } |
1574 | ||
008a351a MK |
1575 | unsigned long get_pll_clk(int pllreg) |
1576 | { | |
060c227a | 1577 | if (cpu_is_exynos5()) { |
d64c8ade | 1578 | if (proid_is_exynos5420() || proid_is_exynos5422()) |
325eb18c | 1579 | return exynos542x_get_pll_clk(pllreg); |
37bb6d89 | 1580 | return exynos5_get_pll_clk(pllreg); |
cf852027 | 1581 | } else if (cpu_is_exynos4()) { |
a5277573 CK |
1582 | if (proid_is_exynos4412()) |
1583 | return exynos4x12_get_pll_clk(pllreg); | |
37bb6d89 | 1584 | return exynos4_get_pll_clk(pllreg); |
a5277573 | 1585 | } |
cf852027 MK |
1586 | |
1587 | return 0; | |
008a351a MK |
1588 | } |
1589 | ||
1590 | unsigned long get_arm_clk(void) | |
1591 | { | |
cf852027 | 1592 | if (cpu_is_exynos5()) { |
37bb6d89 | 1593 | return exynos5_get_arm_clk(); |
cf852027 | 1594 | } else if (cpu_is_exynos4()) { |
a5277573 CK |
1595 | if (proid_is_exynos4412()) |
1596 | return exynos4x12_get_arm_clk(); | |
37bb6d89 | 1597 | return exynos4_get_arm_clk(); |
a5277573 | 1598 | } |
cf852027 MK |
1599 | |
1600 | return 0; | |
008a351a MK |
1601 | } |
1602 | ||
989feb8c RS |
1603 | unsigned long get_i2c_clk(void) |
1604 | { | |
cf852027 | 1605 | if (cpu_is_exynos5()) |
d9527968 | 1606 | return clock_get_periph_rate(PERIPH_ID_I2C0); |
cf852027 | 1607 | else if (cpu_is_exynos4()) |
83d745dd | 1608 | return exynos4_get_i2c_clk(); |
cf852027 MK |
1609 | |
1610 | return 0; | |
989feb8c RS |
1611 | } |
1612 | ||
008a351a MK |
1613 | unsigned long get_pwm_clk(void) |
1614 | { | |
060c227a | 1615 | if (cpu_is_exynos5()) { |
e2338704 | 1616 | return clock_get_periph_rate(PERIPH_ID_PWM0); |
cf852027 | 1617 | } else if (cpu_is_exynos4()) { |
a5277573 CK |
1618 | if (proid_is_exynos4412()) |
1619 | return exynos4x12_get_pwm_clk(); | |
37bb6d89 | 1620 | return exynos4_get_pwm_clk(); |
a5277573 | 1621 | } |
cf852027 MK |
1622 | |
1623 | return 0; | |
008a351a MK |
1624 | } |
1625 | ||
1626 | unsigned long get_uart_clk(int dev_index) | |
1627 | { | |
d9527968 AS |
1628 | enum periph_id id; |
1629 | ||
1630 | switch (dev_index) { | |
1631 | case 0: | |
1632 | id = PERIPH_ID_UART0; | |
1633 | break; | |
1634 | case 1: | |
1635 | id = PERIPH_ID_UART1; | |
1636 | break; | |
1637 | case 2: | |
1638 | id = PERIPH_ID_UART2; | |
1639 | break; | |
1640 | case 3: | |
1641 | id = PERIPH_ID_UART3; | |
1642 | break; | |
1643 | default: | |
1644 | debug("%s: invalid UART index %d", __func__, dev_index); | |
1645 | return -1; | |
1646 | } | |
1647 | ||
060c227a | 1648 | if (cpu_is_exynos5()) { |
d9527968 | 1649 | return clock_get_periph_rate(id); |
cf852027 | 1650 | } else if (cpu_is_exynos4()) { |
a5277573 CK |
1651 | if (proid_is_exynos4412()) |
1652 | return exynos4x12_get_uart_clk(dev_index); | |
37bb6d89 | 1653 | return exynos4_get_uart_clk(dev_index); |
a5277573 | 1654 | } |
cf852027 MK |
1655 | |
1656 | return 0; | |
008a351a | 1657 | } |
68a8cbfa | 1658 | |
c39e969e JC |
1659 | unsigned long get_mmc_clk(int dev_index) |
1660 | { | |
d9527968 AS |
1661 | enum periph_id id; |
1662 | ||
7241df1c PM |
1663 | if (cpu_is_exynos4()) |
1664 | return exynos4_get_mmc_clk(dev_index); | |
1665 | ||
d9527968 AS |
1666 | switch (dev_index) { |
1667 | case 0: | |
1668 | id = PERIPH_ID_SDMMC0; | |
1669 | break; | |
1670 | case 1: | |
1671 | id = PERIPH_ID_SDMMC1; | |
1672 | break; | |
1673 | case 2: | |
1674 | id = PERIPH_ID_SDMMC2; | |
1675 | break; | |
1676 | case 3: | |
1677 | id = PERIPH_ID_SDMMC3; | |
1678 | break; | |
1679 | default: | |
1680 | debug("%s: invalid MMC index %d", __func__, dev_index); | |
1681 | return -1; | |
1682 | } | |
1683 | ||
7241df1c | 1684 | return clock_get_periph_rate(id); |
c39e969e JC |
1685 | } |
1686 | ||
68a8cbfa JC |
1687 | void set_mmc_clk(int dev_index, unsigned int div) |
1688 | { | |
a276172c JC |
1689 | /* If want to set correct value, it needs to substract one from div.*/ |
1690 | if (div > 0) | |
1691 | div -= 1; | |
1692 | ||
060c227a | 1693 | if (cpu_is_exynos5()) { |
d64c8ade | 1694 | if (proid_is_exynos5420() || proid_is_exynos5422()) |
060c227a RS |
1695 | exynos5420_set_mmc_clk(dev_index, div); |
1696 | else | |
1697 | exynos5_set_mmc_clk(dev_index, div); | |
cf852027 | 1698 | } else if (cpu_is_exynos4()) { |
00ee8130 | 1699 | exynos4_set_mmc_clk(dev_index, div); |
a5277573 | 1700 | } |
68a8cbfa | 1701 | } |
37835d4b DL |
1702 | |
1703 | unsigned long get_lcd_clk(void) | |
1704 | { | |
cf852027 | 1705 | if (cpu_is_exynos4()) { |
37835d4b | 1706 | return exynos4_get_lcd_clk(); |
cf852027 | 1707 | } else if (cpu_is_exynos5()) { |
70b4fb66 | 1708 | if (proid_is_exynos5420()) |
496f0e47 | 1709 | return exynos5420_get_lcd_clk(); |
d64c8ade | 1710 | else if (proid_is_exynos5422()) |
70b4fb66 | 1711 | return exynos5800_get_lcd_clk(); |
496f0e47 AK |
1712 | else |
1713 | return exynos5_get_lcd_clk(); | |
1714 | } | |
cf852027 MK |
1715 | |
1716 | return 0; | |
37835d4b DL |
1717 | } |
1718 | ||
1719 | void set_lcd_clk(void) | |
1720 | { | |
cf852027 | 1721 | if (cpu_is_exynos4()) { |
37835d4b | 1722 | exynos4_set_lcd_clk(); |
cf852027 | 1723 | } else if (cpu_is_exynos5()) { |
496f0e47 AK |
1724 | if (proid_is_exynos5250()) |
1725 | exynos5_set_lcd_clk(); | |
70b4fb66 | 1726 | else if (proid_is_exynos5420()) |
496f0e47 | 1727 | exynos5420_set_lcd_clk(); |
70b4fb66 AK |
1728 | else |
1729 | exynos5800_set_lcd_clk(); | |
496f0e47 | 1730 | } |
37835d4b DL |
1731 | } |
1732 | ||
1733 | void set_mipi_clk(void) | |
1734 | { | |
1735 | if (cpu_is_exynos4()) | |
1736 | exynos4_set_mipi_clk(); | |
1737 | } | |
2e206caa | 1738 | |
b56b3042 HR |
1739 | int set_spi_clk(int periph_id, unsigned int rate) |
1740 | { | |
060c227a | 1741 | if (cpu_is_exynos5()) { |
d64c8ade | 1742 | if (proid_is_exynos5420() || proid_is_exynos5422()) |
060c227a | 1743 | return exynos5420_set_spi_clk(periph_id, rate); |
b56b3042 | 1744 | return exynos5_set_spi_clk(periph_id, rate); |
060c227a | 1745 | } |
cf852027 MK |
1746 | |
1747 | return 0; | |
b56b3042 HR |
1748 | } |
1749 | ||
3dd22a37 DKM |
1750 | int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq, |
1751 | unsigned int i2s_id) | |
2e206caa | 1752 | { |
2e206caa | 1753 | if (cpu_is_exynos5()) |
3dd22a37 | 1754 | return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq, i2s_id); |
cf852027 MK |
1755 | |
1756 | return 0; | |
2e206caa RS |
1757 | } |
1758 | ||
3dd22a37 | 1759 | int set_i2s_clk_source(unsigned int i2s_id) |
2e206caa RS |
1760 | { |
1761 | if (cpu_is_exynos5()) | |
3dd22a37 | 1762 | return exynos5_set_i2s_clk_source(i2s_id); |
cf852027 MK |
1763 | |
1764 | return 0; | |
2e206caa RS |
1765 | } |
1766 | ||
1767 | int set_epll_clk(unsigned long rate) | |
1768 | { | |
1769 | if (cpu_is_exynos5()) | |
1770 | return exynos5_set_epll_clk(rate); | |
cf852027 MK |
1771 | |
1772 | return 0; | |
2e206caa | 1773 | } |