blob: 5a5cfa1d36a30e850fc49b157978cef1b3ef727d [file] [log] [blame]
Minkyu Kangb1b24682011-01-24 15:22:23 +09001/*
2 * Copyright (C) 2010 Samsung Electronics
3 * Minkyu Kang <mk7.kang@samsung.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include <asm/io.h>
26#include <asm/arch/clock.h>
27#include <asm/arch/clk.h>
Hatim RVe6365b62012-11-02 01:15:34 +000028#include <asm/arch/periph.h>
Minkyu Kangb1b24682011-01-24 15:22:23 +090029
Minkyu Kang368588e2013-07-05 19:08:33 +090030#define PLL_DIV_1024 1024
31#define PLL_DIV_65535 65535
32#define PLL_DIV_65536 65536
33
Padmavathi Venna37feb7b2013-03-28 04:32:21 +000034/* *
35 * This structure is to store the src bit, div bit and prediv bit
36 * positions of the peripheral clocks of the src and div registers
37 */
38struct clk_bit_info {
39 int8_t src_bit;
40 int8_t div_bit;
41 int8_t prediv_bit;
42};
43
44/* src_bit div_bit prediv_bit */
45static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = {
46 {0, 0, -1},
47 {4, 4, -1},
48 {8, 8, -1},
49 {12, 12, -1},
50 {0, 0, 8},
51 {4, 16, 24},
52 {8, 0, 8},
53 {12, 16, 24},
54 {-1, -1, -1},
55 {16, 0, 8},
56 {20, 16, 24},
57 {24, 0, 8},
58 {0, 0, 4},
59 {4, 12, 16},
60 {-1, -1, -1},
61 {-1, -1, -1},
62 {-1, 24, 0},
63 {-1, 24, 0},
64 {-1, 24, 0},
65 {-1, 24, 0},
66 {-1, 24, 0},
67 {-1, 24, 0},
68 {-1, 24, 0},
69 {-1, 24, 0},
70 {24, 0, -1},
71 {24, 0, -1},
72 {24, 0, -1},
73 {24, 0, -1},
74 {24, 0, -1},
75};
76
Rajeshwari Shinde392a73a2012-10-25 19:49:29 +000077/* Epll Clock division values to achive different frequency output */
78static struct set_epll_con_val exynos5_epll_div[] = {
79 { 192000000, 0, 48, 3, 1, 0 },
80 { 180000000, 0, 45, 3, 1, 0 },
81 { 73728000, 1, 73, 3, 3, 47710 },
82 { 67737600, 1, 90, 4, 3, 20762 },
83 { 49152000, 0, 49, 3, 3, 9961 },
84 { 45158400, 0, 45, 3, 3, 10381 },
85 { 180633600, 0, 45, 3, 1, 10381 }
86};
87
Minkyu Kang1a055aa2012-10-15 01:58:00 +000088/* exynos: return pll clock frequency */
89static int exynos_get_pll_clk(int pllreg, unsigned int r, unsigned int k)
Minkyu Kangb1b24682011-01-24 15:22:23 +090090{
Minkyu Kang1a055aa2012-10-15 01:58:00 +000091 unsigned long m, p, s = 0, mask, fout;
Minkyu Kang368588e2013-07-05 19:08:33 +090092 unsigned int div;
Minkyu Kangb1b24682011-01-24 15:22:23 +090093 unsigned int freq;
Minkyu Kangb1b24682011-01-24 15:22:23 +090094 /*
95 * APLL_CON: MIDV [25:16]
96 * MPLL_CON: MIDV [25:16]
97 * EPLL_CON: MIDV [24:16]
98 * VPLL_CON: MIDV [24:16]
Minkyu Kang1a055aa2012-10-15 01:58:00 +000099 * BPLL_CON: MIDV [25:16]: Exynos5
Minkyu Kangb1b24682011-01-24 15:22:23 +0900100 */
Minkyu Kang1a055aa2012-10-15 01:58:00 +0000101 if (pllreg == APLL || pllreg == MPLL || pllreg == BPLL)
Minkyu Kangb1b24682011-01-24 15:22:23 +0900102 mask = 0x3ff;
103 else
104 mask = 0x1ff;
105
106 m = (r >> 16) & mask;
107
108 /* PDIV [13:8] */
109 p = (r >> 8) & 0x3f;
110 /* SDIV [2:0] */
111 s = r & 0x7;
112
Chander Kashyap6a870e12012-02-05 23:01:45 +0000113 freq = CONFIG_SYS_CLK_FREQ;
Minkyu Kangb1b24682011-01-24 15:22:23 +0900114
115 if (pllreg == EPLL) {
116 k = k & 0xffff;
117 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
Minkyu Kang368588e2013-07-05 19:08:33 +0900118 fout = (m + k / PLL_DIV_65536) * (freq / (p * (1 << s)));
Minkyu Kangb1b24682011-01-24 15:22:23 +0900119 } else if (pllreg == VPLL) {
120 k = k & 0xfff;
Minkyu Kang368588e2013-07-05 19:08:33 +0900121
122 /*
123 * Exynos4210
124 * FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV)
125 *
126 * Exynos4412
127 * FOUT = (MDIV + K / 65535) * FIN / (PDIV * 2^SDIV)
128 *
129 * Exynos5250
130 * FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV)
131 */
132 if (proid_is_exynos4210())
133 div = PLL_DIV_1024;
134 else if (proid_is_exynos4412())
135 div = PLL_DIV_65535;
136 else if (proid_is_exynos5250())
137 div = PLL_DIV_65536;
138 else
139 return 0;
140
141 fout = (m + k / div) * (freq / (p * (1 << s)));
Minkyu Kangb1b24682011-01-24 15:22:23 +0900142 } else {
Minkyu Kang368588e2013-07-05 19:08:33 +0900143 /*
Łukasz Majewski326c4592013-07-12 19:08:25 +0200144 * Exynos4412 / Exynos5250
Minkyu Kang368588e2013-07-05 19:08:33 +0900145 * FOUT = MDIV * FIN / (PDIV * 2^SDIV)
146 *
Łukasz Majewski326c4592013-07-12 19:08:25 +0200147 * Exynos4210
Minkyu Kang368588e2013-07-05 19:08:33 +0900148 * FOUT = MDIV * FIN / (PDIV * 2^(SDIV-1))
149 */
150 if (proid_is_exynos4210())
Minkyu Kang368588e2013-07-05 19:08:33 +0900151 fout = m * (freq / (p * (1 << (s - 1))));
Łukasz Majewski326c4592013-07-12 19:08:25 +0200152 else
153 fout = m * (freq / (p * (1 << s)));
Minkyu Kangb1b24682011-01-24 15:22:23 +0900154 }
Minkyu Kangb1b24682011-01-24 15:22:23 +0900155 return fout;
156}
157
Minkyu Kang1a055aa2012-10-15 01:58:00 +0000158/* exynos4: return pll clock frequency */
159static unsigned long exynos4_get_pll_clk(int pllreg)
160{
161 struct exynos4_clock *clk =
162 (struct exynos4_clock *)samsung_get_base_clock();
163 unsigned long r, k = 0;
164
165 switch (pllreg) {
166 case APLL:
167 r = readl(&clk->apll_con0);
168 break;
169 case MPLL:
170 r = readl(&clk->mpll_con0);
171 break;
172 case EPLL:
173 r = readl(&clk->epll_con0);
174 k = readl(&clk->epll_con1);
175 break;
176 case VPLL:
177 r = readl(&clk->vpll_con0);
178 k = readl(&clk->vpll_con1);
179 break;
180 default:
181 printf("Unsupported PLL (%d)\n", pllreg);
182 return 0;
183 }
184
185 return exynos_get_pll_clk(pllreg, r, k);
186}
187
Chander Kashyap400ab162012-10-07 01:43:17 +0000188/* exynos4x12: return pll clock frequency */
189static unsigned long exynos4x12_get_pll_clk(int pllreg)
190{
191 struct exynos4x12_clock *clk =
192 (struct exynos4x12_clock *)samsung_get_base_clock();
193 unsigned long r, k = 0;
194
195 switch (pllreg) {
196 case APLL:
197 r = readl(&clk->apll_con0);
198 break;
199 case MPLL:
200 r = readl(&clk->mpll_con0);
201 break;
202 case EPLL:
203 r = readl(&clk->epll_con0);
204 k = readl(&clk->epll_con1);
205 break;
206 case VPLL:
207 r = readl(&clk->vpll_con0);
208 k = readl(&clk->vpll_con1);
209 break;
210 default:
211 printf("Unsupported PLL (%d)\n", pllreg);
212 return 0;
213 }
214
215 return exynos_get_pll_clk(pllreg, r, k);
216}
217
Chander Kashyap34076a02012-02-05 23:01:46 +0000218/* exynos5: return pll clock frequency */
219static unsigned long exynos5_get_pll_clk(int pllreg)
220{
221 struct exynos5_clock *clk =
222 (struct exynos5_clock *)samsung_get_base_clock();
Minkyu Kang1a055aa2012-10-15 01:58:00 +0000223 unsigned long r, k = 0, fout;
224 unsigned int pll_div2_sel, fout_sel;
Chander Kashyap34076a02012-02-05 23:01:46 +0000225
226 switch (pllreg) {
227 case APLL:
228 r = readl(&clk->apll_con0);
229 break;
230 case MPLL:
231 r = readl(&clk->mpll_con0);
232 break;
233 case EPLL:
234 r = readl(&clk->epll_con0);
235 k = readl(&clk->epll_con1);
236 break;
237 case VPLL:
238 r = readl(&clk->vpll_con0);
239 k = readl(&clk->vpll_con1);
240 break;
Rajeshwari Shinde84112862012-07-03 20:02:58 +0000241 case BPLL:
242 r = readl(&clk->bpll_con0);
243 break;
Chander Kashyap34076a02012-02-05 23:01:46 +0000244 default:
245 printf("Unsupported PLL (%d)\n", pllreg);
246 return 0;
247 }
248
Minkyu Kang1a055aa2012-10-15 01:58:00 +0000249 fout = exynos_get_pll_clk(pllreg, r, k);
Chander Kashyap34076a02012-02-05 23:01:46 +0000250
Rajeshwari Shinde84112862012-07-03 20:02:58 +0000251 /* According to the user manual, in EVT1 MPLL and BPLL always gives
Rajeshwari Shinde7b9afce2012-07-03 20:02:57 +0000252 * 1.6GHz clock, so divide by 2 to get 800MHz MPLL clock.*/
Rajeshwari Shinde84112862012-07-03 20:02:58 +0000253 if (pllreg == MPLL || pllreg == BPLL) {
Rajeshwari Shinde7b9afce2012-07-03 20:02:57 +0000254 pll_div2_sel = readl(&clk->pll_div2_sel);
Rajeshwari Shinde84112862012-07-03 20:02:58 +0000255
256 switch (pllreg) {
257 case MPLL:
258 fout_sel = (pll_div2_sel >> MPLL_FOUT_SEL_SHIFT)
259 & MPLL_FOUT_SEL_MASK;
260 break;
261 case BPLL:
262 fout_sel = (pll_div2_sel >> BPLL_FOUT_SEL_SHIFT)
263 & BPLL_FOUT_SEL_MASK;
264 break;
Jaehoon Chung0fc779c2012-07-09 21:20:34 +0000265 default:
266 fout_sel = -1;
267 break;
Rajeshwari Shinde84112862012-07-03 20:02:58 +0000268 }
269
270 if (fout_sel == 0)
Rajeshwari Shinde7b9afce2012-07-03 20:02:57 +0000271 fout /= 2;
272 }
273
Chander Kashyap34076a02012-02-05 23:01:46 +0000274 return fout;
275}
276
Padmavathi Venna37feb7b2013-03-28 04:32:21 +0000277static unsigned long exynos5_get_periph_rate(int peripheral)
278{
279 struct clk_bit_info *bit_info = &clk_bit_info[peripheral];
280 unsigned long sclk, sub_clk;
281 unsigned int src, div, sub_div;
282 struct exynos5_clock *clk =
283 (struct exynos5_clock *)samsung_get_base_clock();
284
285 switch (peripheral) {
286 case PERIPH_ID_UART0:
287 case PERIPH_ID_UART1:
288 case PERIPH_ID_UART2:
289 case PERIPH_ID_UART3:
290 src = readl(&clk->src_peric0);
291 div = readl(&clk->div_peric0);
292 break;
293 case PERIPH_ID_PWM0:
294 case PERIPH_ID_PWM1:
295 case PERIPH_ID_PWM2:
296 case PERIPH_ID_PWM3:
297 case PERIPH_ID_PWM4:
298 src = readl(&clk->src_peric0);
299 div = readl(&clk->div_peric3);
300 break;
301 case PERIPH_ID_SPI0:
302 case PERIPH_ID_SPI1:
303 src = readl(&clk->src_peric1);
304 div = readl(&clk->div_peric1);
305 break;
306 case PERIPH_ID_SPI2:
307 src = readl(&clk->src_peric1);
308 div = readl(&clk->div_peric2);
309 break;
310 case PERIPH_ID_SPI3:
311 case PERIPH_ID_SPI4:
312 src = readl(&clk->sclk_src_isp);
313 div = readl(&clk->sclk_div_isp);
314 break;
315 case PERIPH_ID_SDMMC0:
316 case PERIPH_ID_SDMMC1:
317 case PERIPH_ID_SDMMC2:
318 case PERIPH_ID_SDMMC3:
319 src = readl(&clk->src_fsys);
320 div = readl(&clk->div_fsys1);
321 break;
322 case PERIPH_ID_I2C0:
323 case PERIPH_ID_I2C1:
324 case PERIPH_ID_I2C2:
325 case PERIPH_ID_I2C3:
326 case PERIPH_ID_I2C4:
327 case PERIPH_ID_I2C5:
328 case PERIPH_ID_I2C6:
329 case PERIPH_ID_I2C7:
330 sclk = exynos5_get_pll_clk(MPLL);
331 sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit)
332 & 0x7) + 1;
333 div = ((readl(&clk->div_top0) >> bit_info->prediv_bit)
334 & 0x7) + 1;
335 return (sclk / sub_div) / div;
336 default:
337 debug("%s: invalid peripheral %d", __func__, peripheral);
338 return -1;
339 };
340
341 src = (src >> bit_info->src_bit) & 0xf;
342
343 switch (src) {
344 case EXYNOS_SRC_MPLL:
345 sclk = exynos5_get_pll_clk(MPLL);
346 break;
347 case EXYNOS_SRC_EPLL:
348 sclk = exynos5_get_pll_clk(EPLL);
349 break;
350 case EXYNOS_SRC_VPLL:
351 sclk = exynos5_get_pll_clk(VPLL);
352 break;
353 default:
354 return 0;
355 }
356
357 /* Ratio clock division for this peripheral */
358 sub_div = (div >> bit_info->div_bit) & 0xf;
359 sub_clk = sclk / (sub_div + 1);
360
361 /* Pre-ratio clock division for SDMMC0 and 2 */
362 if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) {
363 div = (div >> bit_info->prediv_bit) & 0xff;
364 return sub_clk / (div + 1);
365 }
366
367 return sub_clk;
368}
369
370unsigned long clock_get_periph_rate(int peripheral)
371{
372 if (cpu_is_exynos5())
373 return exynos5_get_periph_rate(peripheral);
374 else
375 return 0;
376}
377
Chander Kashyap4131a772011-12-06 23:34:12 +0000378/* exynos4: return ARM clock frequency */
379static unsigned long exynos4_get_arm_clk(void)
Minkyu Kangb1b24682011-01-24 15:22:23 +0900380{
Chander Kashyap4131a772011-12-06 23:34:12 +0000381 struct exynos4_clock *clk =
382 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kangb1b24682011-01-24 15:22:23 +0900383 unsigned long div;
Chander Kashyap3c7721f2011-12-18 22:56:44 +0000384 unsigned long armclk;
385 unsigned int core_ratio;
386 unsigned int core2_ratio;
Minkyu Kangb1b24682011-01-24 15:22:23 +0900387
388 div = readl(&clk->div_cpu0);
389
Chander Kashyap3c7721f2011-12-18 22:56:44 +0000390 /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
391 core_ratio = (div >> 0) & 0x7;
392 core2_ratio = (div >> 28) & 0x7;
Minkyu Kangb1b24682011-01-24 15:22:23 +0900393
Chander Kashyap3c7721f2011-12-18 22:56:44 +0000394 armclk = get_pll_clk(APLL) / (core_ratio + 1);
395 armclk /= (core2_ratio + 1);
Minkyu Kangb1b24682011-01-24 15:22:23 +0900396
Chander Kashyap3c7721f2011-12-18 22:56:44 +0000397 return armclk;
Minkyu Kangb1b24682011-01-24 15:22:23 +0900398}
399
Chander Kashyap400ab162012-10-07 01:43:17 +0000400/* exynos4x12: return ARM clock frequency */
401static unsigned long exynos4x12_get_arm_clk(void)
402{
403 struct exynos4x12_clock *clk =
404 (struct exynos4x12_clock *)samsung_get_base_clock();
405 unsigned long div;
406 unsigned long armclk;
407 unsigned int core_ratio;
408 unsigned int core2_ratio;
409
410 div = readl(&clk->div_cpu0);
411
412 /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
413 core_ratio = (div >> 0) & 0x7;
414 core2_ratio = (div >> 28) & 0x7;
415
416 armclk = get_pll_clk(APLL) / (core_ratio + 1);
417 armclk /= (core2_ratio + 1);
418
419 return armclk;
420}
421
Chander Kashyap34076a02012-02-05 23:01:46 +0000422/* exynos5: return ARM clock frequency */
423static unsigned long exynos5_get_arm_clk(void)
424{
425 struct exynos5_clock *clk =
426 (struct exynos5_clock *)samsung_get_base_clock();
427 unsigned long div;
428 unsigned long armclk;
429 unsigned int arm_ratio;
430 unsigned int arm2_ratio;
431
432 div = readl(&clk->div_cpu0);
433
434 /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
435 arm_ratio = (div >> 0) & 0x7;
436 arm2_ratio = (div >> 28) & 0x7;
437
438 armclk = get_pll_clk(APLL) / (arm_ratio + 1);
439 armclk /= (arm2_ratio + 1);
440
441 return armclk;
442}
443
Chander Kashyap4131a772011-12-06 23:34:12 +0000444/* exynos4: return pwm clock frequency */
445static unsigned long exynos4_get_pwm_clk(void)
Minkyu Kangb1b24682011-01-24 15:22:23 +0900446{
Chander Kashyap4131a772011-12-06 23:34:12 +0000447 struct exynos4_clock *clk =
448 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kangb1b24682011-01-24 15:22:23 +0900449 unsigned long pclk, sclk;
450 unsigned int sel;
451 unsigned int ratio;
452
Minkyu Kang69b28242011-05-18 16:57:55 +0900453 if (s5p_get_cpu_rev() == 0) {
454 /*
455 * CLK_SRC_PERIL0
456 * PWM_SEL [27:24]
457 */
458 sel = readl(&clk->src_peril0);
459 sel = (sel >> 24) & 0xf;
Minkyu Kangb1b24682011-01-24 15:22:23 +0900460
Minkyu Kang69b28242011-05-18 16:57:55 +0900461 if (sel == 0x6)
462 sclk = get_pll_clk(MPLL);
463 else if (sel == 0x7)
464 sclk = get_pll_clk(EPLL);
465 else if (sel == 0x8)
466 sclk = get_pll_clk(VPLL);
467 else
468 return 0;
469
470 /*
471 * CLK_DIV_PERIL3
472 * PWM_RATIO [3:0]
473 */
474 ratio = readl(&clk->div_peril3);
475 ratio = ratio & 0xf;
476 } else if (s5p_get_cpu_rev() == 1) {
Minkyu Kangb1b24682011-01-24 15:22:23 +0900477 sclk = get_pll_clk(MPLL);
Minkyu Kang69b28242011-05-18 16:57:55 +0900478 ratio = 8;
479 } else
Minkyu Kangb1b24682011-01-24 15:22:23 +0900480 return 0;
481
Minkyu Kangb1b24682011-01-24 15:22:23 +0900482 pclk = sclk / (ratio + 1);
483
484 return pclk;
485}
486
Chander Kashyap400ab162012-10-07 01:43:17 +0000487/* exynos4x12: return pwm clock frequency */
488static unsigned long exynos4x12_get_pwm_clk(void)
489{
490 unsigned long pclk, sclk;
491 unsigned int ratio;
492
493 sclk = get_pll_clk(MPLL);
494 ratio = 8;
495
496 pclk = sclk / (ratio + 1);
497
498 return pclk;
499}
500
Chander Kashyap4131a772011-12-06 23:34:12 +0000501/* exynos4: return uart clock frequency */
502static unsigned long exynos4_get_uart_clk(int dev_index)
Minkyu Kangb1b24682011-01-24 15:22:23 +0900503{
Chander Kashyap4131a772011-12-06 23:34:12 +0000504 struct exynos4_clock *clk =
505 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kangb1b24682011-01-24 15:22:23 +0900506 unsigned long uclk, sclk;
507 unsigned int sel;
508 unsigned int ratio;
509
510 /*
511 * CLK_SRC_PERIL0
512 * UART0_SEL [3:0]
513 * UART1_SEL [7:4]
514 * UART2_SEL [8:11]
515 * UART3_SEL [12:15]
516 * UART4_SEL [16:19]
517 * UART5_SEL [23:20]
518 */
519 sel = readl(&clk->src_peril0);
520 sel = (sel >> (dev_index << 2)) & 0xf;
521
522 if (sel == 0x6)
523 sclk = get_pll_clk(MPLL);
524 else if (sel == 0x7)
525 sclk = get_pll_clk(EPLL);
526 else if (sel == 0x8)
527 sclk = get_pll_clk(VPLL);
528 else
529 return 0;
530
531 /*
532 * CLK_DIV_PERIL0
533 * UART0_RATIO [3:0]
534 * UART1_RATIO [7:4]
535 * UART2_RATIO [8:11]
536 * UART3_RATIO [12:15]
537 * UART4_RATIO [16:19]
538 * UART5_RATIO [23:20]
539 */
540 ratio = readl(&clk->div_peril0);
541 ratio = (ratio >> (dev_index << 2)) & 0xf;
542
543 uclk = sclk / (ratio + 1);
544
545 return uclk;
546}
547
Chander Kashyap400ab162012-10-07 01:43:17 +0000548/* exynos4x12: return uart clock frequency */
549static unsigned long exynos4x12_get_uart_clk(int dev_index)
550{
551 struct exynos4x12_clock *clk =
552 (struct exynos4x12_clock *)samsung_get_base_clock();
553 unsigned long uclk, sclk;
554 unsigned int sel;
555 unsigned int ratio;
556
557 /*
558 * CLK_SRC_PERIL0
559 * UART0_SEL [3:0]
560 * UART1_SEL [7:4]
561 * UART2_SEL [8:11]
562 * UART3_SEL [12:15]
563 * UART4_SEL [16:19]
564 */
565 sel = readl(&clk->src_peril0);
566 sel = (sel >> (dev_index << 2)) & 0xf;
567
568 if (sel == 0x6)
569 sclk = get_pll_clk(MPLL);
570 else if (sel == 0x7)
571 sclk = get_pll_clk(EPLL);
572 else if (sel == 0x8)
573 sclk = get_pll_clk(VPLL);
574 else
575 return 0;
576
577 /*
578 * CLK_DIV_PERIL0
579 * UART0_RATIO [3:0]
580 * UART1_RATIO [7:4]
581 * UART2_RATIO [8:11]
582 * UART3_RATIO [12:15]
583 * UART4_RATIO [16:19]
584 */
585 ratio = readl(&clk->div_peril0);
586 ratio = (ratio >> (dev_index << 2)) & 0xf;
587
588 uclk = sclk / (ratio + 1);
589
590 return uclk;
591}
592
Chander Kashyap34076a02012-02-05 23:01:46 +0000593/* exynos5: return uart clock frequency */
594static unsigned long exynos5_get_uart_clk(int dev_index)
595{
596 struct exynos5_clock *clk =
597 (struct exynos5_clock *)samsung_get_base_clock();
598 unsigned long uclk, sclk;
599 unsigned int sel;
600 unsigned int ratio;
601
602 /*
603 * CLK_SRC_PERIC0
604 * UART0_SEL [3:0]
605 * UART1_SEL [7:4]
606 * UART2_SEL [8:11]
607 * UART3_SEL [12:15]
608 * UART4_SEL [16:19]
609 * UART5_SEL [23:20]
610 */
611 sel = readl(&clk->src_peric0);
612 sel = (sel >> (dev_index << 2)) & 0xf;
613
614 if (sel == 0x6)
615 sclk = get_pll_clk(MPLL);
616 else if (sel == 0x7)
617 sclk = get_pll_clk(EPLL);
618 else if (sel == 0x8)
619 sclk = get_pll_clk(VPLL);
620 else
621 return 0;
622
623 /*
624 * CLK_DIV_PERIC0
625 * UART0_RATIO [3:0]
626 * UART1_RATIO [7:4]
627 * UART2_RATIO [8:11]
628 * UART3_RATIO [12:15]
629 * UART4_RATIO [16:19]
630 * UART5_RATIO [23:20]
631 */
632 ratio = readl(&clk->div_peric0);
633 ratio = (ratio >> (dev_index << 2)) & 0xf;
634
635 uclk = sclk / (ratio + 1);
636
637 return uclk;
638}
639
Jaehoon Chung8788e062012-12-27 22:30:32 +0000640static unsigned long exynos4_get_mmc_clk(int dev_index)
641{
642 struct exynos4_clock *clk =
643 (struct exynos4_clock *)samsung_get_base_clock();
644 unsigned long uclk, sclk;
645 unsigned int sel, ratio, pre_ratio;
Amare1df6282013-04-27 11:42:56 +0530646 int shift = 0;
Jaehoon Chung8788e062012-12-27 22:30:32 +0000647
648 sel = readl(&clk->src_fsys);
649 sel = (sel >> (dev_index << 2)) & 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 switch (dev_index) {
661 case 0:
662 case 1:
663 ratio = readl(&clk->div_fsys1);
664 pre_ratio = readl(&clk->div_fsys1);
665 break;
666 case 2:
667 case 3:
668 ratio = readl(&clk->div_fsys2);
669 pre_ratio = readl(&clk->div_fsys2);
670 break;
671 case 4:
672 ratio = readl(&clk->div_fsys3);
673 pre_ratio = readl(&clk->div_fsys3);
674 break;
675 default:
676 return 0;
677 }
678
679 if (dev_index == 1 || dev_index == 3)
680 shift = 16;
681
682 ratio = (ratio >> shift) & 0xf;
683 pre_ratio = (pre_ratio >> (shift + 8)) & 0xff;
684 uclk = (sclk / (ratio + 1)) / (pre_ratio + 1);
685
686 return uclk;
687}
688
689static unsigned long exynos5_get_mmc_clk(int dev_index)
690{
691 struct exynos5_clock *clk =
692 (struct exynos5_clock *)samsung_get_base_clock();
693 unsigned long uclk, sclk;
694 unsigned int sel, ratio, pre_ratio;
Amare1df6282013-04-27 11:42:56 +0530695 int shift = 0;
Jaehoon Chung8788e062012-12-27 22:30:32 +0000696
697 sel = readl(&clk->src_fsys);
698 sel = (sel >> (dev_index << 2)) & 0xf;
699
700 if (sel == 0x6)
701 sclk = get_pll_clk(MPLL);
702 else if (sel == 0x7)
703 sclk = get_pll_clk(EPLL);
704 else if (sel == 0x8)
705 sclk = get_pll_clk(VPLL);
706 else
707 return 0;
708
709 switch (dev_index) {
710 case 0:
711 case 1:
712 ratio = readl(&clk->div_fsys1);
713 pre_ratio = readl(&clk->div_fsys1);
714 break;
715 case 2:
716 case 3:
717 ratio = readl(&clk->div_fsys2);
718 pre_ratio = readl(&clk->div_fsys2);
719 break;
720 default:
721 return 0;
722 }
723
724 if (dev_index == 1 || dev_index == 3)
725 shift = 16;
726
727 ratio = (ratio >> shift) & 0xf;
728 pre_ratio = (pre_ratio >> (shift + 8)) & 0xff;
729 uclk = (sclk / (ratio + 1)) / (pre_ratio + 1);
730
731 return uclk;
732}
733
Chander Kashyap4131a772011-12-06 23:34:12 +0000734/* exynos4: set the mmc clock */
735static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
Jaehoon Chung9a772212011-05-17 21:19:17 +0000736{
Chander Kashyap4131a772011-12-06 23:34:12 +0000737 struct exynos4_clock *clk =
738 (struct exynos4_clock *)samsung_get_base_clock();
Jaehoon Chung9a772212011-05-17 21:19:17 +0000739 unsigned int addr;
740 unsigned int val;
741
742 /*
743 * CLK_DIV_FSYS1
744 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
745 * CLK_DIV_FSYS2
746 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
Jaehoon Chung29fe8c52012-12-27 22:30:33 +0000747 * CLK_DIV_FSYS3
748 * MMC4_PRE_RATIO [15:8]
Jaehoon Chung9a772212011-05-17 21:19:17 +0000749 */
750 if (dev_index < 2) {
751 addr = (unsigned int)&clk->div_fsys1;
Jaehoon Chung29fe8c52012-12-27 22:30:33 +0000752 } else if (dev_index == 4) {
753 addr = (unsigned int)&clk->div_fsys3;
754 dev_index -= 4;
Jaehoon Chung9a772212011-05-17 21:19:17 +0000755 } else {
756 addr = (unsigned int)&clk->div_fsys2;
757 dev_index -= 2;
758 }
759
760 val = readl(addr);
761 val &= ~(0xff << ((dev_index << 4) + 8));
762 val |= (div & 0xff) << ((dev_index << 4) + 8);
763 writel(val, addr);
764}
765
Chander Kashyap400ab162012-10-07 01:43:17 +0000766/* exynos4x12: set the mmc clock */
767static void exynos4x12_set_mmc_clk(int dev_index, unsigned int div)
768{
769 struct exynos4x12_clock *clk =
770 (struct exynos4x12_clock *)samsung_get_base_clock();
771 unsigned int addr;
772 unsigned int val;
773
774 /*
775 * CLK_DIV_FSYS1
776 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
777 * CLK_DIV_FSYS2
778 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
779 */
780 if (dev_index < 2) {
781 addr = (unsigned int)&clk->div_fsys1;
782 } else {
783 addr = (unsigned int)&clk->div_fsys2;
784 dev_index -= 2;
785 }
786
787 val = readl(addr);
788 val &= ~(0xff << ((dev_index << 4) + 8));
789 val |= (div & 0xff) << ((dev_index << 4) + 8);
790 writel(val, addr);
791}
792
Chander Kashyap34076a02012-02-05 23:01:46 +0000793/* exynos5: set the mmc clock */
794static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
795{
796 struct exynos5_clock *clk =
797 (struct exynos5_clock *)samsung_get_base_clock();
798 unsigned int addr;
799 unsigned int val;
800
801 /*
802 * CLK_DIV_FSYS1
803 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
804 * CLK_DIV_FSYS2
805 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
806 */
807 if (dev_index < 2) {
808 addr = (unsigned int)&clk->div_fsys1;
809 } else {
810 addr = (unsigned int)&clk->div_fsys2;
811 dev_index -= 2;
812 }
813
814 val = readl(addr);
815 val &= ~(0xff << ((dev_index << 4) + 8));
816 val |= (div & 0xff) << ((dev_index << 4) + 8);
817 writel(val, addr);
818}
819
Donghwa Lee77ba1912012-04-05 19:36:12 +0000820/* get_lcd_clk: return lcd clock frequency */
821static unsigned long exynos4_get_lcd_clk(void)
822{
823 struct exynos4_clock *clk =
824 (struct exynos4_clock *)samsung_get_base_clock();
825 unsigned long pclk, sclk;
826 unsigned int sel;
827 unsigned int ratio;
828
829 /*
830 * CLK_SRC_LCD0
831 * FIMD0_SEL [3:0]
832 */
833 sel = readl(&clk->src_lcd0);
834 sel = sel & 0xf;
835
836 /*
837 * 0x6: SCLK_MPLL
838 * 0x7: SCLK_EPLL
839 * 0x8: SCLK_VPLL
840 */
841 if (sel == 0x6)
842 sclk = get_pll_clk(MPLL);
843 else if (sel == 0x7)
844 sclk = get_pll_clk(EPLL);
845 else if (sel == 0x8)
846 sclk = get_pll_clk(VPLL);
847 else
848 return 0;
849
850 /*
851 * CLK_DIV_LCD0
852 * FIMD0_RATIO [3:0]
853 */
854 ratio = readl(&clk->div_lcd0);
855 ratio = ratio & 0xf;
856
857 pclk = sclk / (ratio + 1);
858
859 return pclk;
860}
861
Donghwa Lee3c9d4532012-07-02 01:15:49 +0000862/* get_lcd_clk: return lcd clock frequency */
863static unsigned long exynos5_get_lcd_clk(void)
864{
865 struct exynos5_clock *clk =
866 (struct exynos5_clock *)samsung_get_base_clock();
867 unsigned long pclk, sclk;
868 unsigned int sel;
869 unsigned int ratio;
870
871 /*
872 * CLK_SRC_LCD0
873 * FIMD0_SEL [3:0]
874 */
875 sel = readl(&clk->src_disp1_0);
876 sel = sel & 0xf;
877
878 /*
879 * 0x6: SCLK_MPLL
880 * 0x7: SCLK_EPLL
881 * 0x8: SCLK_VPLL
882 */
883 if (sel == 0x6)
884 sclk = get_pll_clk(MPLL);
885 else if (sel == 0x7)
886 sclk = get_pll_clk(EPLL);
887 else if (sel == 0x8)
888 sclk = get_pll_clk(VPLL);
889 else
890 return 0;
891
892 /*
893 * CLK_DIV_LCD0
894 * FIMD0_RATIO [3:0]
895 */
896 ratio = readl(&clk->div_disp1_0);
897 ratio = ratio & 0xf;
898
899 pclk = sclk / (ratio + 1);
900
901 return pclk;
902}
903
Donghwa Lee77ba1912012-04-05 19:36:12 +0000904void exynos4_set_lcd_clk(void)
905{
906 struct exynos4_clock *clk =
907 (struct exynos4_clock *)samsung_get_base_clock();
908 unsigned int cfg = 0;
909
910 /*
911 * CLK_GATE_BLOCK
912 * CLK_CAM [0]
913 * CLK_TV [1]
914 * CLK_MFC [2]
915 * CLK_G3D [3]
916 * CLK_LCD0 [4]
917 * CLK_LCD1 [5]
918 * CLK_GPS [7]
919 */
920 cfg = readl(&clk->gate_block);
921 cfg |= 1 << 4;
922 writel(cfg, &clk->gate_block);
923
924 /*
925 * CLK_SRC_LCD0
926 * FIMD0_SEL [3:0]
927 * MDNIE0_SEL [7:4]
928 * MDNIE_PWM0_SEL [8:11]
929 * MIPI0_SEL [12:15]
930 * set lcd0 src clock 0x6: SCLK_MPLL
931 */
932 cfg = readl(&clk->src_lcd0);
933 cfg &= ~(0xf);
934 cfg |= 0x6;
935 writel(cfg, &clk->src_lcd0);
936
937 /*
938 * CLK_GATE_IP_LCD0
939 * CLK_FIMD0 [0]
940 * CLK_MIE0 [1]
941 * CLK_MDNIE0 [2]
942 * CLK_DSIM0 [3]
943 * CLK_SMMUFIMD0 [4]
944 * CLK_PPMULCD0 [5]
945 * Gating all clocks for FIMD0
946 */
947 cfg = readl(&clk->gate_ip_lcd0);
948 cfg |= 1 << 0;
949 writel(cfg, &clk->gate_ip_lcd0);
950
951 /*
952 * CLK_DIV_LCD0
953 * FIMD0_RATIO [3:0]
954 * MDNIE0_RATIO [7:4]
955 * MDNIE_PWM0_RATIO [11:8]
956 * MDNIE_PWM_PRE_RATIO [15:12]
957 * MIPI0_RATIO [19:16]
958 * MIPI0_PRE_RATIO [23:20]
959 * set fimd ratio
960 */
961 cfg &= ~(0xf);
962 cfg |= 0x1;
963 writel(cfg, &clk->div_lcd0);
964}
965
Donghwa Lee3c9d4532012-07-02 01:15:49 +0000966void exynos5_set_lcd_clk(void)
967{
968 struct exynos5_clock *clk =
969 (struct exynos5_clock *)samsung_get_base_clock();
970 unsigned int cfg = 0;
971
972 /*
973 * CLK_GATE_BLOCK
974 * CLK_CAM [0]
975 * CLK_TV [1]
976 * CLK_MFC [2]
977 * CLK_G3D [3]
978 * CLK_LCD0 [4]
979 * CLK_LCD1 [5]
980 * CLK_GPS [7]
981 */
982 cfg = readl(&clk->gate_block);
983 cfg |= 1 << 4;
984 writel(cfg, &clk->gate_block);
985
986 /*
987 * CLK_SRC_LCD0
988 * FIMD0_SEL [3:0]
989 * MDNIE0_SEL [7:4]
990 * MDNIE_PWM0_SEL [8:11]
991 * MIPI0_SEL [12:15]
992 * set lcd0 src clock 0x6: SCLK_MPLL
993 */
994 cfg = readl(&clk->src_disp1_0);
995 cfg &= ~(0xf);
Ajay Kumar17dd8562013-01-08 20:42:23 +0000996 cfg |= 0x6;
Donghwa Lee3c9d4532012-07-02 01:15:49 +0000997 writel(cfg, &clk->src_disp1_0);
998
999 /*
1000 * CLK_GATE_IP_LCD0
1001 * CLK_FIMD0 [0]
1002 * CLK_MIE0 [1]
1003 * CLK_MDNIE0 [2]
1004 * CLK_DSIM0 [3]
1005 * CLK_SMMUFIMD0 [4]
1006 * CLK_PPMULCD0 [5]
1007 * Gating all clocks for FIMD0
1008 */
1009 cfg = readl(&clk->gate_ip_disp1);
1010 cfg |= 1 << 0;
1011 writel(cfg, &clk->gate_ip_disp1);
1012
1013 /*
1014 * CLK_DIV_LCD0
1015 * FIMD0_RATIO [3:0]
1016 * MDNIE0_RATIO [7:4]
1017 * MDNIE_PWM0_RATIO [11:8]
1018 * MDNIE_PWM_PRE_RATIO [15:12]
1019 * MIPI0_RATIO [19:16]
1020 * MIPI0_PRE_RATIO [23:20]
1021 * set fimd ratio
1022 */
1023 cfg &= ~(0xf);
1024 cfg |= 0x0;
1025 writel(cfg, &clk->div_disp1_0);
1026}
1027
Donghwa Lee77ba1912012-04-05 19:36:12 +00001028void exynos4_set_mipi_clk(void)
1029{
1030 struct exynos4_clock *clk =
1031 (struct exynos4_clock *)samsung_get_base_clock();
1032 unsigned int cfg = 0;
1033
1034 /*
1035 * CLK_SRC_LCD0
1036 * FIMD0_SEL [3:0]
1037 * MDNIE0_SEL [7:4]
1038 * MDNIE_PWM0_SEL [8:11]
1039 * MIPI0_SEL [12:15]
1040 * set mipi0 src clock 0x6: SCLK_MPLL
1041 */
1042 cfg = readl(&clk->src_lcd0);
1043 cfg &= ~(0xf << 12);
1044 cfg |= (0x6 << 12);
1045 writel(cfg, &clk->src_lcd0);
1046
1047 /*
1048 * CLK_SRC_MASK_LCD0
1049 * FIMD0_MASK [0]
1050 * MDNIE0_MASK [4]
1051 * MDNIE_PWM0_MASK [8]
1052 * MIPI0_MASK [12]
1053 * set src mask mipi0 0x1: Unmask
1054 */
1055 cfg = readl(&clk->src_mask_lcd0);
1056 cfg |= (0x1 << 12);
1057 writel(cfg, &clk->src_mask_lcd0);
1058
1059 /*
1060 * CLK_GATE_IP_LCD0
1061 * CLK_FIMD0 [0]
1062 * CLK_MIE0 [1]
1063 * CLK_MDNIE0 [2]
1064 * CLK_DSIM0 [3]
1065 * CLK_SMMUFIMD0 [4]
1066 * CLK_PPMULCD0 [5]
1067 * Gating all clocks for MIPI0
1068 */
1069 cfg = readl(&clk->gate_ip_lcd0);
1070 cfg |= 1 << 3;
1071 writel(cfg, &clk->gate_ip_lcd0);
1072
1073 /*
1074 * CLK_DIV_LCD0
1075 * FIMD0_RATIO [3:0]
1076 * MDNIE0_RATIO [7:4]
1077 * MDNIE_PWM0_RATIO [11:8]
1078 * MDNIE_PWM_PRE_RATIO [15:12]
1079 * MIPI0_RATIO [19:16]
1080 * MIPI0_PRE_RATIO [23:20]
1081 * set mipi ratio
1082 */
1083 cfg &= ~(0xf << 16);
1084 cfg |= (0x1 << 16);
1085 writel(cfg, &clk->div_lcd0);
1086}
1087
Rajeshwari Shinde1c9412a2012-07-23 21:23:48 +00001088/*
1089 * I2C
1090 *
1091 * exynos5: obtaining the I2C clock
1092 */
1093static unsigned long exynos5_get_i2c_clk(void)
1094{
1095 struct exynos5_clock *clk =
1096 (struct exynos5_clock *)samsung_get_base_clock();
1097 unsigned long aclk_66, aclk_66_pre, sclk;
1098 unsigned int ratio;
1099
1100 sclk = get_pll_clk(MPLL);
1101
1102 ratio = (readl(&clk->div_top1)) >> 24;
1103 ratio &= 0x7;
1104 aclk_66_pre = sclk / (ratio + 1);
1105 ratio = readl(&clk->div_top0);
1106 ratio &= 0x7;
1107 aclk_66 = aclk_66_pre / (ratio + 1);
1108 return aclk_66;
1109}
1110
Rajeshwari Shinde392a73a2012-10-25 19:49:29 +00001111int exynos5_set_epll_clk(unsigned long rate)
1112{
1113 unsigned int epll_con, epll_con_k;
1114 unsigned int i;
1115 unsigned int lockcnt;
1116 unsigned int start;
1117 struct exynos5_clock *clk =
1118 (struct exynos5_clock *)samsung_get_base_clock();
1119
1120 epll_con = readl(&clk->epll_con0);
1121 epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
1122 EPLL_CON0_LOCK_DET_EN_SHIFT) |
1123 EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
1124 EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
1125 EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
1126
1127 for (i = 0; i < ARRAY_SIZE(exynos5_epll_div); i++) {
1128 if (exynos5_epll_div[i].freq_out == rate)
1129 break;
1130 }
1131
1132 if (i == ARRAY_SIZE(exynos5_epll_div))
1133 return -1;
1134
1135 epll_con_k = exynos5_epll_div[i].k_dsm << 0;
1136 epll_con |= exynos5_epll_div[i].en_lock_det <<
1137 EPLL_CON0_LOCK_DET_EN_SHIFT;
1138 epll_con |= exynos5_epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
1139 epll_con |= exynos5_epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
1140 epll_con |= exynos5_epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
1141
1142 /*
1143 * Required period ( in cycles) to genarate a stable clock output.
1144 * The maximum clock time can be up to 3000 * PDIV cycles of PLLs
1145 * frequency input (as per spec)
1146 */
1147 lockcnt = 3000 * exynos5_epll_div[i].p_div;
1148
1149 writel(lockcnt, &clk->epll_lock);
1150 writel(epll_con, &clk->epll_con0);
1151 writel(epll_con_k, &clk->epll_con1);
1152
1153 start = get_timer(0);
1154
1155 while (!(readl(&clk->epll_con0) &
1156 (0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
1157 if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
1158 debug("%s: Timeout waiting for EPLL lock\n", __func__);
1159 return -1;
1160 }
1161 }
1162 return 0;
1163}
1164
1165void exynos5_set_i2s_clk_source(void)
1166{
1167 struct exynos5_clock *clk =
1168 (struct exynos5_clock *)samsung_get_base_clock();
1169
1170 clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
1171 (CLK_SRC_SCLK_EPLL));
1172}
1173
1174int exynos5_set_i2s_clk_prescaler(unsigned int src_frq,
1175 unsigned int dst_frq)
1176{
1177 struct exynos5_clock *clk =
1178 (struct exynos5_clock *)samsung_get_base_clock();
1179 unsigned int div;
1180
1181 if ((dst_frq == 0) || (src_frq == 0)) {
1182 debug("%s: Invalid requency input for prescaler\n", __func__);
1183 debug("src frq = %d des frq = %d ", src_frq, dst_frq);
1184 return -1;
1185 }
1186
1187 div = (src_frq / dst_frq);
1188 if (div > AUDIO_1_RATIO_MASK) {
1189 debug("%s: Frequency ratio is out of range\n", __func__);
1190 debug("src frq = %d des frq = %d ", src_frq, dst_frq);
1191 return -1;
1192 }
1193 clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
1194 (div & AUDIO_1_RATIO_MASK));
1195 return 0;
1196}
1197
Hatim RVe6365b62012-11-02 01:15:34 +00001198/**
1199 * Linearly searches for the most accurate main and fine stage clock scalars
1200 * (divisors) for a specified target frequency and scalar bit sizes by checking
1201 * all multiples of main_scalar_bits values. Will always return scalars up to or
1202 * slower than target.
1203 *
1204 * @param main_scalar_bits Number of main scalar bits, must be > 0 and < 32
1205 * @param fine_scalar_bits Number of fine scalar bits, must be > 0 and < 32
1206 * @param input_freq Clock frequency to be scaled in Hz
1207 * @param target_freq Desired clock frequency in Hz
1208 * @param best_fine_scalar Pointer to store the fine stage divisor
1209 *
1210 * @return best_main_scalar Main scalar for desired frequency or -1 if none
1211 * found
1212 */
1213static int clock_calc_best_scalar(unsigned int main_scaler_bits,
1214 unsigned int fine_scalar_bits, unsigned int input_rate,
1215 unsigned int target_rate, unsigned int *best_fine_scalar)
1216{
1217 int i;
1218 int best_main_scalar = -1;
1219 unsigned int best_error = target_rate;
1220 const unsigned int cap = (1 << fine_scalar_bits) - 1;
1221 const unsigned int loops = 1 << main_scaler_bits;
1222
1223 debug("Input Rate is %u, Target is %u, Cap is %u\n", input_rate,
1224 target_rate, cap);
1225
1226 assert(best_fine_scalar != NULL);
1227 assert(main_scaler_bits <= fine_scalar_bits);
1228
1229 *best_fine_scalar = 1;
1230
1231 if (input_rate == 0 || target_rate == 0)
1232 return -1;
1233
1234 if (target_rate >= input_rate)
1235 return 1;
1236
1237 for (i = 1; i <= loops; i++) {
1238 const unsigned int effective_div = max(min(input_rate / i /
1239 target_rate, cap), 1);
1240 const unsigned int effective_rate = input_rate / i /
1241 effective_div;
1242 const int error = target_rate - effective_rate;
1243
1244 debug("%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div,
1245 effective_rate, error);
1246
1247 if (error >= 0 && error <= best_error) {
1248 best_error = error;
1249 best_main_scalar = i;
1250 *best_fine_scalar = effective_div;
1251 }
1252 }
1253
1254 return best_main_scalar;
1255}
1256
1257static int exynos5_set_spi_clk(enum periph_id periph_id,
1258 unsigned int rate)
1259{
1260 struct exynos5_clock *clk =
1261 (struct exynos5_clock *)samsung_get_base_clock();
1262 int main;
1263 unsigned int fine;
1264 unsigned shift, pre_shift;
1265 unsigned mask = 0xff;
1266 u32 *reg;
1267
1268 main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
1269 if (main < 0) {
1270 debug("%s: Cannot set clock rate for periph %d",
1271 __func__, periph_id);
1272 return -1;
1273 }
1274 main = main - 1;
1275 fine = fine - 1;
1276
1277 switch (periph_id) {
1278 case PERIPH_ID_SPI0:
1279 reg = &clk->div_peric1;
1280 shift = 0;
1281 pre_shift = 8;
1282 break;
1283 case PERIPH_ID_SPI1:
1284 reg = &clk->div_peric1;
1285 shift = 16;
1286 pre_shift = 24;
1287 break;
1288 case PERIPH_ID_SPI2:
1289 reg = &clk->div_peric2;
1290 shift = 0;
1291 pre_shift = 8;
1292 break;
1293 case PERIPH_ID_SPI3:
1294 reg = &clk->sclk_div_isp;
1295 shift = 0;
1296 pre_shift = 4;
1297 break;
1298 case PERIPH_ID_SPI4:
1299 reg = &clk->sclk_div_isp;
1300 shift = 12;
1301 pre_shift = 16;
1302 break;
1303 default:
1304 debug("%s: Unsupported peripheral ID %d\n", __func__,
1305 periph_id);
1306 return -1;
1307 }
1308 clrsetbits_le32(reg, mask << shift, (main & mask) << shift);
1309 clrsetbits_le32(reg, mask << pre_shift, (fine & mask) << pre_shift);
1310
1311 return 0;
1312}
1313
Piotr Wilczek01d589f2012-11-20 02:19:02 +00001314static unsigned long exynos4_get_i2c_clk(void)
1315{
1316 struct exynos4_clock *clk =
1317 (struct exynos4_clock *)samsung_get_base_clock();
1318 unsigned long sclk, aclk_100;
1319 unsigned int ratio;
1320
1321 sclk = get_pll_clk(APLL);
1322
1323 ratio = (readl(&clk->div_top)) >> 4;
1324 ratio &= 0xf;
1325 aclk_100 = sclk / (ratio + 1);
1326 return aclk_100;
Minkyu Kangb1b24682011-01-24 15:22:23 +09001327}
1328
1329unsigned long get_pll_clk(int pllreg)
1330{
Chander Kashyap34076a02012-02-05 23:01:46 +00001331 if (cpu_is_exynos5())
1332 return exynos5_get_pll_clk(pllreg);
Chander Kashyap400ab162012-10-07 01:43:17 +00001333 else {
1334 if (proid_is_exynos4412())
1335 return exynos4x12_get_pll_clk(pllreg);
Chander Kashyap34076a02012-02-05 23:01:46 +00001336 return exynos4_get_pll_clk(pllreg);
Chander Kashyap400ab162012-10-07 01:43:17 +00001337 }
Minkyu Kangb1b24682011-01-24 15:22:23 +09001338}
1339
1340unsigned long get_arm_clk(void)
1341{
Chander Kashyap34076a02012-02-05 23:01:46 +00001342 if (cpu_is_exynos5())
1343 return exynos5_get_arm_clk();
Chander Kashyap400ab162012-10-07 01:43:17 +00001344 else {
1345 if (proid_is_exynos4412())
1346 return exynos4x12_get_arm_clk();
Chander Kashyap34076a02012-02-05 23:01:46 +00001347 return exynos4_get_arm_clk();
Chander Kashyap400ab162012-10-07 01:43:17 +00001348 }
Minkyu Kangb1b24682011-01-24 15:22:23 +09001349}
1350
Rajeshwari Shinde1c9412a2012-07-23 21:23:48 +00001351unsigned long get_i2c_clk(void)
1352{
1353 if (cpu_is_exynos5()) {
1354 return exynos5_get_i2c_clk();
Piotr Wilczek01d589f2012-11-20 02:19:02 +00001355 } else if (cpu_is_exynos4()) {
1356 return exynos4_get_i2c_clk();
Rajeshwari Shinde1c9412a2012-07-23 21:23:48 +00001357 } else {
1358 debug("I2C clock is not set for this CPU\n");
1359 return 0;
1360 }
1361}
1362
Minkyu Kangb1b24682011-01-24 15:22:23 +09001363unsigned long get_pwm_clk(void)
1364{
Chander Kashyap34076a02012-02-05 23:01:46 +00001365 if (cpu_is_exynos5())
Padmavathi Vennabb714162013-03-28 04:32:23 +00001366 return clock_get_periph_rate(PERIPH_ID_PWM0);
Chander Kashyap400ab162012-10-07 01:43:17 +00001367 else {
1368 if (proid_is_exynos4412())
1369 return exynos4x12_get_pwm_clk();
Chander Kashyap34076a02012-02-05 23:01:46 +00001370 return exynos4_get_pwm_clk();
Chander Kashyap400ab162012-10-07 01:43:17 +00001371 }
Minkyu Kangb1b24682011-01-24 15:22:23 +09001372}
1373
1374unsigned long get_uart_clk(int dev_index)
1375{
Chander Kashyap34076a02012-02-05 23:01:46 +00001376 if (cpu_is_exynos5())
1377 return exynos5_get_uart_clk(dev_index);
Chander Kashyap400ab162012-10-07 01:43:17 +00001378 else {
1379 if (proid_is_exynos4412())
1380 return exynos4x12_get_uart_clk(dev_index);
Chander Kashyap34076a02012-02-05 23:01:46 +00001381 return exynos4_get_uart_clk(dev_index);
Chander Kashyap400ab162012-10-07 01:43:17 +00001382 }
Minkyu Kangb1b24682011-01-24 15:22:23 +09001383}
Jaehoon Chung9a772212011-05-17 21:19:17 +00001384
Jaehoon Chung8788e062012-12-27 22:30:32 +00001385unsigned long get_mmc_clk(int dev_index)
1386{
1387 if (cpu_is_exynos5())
1388 return exynos5_get_mmc_clk(dev_index);
1389 else
1390 return exynos4_get_mmc_clk(dev_index);
1391}
1392
Jaehoon Chung9a772212011-05-17 21:19:17 +00001393void set_mmc_clk(int dev_index, unsigned int div)
1394{
Chander Kashyap34076a02012-02-05 23:01:46 +00001395 if (cpu_is_exynos5())
1396 exynos5_set_mmc_clk(dev_index, div);
Chander Kashyap400ab162012-10-07 01:43:17 +00001397 else {
1398 if (proid_is_exynos4412())
1399 exynos4x12_set_mmc_clk(dev_index, div);
Chander Kashyap34076a02012-02-05 23:01:46 +00001400 exynos4_set_mmc_clk(dev_index, div);
Chander Kashyap400ab162012-10-07 01:43:17 +00001401 }
Jaehoon Chung9a772212011-05-17 21:19:17 +00001402}
Donghwa Lee77ba1912012-04-05 19:36:12 +00001403
1404unsigned long get_lcd_clk(void)
1405{
1406 if (cpu_is_exynos4())
1407 return exynos4_get_lcd_clk();
1408 else
Donghwa Lee3c9d4532012-07-02 01:15:49 +00001409 return exynos5_get_lcd_clk();
Donghwa Lee77ba1912012-04-05 19:36:12 +00001410}
1411
1412void set_lcd_clk(void)
1413{
1414 if (cpu_is_exynos4())
1415 exynos4_set_lcd_clk();
Donghwa Lee3c9d4532012-07-02 01:15:49 +00001416 else
1417 exynos5_set_lcd_clk();
Donghwa Lee77ba1912012-04-05 19:36:12 +00001418}
1419
1420void set_mipi_clk(void)
1421{
1422 if (cpu_is_exynos4())
1423 exynos4_set_mipi_clk();
1424}
Rajeshwari Shinde392a73a2012-10-25 19:49:29 +00001425
Hatim RVe6365b62012-11-02 01:15:34 +00001426int set_spi_clk(int periph_id, unsigned int rate)
1427{
1428 if (cpu_is_exynos5())
1429 return exynos5_set_spi_clk(periph_id, rate);
1430 else
1431 return 0;
1432}
1433
Rajeshwari Shinde392a73a2012-10-25 19:49:29 +00001434int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
1435{
1436
1437 if (cpu_is_exynos5())
1438 return exynos5_set_i2s_clk_prescaler(src_frq, dst_frq);
1439 else
1440 return 0;
1441}
1442
1443void set_i2s_clk_source(void)
1444{
1445 if (cpu_is_exynos5())
1446 exynos5_set_i2s_clk_source();
1447}
1448
1449int set_epll_clk(unsigned long rate)
1450{
1451 if (cpu_is_exynos5())
1452 return exynos5_set_epll_clk(rate);
1453 else
1454 return 0;
1455}