Commit | Line | Data |
---|---|---|
3c2a0909 S |
1 | /* |
2 | * Copyright (c) 2013 Samsung Electronics Co., Ltd. | |
3 | * http://www.samsung.com | |
4 | * | |
5 | * EXYNOS5430 - EAGLE Core frequency scaling support | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | */ | |
11 | ||
12 | #include <linux/kernel.h> | |
13 | #include <linux/err.h> | |
14 | #include <linux/clk.h> | |
15 | #include <linux/io.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/cpufreq.h> | |
18 | #include <linux/clk-private.h> | |
19 | ||
20 | #include <mach/map.h> | |
21 | #include <mach/regs-clock.h> | |
22 | #include <mach/regs-clock-exynos5430.h> | |
23 | #include <mach/regs-pmu.h> | |
24 | #include <mach/cpufreq.h> | |
25 | #include <mach/asv-exynos.h> | |
26 | ||
27 | #define CPUFREQ_LEVEL_END_CA15 (L23 + 1) | |
28 | #define L2_LOCAL_PWR_EN 0x7 | |
29 | ||
30 | #undef PRINT_DIV_VAL | |
31 | #undef ENABLE_CLKOUT | |
32 | ||
33 | #define EMA_VAL_REG (S5P_VA_CHIPID2 + 0x20) | |
34 | #define EMA_CON1_SHIFT 2 | |
35 | #define EMA_CON2_SHIFT 5 | |
36 | #define EMA_CON_MASK 0x7 | |
37 | #define EMA_VAL_0 0x0 | |
38 | #define EMA_VAL_1 0x1 | |
39 | #define EMA_VAL_3 0x3 | |
40 | #define EMA_VAL_4 0x4 | |
41 | #define EMA_VOLT 900000 | |
42 | #define EGL_L1_EMA_SHIFT 8 | |
43 | #define EGL_L2_EMA_SHIFT 20 | |
44 | #define CLK_EGL_EMA_OFFSET 0x0330 | |
45 | ||
46 | static int max_support_idx_CA15; | |
47 | static int min_support_idx_CA15 = (CPUFREQ_LEVEL_END_CA15 - 1); | |
48 | ||
49 | static struct clk *mout_egl; | |
50 | static struct clk *mout_egl_pll; | |
51 | static struct clk *sclk_bus_pll; | |
52 | static struct clk *mout_bus_pll_user; | |
53 | static struct clk *fout_egl_pll; | |
54 | static unsigned int spd_option_flag, spd_sel; | |
55 | ||
56 | static void __iomem *clk_egl_2_base; | |
57 | static int egl_ema_con1; | |
58 | static int egl_ema_con2; | |
59 | ||
60 | static unsigned int exynos5430_volt_table_CA15[CPUFREQ_LEVEL_END_CA15]; | |
61 | static unsigned int exynos5430_abb_table_CA15[CPUFREQ_LEVEL_END_CA15]; | |
62 | ||
63 | static struct cpufreq_frequency_table exynos5430_freq_table_CA15[] = { | |
64 | {L0, 2500 * 1000}, | |
65 | {L1, 2400 * 1000}, | |
66 | {L2, 2300 * 1000}, | |
67 | {L3, 2200 * 1000}, | |
68 | {L4, 2100 * 1000}, | |
69 | {L5, 2000 * 1000}, | |
70 | {L6, 1900 * 1000}, | |
71 | {L7, 1800 * 1000}, | |
72 | {L8, 1700 * 1000}, | |
73 | {L9, 1600 * 1000}, | |
74 | {L10, 1500 * 1000}, | |
75 | {L11, 1400 * 1000}, | |
76 | {L12, 1300 * 1000}, | |
77 | {L13, 1200 * 1000}, | |
78 | {L14, 1100 * 1000}, | |
79 | {L15, 1000 * 1000}, | |
80 | {L16, 900 * 1000}, | |
81 | {L17, 800 * 1000}, | |
82 | {L18, 700 * 1000}, | |
83 | {L19, 600 * 1000}, | |
84 | {L20, 500 * 1000}, | |
85 | {L21, 400 * 1000}, | |
86 | {L22, 300 * 1000}, | |
87 | {L23, 200 * 1000}, | |
88 | {0, CPUFREQ_TABLE_END}, | |
89 | }; | |
90 | ||
91 | static struct cpufreq_clkdiv exynos5430_clkdiv_table_CA15[CPUFREQ_LEVEL_END_CA15]; | |
92 | ||
93 | static unsigned int clkdiv_cpu0_5430_CA15[CPUFREQ_LEVEL_END_CA15][6] = { | |
94 | /* | |
95 | * Clock divider value for following | |
96 | * { EGL1, EGL2, ACLK_EGL, PCLK_EGL, | |
97 | * ATCLK, PCLK_DBG_EGL } | |
98 | */ | |
99 | ||
100 | /* ARM L0: 2.5GHz */ | |
101 | { 0, 0, 4, 7, 7, 7 }, | |
102 | ||
103 | /* ARM L1: 2.4GMHz */ | |
104 | { 0, 0, 4, 7, 7, 7 }, | |
105 | ||
106 | /* ARM L2: 2.3GMHz */ | |
107 | { 0, 0, 4, 7, 7, 7 }, | |
108 | ||
109 | /* ARM L3: 2.2GHz */ | |
110 | { 0, 0, 4, 7, 7, 7 }, | |
111 | ||
112 | /* ARM L4: 2.1GHz */ | |
113 | { 0, 0, 4, 7, 7, 7 }, | |
114 | ||
115 | /* ARM L5: 2.0GHz */ | |
116 | { 0, 0, 4, 7, 7, 7 }, | |
117 | ||
118 | /* ARM L6: 1.9GHz */ | |
119 | { 0, 0, 4, 7, 7, 7 }, | |
120 | ||
121 | /* ARM L7: 1.8GHz */ | |
122 | { 0, 0, 4, 7, 7, 7 }, | |
123 | ||
124 | /* ARM L8: 1.7GHz */ | |
125 | { 0, 0, 4, 7, 7, 7 }, | |
126 | ||
127 | /* ARM L9: 1.6GHz */ | |
128 | { 0, 0, 4, 7, 7, 7 }, | |
129 | ||
130 | /* ARM L10: 1.5GHz */ | |
131 | { 0, 0, 3, 7, 7, 7 }, | |
132 | ||
133 | /* ARM L11: 1.4GHz */ | |
134 | { 0, 0, 3, 7, 7, 7 }, | |
135 | ||
136 | /* ARM L12: 1.3GHz */ | |
137 | { 0, 0, 3, 7, 7, 7 }, | |
138 | ||
139 | /* ARM L13: 1.2GHz */ | |
140 | { 0, 0, 3, 7, 7, 7 }, | |
141 | ||
142 | /* ARM L14: 1.1GHz */ | |
143 | { 0, 0, 2, 7, 7, 7 }, | |
144 | ||
145 | /* ARM L15: 1.0GHz */ | |
146 | { 0, 0, 2, 7, 7, 7 }, | |
147 | ||
148 | /* ARM L16: 900MHz */ | |
149 | { 0, 0, 2, 7, 7, 7 }, | |
150 | ||
151 | /* ARM L17: 800MHz */ | |
152 | { 0, 0, 2, 7, 7, 7 }, | |
153 | ||
154 | /* ARM L18: 700MHz */ | |
155 | { 0, 0, 2, 7, 7, 7 }, | |
156 | ||
157 | /* ARM L19: 600MHz */ | |
158 | { 0, 0, 2, 7, 7, 7 }, | |
159 | ||
160 | /* ARM L20: 500MHz */ | |
161 | { 0, 0, 2, 7, 7, 7 }, | |
162 | ||
163 | /* ARM L21: 400MHz */ | |
164 | { 0, 0, 2, 7, 7, 7 }, | |
165 | ||
166 | /* ARM L22: 300MHz */ | |
167 | { 0, 0, 2, 7, 7, 7 }, | |
168 | ||
169 | /* ARM L23: 200MHz */ | |
170 | { 0, 0, 2, 7, 7, 7 }, | |
171 | }; | |
172 | ||
173 | static unsigned int clkdiv_cpu1_5430_CA15[CPUFREQ_LEVEL_END_CA15][2] = { | |
174 | /* | |
175 | * Clock divider value for following | |
176 | * { SCLK_EGL_PLL, SCLK_HPM_EGL } | |
177 | */ | |
178 | ||
179 | /* ARM L0: 2.5GHz */ | |
180 | { 1, 7 }, | |
181 | ||
182 | /* ARM L1: 2.4GMHz */ | |
183 | { 1, 7 }, | |
184 | ||
185 | /* ARM L2: 2.3GMHz */ | |
186 | { 1, 7 }, | |
187 | ||
188 | /* ARM L3: 2.2GHz */ | |
189 | { 1, 7 }, | |
190 | ||
191 | /* ARM L4: 2.1GHz */ | |
192 | { 1, 7 }, | |
193 | ||
194 | /* ARM L5: 2.0GHz */ | |
195 | { 1, 7 }, | |
196 | ||
197 | /* ARM L6: 1.9GHz */ | |
198 | { 1, 7 }, | |
199 | ||
200 | /* ARM L7: 1.8GHz */ | |
201 | { 1, 7 }, | |
202 | ||
203 | /* ARM L8: 1.7GHz */ | |
204 | { 1, 7 }, | |
205 | ||
206 | /* ARM L9: 1.6GHz */ | |
207 | { 1, 7 }, | |
208 | ||
209 | /* ARM L10: 1.5GHz */ | |
210 | { 1, 7 }, | |
211 | ||
212 | /* ARM L11: 1.4GHz */ | |
213 | { 1, 7 }, | |
214 | ||
215 | /* ARM L12: 1.3GHz */ | |
216 | { 1, 7 }, | |
217 | ||
218 | /* ARM L13: 1.2GHz */ | |
219 | { 1, 7 }, | |
220 | ||
221 | /* ARM L14: 1.1GHz */ | |
222 | { 1, 7 }, | |
223 | ||
224 | /* ARM L15: 1.0GHz */ | |
225 | { 1, 7 }, | |
226 | ||
227 | /* ARM L16: 900MHz */ | |
228 | { 1, 7 }, | |
229 | ||
230 | /* ARM L17: 800MHz */ | |
231 | { 1, 7 }, | |
232 | ||
233 | /* ARM L18: 700MHz */ | |
234 | { 1, 7 }, | |
235 | ||
236 | /* ARM L19: 600MHz */ | |
237 | { 1, 7 }, | |
238 | ||
239 | /* ARM L20: 500MHz */ | |
240 | { 1, 7 }, | |
241 | ||
242 | /* ARM L21: 400MHz */ | |
243 | { 1, 7 }, | |
244 | ||
245 | /* ARM L22: 300MHz */ | |
246 | { 1, 7 }, | |
247 | ||
248 | /* ARM L23: 200MHz */ | |
249 | { 1, 7 }, | |
250 | }; | |
251 | ||
252 | static unsigned int exynos5430_egl_pll_pms_table_CA15[CPUFREQ_LEVEL_END_CA15] = { | |
253 | /* MDIV | PDIV | SDIV */ | |
254 | /* EGL_PLL FOUT L0: 2.5GHz */ | |
255 | PLL2450X_PMS(625, 6, 0), | |
256 | ||
257 | /* EGL_PLL FOUT L1: 2.4GHz */ | |
258 | PLL2450X_PMS(500, 5, 0), | |
259 | ||
260 | /* EGL_PLL FOUT L2: 2.3GHz */ | |
261 | PLL2450X_PMS(575, 6, 0), | |
262 | ||
263 | /* EGL_PLL FOUT L3: 2.2GHz */ | |
264 | PLL2450X_PMS(550, 6, 0), | |
265 | ||
266 | /* EGL_PLL FOUT L4: 2.1GHz */ | |
267 | PLL2450X_PMS(350, 4, 0), | |
268 | ||
269 | /* EGL_PLL FOUT L5: 2.0GHz */ | |
270 | PLL2450X_PMS(500, 6, 0), | |
271 | ||
272 | /* EGL_PLL FOUT L6: 1.9GHz */ | |
273 | PLL2450X_PMS(475, 6, 0), | |
274 | ||
275 | /* EGL_PLL FOUT L7: 1.8GHz */ | |
276 | PLL2450X_PMS(375, 5, 0), | |
277 | ||
278 | /* EGL_PLL FOUT L8: 1.7GHz */ | |
279 | PLL2450X_PMS(425, 6, 0), | |
280 | ||
281 | /* EGL_PLL FOUT L9: 1.6GHz */ | |
282 | PLL2450X_PMS(400, 6, 0), | |
283 | ||
284 | /* EGL_PLL FOUT L10: 1.5GHz */ | |
285 | PLL2450X_PMS(250, 4, 0), | |
286 | ||
287 | /* EGL_PLL FOUT L11: 1.4GHz */ | |
288 | PLL2450X_PMS(350, 6, 0), | |
289 | ||
290 | /* EGL_PLL FOUT L12: 1.3GHz */ | |
291 | PLL2450X_PMS(325, 6, 0), | |
292 | ||
293 | /* EGL_PLL FOUT L13: 1.2GHz */ | |
294 | PLL2450X_PMS(500, 5, 1), | |
295 | ||
296 | /* EGL_PLL FOUT L14: 1.1GHz */ | |
297 | PLL2450X_PMS(550, 6, 1), | |
298 | ||
299 | /* EGL_PLL FOUT L15: 1.0GHz */ | |
300 | PLL2450X_PMS(500, 6, 1), | |
301 | ||
302 | /* EGL_PLL FOUT L16: 900MHz */ | |
303 | PLL2450X_PMS(375, 5, 1), | |
304 | ||
305 | /* EGL_PLL FOUT L17: 800MHz */ | |
306 | PLL2450X_PMS(400, 6, 1), | |
307 | ||
308 | /* EGL_PLL FOUT L18: 700MHz */ | |
309 | PLL2450X_PMS(350, 6, 1), | |
310 | ||
311 | /* EGL_PLL FOUT L19: 600MHz */ | |
312 | PLL2450X_PMS(500, 5, 2), | |
313 | ||
314 | /* EGL_PLL FOUT L20: 500MHz */ | |
315 | PLL2450X_PMS(500, 6, 2), | |
316 | ||
317 | /* EGL_PLL FOUT L21: 400MHz */ | |
318 | PLL2450X_PMS(400, 6, 2), | |
319 | ||
320 | /* EGL_PLL FOUT L22: 300MHz */ | |
321 | PLL2450X_PMS(500, 5, 3), | |
322 | ||
323 | /* EGL_PLL FOUT L23: 200MHz */ | |
324 | PLL2450X_PMS(400, 6, 3), | |
325 | }; | |
326 | ||
327 | /* | |
328 | * ASV group voltage table | |
329 | */ | |
330 | static const unsigned int asv_voltage_5430_CA15[CPUFREQ_LEVEL_END_CA15] = { | |
331 | 1300000, /* LO 2500 */ | |
332 | 1300000, /* L1 2400 */ | |
333 | 1300000, /* L2 2300 */ | |
334 | 1300000, /* L3 2200 */ | |
335 | 1300000, /* L4 2100 */ | |
336 | 1300000, /* L5 2000 */ | |
337 | 1300000, /* L6 1900 */ | |
338 | 1300000, /* L7 1800 */ | |
339 | 1275000, /* L8 1700 */ | |
340 | 1250000, /* L9 1600 */ | |
341 | 1225000, /* L10 1500 */ | |
342 | 1187500, /* L11 1400 */ | |
343 | 1150000, /* L12 1300 */ | |
344 | 1125000, /* L13 1200 */ | |
345 | 1100000, /* L14 1100 */ | |
346 | 1075000, /* L15 1000 */ | |
347 | 1050000, /* L16 900 */ | |
348 | 1025000, /* L17 800 */ | |
349 | 1025000, /* L18 700 */ | |
350 | 1000000, /* L19 600 */ | |
351 | 1000000, /* L20 500 */ | |
352 | 975000, /* L21 400 */ | |
353 | 925000, /* L22 300 */ | |
354 | 925000, /* L23 200 */ | |
355 | }; | |
356 | ||
357 | /* Minimum memory throughput in megabytes per second */ | |
358 | static int exynos5430_bus_table_CA15[CPUFREQ_LEVEL_END_CA15] = { | |
359 | 825000, /* 2.5 GHz */ | |
360 | 825000, /* 2.4 GHz */ | |
361 | 825000, /* 2.3 GHz */ | |
362 | 825000, /* 2.2 GHz */ | |
363 | 825000, /* 2.1 GHz */ | |
364 | 825000, /* 2.0 GHz */ | |
365 | 825000, /* 1.9 GHz */ | |
366 | 825000, /* 1.8 GHz */ | |
367 | 633000, /* 1.7 MHz */ | |
368 | 633000, /* 1.6 GHz */ | |
369 | 633000, /* 1.5 GHz */ | |
370 | 633000, /* 1.4 GHz */ | |
371 | 543000, /* 1.3 GHz */ | |
372 | 543000, /* 1.2 GHz */ | |
373 | 413000, /* 1.1 GHz */ | |
374 | 413000, /* 1.0 GHz */ | |
375 | 0, /* 900 MHz */ | |
376 | 0, /* 800 MHz */ | |
377 | 0, /* 700 MHz */ | |
378 | 0, /* 600 MHz */ | |
379 | 0, /* 500 MHz */ | |
380 | 0, /* 400 MHz */ | |
381 | 0, /* 300 MHz */ | |
382 | 0, /* 200 MHz */ | |
383 | }; | |
384 | ||
385 | static int exynos5430_ema_valid_check_CA15(int ema_con_val) | |
386 | { | |
387 | int ret = 0; | |
388 | ||
389 | switch (ema_con_val) { | |
390 | case EMA_VAL_0: | |
391 | case EMA_VAL_1: | |
392 | case EMA_VAL_3: | |
393 | case EMA_VAL_4: | |
394 | ret = ema_con_val; | |
395 | break; | |
396 | default: | |
397 | ret = -EINVAL; | |
398 | break; | |
399 | } | |
400 | ||
401 | return ret; | |
402 | } | |
403 | ||
404 | static void exynos5430_set_ema_CA15(unsigned int target_volt) | |
405 | { | |
406 | unsigned int tmp; | |
407 | ||
408 | tmp = __raw_readl(clk_egl_2_base + CLK_EGL_EMA_OFFSET); | |
409 | ||
410 | if (target_volt > EMA_VOLT) { | |
411 | if (egl_ema_con1 > 0) { | |
412 | tmp &= ~((EMA_CON_MASK << EGL_L1_EMA_SHIFT) | | |
413 | (EMA_CON_MASK << EGL_L2_EMA_SHIFT)); | |
414 | tmp |= ((egl_ema_con1 << EGL_L1_EMA_SHIFT) | | |
415 | (egl_ema_con1 << EGL_L2_EMA_SHIFT)); | |
416 | __raw_writel(tmp, clk_egl_2_base + CLK_EGL_EMA_OFFSET); | |
417 | } | |
418 | } else { | |
419 | if (egl_ema_con2 > 0) { | |
420 | tmp &= ~((EMA_CON_MASK << EGL_L1_EMA_SHIFT) | | |
421 | (EMA_CON_MASK << EGL_L2_EMA_SHIFT)); | |
422 | tmp |= ((egl_ema_con2 << EGL_L1_EMA_SHIFT) | | |
423 | (egl_ema_con2 << EGL_L2_EMA_SHIFT)); | |
424 | __raw_writel(tmp, clk_egl_2_base + CLK_EGL_EMA_OFFSET); | |
425 | } | |
426 | } | |
427 | } | |
428 | ||
429 | static void exynos5430_set_clkdiv_CA15(unsigned int div_index) | |
430 | { | |
431 | unsigned int tmp, tmp1; | |
432 | ||
433 | /* Change Divider - EGL0 */ | |
434 | tmp = exynos5430_clkdiv_table_CA15[div_index].clkdiv0; | |
435 | ||
436 | __raw_writel(tmp, EXYNOS5430_DIV_EGL0); | |
437 | ||
438 | while (__raw_readl(EXYNOS5430_DIV_STAT_EGL0) & 0x111111) | |
439 | cpu_relax(); | |
440 | ||
441 | /* Change Divider - EGL1 */ | |
442 | tmp1 = exynos5430_clkdiv_table_CA15[div_index].clkdiv1; | |
443 | ||
444 | __raw_writel(tmp1, EXYNOS5430_DIV_EGL1); | |
445 | ||
446 | while (__raw_readl(EXYNOS5430_DIV_STAT_EGL1) & 0x11) | |
447 | cpu_relax(); | |
448 | ||
449 | #ifdef PRINT_DIV_VAL | |
450 | tmp = __raw_readl(EXYNOS5430_DIV_EGL0); | |
451 | tmp1 = __raw_readl(EXYNOS5430_DIV_EGL1); | |
452 | ||
453 | pr_info("%s: DIV_EGL0[0x%08x], DIV_EGL1[0x%08x]\n", | |
454 | __func__, tmp, tmp1); | |
455 | #endif | |
456 | } | |
457 | ||
458 | static void exynos5430_set_egl_pll_CA15(unsigned int new_index, unsigned int old_index) | |
459 | { | |
460 | unsigned int tmp, pdiv; | |
461 | ||
462 | /* 1. before change to BUS_PLL, set div for BUS_PLL output */ | |
463 | if ((new_index < L17) && (old_index < L17)) | |
464 | exynos5430_set_clkdiv_CA15(L17); /* pll_safe_idx of CA15 */ | |
465 | ||
466 | /* 2. CLKMUX_SEL_EGL = MOUT_BUS_PLL_USER, EGLCLK uses BUS_PLL_USER for lock time */ | |
467 | if (clk_set_parent(mout_egl, mout_bus_pll_user)) | |
468 | pr_err("Unable to set parent %s of clock %s.\n", | |
469 | mout_bus_pll_user->name, mout_egl->name); | |
470 | do { | |
471 | cpu_relax(); | |
472 | tmp = __raw_readl(EXYNOS5430_SRC_STAT_EGL2); | |
473 | tmp &= EXYNOS5430_SRC_STAT_EGL2_EGL_MASK; | |
474 | tmp >>= EXYNOS5430_SRC_STAT_EGL2_EGL_SHIFT; | |
475 | } while (tmp != 0x2); | |
476 | ||
477 | /* 3. Set EGL_PLL Lock time */ | |
478 | pdiv = ((exynos5430_egl_pll_pms_table_CA15[new_index] & | |
479 | EXYNOS5430_PLL_PDIV_MASK) >> EXYNOS5430_PLL_PDIV_SHIFT); | |
480 | ||
481 | __raw_writel((pdiv * 150), EXYNOS5430_EGL_PLL_LOCK); | |
482 | ||
483 | /* 4. Change PLL PMS values */ | |
484 | tmp = __raw_readl(EXYNOS5430_EGL_PLL_CON0); | |
485 | tmp &= ~(EXYNOS5430_PLL_MDIV_MASK | | |
486 | EXYNOS5430_PLL_PDIV_MASK | | |
487 | EXYNOS5430_PLL_SDIV_MASK); | |
488 | tmp |= exynos5430_egl_pll_pms_table_CA15[new_index]; | |
489 | __raw_writel(tmp, EXYNOS5430_EGL_PLL_CON0); | |
490 | ||
491 | /* 5. wait_lock_time */ | |
492 | do { | |
493 | cpu_relax(); | |
494 | tmp = __raw_readl(EXYNOS5430_EGL_PLL_CON0); | |
495 | } while (!(tmp & (0x1 << EXYNOS5430_EGL_PLL_CON0_LOCKED_SHIFT))); | |
496 | ||
497 | /* 6. CLKMUX_SEL_EGL = MOUT_EGL_PLL */ | |
498 | if (clk_set_parent(mout_egl, mout_egl_pll)) | |
499 | pr_err("Unable to set parent %s of clock %s.\n", | |
500 | mout_egl_pll->name, mout_egl->name); | |
501 | do { | |
502 | cpu_relax(); | |
503 | tmp = __raw_readl(EXYNOS5430_SRC_STAT_EGL2); | |
504 | tmp &= EXYNOS5430_SRC_STAT_EGL2_EGL_MASK; | |
505 | tmp >>= EXYNOS5430_SRC_STAT_EGL2_EGL_SHIFT; | |
506 | } while (tmp != 0x1); | |
507 | ||
508 | /* 7. restore original div value */ | |
509 | if ((new_index < L17) && (old_index < L17)) | |
510 | exynos5430_set_clkdiv_CA15(new_index); | |
511 | } | |
512 | ||
513 | static bool exynos5430_pms_change_CA15(unsigned int old_index, | |
514 | unsigned int new_index) | |
515 | { | |
516 | unsigned int old_pm = (exynos5430_egl_pll_pms_table_CA15[old_index] >> | |
517 | EXYNOS5430_PLL_PDIV_SHIFT); | |
518 | unsigned int new_pm = (exynos5430_egl_pll_pms_table_CA15[new_index] >> | |
519 | EXYNOS5430_PLL_PDIV_SHIFT); | |
520 | ||
521 | return (old_pm == new_pm) ? 0 : 1; | |
522 | } | |
523 | ||
524 | static void exynos5430_set_frequency_CA15(unsigned int old_index, | |
525 | unsigned int new_index) | |
526 | { | |
527 | unsigned int tmp; | |
528 | ||
529 | if (old_index > new_index) { | |
530 | if (!exynos5430_pms_change_CA15(old_index, new_index)) { | |
531 | /* 1. Change the system clock divider values */ | |
532 | exynos5430_set_clkdiv_CA15(new_index); | |
533 | /* 2. Change just s value in egl_pll m,p,s value */ | |
534 | tmp = __raw_readl(EXYNOS5430_EGL_PLL_CON0); | |
535 | tmp &= ~EXYNOS5430_PLL_SDIV_MASK; | |
536 | tmp |= (exynos5430_egl_pll_pms_table_CA15[new_index] & EXYNOS5430_PLL_SDIV_MASK); | |
537 | __raw_writel(tmp, EXYNOS5430_EGL_PLL_CON0); | |
538 | } else { | |
539 | /* Clock Configuration Procedure */ | |
540 | /* 1. Change the system clock divider values */ | |
541 | exynos5430_set_clkdiv_CA15(new_index); | |
542 | /* 2. Change the egl_pll m,p,s value */ | |
543 | exynos5430_set_egl_pll_CA15(new_index, old_index); | |
544 | } | |
545 | } else if (old_index < new_index) { | |
546 | if (!exynos5430_pms_change_CA15(old_index, new_index)) { | |
547 | /* 1. Change just s value in egl_pll m,p,s value */ | |
548 | tmp = __raw_readl(EXYNOS5430_EGL_PLL_CON0); | |
549 | tmp &= ~EXYNOS5430_PLL_SDIV_MASK; | |
550 | tmp |= (exynos5430_egl_pll_pms_table_CA15[new_index] & EXYNOS5430_PLL_SDIV_MASK); | |
551 | __raw_writel(tmp, EXYNOS5430_EGL_PLL_CON0); | |
552 | /* 2. Change the system clock divider values */ | |
553 | exynos5430_set_clkdiv_CA15(new_index); | |
554 | } else { | |
555 | /* Clock Configuration Procedure */ | |
556 | /* 1. Change the egl_pll m,p,s value */ | |
557 | exynos5430_set_egl_pll_CA15(new_index, old_index); | |
558 | /* 2. Change the system clock divider values */ | |
559 | exynos5430_set_clkdiv_CA15(new_index); | |
560 | } | |
561 | } | |
562 | ||
563 | clk_set_rate(fout_egl_pll, exynos5430_freq_table_CA15[new_index].frequency * 1000); | |
564 | } | |
565 | ||
566 | static void __init set_volt_table_CA15(void) | |
567 | { | |
568 | unsigned int i; | |
569 | unsigned int asv_volt = 0; | |
570 | ||
571 | for (i = 0; i < CPUFREQ_LEVEL_END_CA15; i++) { | |
572 | asv_volt = get_match_volt(ID_ARM, exynos5430_freq_table_CA15[i].frequency); | |
573 | if (!asv_volt) | |
574 | exynos5430_volt_table_CA15[i] = asv_voltage_5430_CA15[i]; | |
575 | else | |
576 | exynos5430_volt_table_CA15[i] = asv_volt; | |
577 | ||
578 | pr_info("CPUFREQ of CA15 L%d : %d uV\n", i, | |
579 | exynos5430_volt_table_CA15[i]); | |
580 | ||
581 | exynos5430_abb_table_CA15[i] = | |
582 | get_match_abb(ID_ARM, exynos5430_freq_table_CA15[i].frequency); | |
583 | ||
584 | pr_info("CPUFREQ of CA15 L%d : ABB %d\n", i, | |
585 | exynos5430_abb_table_CA15[i]); | |
586 | } | |
587 | ||
588 | exynos5430_get_egl_speed_option(&spd_option_flag, &spd_sel); | |
589 | ||
590 | if (spd_option_flag == EGL_DISABLE_SPD_OPTION) { | |
591 | max_support_idx_CA15 = L13; /* 1.2 GHz */ | |
592 | } else { | |
593 | if (spd_sel == EGL_SPD_SEL_1500_MHZ) | |
594 | max_support_idx_CA15 = L10; /* 1.5 GHz */ | |
595 | #if defined(CONFIG_SOC_EXYNOS5430_L) | |
596 | else if (spd_sel == EGL_SPD_SEL_1700_MHZ) | |
597 | max_support_idx_CA15 = L8; /* 1.7 GHz */ | |
598 | else if (spd_sel == EGL_SPD_SEL_1900_MHZ || | |
599 | spd_sel == EGL_SPD_SEL_2000_MHZ || | |
600 | spd_sel == EGL_SPD_SEL_2100_MHZ) | |
601 | max_support_idx_CA15 = L7; /* 1.8 GHz */ | |
602 | #else | |
603 | else if (spd_sel == EGL_SPD_SEL_1700_MHZ) | |
604 | max_support_idx_CA15 = L8; /* 1.7 GHz */ | |
605 | else if (spd_sel == EGL_SPD_SEL_1900_MHZ) | |
606 | max_support_idx_CA15 = L6; /* 1.9 GHz */ | |
607 | else if (spd_sel == EGL_SPD_SEL_2000_MHZ) | |
608 | max_support_idx_CA15 = L5; /* 2.0 GHz */ | |
609 | else if (spd_sel == EGL_SPD_SEL_2100_MHZ) | |
610 | max_support_idx_CA15 = L5; /* 2.0 GHz */ | |
611 | #endif | |
612 | else | |
613 | panic("can not support speed select (0x%x)\n", spd_sel); | |
614 | } | |
615 | min_support_idx_CA15 = L17; /* 800 MHz */ | |
616 | ||
617 | pr_info("CPUFREQ of CA15 max_freq : L%d %u khz\n", max_support_idx_CA15, | |
618 | exynos5430_freq_table_CA15[max_support_idx_CA15].frequency); | |
619 | pr_info("CPUFREQ of CA15 min_freq : L%d %u khz\n", min_support_idx_CA15, | |
620 | exynos5430_freq_table_CA15[min_support_idx_CA15].frequency); | |
621 | } | |
622 | ||
623 | static bool exynos5430_is_alive_CA15(void) | |
624 | { | |
625 | unsigned int tmp; | |
626 | ||
627 | tmp = __raw_readl(EXYNOS5430_EGL_PLL_CON1); | |
628 | tmp &= EXYNOS5430_PLL_BYPASS_MASK; | |
629 | tmp >>= EXYNOS5430_PLL_BYPASS_SHIFT; | |
630 | ||
631 | return !tmp ? true : false; | |
632 | } | |
633 | ||
634 | int __init exynos5_cpufreq_CA15_init(struct exynos_dvfs_info *info) | |
635 | { | |
636 | int i; | |
637 | unsigned int tmp; | |
638 | unsigned long rate; | |
639 | ||
640 | set_volt_table_CA15(); | |
641 | ||
642 | mout_egl = __clk_lookup("mout_egl"); | |
643 | if (!mout_egl) { | |
644 | pr_err("failed get mout_egl clk\n"); | |
645 | return -EINVAL; | |
646 | } | |
647 | ||
648 | mout_egl_pll = __clk_lookup("mout_egl_pll"); | |
649 | if (!mout_egl_pll) { | |
650 | pr_err("failed get mout_egl_pll clk\n"); | |
651 | goto err_mout_egl_pll; | |
652 | } | |
653 | ||
654 | if (clk_set_parent(mout_egl, mout_egl_pll)) { | |
655 | pr_err("Unable to set parent %s of clock %s.\n", | |
656 | mout_egl_pll->name, mout_egl->name); | |
657 | goto err_clk_set_parent_egl; | |
658 | } | |
659 | ||
660 | sclk_bus_pll = __clk_lookup("sclk_bus_pll"); | |
661 | if (!sclk_bus_pll) { | |
662 | pr_err("failed get sclk_bus_pll clk\n"); | |
663 | goto err_sclk_bus_pll; | |
664 | } | |
665 | ||
666 | mout_bus_pll_user = __clk_lookup("mout_bus_pll_egl_user"); | |
667 | if (!mout_bus_pll_user) { | |
668 | pr_err("failed get mout_bus_pll_egl_user clk\n"); | |
669 | goto err_mout_bus_pll_user; | |
670 | } | |
671 | ||
672 | if (clk_set_parent(mout_bus_pll_user, sclk_bus_pll)) { | |
673 | pr_err("Unable to set parent %s of clock %s.\n", | |
674 | sclk_bus_pll->name, mout_bus_pll_user->name); | |
675 | goto err_clk_set_parent_bus_pll; | |
676 | } | |
677 | ||
678 | rate = clk_get_rate(mout_bus_pll_user) / 1000; | |
679 | ||
680 | fout_egl_pll = __clk_lookup("fout_egl_pll"); | |
681 | if (!fout_egl_pll) { | |
682 | pr_err("failed get fout_egl_pll clk\n"); | |
683 | goto err_fout_egl_pll; | |
684 | } | |
685 | ||
686 | clk_put(sclk_bus_pll); | |
687 | ||
688 | for (i = L0; i < CPUFREQ_LEVEL_END_CA15; i++) { | |
689 | exynos5430_clkdiv_table_CA15[i].index = i; | |
690 | ||
691 | /* CLK_DIV_EGL0 */ | |
692 | tmp = __raw_readl(EXYNOS5430_DIV_EGL0); | |
693 | ||
694 | tmp &= ~(EXYNOS5430_DIV_EGL0_EGL1_MASK | | |
695 | EXYNOS5430_DIV_EGL0_EGL2_MASK | | |
696 | EXYNOS5430_DIV_EGL0_ACLK_EGL_MASK | | |
697 | EXYNOS5430_DIV_EGL0_PCLK_EGL_MASK | | |
698 | EXYNOS5430_DIV_EGL0_ATCLK_EGL_MASK | | |
699 | EXYNOS5430_DIV_EGL0_PCLK_DBG_EGL_MASK); | |
700 | ||
701 | tmp |= ((clkdiv_cpu0_5430_CA15[i][0] << EXYNOS5430_DIV_EGL0_EGL1_SHIFT) | | |
702 | (clkdiv_cpu0_5430_CA15[i][1] << EXYNOS5430_DIV_EGL0_EGL2_SHIFT) | | |
703 | (clkdiv_cpu0_5430_CA15[i][2] << EXYNOS5430_DIV_EGL0_ACLK_EGL_SHIFT) | | |
704 | (clkdiv_cpu0_5430_CA15[i][3] << EXYNOS5430_DIV_EGL0_PCLK_EGL_SHIFT) | | |
705 | (clkdiv_cpu0_5430_CA15[i][4] << EXYNOS5430_DIV_EGL0_ATCLK_EGL_SHIFT) | | |
706 | (clkdiv_cpu0_5430_CA15[i][5] << EXYNOS5430_DIV_EGL0_PCLK_DBG_EGL_SHIFT)); | |
707 | ||
708 | exynos5430_clkdiv_table_CA15[i].clkdiv0 = tmp; | |
709 | ||
710 | /* CLK_DIV_EGL1 */ | |
711 | tmp = __raw_readl(EXYNOS5430_DIV_EGL1); | |
712 | ||
713 | tmp &= ~(EXYNOS5430_DIV_EGL1_EGL_PLL_MASK | | |
714 | EXYNOS5430_DIV_EGL1_SCLK_HPM_EGL_MASK); | |
715 | ||
716 | tmp |= ((clkdiv_cpu1_5430_CA15[i][0] << EXYNOS5430_DIV_EGL1_EGL_PLL_SHIFT) | | |
717 | (clkdiv_cpu1_5430_CA15[i][1] << EXYNOS5430_DIV_EGL1_SCLK_HPM_EGL_SHIFT)); | |
718 | ||
719 | exynos5430_clkdiv_table_CA15[i].clkdiv1 = tmp; | |
720 | } | |
721 | ||
722 | /* Save EMA control values */ | |
723 | tmp = __raw_readl(EMA_VAL_REG); | |
724 | egl_ema_con1 = (tmp >> EMA_CON1_SHIFT) & EMA_CON_MASK; | |
725 | egl_ema_con2 = (tmp >> EMA_CON2_SHIFT) & EMA_CON_MASK; | |
726 | ||
727 | egl_ema_con1 = exynos5430_ema_valid_check_CA15(egl_ema_con1); | |
728 | egl_ema_con2 = exynos5430_ema_valid_check_CA15(egl_ema_con2); | |
729 | ||
730 | pr_info("%s: ema_con1[%d], ema_con2[%d]\n", __func__, egl_ema_con1, egl_ema_con2); | |
731 | ||
732 | clk_egl_2_base = ioremap(EXYNOS5430_PA_CMU_EGL2, SZ_4K); | |
733 | if (!clk_egl_2_base) { | |
734 | pr_err("failed to ioremap for EMA\n"); | |
735 | goto err_ioremap; | |
736 | } | |
737 | ||
738 | info->mpll_freq_khz = rate; | |
739 | info->pll_safe_idx = L17; | |
740 | info->max_support_idx = max_support_idx_CA15; | |
741 | info->min_support_idx = min_support_idx_CA15; | |
742 | if (spd_option_flag == EGL_DISABLE_SPD_OPTION) { | |
743 | /* booting frequency is 800MHz */ | |
744 | info->boot_cpu_min_qos = exynos5430_freq_table_CA15[L17].frequency; | |
745 | info->boot_cpu_max_qos = exynos5430_freq_table_CA15[L17].frequency; | |
746 | } else { | |
747 | /* booting frequency is 1.2GHz */ | |
748 | info->boot_cpu_min_qos = exynos5430_freq_table_CA15[L13].frequency; | |
749 | info->boot_cpu_max_qos = exynos5430_freq_table_CA15[L13].frequency; | |
750 | } | |
751 | info->bus_table = exynos5430_bus_table_CA15; | |
752 | info->cpu_clk = fout_egl_pll; | |
753 | ||
754 | info->volt_table = exynos5430_volt_table_CA15; | |
755 | info->abb_table = exynos5430_abb_table_CA15; | |
756 | info->freq_table = exynos5430_freq_table_CA15; | |
757 | info->set_freq = exynos5430_set_frequency_CA15; | |
758 | info->set_ema = exynos5430_set_ema_CA15; | |
759 | info->need_apll_change = exynos5430_pms_change_CA15; | |
760 | info->is_alive = exynos5430_is_alive_CA15; | |
761 | ||
762 | #ifdef ENABLE_CLKOUT | |
763 | /* dividing EGL_CLK to 1/16 */ | |
764 | tmp = __raw_readl(EXYNOS5430_CLKOUT_CMU_EGL); | |
765 | tmp &= ~0xfff; | |
766 | tmp |= 0xf02; | |
767 | __raw_writel(tmp, EXYNOS5430_CLKOUT_CMU_EGL); | |
768 | #endif | |
769 | ||
770 | __raw_writel(0x00, EXYNOS5430_EGL_STOPCTRL); | |
771 | ||
772 | return 0; | |
773 | ||
774 | err_ioremap: | |
775 | clk_put(fout_egl_pll); | |
776 | err_fout_egl_pll: | |
777 | err_clk_set_parent_bus_pll: | |
778 | clk_put(mout_bus_pll_user); | |
779 | err_mout_bus_pll_user: | |
780 | clk_put(sclk_bus_pll); | |
781 | err_sclk_bus_pll: | |
782 | err_clk_set_parent_egl: | |
783 | clk_put(mout_egl_pll); | |
784 | err_mout_egl_pll: | |
785 | clk_put(mout_egl); | |
786 | ||
787 | pr_debug("%s: failed initialization\n", __func__); | |
788 | return -EINVAL; | |
789 | } |