2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
5 * EXYNOS7420 - ATLAS Core frequency scaling support
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.
12 #include <linux/kernel.h>
13 #include <linux/err.h>
14 #include <linux/clk.h>
16 #include <linux/slab.h>
17 #include <linux/cpufreq.h>
18 #include <linux/clk-private.h>
21 #include <mach/regs-clock.h>
22 #include <mach/regs-clock-exynos7420.h>
23 #include <mach/regs-pmu.h>
24 #include <mach/cpufreq.h>
25 #include <mach/asv-exynos.h>
28 #define CPUFREQ_LEVEL_END_CA57 (L23 + 1)
31 #define ATLAS_EMA_CON (EXYNOS7420_VA_SYSREG + 0x0138)
32 #define CPU_EMA_REG1 (EXYNOS7420_VA_SYSREG + 0x2908)
34 static int max_support_idx_CA57
;
35 static int min_support_idx_CA57
= (CPUFREQ_LEVEL_END_CA57
- 1);
37 static struct clk
*mout_atlas
;
38 static struct clk
*mout_atlas_pll
;
39 static struct clk
*mout_bus0_pll_atlas
;
41 static unsigned int exynos7420_volt_table_CA57
[CPUFREQ_LEVEL_END_CA57
];
42 static unsigned int exynos7420_abb_table_CA57
[CPUFREQ_LEVEL_END_CA57
];
44 static int en_smpl_warn
= 0;
45 static BLOCKING_NOTIFIER_HEAD(exynos_cpufreq_smpl_warn_notifier_list
);
46 int exynos_cpufreq_smpl_warn_register_notifier(struct notifier_block
*nb
)
48 return blocking_notifier_chain_register(&exynos_cpufreq_smpl_warn_notifier_list
, nb
);
51 int exynos_cpufreq_smpl_warn_unregister_notifier(struct notifier_block
*nb
)
53 return blocking_notifier_chain_unregister(&exynos_cpufreq_smpl_warn_notifier_list
, nb
);
56 int exynos_cpufreq_smpl_warn_notify_call_chain(void)
58 int ret
= blocking_notifier_call_chain(&exynos_cpufreq_smpl_warn_notifier_list
, 0, NULL
);
59 return notifier_to_errno(ret
);
61 EXPORT_SYMBOL(exynos_cpufreq_smpl_warn_notify_call_chain
);
64 static struct cpufreq_frequency_table exynos7420_freq_table_CA57
[] = {
89 {0, CPUFREQ_TABLE_END
},
92 static struct apll_freq exynos7420_apll_freq_CA57
[] = {
96 * clock divider for ATLAS1, ATLAS2, ACLK_ATLAS, PCLK_ATLAS, ATCLK, PCLK_DBG_ATLAS,
97 * clock divider for SCLK_ATLAS_PLL, SCLK_HPM_ATLAS, SCLK_CNTCLK
98 * PLL M, P, S values are NOT used, Instead CCF clk_set_rate is used
100 APLL_ATLAS_FREQ(2496, 0, 0, 2, 6, 6, 6, 1, 5, 6, 208, 2, 0), /* ARM L0: 2.5GHz */
101 APLL_ATLAS_FREQ(2400, 0, 0, 2, 6, 6, 6, 1, 5, 6, 200, 2, 0), /* ARM L1: 2.4GMHz */
102 APLL_ATLAS_FREQ(2304, 0, 0, 2, 6, 6, 6, 1, 5, 6, 192, 2, 0), /* ARM L2: 2.3GMHz */
103 APLL_ATLAS_FREQ(2200, 0, 0, 2, 6, 6, 6, 1, 5, 6, 275, 3, 0), /* ARM L3: 2.2GHz */
104 APLL_ATLAS_FREQ(2100, 0, 0, 2, 6, 6, 6, 1, 5, 6, 175, 2, 0), /* ARM L4: 2.1GHz */
105 APLL_ATLAS_FREQ(2000, 0, 0, 2, 6, 6, 6, 1, 5, 6, 250, 3, 0), /* ARM L5: 2.0GHz */
106 APLL_ATLAS_FREQ(1896, 0, 0, 2, 6, 6, 6, 1, 4, 6, 158, 2, 0), /* ARM L6: 1.9GHz */
107 APLL_ATLAS_FREQ(1800, 0, 0, 2, 6, 6, 6, 1, 4, 6, 150, 2, 0), /* ARM L7: 1.8GHz */
108 APLL_ATLAS_FREQ(1704, 0, 0, 2, 6, 6, 6, 1, 4, 6, 142, 2, 0), /* ARM L8: 1.7GHz */
109 APLL_ATLAS_FREQ(1600, 0, 0, 2, 6, 6, 6, 1, 4, 6, 200, 3, 0), /* ARM L9: 1.6GHz */
110 APLL_ATLAS_FREQ(1500, 0, 0, 2, 6, 6, 6, 1, 4, 6, 250, 2, 1), /* ARM L10: 1.5GHz */
111 APLL_ATLAS_FREQ(1400, 0, 0, 2, 6, 6, 6, 1, 4, 6, 350, 3, 1), /* ARM L11: 1.4GHz */
112 APLL_ATLAS_FREQ(1300, 0, 0, 2, 6, 6, 6, 1, 4, 6, 325, 3, 1), /* ARM L12: 1.3GHz */
113 APLL_ATLAS_FREQ(1200, 0, 0, 1, 6, 6, 6, 1, 3, 6, 200, 2, 1), /* ARM L13: 1.2GHz */
114 APLL_ATLAS_FREQ(1100, 0, 0, 1, 6, 6, 6, 1, 3, 6, 275, 3, 1), /* ARM L14: 1.1GHz */
115 APLL_ATLAS_FREQ(1000, 0, 0, 1, 6, 6, 6, 1, 3, 6, 250, 3, 1), /* ARM L15: 1.0GHz */
116 APLL_ATLAS_FREQ( 900, 0, 0, 1, 6, 6, 6, 1, 3, 6, 150, 2, 1), /* ARM L16: 900MHz */
117 APLL_ATLAS_FREQ( 800, 0, 0, 1, 5, 5, 5, 1, 3, 5, 200, 3, 1), /* ARM L17: 800MHz */
118 APLL_ATLAS_FREQ( 700, 0, 0, 1, 5, 5, 5, 1, 3, 5, 350, 3, 2), /* ARM L18: 700MHz */
119 APLL_ATLAS_FREQ( 600, 0, 0, 1, 4, 4, 4, 1, 3, 4, 200, 2, 2), /* ARM L19: 600MHz */
120 APLL_ATLAS_FREQ( 500, 0, 0, 1, 3, 3, 3, 1, 2, 3, 250, 3, 2), /* ARM L20: 500MHz */
121 APLL_ATLAS_FREQ( 400, 0, 0, 1, 3, 3, 3, 1, 2, 3, 200, 3, 2), /* ARM L21: 400MHz */
122 APLL_ATLAS_FREQ( 300, 0, 0, 1, 3, 3, 3, 1, 2, 3, 200, 2, 3), /* ARM L22: 300MHz */
123 APLL_ATLAS_FREQ( 200, 0, 0, 1, 3, 3, 3, 1, 1, 3, 200, 3, 3), /* ARM L23: 200MHz */
127 * ASV group voltage table
129 static const unsigned int asv_voltage_7420_CA57
[CPUFREQ_LEVEL_END_CA57
] = {
130 1250000, /* L0 2500 */
131 1250000, /* L1 2400 */
132 1250000, /* L2 2300 */
133 1250000, /* L3 2200 */
134 1250000, /* L4 2100 */
135 1200000, /* L5 2000 */
136 1156250, /* L6 1900 */
137 1118750, /* L7 1800 */
138 1081250, /* L8 1700 */
139 1043750, /* L9 1600 */
140 1012500, /* L10 1500 */
141 981250, /* L11 1400 */
142 950000, /* L12 1300 */
143 925000, /* L13 1200 */
144 900000, /* L14 1100 */
145 875000, /* L15 1000 */
146 850000, /* L16 900 */
147 825000, /* L17 800 */
148 800000, /* L18 700 */
149 775000, /* L19 600 */
150 750000, /* L20 500 */
151 725000, /* L21 400 */
152 700000, /* L22 300 */
153 675000, /* L23 200 */
156 /* minimum memory throughput in megabytes per second */
157 static int exynos7420_bus_table_CA57
[CPUFREQ_LEVEL_END_CA57
] = {
158 1552000, /* 2.5 GHz */
159 1552000, /* 2.4 GHz */
160 1552000, /* 2.3 GHz */
161 1552000, /* 2.2 GHz */
162 1552000, /* 2.1 GHz */
163 1456000, /* 2.0 GHz */
164 1264000, /* 1.9 GHz */
165 1026000, /* 1.8 GHz */
166 828000, /* 1.7 MHz */
167 828000, /* 1.6 GHz */
168 828000, /* 1.5 GHz */
169 828000, /* 1.4 GHz */
170 828000, /* 1.3 GHz */
171 828000, /* 1.2 GHz */
172 632000, /* 1.1 GHz */
173 543000, /* 1.0 GHz */
174 543000, /* 900 MHz */
175 416000, /* 800 MHz */
184 static int exynos7420_cpufreq_smpl_warn_notifier_call(
185 struct notifier_block
*notifer
,
186 unsigned long event
, void *v
)
190 state
= __raw_readl(EXYNOS7420_ATLAS_SMPL_CTRL0
);
192 __raw_writel(state
, EXYNOS7420_ATLAS_SMPL_CTRL0
);
194 __raw_writel(state
, EXYNOS7420_ATLAS_SMPL_CTRL0
);
196 pr_info("%s: SMPL_WARN: SMPL_WARN is cleared\n",__func__
);
201 static int exynos7420_check_smpl_CA57(void)
205 tmp
= __raw_readl(EXYNOS7420_ATLAS_SMPL_CTRL1
);
208 pr_info("%s: SMPL_WARN HAPPENED!\n", __func__
);
215 static struct notifier_block exynos7420_cpufreq_smpl_warn_notifier
= {
216 .notifier_call
= exynos7420_cpufreq_smpl_warn_notifier_call
,
219 static void exynos7420_set_clkdiv_CA57(unsigned int div_index
)
221 unsigned int tmp
, tmp1
;
223 /* Change Divider - ATLAS0 */
224 tmp
= exynos7420_apll_freq_CA57
[div_index
].clk_div_cpu0
;
226 __raw_writel(tmp
, EXYNOS7420_DIV_ATLAS0
);
228 while (__raw_readl(EXYNOS7420_DIV_STAT_ATLAS0
) & 0x4101111)
231 /* Change Divider - ATLAS1 */
232 tmp1
= exynos7420_apll_freq_CA57
[div_index
].clk_div_cpu1
;
234 __raw_writel(tmp1
, EXYNOS7420_DIV_ATLAS1
);
236 while (__raw_readl(EXYNOS7420_DIV_STAT_ATLAS1
) & 0x111)
240 tmp
= __raw_readl(EXYNOS7420_DIV_ATLAS0
);
241 tmp1
= __raw_readl(EXYNOS7420_DIV_ATLAS1
);
243 pr_info("%s: DIV_ATLAS0[0x%08x], DIV_ATLAS1[0x%08x]\n",
244 __func__
, tmp
, tmp1
);
248 static bool exynos7420_pms_change_CA57(unsigned int old_index
,
249 unsigned int new_index
)
251 unsigned int old_pm
= (exynos7420_apll_freq_CA57
[old_index
].mps
>>
252 EXYNOS7420_PLL_PDIV_SHIFT
);
253 unsigned int new_pm
= (exynos7420_apll_freq_CA57
[new_index
].mps
>>
254 EXYNOS7420_PLL_PDIV_SHIFT
);
256 return (old_pm
== new_pm
) ? 0 : 1;
259 static void exynos7420_set_atlas_pll_CA57(unsigned int new_index
, unsigned int old_index
)
263 if (!exynos7420_pms_change_CA57(old_index
, new_index
)) {
264 /* Change MOUT_ATLAS_PLL frequency
265 When PM value are matching with previous frequency
266 then only S value should be change in this case
267 don't need to change ATLAS_PLL to BUS0_PLL_ATLASO */
268 clk_set_rate(mout_atlas_pll
, exynos7420_freq_table_CA57
[new_index
].frequency
* 1000);
270 /* 1. before change to BUS0_PLL, set div for BUS0_PLL output */
271 if ((new_index
> L17
) && (old_index
> L17
))
272 exynos7420_set_clkdiv_CA57(L17
); /* pll_safe_idx of CA57 */
274 /* 2. MUX_SEL_ATLAS = MOUT_BUS0_PLL_ALTAS, ATLASCLK uses BUS0_PLL_ATLAS for lock time */
275 if (clk_set_parent(mout_atlas
, mout_bus0_pll_atlas
))
276 pr_err("Unable to set parent %s of clock %s.\n",
277 mout_bus0_pll_atlas
->name
, mout_atlas
->name
);
280 tmp
= __raw_readl(EXYNOS7420_MUX_STAT_ATLAS2
);
281 tmp
&= EXYNOS7420_MUX_STAT_CORE2_MASK
;
282 tmp
>>= EXYNOS7420_MUX_STAT_CORE2_SHIFT
;
283 } while (tmp
!= 0x1);
285 /* 3. Change MOUT_ATLAS_PLL Frequency */
286 clk_set_rate(mout_atlas_pll
, exynos7420_freq_table_CA57
[new_index
].frequency
* 1000);
288 /* 4. MUX_SEL_ATLAS = MOUT_ATLAS_PLL */
289 if (clk_set_parent(mout_atlas
, mout_atlas_pll
))
290 pr_err("Unable to set parent %s of clock %s.\n",
291 mout_atlas_pll
->name
, mout_atlas
->name
);
294 tmp
= __raw_readl(EXYNOS7420_MUX_STAT_ATLAS2
);
295 tmp
&= EXYNOS7420_MUX_STAT_CORE2_MASK
;
296 tmp
>>= EXYNOS7420_MUX_STAT_CORE2_SHIFT
;
297 } while (tmp
!= 0x0);
299 /* 5. restore original div value */
300 if ((new_index
> L17
) && (old_index
> L17
))
301 exynos7420_set_clkdiv_CA57(new_index
);
305 static void exynos7420_set_frequency_CA57(unsigned int old_index
,
306 unsigned int new_index
)
308 if (old_index
> new_index
) {
309 /* Clock Configuration Procedure */
310 /* 1. Change the system clock divider values */
311 exynos7420_set_clkdiv_CA57(new_index
);
312 /* 2. Change the atlas_pll m,p,s value */
313 exynos7420_set_atlas_pll_CA57(new_index
, old_index
);
314 } else if (old_index
< new_index
) {
315 /* Clock Configuration Procedure */
316 /* 1. Change the atlas_pll m,p,s value */
317 exynos7420_set_atlas_pll_CA57(new_index
, old_index
);
318 /* 2. Change the system clock divider values */
319 exynos7420_set_clkdiv_CA57(new_index
);
322 pr_debug("[%s] Atlas NewFreq: %d OldFreq: %d\n", __func__
, exynos7420_freq_table_CA57
[new_index
].frequency
,
323 exynos7420_freq_table_CA57
[old_index
].frequency
);
326 static void __init
set_volt_table_CA57(void)
329 unsigned int asv_volt
= 0;
331 for (i
= 0; i
< CPUFREQ_LEVEL_END_CA57
; i
++) {
332 asv_volt
= get_match_volt(ID_CL1
, exynos7420_freq_table_CA57
[i
].frequency
);
334 exynos7420_volt_table_CA57
[i
] = asv_voltage_7420_CA57
[i
];
336 exynos7420_volt_table_CA57
[i
] = asv_volt
;
338 pr_info("CPUFREQ of CA57 L%d : %d uV\n", i
,
339 exynos7420_volt_table_CA57
[i
]);
341 exynos7420_abb_table_CA57
[i
] =
342 get_match_abb(ID_CL1
, exynos7420_freq_table_CA57
[i
].frequency
);
344 pr_info("CPUFREQ of CA57 L%d : ABB %d\n", i
,
345 exynos7420_abb_table_CA57
[i
]);
348 #if defined(CONFIG_CPU_THERMAL) && defined(CONFIG_EXYNOS5_DYNAMIC_CPU_HOTPLUG)
349 switch (exynos_get_table_ver()) {
353 max_support_idx_CA57
= L7
; break; /* 1.8GHz */
355 max_support_idx_CA57
= L10
; break; /* 1.5GHz */
357 max_support_idx_CA57
= L4
; /* 2.1GHz */
360 max_support_idx_CA57
= L13
; /* 1.2 GHz */
363 min_support_idx_CA57
= L17
; /* 800 MHz */
365 pr_info("CPUFREQ of CA57 max_freq : L%d %u khz\n", max_support_idx_CA57
,
366 exynos7420_freq_table_CA57
[max_support_idx_CA57
].frequency
);
367 pr_info("CPUFREQ of CA57 min_freq : L%d %u khz\n", min_support_idx_CA57
,
368 exynos7420_freq_table_CA57
[min_support_idx_CA57
].frequency
);
370 static bool exynos7420_is_alive_CA57(void)
374 tmp
= __raw_readl(EXYNOS7420_ATLAS_PLL_CON1
);
375 tmp
&= EXYNOS7420_PLL_BYPASS_MASK
;
376 tmp
>>= EXYNOS7420_PLL_BYPASS_SHIFT
;
378 return !tmp
? true : false;
381 static void exynos7420_set_ema_CA57(unsigned int volt
)
383 exynos_set_ema(ID_CL1
, volt
);
386 int __init
exynos_cpufreq_cluster1_init(struct exynos_dvfs_info
*info
)
389 struct device_node
*pmic_node
;
392 set_volt_table_CA57();
394 mout_atlas_pll
= clk_get(NULL
, "mout_atlas_pll");
395 if (IS_ERR(mout_atlas_pll
)) {
396 pr_err("failed get mout_atlas_pll clk\n");
397 goto err_mout_atlas_pll
;
400 mout_atlas
= clk_get(NULL
, "mout_atlas");
401 if (IS_ERR(mout_atlas
)) {
402 pr_err("failed get mout_atlas clk\n");
406 if (clk_set_parent(mout_atlas
, mout_atlas_pll
)) {
407 pr_err("Unable to set parent %s of clock %s.\n",
408 mout_atlas_pll
->name
, mout_atlas
->name
);
409 goto err_clk_set_parent_atlas
;
412 mout_bus0_pll_atlas
= clk_get(NULL
, "mout_bus0_pll_atlas");
413 if (IS_ERR(mout_bus0_pll_atlas
)) {
414 pr_err("failed get mout_bus0_pll_atlas clk\n");
415 goto err_mout_bus0_pll_atlas
;
418 if (clk_prepare_enable(mout_atlas_pll
) || clk_prepare_enable(mout_atlas
)) {
419 pr_err("Unable to enable Atlas clocks \n");
420 goto err_clk_prepare_enable
;
423 rate
= clk_get_rate(mout_bus0_pll_atlas
) / 1000;
425 info
->mpll_freq_khz
= rate
;
426 info
->pll_safe_idx
= L17
;
427 info
->max_support_idx
= max_support_idx_CA57
;
428 info
->min_support_idx
= min_support_idx_CA57
;
430 /* booting frequency is 1.7GHz */
431 info
->boot_cpu_min_qos
= exynos7420_freq_table_CA57
[L8
].frequency
;
432 info
->boot_cpu_max_qos
= exynos7420_freq_table_CA57
[L8
].frequency
;
433 info
->bus_table
= exynos7420_bus_table_CA57
;
434 info
->cpu_clk
= mout_atlas_pll
;
436 /* reboot limit frequency is 800MHz */
437 info
->reboot_limit_freq
= exynos7420_freq_table_CA57
[L17
].frequency
;
439 info
->volt_table
= exynos7420_volt_table_CA57
;
440 info
->abb_table
= NULL
; //exynos7420_abb_table_CA57;
441 info
->freq_table
= exynos7420_freq_table_CA57
;
442 info
->set_freq
= exynos7420_set_frequency_CA57
;
443 info
->need_apll_change
= exynos7420_pms_change_CA57
;
444 info
->is_alive
= exynos7420_is_alive_CA57
;
445 info
->set_ema
= exynos7420_set_ema_CA57
;
447 pmic_node
= of_find_compatible_node(NULL
, NULL
, "samsung,s2mps15-pmic");
450 pr_err("%s: faile to get pmic dt_node\n", __func__
);
452 ret
= of_property_read_u32(pmic_node
, "smpl_warn_en", &en_smpl_warn
);
454 pr_err("%s: faile to get Property of smpl_warn_en\n", __func__
);
458 info
->check_smpl
= exynos7420_check_smpl_CA57
;
460 /* ATLAS_RATIO_SMPL */
461 tmp
= __raw_readl(EXYNOS7420_ATLAS_SMPL_CTRL0
);
464 __raw_writel(tmp
, EXYNOS7420_ATLAS_SMPL_CTRL0
);
465 pr_info("%s SMPL_WARN ENABLE (DIV:%d) ", __func__
, tmp
&0x3F);
467 exynos_cpufreq_smpl_warn_register_notifier(&exynos7420_cpufreq_smpl_warn_notifier
);
472 err_clk_prepare_enable
:
473 err_mout_bus0_pll_atlas
:
474 err_clk_set_parent_atlas
:
477 clk_put(mout_atlas_pll
);
480 pr_debug("%s: failed initialization\n", __func__
);