]>
Commit | Line | Data |
---|---|---|
008a351a MK |
1 | /* |
2 | * Copyright (C) 2010 Samsung Electronics | |
3 | * Minkyu Kang <mk7.kang@samsung.com> | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
008a351a MK |
6 | */ |
7 | ||
8 | #include <common.h> | |
9 | #include <asm/io.h> | |
10 | #include <asm/arch/clock.h> | |
11 | #include <asm/arch/clk.h> | |
b56b3042 | 12 | #include <asm/arch/periph.h> |
008a351a | 13 | |
e161f60f MK |
14 | #define PLL_DIV_1024 1024 |
15 | #define PLL_DIV_65535 65535 | |
16 | #define PLL_DIV_65536 65536 | |
17 | ||
12a46a38 PV |
18 | /* * |
19 | * This structure is to store the src bit, div bit and prediv bit | |
20 | * positions of the peripheral clocks of the src and div registers | |
21 | */ | |
22 | struct clk_bit_info { | |
23 | int8_t src_bit; | |
24 | int8_t div_bit; | |
25 | int8_t prediv_bit; | |
26 | }; | |
27 | ||
28 | /* src_bit div_bit prediv_bit */ | |
29 | static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = { | |
30 | {0, 0, -1}, | |
31 | {4, 4, -1}, | |
32 | {8, 8, -1}, | |
33 | {12, 12, -1}, | |
34 | {0, 0, 8}, | |
35 | {4, 16, 24}, | |
36 | {8, 0, 8}, | |
37 | {12, 16, 24}, | |
38 | {-1, -1, -1}, | |
39 | {16, 0, 8}, | |
40 | {20, 16, 24}, | |
41 | {24, 0, 8}, | |
42 | {0, 0, 4}, | |
43 | {4, 12, 16}, | |
44 | {-1, -1, -1}, | |
45 | {-1, -1, -1}, | |
46 | {-1, 24, 0}, | |
47 | {-1, 24, 0}, | |
48 | {-1, 24, 0}, | |
49 | {-1, 24, 0}, | |
50 | {-1, 24, 0}, | |
51 | {-1, 24, 0}, | |
52 | {-1, 24, 0}, | |
53 | {-1, 24, 0}, | |
54 | {24, 0, -1}, | |
55 | {24, 0, -1}, | |
56 | {24, 0, -1}, | |
57 | {24, 0, -1}, | |
58 | {24, 0, -1}, | |
59 | }; | |
60 | ||
2e206caa RS |
61 | /* Epll Clock division values to achive different frequency output */ |
62 | static struct set_epll_con_val exynos5_epll_div[] = { | |
63 | { 192000000, 0, 48, 3, 1, 0 }, | |
64 | { 180000000, 0, 45, 3, 1, 0 }, | |
65 | { 73728000, 1, 73, 3, 3, 47710 }, | |
66 | { 67737600, 1, 90, 4, 3, 20762 }, | |
67 | { 49152000, 0, 49, 3, 3, 9961 }, | |
68 | { 45158400, 0, 45, 3, 3, 10381 }, | |
69 | { 180633600, 0, 45, 3, 1, 10381 } | |
70 | }; | |
71 | ||
bb6527bc MK |
72 | /* exynos: return pll clock frequency */ |
73 | static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k) | |
008a351a | 74 | { |
bb6527bc | 75 | unsigned long m, p, s = 0, mask, fout; |
e161f60f | 76 | unsigned int div; |
008a351a | 77 | unsigned int freq; |
008a351a MK |
78 | /* |
79 | * APLL_CON: MIDV [25:16] | |
80 | * MPLL_CON: MIDV [25:16] | |
81 | * EPLL_CON: MIDV [24:16] | |
82 | * VPLL_CON: MIDV [24:16] | |
bb6527bc | 83 | * BPLL_CON: MIDV [25:16]: Exynos5 |
008a351a | 84 | */ |
bb6527bc | 85 | if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL) |
008a351a MK |
86 | mask = 0x3ff; |
87 | else | |
88 | mask = 0x1ff; | |
89 | ||
90 | m = (r >> 16) & mask; | |
91 | ||
92 | /* PDIV [13:8] */ | |
93 | p = (r >> 8) & 0x3f; | |
94 | /* SDIV [2:0] */ | |
95 | s = r & 0x7; | |
96 | ||
5e46f83c | 97 | freq = CONFIG_SYS_CLK_FREQ; |
008a351a MK |
98 | |
99 | if (pllreg == EPLL) { | |
100 | k = k & 0xffff; | |
101 | /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */ | |
e161f60f | 102 | fout = (m + k / PLL_DIV_65536) * (freq / (p * (1 << s))); |
008a351a MK |
103 | } else if (pllreg == VPLL) { |
104 | k = k & 0xfff; | |
e161f60f MK |
105 | |
106 | /* | |
107 | * Exynos4210 | |
108 | * FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) | |
109 | * | |
110 | * Exynos4412 | |
111 | * FOUT = (MDIV + K / 65535) * FIN / (PDIV * 2^SDIV) | |
112 | * | |
113 | * Exynos5250 | |
114 | * FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) | |
115 | */ | |
116 | if (proid_is_exynos4210()) | |
117 | div = PLL_DIV_1024; | |
118 | else if (proid_is_exynos4412()) | |
119 | div = PLL_DIV_65535; | |
120 | else if (proid_is_exynos5250()) | |
121 | div = PLL_DIV_65536; | |
122 | else | |
123 | return 0; | |
124 | ||
125 | fout = (m + k / div) * (freq / (p * (1 << s))); | |
008a351a | 126 | } else { |
e161f60f | 127 | /* |
f4eaf88e | 128 | * Exynos4412 / Exynos5250 |
e161f60f MK |
129 | * FOUT = MDIV * FIN / (PDIV * 2^SDIV) |
130 | * | |
f4eaf88e | 131 | * Exynos4210 |
e161f60f MK |
132 | * FOUT = MDIV * FIN / (PDIV * 2^(SDIV-1)) |
133 | */ | |
134 | if (proid_is_exynos4210()) | |
e161f60f | 135 | fout = m * (freq / (p * (1 << (s - 1)))); |
f4eaf88e ŁM |
136 | else |
137 | fout = m * (freq / (p * (1 << s))); | |
008a351a | 138 | } |
008a351a MK |
139 | return fout; |
140 | } | |
141 | ||
bb6527bc MK |
142 | /* exynos4: return pll clock frequency */ |
143 | static unsigned long exynos4_get_pll_clk(int pllreg) | |
144 | { | |
145 | struct exynos4_clock *clk = | |
146 | (struct exynos4_clock *)samsung_get_base_clock(); | |
147 | unsigned long r, k = 0; | |
148 | ||
149 | switch (pllreg) { | |
150 | case APLL: | |
151 | r = readl(&clk->apll_con0); | |
152 | break; | |
153 | case MPLL: | |
154 | r = readl(&clk->mpll_con0); | |
155 | break; | |
156 | case EPLL: | |
157 | r = readl(&clk->epll_con0); | |
158 | k = readl(&clk->epll_con1); | |
159 | break; | |
160 | case VPLL: | |
161 | r = readl(&clk->vpll_con0); | |
162 | k = readl(&clk->vpll_con1); | |
163 | break; | |
164 | default: | |
165 | printf("Unsupported PLL (%d)\n", pllreg); | |
166 | return 0; | |
167 | } | |
168 | ||
169 | return exynos_get_pll_clk(pllreg, r, k); | |
170 | } | |
171 | ||
a5277573 CK |
172 | /* exynos4x12: return pll clock frequency */ |
173 | static unsigned long exynos4x12_get_pll_clk(int pllreg) | |
174 | { | |
175 | struct exynos4x12_clock *clk = | |
176 | (struct exynos4x12_clock *)samsung_get_base_clock(); | |
177 | unsigned long r, k = 0; | |
178 | ||
179 | switch (pllreg) { | |
180 | case APLL: | |
181 | r = readl(&clk->apll_con0); | |
182 | break; | |
183 | case MPLL: | |
184 | r = readl(&clk->mpll_con0); | |
185 | break; | |
186 | case EPLL: | |
187 | r = readl(&clk->epll_con0); | |
188 | k = readl(&clk->epll_con1); | |
189 | break; | |
190 | case VPLL: | |
191 | r = readl(&clk->vpll_con0); | |
192 | k = readl(&clk->vpll_con1); | |
193 | break; | |
194 | default: | |
195 | printf("Unsupported PLL (%d)\n", pllreg); | |
196 | return 0; | |
197 | } | |
198 | ||
199 | return exynos_get_pll_clk(pllreg, r, k); | |
200 | } | |
201 | ||
37bb6d89 CK |
202 | /* exynos5: return pll clock frequency */ |
203 | static unsigned long exynos5_get_pll_clk(int pllreg) | |
204 | { | |
205 | struct exynos5_clock *clk = | |
206 | (struct exynos5_clock *)samsung_get_base_clock(); | |
bb6527bc MK |
207 | unsigned long r, k = 0, fout; |
208 | unsigned int pll_div2_sel, fout_sel; | |
37bb6d89 CK |
209 | |
210 | switch (pllreg) { | |
211 | case APLL: | |
212 | r = readl(&clk->apll_con0); | |
213 | break; | |
214 | case MPLL: | |
215 | r = readl(&clk->mpll_con0); | |
216 | break; | |
217 | case EPLL: | |
218 | r = readl(&clk->epll_con0); | |
219 | k = readl(&clk->epll_con1); | |
220 | break; | |
221 | case VPLL: | |
222 | r = readl(&clk->vpll_con0); | |
223 | k = readl(&clk->vpll_con1); | |
224 | break; | |
10bc1a7f RS |
225 | case BPLL: |
226 | r = readl(&clk->bpll_con0); | |
227 | break; | |
37bb6d89 CK |
228 | default: |
229 | printf("Unsupported PLL (%d)\n", pllreg); | |
230 | return 0; | |
231 | } | |
232 | ||
bb6527bc | 233 | fout = exynos_get_pll_clk(pllreg, r, k); |
37bb6d89 | 234 | |
10bc1a7f | 235 | /* According to the user manual, in EVT1 MPLL and BPLL always gives |
6071bcae | 236 | * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/ |
10bc1a7f | 237 | if (pllreg == MPLL || pllreg == BPLL) { |
6071bcae | 238 | pll_div2_sel = readl(&clk->pll_div2_sel); |
10bc1a7f RS |
239 | |
240 | switch (pllreg) { | |
241 | case MPLL: | |
242 | fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT) | |
243 | & MPLL_FOUT_SEL_MASK; | |
244 | break; | |
245 | case BPLL: | |
246 | fout_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT) | |
247 | & BPLL_FOUT_SEL_MASK; | |
248 | break; | |
f8c5cfad JC |
249 | default: |
250 | fout_sel = -1; | |
251 | break; | |
10bc1a7f RS |
252 | } |
253 | ||
254 | if (fout_sel == 0) | |
6071bcae RS |
255 | fout /= 2; |
256 | } | |
257 | ||
37bb6d89 CK |
258 | return fout; |
259 | } | |
260 | ||
12a46a38 PV |
261 | static unsigned long exynos5_get_periph_rate(int peripheral) |
262 | { | |
263 | struct clk_bit_info *bit_info = &clk_bit_info[peripheral]; | |
264 | unsigned long sclk, sub_clk; | |
265 | unsigned int src, div, sub_div; | |
266 | struct exynos5_clock *clk = | |
267 | (struct exynos5_clock *)samsung_get_base_clock(); | |
268 | ||
269 | switch (peripheral) { | |
270 | case PERIPH_ID_UART0: | |
271 | case PERIPH_ID_UART1: | |
272 | case PERIPH_ID_UART2: | |
273 | case PERIPH_ID_UART3: | |
274 | src = readl(&clk->src_peric0); | |
275 | div = readl(&clk->div_peric0); | |
276 | break; | |
277 | case PERIPH_ID_PWM0: | |
278 | case PERIPH_ID_PWM1: | |
279 | case PERIPH_ID_PWM2: | |
280 | case PERIPH_ID_PWM3: | |
281 | case PERIPH_ID_PWM4: | |
282 | src = readl(&clk->src_peric0); | |
283 | div = readl(&clk->div_peric3); | |
284 | break; | |
285 | case PERIPH_ID_SPI0: | |
286 | case PERIPH_ID_SPI1: | |
287 | src = readl(&clk->src_peric1); | |
288 | div = readl(&clk->div_peric1); | |
289 | break; | |
290 | case PERIPH_ID_SPI2: | |
291 | src = readl(&clk->src_peric1); | |
292 | div = readl(&clk->div_peric2); | |
293 | break; | |
294 | case PERIPH_ID_SPI3: | |
295 | case PERIPH_ID_SPI4: | |
296 | src = readl(&clk->sclk_src_isp); | |
297 | div = readl(&clk->sclk_div_isp); | |
298 | break; | |
299 | case PERIPH_ID_SDMMC0: | |
300 | case PERIPH_ID_SDMMC1: | |
301 | case PERIPH_ID_SDMMC2: | |
302 | case PERIPH_ID_SDMMC3: | |
303 | src = readl(&clk->src_fsys); | |
304 | div = readl(&clk->div_fsys1); | |
305 | break; | |
306 | case PERIPH_ID_I2C0: | |
307 | case PERIPH_ID_I2C1: | |
308 | case PERIPH_ID_I2C2: | |
309 | case PERIPH_ID_I2C3: | |
310 | case PERIPH_ID_I2C4: | |
311 | case PERIPH_ID_I2C5: | |
312 | case PERIPH_ID_I2C6: | |
313 | case PERIPH_ID_I2C7: | |
314 | sclk = exynos5_get_pll_clk(MPLL); | |
315 | sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit) | |
316 | & 0x7) + 1; | |
317 | div = ((readl(&clk->div_top0) >> bit_info->prediv_bit) | |
318 | & 0x7) + 1; | |
319 | return (sclk / sub_div) / div; | |
320 | default: | |
321 | debug("%s: invalid peripheral %d", __func__, peripheral); | |
322 | return -1; | |
323 | }; | |
324 | ||
325 | src = (src >> bit_info->src_bit) & 0xf; | |
326 | ||
327 | switch (src) { | |
328 | case EXYNOS_SRC_MPLL: | |
329 | sclk = exynos5_get_pll_clk(MPLL); | |
330 | break; | |
331 | case EXYNOS_SRC_EPLL: | |
332 | sclk = exynos5_get_pll_clk(EPLL); | |
333 | break; | |
334 | case EXYNOS_SRC_VPLL: | |
335 | sclk = exynos5_get_pll_clk(VPLL); | |
336 | break; | |
337 | default: | |
338 | return 0; | |
339 | } | |
340 | ||
341 | /* Ratio clock division for this peripheral */ | |
342 | sub_div = (div >> bit_info->div_bit) & 0xf; | |
343 | sub_clk = sclk / (sub_div + 1); | |
344 | ||
345 | /* Pre-ratio clock division for SDMMC0 and 2 */ | |
346 | if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) { | |
347 | div = (div >> bit_info->prediv_bit) & 0xff; | |
348 | return sub_clk / (div + 1); | |
349 | } | |
350 | ||
351 | return sub_clk; | |
352 | } | |
353 | ||
354 | unsigned long clock_get_periph_rate(int peripheral) | |
355 | { | |
356 | if (cpu_is_exynos5()) | |
357 | return exynos5_get_periph_rate(peripheral); | |
358 | else | |
359 | return 0; | |
360 | } | |
361 | ||
393cb361 CK |
362 | /* exynos4: return ARM clock frequency */ |
363 | static unsigned long exynos4_get_arm_clk(void) | |
008a351a | 364 | { |
393cb361 CK |
365 | struct exynos4_clock *clk = |
366 | (struct exynos4_clock *)samsung_get_base_clock(); | |
008a351a | 367 | unsigned long div; |
db68bc2c CK |
368 | unsigned long armclk; |
369 | unsigned int core_ratio; | |
370 | unsigned int core2_ratio; | |
008a351a MK |
371 | |
372 | div = readl(&clk->div_cpu0); | |
373 | ||
db68bc2c CK |
374 | /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */ |
375 | core_ratio = (div >> 0) & 0x7; | |
376 | core2_ratio = (div >> 28) & 0x7; | |
008a351a | 377 | |
db68bc2c CK |
378 | armclk = get_pll_clk(APLL) / (core_ratio + 1); |
379 | armclk /= (core2_ratio + 1); | |
008a351a | 380 | |
db68bc2c | 381 | return armclk; |
008a351a MK |
382 | } |
383 | ||
a5277573 CK |
384 | /* exynos4x12: return ARM clock frequency */ |
385 | static unsigned long exynos4x12_get_arm_clk(void) | |
386 | { | |
387 | struct exynos4x12_clock *clk = | |
388 | (struct exynos4x12_clock *)samsung_get_base_clock(); | |
389 | unsigned long div; | |
390 | unsigned long armclk; | |
391 | unsigned int core_ratio; | |
392 | unsigned int core2_ratio; | |
393 | ||
394 | div = readl(&clk->div_cpu0); | |
395 | ||
396 | /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */ | |
397 | core_ratio = (div >> 0) & 0x7; | |
398 | core2_ratio = (div >> 28) & 0x7; | |
399 | ||
400 | armclk = get_pll_clk(APLL) / (core_ratio + 1); | |
401 | armclk /= (core2_ratio + 1); | |
402 | ||
403 | return armclk; | |
404 | } | |
405 | ||
37bb6d89 CK |
406 | /* exynos5: return ARM clock frequency */ |
407 | static unsigned long exynos5_get_arm_clk(void) | |
408 | { | |
409 | struct exynos5_clock *clk = | |
410 | (struct exynos5_clock *)samsung_get_base_clock(); | |
411 | unsigned long div; | |
412 | unsigned long armclk; | |
413 | unsigned int arm_ratio; | |
414 | unsigned int arm2_ratio; | |
415 | ||
416 | div = readl(&clk->div_cpu0); | |
417 | ||
418 | /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */ | |
419 | arm_ratio = (div >> 0) & 0x7; | |
420 | arm2_ratio = (div >> 28) & 0x7; | |
421 | ||
422 | armclk = get_pll_clk(APLL) / (arm_ratio + 1); | |
423 | armclk /= (arm2_ratio + 1); | |
424 | ||
425 | return armclk; | |
426 | } | |
427 | ||
393cb361 CK |
428 | /* exynos4: return pwm clock frequency */ |
429 | static unsigned long exynos4_get_pwm_clk(void) | |
008a351a | 430 | { |
393cb361 CK |
431 | struct exynos4_clock *clk = |
432 | (struct exynos4_clock *)samsung_get_base_clock(); | |
008a351a MK |
433 | unsigned long pclk, sclk; |
434 | unsigned int sel; | |
435 | unsigned int ratio; | |
436 | ||
b4f73910 MK |
437 | if (s5p_get_cpu_rev() == 0) { |
438 | /* | |
439 | * CLK_SRC_PERIL0 | |
440 | * PWM_SEL [27:24] | |
441 | */ | |
442 | sel = readl(&clk->src_peril0); | |
443 | sel = (sel >> 24) & 0xf; | |
444 | ||
445 | if (sel == 0x6) | |
446 | sclk = get_pll_clk(MPLL); | |
447 | else if (sel == 0x7) | |
448 | sclk = get_pll_clk(EPLL); | |
449 | else if (sel == 0x8) | |
450 | sclk = get_pll_clk(VPLL); | |
451 | else | |
452 | return 0; | |
453 | ||
454 | /* | |
455 | * CLK_DIV_PERIL3 | |
456 | * PWM_RATIO [3:0] | |
457 | */ | |
458 | ratio = readl(&clk->div_peril3); | |
459 | ratio = ratio & 0xf; | |
460 | } else if (s5p_get_cpu_rev() == 1) { | |
008a351a | 461 | sclk = get_pll_clk(MPLL); |
b4f73910 MK |
462 | ratio = 8; |
463 | } else | |
008a351a MK |
464 | return 0; |
465 | ||
008a351a MK |
466 | pclk = sclk / (ratio + 1); |
467 | ||
468 | return pclk; | |
469 | } | |
470 | ||
a5277573 CK |
471 | /* exynos4x12: return pwm clock frequency */ |
472 | static unsigned long exynos4x12_get_pwm_clk(void) | |
473 | { | |
474 | unsigned long pclk, sclk; | |
475 | unsigned int ratio; | |
476 | ||
477 | sclk = get_pll_clk(MPLL); | |
478 | ratio = 8; | |
479 | ||
480 | pclk = sclk / (ratio + 1); | |
481 | ||
482 | return pclk; | |
483 | } | |
484 | ||
393cb361 CK |
485 | /* exynos4: return uart clock frequency */ |
486 | static unsigned long exynos4_get_uart_clk(int dev_index) | |
008a351a | 487 | { |
393cb361 CK |
488 | struct exynos4_clock *clk = |
489 | (struct exynos4_clock *)samsung_get_base_clock(); | |
008a351a MK |
490 | unsigned long uclk, sclk; |
491 | unsigned int sel; | |
492 | unsigned int ratio; | |
493 | ||
494 | /* | |
495 | * CLK_SRC_PERIL0 | |
496 | * UART0_SEL [3:0] | |
497 | * UART1_SEL [7:4] | |
498 | * UART2_SEL [8:11] | |
499 | * UART3_SEL [12:15] | |
500 | * UART4_SEL [16:19] | |
501 | * UART5_SEL [23:20] | |
502 | */ | |
503 | sel = readl(&clk->src_peril0); | |
504 | sel = (sel >> (dev_index << 2)) & 0xf; | |
505 | ||
506 | if (sel == 0x6) | |
507 | sclk = get_pll_clk(MPLL); | |
508 | else if (sel == 0x7) | |
509 | sclk = get_pll_clk(EPLL); | |
510 | else if (sel == 0x8) | |
511 | sclk = get_pll_clk(VPLL); | |
512 | else | |
513 | return 0; | |
514 | ||
515 | /* | |
516 | * CLK_DIV_PERIL0 | |
517 | * UART0_RATIO [3:0] | |
518 | * UART1_RATIO [7:4] | |
519 | * UART2_RATIO [8:11] | |
520 | * UART3_RATIO [12:15] | |
521 | * UART4_RATIO [16:19] | |
522 | * UART5_RATIO [23:20] | |
523 | */ | |
524 | ratio = readl(&clk->div_peril0); | |
525 | ratio = (ratio >> (dev_index << 2)) & 0xf; | |
526 | ||
527 | uclk = sclk / (ratio + 1); | |
528 | ||
529 | return uclk; | |
530 | } | |
531 | ||
a5277573 CK |
532 | /* exynos4x12: return uart clock frequency */ |
533 | static unsigned long exynos4x12_get_uart_clk(int dev_index) | |
534 | { | |
535 | struct exynos4x12_clock *clk = | |
536 | (struct exynos4x12_clock *)samsung_get_base_clock(); | |
537 | unsigned long uclk, sclk; | |
538 | unsigned int sel; | |
539 | unsigned int ratio; | |
540 | ||
541 | /* | |
542 | * CLK_SRC_PERIL0 | |
543 | * UART0_SEL [3:0] | |
544 | * UART1_SEL [7:4] | |
545 | * UART2_SEL [8:11] | |
546 | * UART3_SEL [12:15] | |
547 | * UART4_SEL [16:19] | |
548 | */ | |
549 | sel = readl(&clk->src_peril0); | |
550 | sel = (sel >> (dev_index << 2)) & 0xf; | |
551 | ||
552 | if (sel == 0x6) | |
553 | sclk = get_pll_clk(MPLL); | |
554 | else if (sel == 0x7) | |
555 | sclk = get_pll_clk(EPLL); | |
556 | else if (sel == 0x8) | |
557 | sclk = get_pll_clk(VPLL); | |
558 | else | |
559 | return 0; | |
560 | ||
561 | /* | |
562 | * CLK_DIV_PERIL0 | |
563 | * UART0_RATIO [3:0] | |
564 | * UART1_RATIO [7:4] | |
565 | * UART2_RATIO [8:11] | |
566 | * UART3_RATIO [12:15] | |
567 | * UART4_RATIO [16:19] | |
568 | */ | |
569 | ratio = readl(&clk->div_peril0); | |
570 | ratio = (ratio >> (dev_index << 2)) & 0xf; | |
571 | ||
572 | uclk = sclk / (ratio + 1); | |
573 | ||
574 | return uclk; | |
575 | } | |
576 | ||
37bb6d89 CK |
577 | /* exynos5: return uart clock frequency */ |
578 | static unsigned long exynos5_get_uart_clk(int dev_index) | |
579 | { | |
580 | struct exynos5_clock *clk = | |
581 | (struct exynos5_clock *)samsung_get_base_clock(); | |
582 | unsigned long uclk, sclk; | |
583 | unsigned int sel; | |
584 | unsigned int ratio; | |
585 | ||
586 | /* | |
587 | * CLK_SRC_PERIC0 | |
588 | * UART0_SEL [3:0] | |
589 | * UART1_SEL [7:4] | |
590 | * UART2_SEL [8:11] | |
591 | * UART3_SEL [12:15] | |
592 | * UART4_SEL [16:19] | |
593 | * UART5_SEL [23:20] | |
594 | */ | |
595 | sel = readl(&clk->src_peric0); | |
596 | sel = (sel >> (dev_index << 2)) & 0xf; | |
597 | ||
598 | if (sel == 0x6) | |
599 | sclk = get_pll_clk(MPLL); | |
600 | else if (sel == 0x7) | |
601 | sclk = get_pll_clk(EPLL); | |
602 | else if (sel == 0x8) | |
603 | sclk = get_pll_clk(VPLL); | |
604 | else | |
605 | return 0; | |
606 | ||
607 | /* | |
608 | * CLK_DIV_PERIC0 | |
609 | * UART0_RATIO [3:0] | |
610 | * UART1_RATIO [7:4] | |
611 | * UART2_RATIO [8:11] | |
612 | * UART3_RATIO [12:15] | |
613 | * UART4_RATIO [16:19] | |
614 | * UART5_RATIO [23:20] | |
615 | */ | |
616 | ratio = readl(&clk->div_peric0); | |
617 | ratio = (ratio >> (dev_index << 2)) & 0xf; | |
618 | ||
619 | uclk = sclk / (ratio + 1); | |
620 | ||
621 | return uclk; | |
622 | } | |
623 | ||
c39e969e JC |
624 | static unsigned long exynos4_get_mmc_clk(int dev_index) |
625 | { | |
626 | struct exynos4_clock *clk = | |
627 | (struct exynos4_clock *)samsung_get_base_clock(); | |
628 | unsigned long uclk, sclk; | |
629 | unsigned int sel, ratio, pre_ratio; | |
2b81c26b | 630 | int shift = 0; |
c39e969e JC |
631 | |
632 | sel = readl(&clk->src_fsys); | |
633 | sel = (sel >> (dev_index << 2)) & 0xf; | |
634 | ||
635 | if (sel == 0x6) | |
636 | sclk = get_pll_clk(MPLL); | |
637 | else if (sel == 0x7) | |
638 | sclk = get_pll_clk(EPLL); | |
639 | else if (sel == 0x8) | |
640 | sclk = get_pll_clk(VPLL); | |
641 | else | |
642 | return 0; | |
643 | ||
644 | switch (dev_index) { | |
645 | case 0: | |
646 | case 1: | |
647 | ratio = readl(&clk->div_fsys1); | |
648 | pre_ratio = readl(&clk->div_fsys1); | |
649 | break; | |
650 | case 2: | |
651 | case 3: | |
652 | ratio = readl(&clk->div_fsys2); | |
653 | pre_ratio = readl(&clk->div_fsys2); | |
654 | break; | |
655 | case 4: | |
656 | ratio = readl(&clk->div_fsys3); | |
657 | pre_ratio = readl(&clk->div_fsys3); | |
658 | break; | |
659 | default: | |
660 | return 0; | |
661 | } | |
662 | ||
663 | if (dev_index == 1 || dev_index == 3) | |
664 | shift = 16; | |
665 | ||
666 | ratio = (ratio >> shift) & 0xf; | |
667 | pre_ratio = (pre_ratio >> (shift + 8)) & 0xff; | |
668 | uclk = (sclk / (ratio + 1)) / (pre_ratio + 1); | |
669 | ||
670 | return uclk; | |
671 | } | |
672 | ||
673 | static unsigned long exynos5_get_mmc_clk(int dev_index) | |
674 | { | |
675 | struct exynos5_clock *clk = | |
676 | (struct exynos5_clock *)samsung_get_base_clock(); | |
677 | unsigned long uclk, sclk; | |
678 | unsigned int sel, ratio, pre_ratio; | |
2b81c26b | 679 | int shift = 0; |
c39e969e JC |
680 | |
681 | sel = readl(&clk->src_fsys); | |
682 | sel = (sel >> (dev_index << 2)) & 0xf; | |
683 | ||
684 | if (sel == 0x6) | |
685 | sclk = get_pll_clk(MPLL); | |
686 | else if (sel == 0x7) | |
687 | sclk = get_pll_clk(EPLL); | |
688 | else if (sel == 0x8) | |
689 | sclk = get_pll_clk(VPLL); | |
690 | else | |
691 | return 0; | |
692 | ||
693 | switch (dev_index) { | |
694 | case 0: | |
695 | case 1: | |
696 | ratio = readl(&clk->div_fsys1); | |
697 | pre_ratio = readl(&clk->div_fsys1); | |
698 | break; | |
699 | case 2: | |
700 | case 3: | |
701 | ratio = readl(&clk->div_fsys2); | |
702 | pre_ratio = readl(&clk->div_fsys2); | |
703 | break; | |
704 | default: | |
705 | return 0; | |
706 | } | |
707 | ||
708 | if (dev_index == 1 || dev_index == 3) | |
709 | shift = 16; | |
710 | ||
711 | ratio = (ratio >> shift) & 0xf; | |
712 | pre_ratio = (pre_ratio >> (shift + 8)) & 0xff; | |
713 | uclk = (sclk / (ratio + 1)) / (pre_ratio + 1); | |
714 | ||
715 | return uclk; | |
716 | } | |
717 | ||
393cb361 CK |
718 | /* exynos4: set the mmc clock */ |
719 | static void exynos4_set_mmc_clk(int dev_index, unsigned int div) | |
68a8cbfa | 720 | { |
393cb361 CK |
721 | struct exynos4_clock *clk = |
722 | (struct exynos4_clock *)samsung_get_base_clock(); | |
68a8cbfa JC |
723 | unsigned int addr; |
724 | unsigned int val; | |
725 | ||
726 | /* | |
727 | * CLK_DIV_FSYS1 | |
728 | * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24] | |
729 | * CLK_DIV_FSYS2 | |
730 | * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24] | |
5374d386 JC |
731 | * CLK_DIV_FSYS3 |
732 | * MMC4_PRE_RATIO [15:8] | |
68a8cbfa JC |
733 | */ |
734 | if (dev_index < 2) { | |
735 | addr = (unsigned int)&clk->div_fsys1; | |
5374d386 JC |
736 | } else if (dev_index == 4) { |
737 | addr = (unsigned int)&clk->div_fsys3; | |
738 | dev_index -= 4; | |
68a8cbfa JC |
739 | } else { |
740 | addr = (unsigned int)&clk->div_fsys2; | |
741 | dev_index -= 2; | |
742 | } | |
743 | ||
744 | val = readl(addr); | |
745 | val &= ~(0xff << ((dev_index << 4) + 8)); | |
746 | val |= (div & 0xff) << ((dev_index << 4) + 8); | |
747 | writel(val, addr); | |
748 | } | |
749 | ||
a5277573 CK |
750 | /* exynos4x12: set the mmc clock */ |
751 | static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div) | |
752 | { | |
753 | struct exynos4x12_clock *clk = | |
754 | (struct exynos4x12_clock *)samsung_get_base_clock(); | |
755 | unsigned int addr; | |
756 | unsigned int val; | |
757 | ||
758 | /* | |
759 | * CLK_DIV_FSYS1 | |
760 | * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24] | |
761 | * CLK_DIV_FSYS2 | |
762 | * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24] | |
763 | */ | |
764 | if (dev_index < 2) { | |
765 | addr = (unsigned int)&clk->div_fsys1; | |
766 | } else { | |
767 | addr = (unsigned int)&clk->div_fsys2; | |
768 | dev_index -= 2; | |
769 | } | |
770 | ||
771 | val = readl(addr); | |
772 | val &= ~(0xff << ((dev_index << 4) + 8)); | |
773 | val |= (div & 0xff) << ((dev_index << 4) + 8); | |
774 | writel(val, addr); | |
775 | } | |
776 | ||
37bb6d89 CK |
777 | /* exynos5: set the mmc clock */ |
778 | static void exynos5_set_mmc_clk(int dev_index, unsigned int div) | |
779 | { | |
780 | struct exynos5_clock *clk = | |
781 | (struct exynos5_clock *)samsung_get_base_clock(); | |
782 | unsigned int addr; | |
783 | unsigned int val; | |
784 | ||
785 | /* | |
786 | * CLK_DIV_FSYS1 | |
787 | * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24] | |
788 | * CLK_DIV_FSYS2 | |
789 | * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24] | |
790 | */ | |
791 | if (dev_index < 2) { | |
792 | addr = (unsigned int)&clk->div_fsys1; | |
793 | } else { | |
794 | addr = (unsigned int)&clk->div_fsys2; | |
795 | dev_index -= 2; | |
796 | } | |
797 | ||
798 | val = readl(addr); | |
799 | val &= ~(0xff << ((dev_index << 4) + 8)); | |
800 | val |= (div & 0xff) << ((dev_index << 4) + 8); | |
801 | writel(val, addr); | |
802 | } | |
803 | ||
37835d4b DL |
804 | /* get_lcd_clk: return lcd clock frequency */ |
805 | static unsigned long exynos4_get_lcd_clk(void) | |
806 | { | |
807 | struct exynos4_clock *clk = | |
808 | (struct exynos4_clock *)samsung_get_base_clock(); | |
809 | unsigned long pclk, sclk; | |
810 | unsigned int sel; | |
811 | unsigned int ratio; | |
812 | ||
813 | /* | |
814 | * CLK_SRC_LCD0 | |
815 | * FIMD0_SEL [3:0] | |
816 | */ | |
817 | sel = readl(&clk->src_lcd0); | |
818 | sel = sel & 0xf; | |
819 | ||
820 | /* | |
821 | * 0x6: SCLK_MPLL | |
822 | * 0x7: SCLK_EPLL | |
823 | * 0x8: SCLK_VPLL | |
824 | */ | |
825 | if (sel == 0x6) | |
826 | sclk = get_pll_clk(MPLL); | |
827 | else if (sel == 0x7) | |
828 | sclk = get_pll_clk(EPLL); | |
829 | else if (sel == 0x8) | |
830 | sclk = get_pll_clk(VPLL); | |
831 | else | |
832 | return 0; | |
833 | ||
834 | /* | |
835 | * CLK_DIV_LCD0 | |
836 | * FIMD0_RATIO [3:0] | |
837 | */ | |
838 | ratio = readl(&clk->div_lcd0); | |
839 | ratio = ratio & 0xf; | |
840 | ||
841 | pclk = sclk / (ratio + 1); | |
842 | ||
843 | return pclk; | |
844 | } | |
845 | ||
2c5cd25c DL |
846 | /* get_lcd_clk: return lcd clock frequency */ |
847 | static unsigned long exynos5_get_lcd_clk(void) | |
848 | { | |
849 | struct exynos5_clock *clk = | |
850 | (struct exynos5_clock *)samsung_get_base_clock(); | |
851 | unsigned long pclk, sclk; | |
852 | unsigned int sel; | |
853 | unsigned int ratio; | |
854 | ||
855 | /* | |
856 | * CLK_SRC_LCD0 | |
857 | * FIMD0_SEL [3:0] | |
858 | */ | |
859 | sel = readl(&clk->src_disp1_0); | |
860 | sel = sel & 0xf; | |
861 | ||
862 | /* | |
863 | * 0x6: SCLK_MPLL | |
864 | * 0x7: SCLK_EPLL | |
865 | * 0x8: SCLK_VPLL | |
866 | */ | |
867 | if (sel == 0x6) | |
868 | sclk = get_pll_clk(MPLL); | |
869 | else if (sel == 0x7) | |
870 | sclk = get_pll_clk(EPLL); | |
871 | else if (sel == 0x8) | |
872 | sclk = get_pll_clk(VPLL); | |
873 | else | |
874 | return 0; | |
875 | ||
876 | /* | |
877 | * CLK_DIV_LCD0 | |
878 | * FIMD0_RATIO [3:0] | |
879 | */ | |
880 | ratio = readl(&clk->div_disp1_0); | |
881 | ratio = ratio & 0xf; | |
882 | ||
883 | pclk = sclk / (ratio + 1); | |
884 | ||
885 | return pclk; | |
886 | } | |
887 | ||
37835d4b DL |
888 | void exynos4_set_lcd_clk(void) |
889 | { | |
890 | struct exynos4_clock *clk = | |
891 | (struct exynos4_clock *)samsung_get_base_clock(); | |
892 | unsigned int cfg = 0; | |
893 | ||
894 | /* | |
895 | * CLK_GATE_BLOCK | |
896 | * CLK_CAM [0] | |
897 | * CLK_TV [1] | |
898 | * CLK_MFC [2] | |
899 | * CLK_G3D [3] | |
900 | * CLK_LCD0 [4] | |
901 | * CLK_LCD1 [5] | |
902 | * CLK_GPS [7] | |
903 | */ | |
904 | cfg = readl(&clk->gate_block); | |
905 | cfg |= 1 << 4; | |
906 | writel(cfg, &clk->gate_block); | |
907 | ||
908 | /* | |
909 | * CLK_SRC_LCD0 | |
910 | * FIMD0_SEL [3:0] | |
911 | * MDNIE0_SEL [7:4] | |
912 | * MDNIE_PWM0_SEL [8:11] | |
913 | * MIPI0_SEL [12:15] | |
914 | * set lcd0 src clock 0x6: SCLK_MPLL | |
915 | */ | |
916 | cfg = readl(&clk->src_lcd0); | |
917 | cfg &= ~(0xf); | |
918 | cfg |= 0x6; | |
919 | writel(cfg, &clk->src_lcd0); | |
920 | ||
921 | /* | |
922 | * CLK_GATE_IP_LCD0 | |
923 | * CLK_FIMD0 [0] | |
924 | * CLK_MIE0 [1] | |
925 | * CLK_MDNIE0 [2] | |
926 | * CLK_DSIM0 [3] | |
927 | * CLK_SMMUFIMD0 [4] | |
928 | * CLK_PPMULCD0 [5] | |
929 | * Gating all clocks for FIMD0 | |
930 | */ | |
931 | cfg = readl(&clk->gate_ip_lcd0); | |
932 | cfg |= 1 << 0; | |
933 | writel(cfg, &clk->gate_ip_lcd0); | |
934 | ||
935 | /* | |
936 | * CLK_DIV_LCD0 | |
937 | * FIMD0_RATIO [3:0] | |
938 | * MDNIE0_RATIO [7:4] | |
939 | * MDNIE_PWM0_RATIO [11:8] | |
940 | * MDNIE_PWM_PRE_RATIO [15:12] | |
941 | * MIPI0_RATIO [19:16] | |
942 | * MIPI0_PRE_RATIO [23:20] | |
943 | * set fimd ratio | |
944 | */ | |
945 | cfg &= ~(0xf); | |
946 | cfg |= 0x1; | |
947 | writel(cfg, &clk->div_lcd0); | |
948 | } | |
949 | ||
2c5cd25c DL |
950 | void exynos5_set_lcd_clk(void) |
951 | { | |
952 | struct exynos5_clock *clk = | |
953 | (struct exynos5_clock *)samsung_get_base_clock(); | |
954 | unsigned int cfg = 0; | |
955 | ||
956 | /* | |
957 | * CLK_GATE_BLOCK | |
958 | * CLK_CAM [0] | |
959 | * CLK_TV [1] | |
960 | * CLK_MFC [2] | |
961 | * CLK_G3D [3] | |
962 | * CLK_LCD0 [4] | |
963 | * CLK_LCD1 [5] | |
964 | * CLK_GPS [7] | |
965 | */ | |
966 | cfg = readl(&clk->gate_block); | |
967 | cfg |= 1 << 4; | |
968 | writel(cfg, &clk->gate_block); | |
969 | ||
970 | /* | |
971 | * CLK_SRC_LCD0 | |
972 | * FIMD0_SEL [3:0] | |
973 | * MDNIE0_SEL [7:4] | |
974 | * MDNIE_PWM0_SEL [8:11] | |
975 | * MIPI0_SEL [12:15] | |
976 | * set lcd0 src clock 0x6: SCLK_MPLL | |
977 | */ | |
978 | cfg = readl(&clk->src_disp1_0); | |
979 | cfg &= ~(0xf); | |
1673f199 | 980 | cfg |= 0x6; |
2c5cd25c DL |
981 | writel(cfg, &clk->src_disp1_0); |
982 | ||
983 | /* | |
984 | * CLK_GATE_IP_LCD0 | |
985 | * CLK_FIMD0 [0] | |
986 | * CLK_MIE0 [1] | |
987 | * CLK_MDNIE0 [2] | |
988 | * CLK_DSIM0 [3] | |
989 | * CLK_SMMUFIMD0 [4] | |
990 | * CLK_PPMULCD0 [5] | |
991 | * Gating all clocks for FIMD0 | |
992 | */ | |
993 | cfg = readl(&clk->gate_ip_disp1); | |
994 | cfg |= 1 << 0; | |
995 | writel(cfg, &clk->gate_ip_disp1); | |
996 | ||
997 | /* | |
998 | * CLK_DIV_LCD0 | |
999 | * FIMD0_RATIO [3:0] | |
1000 | * MDNIE0_RATIO [7:4] | |
1001 | * MDNIE_PWM0_RATIO [11:8] | |
1002 | * MDNIE_PWM_PRE_RATIO [15:12] | |
1003 | * MIPI0_RATIO [19:16] | |
1004 | * MIPI0_PRE_RATIO [23:20] | |
1005 | * set fimd ratio | |
1006 | */ | |
1007 | cfg &= ~(0xf); | |
1008 | cfg |= 0x0; | |
1009 | writel(cfg, &clk->div_disp1_0); | |
1010 | } | |
1011 | ||
37835d4b DL |
1012 | void exynos4_set_mipi_clk(void) |
1013 | { | |
1014 | struct exynos4_clock *clk = | |
1015 | (struct exynos4_clock *)samsung_get_base_clock(); | |
1016 | unsigned int cfg = 0; | |
1017 | ||
1018 | /* | |
1019 | * CLK_SRC_LCD0 | |
1020 | * FIMD0_SEL [3:0] | |
1021 | * MDNIE0_SEL [7:4] | |
1022 | * MDNIE_PWM0_SEL [8:11] | |
1023 | * MIPI0_SEL [12:15] | |
1024 | * set mipi0 src clock 0x6: SCLK_MPLL | |
1025 | */ | |
1026 | cfg = readl(&clk->src_lcd0); | |
1027 | cfg &= ~(0xf << 12); | |
1028 | cfg |= (0x6 << 12); | |
1029 | writel(cfg, &clk->src_lcd0); | |
1030 | ||
1031 | /* | |
1032 | * CLK_SRC_MASK_LCD0 | |
1033 | * FIMD0_MASK [0] | |
1034 | * MDNIE0_MASK [4] | |
1035 | * MDNIE_PWM0_MASK [8] | |
1036 | * MIPI0_MASK [12] | |
1037 | * set src mask mipi0 0x1: Unmask | |
1038 | */ | |
1039 | cfg = readl(&clk->src_mask_lcd0); | |
1040 | cfg |= (0x1 << 12); | |
1041 | writel(cfg, &clk->src_mask_lcd0); | |
1042 | ||
1043 | /* | |
1044 | * CLK_GATE_IP_LCD0 | |
1045 | * CLK_FIMD0 [0] | |
1046 | * CLK_MIE0 [1] | |
1047 | * CLK_MDNIE0 [2] | |
1048 | * CLK_DSIM0 [3] | |
1049 | * CLK_SMMUFIMD0 [4] | |
1050 | * CLK_PPMULCD0 [5] | |
1051 | * Gating all clocks for MIPI0 | |
1052 | */ | |
1053 | cfg = readl(&clk->gate_ip_lcd0); | |
1054 | cfg |= 1 << 3; | |
1055 | writel(cfg, &clk->gate_ip_lcd0); | |
1056 | ||
1057 | /* | |
1058 | * CLK_DIV_LCD0 | |
1059 | * FIMD0_RATIO [3:0] | |
1060 | * MDNIE0_RATIO [7:4] | |
1061 | * MDNIE_PWM0_RATIO [11:8] | |
1062 | * MDNIE_PWM_PRE_RATIO [15:12] | |
1063 | * MIPI0_RATIO [19:16] | |
1064 | * MIPI0_PRE_RATIO [23:20] | |
1065 | * set mipi ratio | |
1066 | */ | |
1067 | cfg &= ~(0xf << 16); | |
1068 | cfg |= (0x1 << 16); | |
1069 | writel(cfg, &clk->div_lcd0); | |
1070 | } | |
1071 | ||
989feb8c RS |
1072 | /* |
1073 | * I2C | |
1074 | * | |
1075 | * exynos5: obtaining the I2C clock | |
1076 | */ | |
1077 | static unsigned long exynos5_get_i2c_clk(void) | |
1078 | { | |
1079 | struct exynos5_clock *clk = | |
1080 | (struct exynos5_clock *)samsung_get_base_clock(); | |
1081 | unsigned long aclk_66, aclk_66_pre, sclk; | |
1082 | unsigned int ratio; | |
1083 | ||
1084 | sclk = get_pll_clk(MPLL); | |
1085 | ||
1086 | ratio = (readl(&clk->div_top1)) >> 24; | |
1087 | ratio &= 0x7; | |
1088 | aclk_66_pre = sclk / (ratio + 1); | |
1089 | ratio = readl(&clk->div_top0); | |
1090 | ratio &= 0x7; | |
1091 | aclk_66 = aclk_66_pre / (ratio + 1); | |
1092 | return aclk_66; | |
1093 | } | |
1094 | ||
2e206caa RS |
1095 | int exynos5_set_epll_clk(unsigned long rate) |
1096 | { | |
1097 | unsigned int epll_con, epll_con_k; | |
1098 | unsigned int i; | |
1099 | unsigned int lockcnt; | |
1100 | unsigned int start; | |
1101 | struct exynos5_clock *clk = | |
1102 | (struct exynos5_clock *)samsung_get_base_clock(); | |
1103 | ||
1104 | epll_con = readl(&clk->epll_con0); | |
1105 | epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK << | |
1106 | EPLL_CON0_LOCK_DET_EN_SHIFT) | | |
1107 | EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT | | |
1108 | EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT | | |
1109 | EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT); | |
1110 | ||
1111 | for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) { | |
1112 | if (exynos5_epll_div[i].freq_out == rate) | |
1113 | break; | |
1114 | } | |
1115 | ||
1116 | if (i == ARRAY_SIZE(exynos5_epll_div)) | |
1117 | return -1; | |
1118 | ||
1119 | epll_con_k = exynos5_epll_div[i].k_dsm << 0; | |
1120 | epll_con |= exynos5_epll_div[i].en_lock_det << | |
1121 | EPLL_CON0_LOCK_DET_EN_SHIFT; | |
1122 | epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT; | |
1123 | epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT; | |
1124 | epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT; | |
1125 | ||
1126 | /* | |
1127 | * Required period ( in cycles) to genarate a stable clock output. | |
1128 | * The maximum clock time can be up to 3000 * PDIV cycles of PLLs | |
1129 | * frequency input (as per spec) | |
1130 | */ | |
1131 | lockcnt = 3000 * exynos5_epll_div[i].p_div; | |
1132 | ||
1133 | writel(lockcnt, &clk->epll_lock); | |
1134 | writel(epll_con, &clk->epll_con0); | |
1135 | writel(epll_con_k, &clk->epll_con1); | |
1136 | ||
1137 | start = get_timer(0); | |
1138 | ||
1139 | while (!(readl(&clk->epll_con0) & | |
1140 | (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) { | |
1141 | if (get_timer(start) > TIMEOUT_EPLL_LOCK) { | |
1142 | debug("%s: Timeout waiting for EPLL lock\n", __func__); | |
1143 | return -1; | |
1144 | } | |
1145 | } | |
1146 | return 0; | |
1147 | } | |
1148 | ||
1149 | void exynos5_set_i2s_clk_source(void) | |
1150 | { | |
1151 | struct exynos5_clock *clk = | |
1152 | (struct exynos5_clock *)samsung_get_base_clock(); | |
1153 | ||
1154 | clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK, | |
1155 | (CLK_SRC_SCLK_EPLL)); | |
1156 | } | |
1157 | ||
1158 | int exynos5_set_i2s_clk_prescaler(unsigned int src_frq, | |
1159 | unsigned int dst_frq) | |
1160 | { | |
1161 | struct exynos5_clock *clk = | |
1162 | (struct exynos5_clock *)samsung_get_base_clock(); | |
1163 | unsigned int div; | |
1164 | ||
1165 | if ((dst_frq == 0) || (src_frq == 0)) { | |
1166 | debug("%s: Invalid requency input for prescaler\n", __func__); | |
1167 | debug("src frq = %d des frq = %d ", src_frq, dst_frq); | |
1168 | return -1; | |
1169 | } | |
1170 | ||
1171 | div = (src_frq / dst_frq); | |
1172 | if (div > AUDIO_1_RATIO_MASK) { | |
1173 | debug("%s: Frequency ratio is out of range\n", __func__); | |
1174 | debug("src frq = %d des frq = %d ", src_frq, dst_frq); | |
1175 | return -1; | |
1176 | } | |
1177 | clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK, | |
1178 | (div & AUDIO_1_RATIO_MASK)); | |
1179 | return 0; | |
1180 | } | |
1181 | ||
b56b3042 HR |
1182 | /** |
1183 | * Linearly searches for the most accurate main and fine stage clock scalars | |
1184 | * (divisors) for a specified target frequency and scalar bit sizes by checking | |
1185 | * all multiples of main_scalar_bits values. Will always return scalars up to or | |
1186 | * slower than target. | |
1187 | * | |
1188 | * @param main_scalar_bits Number of main scalar bits, must be > 0 and < 32 | |
1189 | * @param fine_scalar_bits Number of fine scalar bits, must be > 0 and < 32 | |
1190 | * @param input_freq Clock frequency to be scaled in Hz | |
1191 | * @param target_freq Desired clock frequency in Hz | |
1192 | * @param best_fine_scalar Pointer to store the fine stage divisor | |
1193 | * | |
1194 | * @return best_main_scalar Main scalar for desired frequency or -1 if none | |
1195 | * found | |
1196 | */ | |
1197 | static int clock_calc_best_scalar(unsigned int main_scaler_bits, | |
1198 | unsigned int fine_scalar_bits, unsigned int input_rate, | |
1199 | unsigned int target_rate, unsigned int *best_fine_scalar) | |
1200 | { | |
1201 | int i; | |
1202 | int best_main_scalar = -1; | |
1203 | unsigned int best_error = target_rate; | |
1204 | const unsigned int cap = (1 << fine_scalar_bits) - 1; | |
1205 | const unsigned int loops = 1 << main_scaler_bits; | |
1206 | ||
1207 | debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate, | |
1208 | target_rate, cap); | |
1209 | ||
1210 | assert(best_fine_scalar != NULL); | |
1211 | assert(main_scaler_bits <= fine_scalar_bits); | |
1212 | ||
1213 | *best_fine_scalar = 1; | |
1214 | ||
1215 | if (input_rate == 0 || target_rate == 0) | |
1216 | return -1; | |
1217 | ||
1218 | if (target_rate >= input_rate) | |
1219 | return 1; | |
1220 | ||
1221 | for (i = 1; i <= loops; i++) { | |
1222 | const unsigned int effective_div = max(min(input_rate / i / | |
1223 | target_rate, cap), 1); | |
1224 | const unsigned int effective_rate = input_rate / i / | |
1225 | effective_div; | |
1226 | const int error = target_rate - effective_rate; | |
1227 | ||
1228 | debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div, | |
1229 | effective_rate, error); | |
1230 | ||
1231 | if (error >= 0 && error <= best_error) { | |
1232 | best_error = error; | |
1233 | best_main_scalar = i; | |
1234 | *best_fine_scalar = effective_div; | |
1235 | } | |
1236 | } | |
1237 | ||
1238 | return best_main_scalar; | |
1239 | } | |
1240 | ||
1241 | static int exynos5_set_spi_clk(enum periph_id periph_id, | |
1242 | unsigned int rate) | |
1243 | { | |
1244 | struct exynos5_clock *clk = | |
1245 | (struct exynos5_clock *)samsung_get_base_clock(); | |
1246 | int main; | |
1247 | unsigned int fine; | |
1248 | unsigned shift, pre_shift; | |
1249 | unsigned mask = 0xff; | |
1250 | u32 *reg; | |
1251 | ||
1252 | main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine); | |
1253 | if (main < 0) { | |
1254 | debug("%s: Cannot set clock rate for periph %d", | |
1255 | __func__, periph_id); | |
1256 | return -1; | |
1257 | } | |
1258 | main = main - 1; | |
1259 | fine = fine - 1; | |
1260 | ||
1261 | switch (periph_id) { | |
1262 | case PERIPH_ID_SPI0: | |
1263 | reg = &clk->div_peric1; | |
1264 | shift = 0; | |
1265 | pre_shift = 8; | |
1266 | break; | |
1267 | case PERIPH_ID_SPI1: | |
1268 | reg = &clk->div_peric1; | |
1269 | shift = 16; | |
1270 | pre_shift = 24; | |
1271 | break; | |
1272 | case PERIPH_ID_SPI2: | |
1273 | reg = &clk->div_peric2; | |
1274 | shift = 0; | |
1275 | pre_shift = 8; | |
1276 | break; | |
1277 | case PERIPH_ID_SPI3: | |
1278 | reg = &clk->sclk_div_isp; | |
1279 | shift = 0; | |
1280 | pre_shift = 4; | |
1281 | break; | |
1282 | case PERIPH_ID_SPI4: | |
1283 | reg = &clk->sclk_div_isp; | |
1284 | shift = 12; | |
1285 | pre_shift = 16; | |
1286 | break; | |
1287 | default: | |
1288 | debug("%s: Unsupported peripheral ID %d\n", __func__, | |
1289 | periph_id); | |
1290 | return -1; | |
1291 | } | |
1292 | clrsetbits_le32(reg, mask << shift, (main & mask) << shift); | |
1293 | clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift); | |
1294 | ||
1295 | return 0; | |
1296 | } | |
1297 | ||
83d745dd PW |
1298 | static unsigned long exynos4_get_i2c_clk(void) |
1299 | { | |
1300 | struct exynos4_clock *clk = | |
1301 | (struct exynos4_clock *)samsung_get_base_clock(); | |
1302 | unsigned long sclk, aclk_100; | |
1303 | unsigned int ratio; | |
1304 | ||
1305 | sclk = get_pll_clk(APLL); | |
1306 | ||
1307 | ratio = (readl(&clk->div_top)) >> 4; | |
1308 | ratio &= 0xf; | |
1309 | aclk_100 = sclk / (ratio + 1); | |
1310 | return aclk_100; | |
b56b3042 HR |
1311 | } |
1312 | ||
008a351a MK |
1313 | unsigned long get_pll_clk(int pllreg) |
1314 | { | |
37bb6d89 CK |
1315 | if (cpu_is_exynos5()) |
1316 | return exynos5_get_pll_clk(pllreg); | |
a5277573 CK |
1317 | else { |
1318 | if (proid_is_exynos4412()) | |
1319 | return exynos4x12_get_pll_clk(pllreg); | |
37bb6d89 | 1320 | return exynos4_get_pll_clk(pllreg); |
a5277573 | 1321 | } |
008a351a MK |
1322 | } |
1323 | ||
1324 | unsigned long get_arm_clk(void) | |
1325 | { | |
37bb6d89 CK |
1326 | if (cpu_is_exynos5()) |
1327 | return exynos5_get_arm_clk(); | |
a5277573 CK |
1328 | else { |
1329 | if (proid_is_exynos4412()) | |
1330 | return exynos4x12_get_arm_clk(); | |
37bb6d89 | 1331 | return exynos4_get_arm_clk(); |
a5277573 | 1332 | } |
008a351a MK |
1333 | } |
1334 | ||
989feb8c RS |
1335 | unsigned long get_i2c_clk(void) |
1336 | { | |
1337 | if (cpu_is_exynos5()) { | |
1338 | return exynos5_get_i2c_clk(); | |
83d745dd PW |
1339 | } else if (cpu_is_exynos4()) { |
1340 | return exynos4_get_i2c_clk(); | |
989feb8c RS |
1341 | } else { |
1342 | debug("I2C clock is not set for this CPU\n"); | |
1343 | return 0; | |
1344 | } | |
1345 | } | |
1346 | ||
008a351a MK |
1347 | unsigned long get_pwm_clk(void) |
1348 | { | |
37bb6d89 | 1349 | if (cpu_is_exynos5()) |
e2338704 | 1350 | return clock_get_periph_rate(PERIPH_ID_PWM0); |
a5277573 CK |
1351 | else { |
1352 | if (proid_is_exynos4412()) | |
1353 | return exynos4x12_get_pwm_clk(); | |
37bb6d89 | 1354 | return exynos4_get_pwm_clk(); |
a5277573 | 1355 | } |
008a351a MK |
1356 | } |
1357 | ||
1358 | unsigned long get_uart_clk(int dev_index) | |
1359 | { | |
37bb6d89 CK |
1360 | if (cpu_is_exynos5()) |
1361 | return exynos5_get_uart_clk(dev_index); | |
a5277573 CK |
1362 | else { |
1363 | if (proid_is_exynos4412()) | |
1364 | return exynos4x12_get_uart_clk(dev_index); | |
37bb6d89 | 1365 | return exynos4_get_uart_clk(dev_index); |
a5277573 | 1366 | } |
008a351a | 1367 | } |
68a8cbfa | 1368 | |
c39e969e JC |
1369 | unsigned long get_mmc_clk(int dev_index) |
1370 | { | |
1371 | if (cpu_is_exynos5()) | |
1372 | return exynos5_get_mmc_clk(dev_index); | |
1373 | else | |
1374 | return exynos4_get_mmc_clk(dev_index); | |
1375 | } | |
1376 | ||
68a8cbfa JC |
1377 | void set_mmc_clk(int dev_index, unsigned int div) |
1378 | { | |
37bb6d89 CK |
1379 | if (cpu_is_exynos5()) |
1380 | exynos5_set_mmc_clk(dev_index, div); | |
a5277573 CK |
1381 | else { |
1382 | if (proid_is_exynos4412()) | |
1383 | exynos4x12_set_mmc_clk(dev_index, div); | |
37bb6d89 | 1384 | exynos4_set_mmc_clk(dev_index, div); |
a5277573 | 1385 | } |
68a8cbfa | 1386 | } |
37835d4b DL |
1387 | |
1388 | unsigned long get_lcd_clk(void) | |
1389 | { | |
1390 | if (cpu_is_exynos4()) | |
1391 | return exynos4_get_lcd_clk(); | |
1392 | else | |
2c5cd25c | 1393 | return exynos5_get_lcd_clk(); |
37835d4b DL |
1394 | } |
1395 | ||
1396 | void set_lcd_clk(void) | |
1397 | { | |
1398 | if (cpu_is_exynos4()) | |
1399 | exynos4_set_lcd_clk(); | |
2c5cd25c DL |
1400 | else |
1401 | exynos5_set_lcd_clk(); | |
37835d4b DL |
1402 | } |
1403 | ||
1404 | void set_mipi_clk(void) | |
1405 | { | |
1406 | if (cpu_is_exynos4()) | |
1407 | exynos4_set_mipi_clk(); | |
1408 | } | |
2e206caa | 1409 | |
b56b3042 HR |
1410 | int set_spi_clk(int periph_id, unsigned int rate) |
1411 | { | |
1412 | if (cpu_is_exynos5()) | |
1413 | return exynos5_set_spi_clk(periph_id, rate); | |
1414 | else | |
1415 | return 0; | |
1416 | } | |
1417 | ||
2e206caa RS |
1418 | int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq) |
1419 | { | |
1420 | ||
1421 | if (cpu_is_exynos5()) | |
1422 | return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq); | |
1423 | else | |
1424 | return 0; | |
1425 | } | |
1426 | ||
1427 | void set_i2s_clk_source(void) | |
1428 | { | |
1429 | if (cpu_is_exynos5()) | |
1430 | exynos5_set_i2s_clk_source(); | |
1431 | } | |
1432 | ||
1433 | int set_epll_clk(unsigned long rate) | |
1434 | { | |
1435 | if (cpu_is_exynos5()) | |
1436 | return exynos5_set_epll_clk(rate); | |
1437 | else | |
1438 | return 0; | |
1439 | } |