2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
5 * EXYNOS5433 - APOLLO 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-exynos5433.h>
23 #include <mach/regs-pmu.h>
24 #include <mach/cpufreq.h>
25 #include <mach/asv-exynos.h>
27 #define CPUFREQ_LEVEL_END_CA53 (L18 + 1)
28 #define L2_LOCAL_PWR_EN 0x7
33 static int max_support_idx_CA53
;
34 static int min_support_idx_CA53
= (CPUFREQ_LEVEL_END_CA53
- 1);
36 static struct clk
*mout_apollo
;
37 static struct clk
*mout_apollo_pll
;
38 static struct clk
*mout_bus_pll_div2
;
39 static struct clk
*mout_bus_pll_user
;
40 static struct clk
*fout_apollo_pll
;
42 static unsigned int exynos5433_volt_table_CA53
[CPUFREQ_LEVEL_END_CA53
];
43 static unsigned int exynos5433_abb_table_CA53
[CPUFREQ_LEVEL_END_CA53
];
45 static struct cpufreq_frequency_table exynos5433_freq_table_CA53
[] = {
65 {0, CPUFREQ_TABLE_END
},
68 static struct apll_freq exynos5433_apll_freq_CA53
[] = {
72 * clock divider for APOLLO1, APOLLO2 ACLK_APOLLO, PCLK_APOLLO, ATCLK, PCLK_DBG, SCLK_CNTCLK, RESERVED
73 * clock divider for APOLLO_PLL, SCLK_HPM_APOLLO, RESERVED
76 APLL_FREQ(2000, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 500, 6, 0), /* ARM L0: 2.0GHz */
77 APLL_FREQ(1900, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 475, 6, 0), /* ARM L1: 1.9GMHz */
78 APLL_FREQ(1800, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 375, 5, 0), /* ARM L2: 1.8GMHz */
79 APLL_FREQ(1700, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 425, 6, 0), /* ARM L3: 1.7GHz */
80 APLL_FREQ(1600, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 400, 6, 0), /* ARM L4: 1.6GHz */
81 APLL_FREQ(1500, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 250, 4, 0), /* ARM L5: 1.5GMHz */
82 APLL_FREQ(1400, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 350, 6, 0), /* ARM L6: 1.4GMHz */
83 APLL_FREQ(1300, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 325, 6, 0), /* ARM L7: 1.3GHz */
84 APLL_FREQ(1200, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 500, 5, 1), /* ARM L8: 1.2GHz */
85 APLL_FREQ(1100, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 550, 6, 1), /* ARM L9: 1.1GHz */
86 APLL_FREQ(1000, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 500, 6, 1), /* ARM L10: 1000MHz */
87 APLL_FREQ( 900, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 375, 5, 1), /* ARM L11: 900MHz */
88 APLL_FREQ( 800, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 400, 6, 1), /* ARM L12: 800MHz */
89 APLL_FREQ( 700, 0, 0, 2, 7, 7, 7, 3, 0, 1, 7, 0, 350, 6, 1), /* ARM L13: 700MHz */
90 APLL_FREQ( 600, 0, 0, 1, 7, 7, 7, 3, 0, 1, 7, 0, 500, 5, 2), /* ARM L14: 600MHz */
91 APLL_FREQ( 500, 0, 0, 1, 7, 7, 7, 3, 0, 1, 7, 0, 500, 6, 2), /* ARM L15: 500MHz */
92 APLL_FREQ( 400, 0, 0, 1, 7, 7, 7, 3, 0, 1, 7, 0, 400, 6, 2), /* ARM L16: 400MHz */
93 APLL_FREQ( 300, 0, 0, 1, 7, 7, 7, 3, 0, 1, 7, 0, 500, 5, 3), /* ARM L17: 300MHz */
94 APLL_FREQ( 200, 0, 0, 1, 7, 7, 7, 3, 0, 1, 7, 0, 400, 6, 3), /* ARM L18: 200MHz */
98 * ASV group voltage table
100 static const unsigned int asv_voltage_5433_CA53
[CPUFREQ_LEVEL_END_CA53
] = {
101 1375000, /* L0 2000 */
102 1375000, /* L1 1900 */
103 1375000, /* L2 1800 */
104 1325000, /* L3 1700 */
105 1275000, /* L4 1600 */
106 1250000, /* L5 1500 */
107 1200000, /* L6 1400 */
108 1150000, /* L7 1300 */
109 1112500, /* L8 1200 */
110 1075000, /* L9 1100 */
111 1050000, /* L10 1000 */
112 1025000, /* L11 900 */
113 1000000, /* L12 800 */
114 975000, /* L13 700 */
115 950000, /* L14 600 */
116 925000, /* L15 500 */
117 900000, /* L16 400 */
118 875000, /* L17 300 */
119 850000, /* L18 200 */
122 /* Minimum memory throughput in megabytes per second */
123 static int exynos5433_bus_table_CA53
[CPUFREQ_LEVEL_END_CA53
] = {
124 667000, /* 2.0 GHz */
125 667000, /* 1.9 GHz */
126 667000, /* 1.8 GHz */
127 667000, /* 1.7 GHz */
128 667000, /* 1.6 GHz */
129 667000, /* 1.5 GHz */
130 667000, /* 1.4 GHz */
131 667000, /* 1.3 GHz */
132 667000, /* 1.2 GHz */
133 667000, /* 1.1 GHz */
134 543000, /* 1.0 GHz */
135 413000, /* 900 MHz */
136 413000, /* 800 MHz */
137 413000, /* 700 MHz */
138 413000, /* 600 MHz */
139 413000, /* 500 MHz */
145 static void exynos5433_set_clkdiv_CA53(unsigned int div_index
)
147 unsigned int tmp
, tmp1
;
149 /* Change Divider - APOLLO0 */
150 tmp
= exynos5433_apll_freq_CA53
[div_index
].clk_div_cpu0
;
152 __raw_writel(tmp
, EXYNOS5430_DIV_KFC0
);
154 while (__raw_readl(EXYNOS5430_DIV_STAT_KFC0
) & 0x1111111)
157 /* Change Divider - APOLLO1 */
158 tmp1
= exynos5433_apll_freq_CA53
[div_index
].clk_div_cpu1
;
160 __raw_writel(tmp1
, EXYNOS5430_DIV_KFC1
);
162 while (__raw_readl(EXYNOS5430_DIV_STAT_KFC1
) & 0x11)
166 tmp
= __raw_readl(EXYNOS5430_DIV_KFC0
);
167 tmp1
= __raw_readl(EXYNOS5430_DIV_KFC1
);
168 pr_info("%s: DIV_APOLLO0[0x%08x], DIV_APOLLO1[0x%08x]\n",
169 __func__
, tmp
, tmp1
);
173 static void exynos5433_set_apollo_pll_CA53(unsigned int new_index
, unsigned int old_index
)
175 unsigned int tmp
, pdiv
;
177 /* 1. before change to BUS_PLL, set div for BUS_PLL output */
178 if ((new_index
> L12
) && (old_index
> L12
))
179 exynos5433_set_clkdiv_CA53(L12
); /* pll_safe_idx of CA53 */
181 /* 2. CLKMUX_SEL_APOLLO2 = MOUT_BUS_PLL_USER, APOLLOCLK uses BUS_PLL_USER for lock time */
182 if (clk_set_parent(mout_apollo
, mout_bus_pll_user
))
183 pr_err("Unable to set parent %s of clock %s.\n",
184 mout_bus_pll_user
->name
, mout_apollo
->name
);
187 tmp
= __raw_readl(EXYNOS5430_SRC_STAT_KFC2
);
188 tmp
&= EXYNOS5430_SRC_STAT_KFC2_KFC_MASK
;
189 tmp
>>= EXYNOS5430_SRC_STAT_KFC2_KFC_SHIFT
;
190 } while (tmp
!= 0x2);
192 /* 3. Set APOLLO_PLL Lock time */
193 pdiv
= ((exynos5433_apll_freq_CA53
[new_index
].mps
&
194 EXYNOS5430_PLL_PDIV_MASK
) >> EXYNOS5430_PLL_PDIV_SHIFT
);
196 __raw_writel((pdiv
* 150), EXYNOS5430_KFC_PLL_LOCK
);
198 /* 4. Change PLL PMS values */
199 tmp
= __raw_readl(EXYNOS5430_KFC_PLL_CON0
);
200 tmp
&= ~(EXYNOS5430_PLL_MDIV_MASK
|
201 EXYNOS5430_PLL_PDIV_MASK
|
202 EXYNOS5430_PLL_SDIV_MASK
);
203 tmp
|= exynos5433_apll_freq_CA53
[new_index
].mps
;
204 __raw_writel(tmp
, EXYNOS5430_KFC_PLL_CON0
);
206 /* 5. wait_lock_time */
209 tmp
= __raw_readl(EXYNOS5430_KFC_PLL_CON0
);
210 } while (!(tmp
& (0x1 << EXYNOS5430_KFC_PLL_CON0_LOCKED_SHIFT
)));
212 /* 6. CLKMUX_SEL_APOLLO2 = MOUT_APOLLO_PLL */
213 if (clk_set_parent(mout_apollo
, mout_apollo_pll
))
214 pr_err("Unable to set parent %s of clock %s.\n",
215 mout_apollo_pll
->name
, mout_apollo
->name
);
218 tmp
= __raw_readl(EXYNOS5430_SRC_STAT_KFC2
);
219 tmp
&= EXYNOS5430_SRC_STAT_KFC2_KFC_MASK
;
220 tmp
>>= EXYNOS5430_SRC_STAT_KFC2_KFC_SHIFT
;
221 } while (tmp
!= 0x1);
223 /* 7. restore original div value */
224 if ((new_index
> L12
) && (old_index
> L12
))
225 exynos5433_set_clkdiv_CA53(new_index
);
228 static bool exynos5433_pms_change_CA53(unsigned int old_index
,
229 unsigned int new_index
)
231 unsigned int old_pm
= (exynos5433_apll_freq_CA53
[old_index
].mps
>>
232 EXYNOS5430_PLL_PDIV_SHIFT
);
233 unsigned int new_pm
= (exynos5433_apll_freq_CA53
[new_index
].mps
>>
234 EXYNOS5430_PLL_PDIV_SHIFT
);
236 return (old_pm
== new_pm
) ? 0 : 1;
239 static void exynos5433_set_frequency_CA53(unsigned int old_index
,
240 unsigned int new_index
)
244 if (old_index
> new_index
) {
245 if (!exynos5433_pms_change_CA53(old_index
, new_index
)) {
246 /* 1. Change the system clock divider values */
247 exynos5433_set_clkdiv_CA53(new_index
);
248 /* 2. Change just s value in apollo_pll m,p,s value */
249 tmp
= __raw_readl(EXYNOS5430_KFC_PLL_CON0
);
250 tmp
&= ~EXYNOS5430_PLL_SDIV_MASK
;
251 tmp
|= (exynos5433_apll_freq_CA53
[new_index
].mps
& EXYNOS5430_PLL_SDIV_MASK
);
252 __raw_writel(tmp
, EXYNOS5430_KFC_PLL_CON0
);
254 /* Clock Configuration Procedure */
255 /* 1. Change the system clock divider values */
256 exynos5433_set_clkdiv_CA53(new_index
);
257 /* 2. Change the apollo_pll m,p,s value */
258 exynos5433_set_apollo_pll_CA53(new_index
, old_index
);
260 } else if (old_index
< new_index
) {
261 if (!exynos5433_pms_change_CA53(old_index
, new_index
)) {
262 /* 1. Change just s value in apollo_pll m,p,s value */
263 tmp
= __raw_readl(EXYNOS5430_KFC_PLL_CON0
);
264 tmp
&= ~EXYNOS5430_PLL_SDIV_MASK
;
265 tmp
|= (exynos5433_apll_freq_CA53
[new_index
].mps
& EXYNOS5430_PLL_SDIV_MASK
);
266 __raw_writel(tmp
, EXYNOS5430_KFC_PLL_CON0
);
267 /* 2. Change the system clock divider values */
268 exynos5433_set_clkdiv_CA53(new_index
);
270 /* Clock Configuration Procedure */
271 /* 1. Change the apollo_pll m,p,s value */
272 exynos5433_set_apollo_pll_CA53(new_index
, old_index
);
273 /* 2. Change the system clock divider values */
274 exynos5433_set_clkdiv_CA53(new_index
);
278 clk_set_rate(fout_apollo_pll
, exynos5433_freq_table_CA53
[new_index
].frequency
* 1000);
279 pr_debug("[%s] APOLLO NewFreq: %d OldFreq: %d\n", __func__
, exynos5433_freq_table_CA53
[new_index
].frequency
,
280 exynos5433_freq_table_CA53
[old_index
].frequency
);
283 static void __init
set_volt_table_CA53(void)
286 unsigned int asv_volt
= 0;
288 for (i
= 0; i
< CPUFREQ_LEVEL_END_CA53
; i
++) {
289 asv_volt
= get_match_volt(ID_CL0
, exynos5433_freq_table_CA53
[i
].frequency
);
291 exynos5433_volt_table_CA53
[i
] = asv_voltage_5433_CA53
[i
];
293 exynos5433_volt_table_CA53
[i
] = asv_volt
;
295 pr_info("CPUFREQ of CA53 L%d : %d uV\n", i
,
296 exynos5433_volt_table_CA53
[i
]);
298 exynos5433_abb_table_CA53
[i
] =
299 get_match_abb(ID_CL0
, exynos5433_freq_table_CA53
[i
].frequency
);
301 pr_info("CPUFREQ of CA53 L%d : ABB %d\n", i
,
302 exynos5433_abb_table_CA53
[i
]);
305 max_support_idx_CA53
= L7
; /* 1.3GHz */
306 min_support_idx_CA53
= L16
; /* 400MHz */
307 pr_info("CPUFREQ of CA53 max_freq : L%d %u khz\n", max_support_idx_CA53
,
308 exynos5433_freq_table_CA53
[max_support_idx_CA53
].frequency
);
309 pr_info("CPUFREQ of CA53 min_freq : L%d %u khz\n", min_support_idx_CA53
,
310 exynos5433_freq_table_CA53
[min_support_idx_CA53
].frequency
);
313 static bool exynos5433_is_alive_CA53(void)
317 tmp
= __raw_readl(EXYNOS5430_KFC_PLL_CON1
);
318 tmp
&= EXYNOS5430_PLL_BYPASS_MASK
;
319 tmp
>>= EXYNOS5430_PLL_BYPASS_SHIFT
;
321 return !tmp
? true : false;
324 int __init
exynos_cpufreq_cluster0_init(struct exynos_dvfs_info
*info
)
328 set_volt_table_CA53();
330 mout_apollo
= clk_get(NULL
, "mout_kfc");
331 if (IS_ERR(mout_apollo
)) {
332 pr_err("failed get mout_apollo clk\n");
336 mout_apollo_pll
= clk_get(NULL
, "mout_kfc_pll");
337 if (IS_ERR(mout_apollo_pll
)) {
338 pr_err("failed get mout_apollo_pll clk\n");
339 goto err_mout_apollo_pll
;
342 mout_bus_pll_div2
= clk_get(NULL
, "mout_bus_pll_div2");
343 if (IS_ERR(mout_bus_pll_div2
)) {
344 pr_err("failed get mout_bus_pll_div2 clk\n");
345 goto err_sclk_bus_pll
;
348 mout_bus_pll_user
= clk_get(NULL
, "mout_bus_pll_kfc_user");
349 if (IS_ERR(mout_bus_pll_user
)) {
350 pr_err("failed get mout_bus_pll_user clk\n");
351 goto err_mout_bus_pll_user
;
354 if (clk_set_parent(mout_bus_pll_user
, mout_bus_pll_div2
)) {
355 pr_err("Unable to set parent %s of clock %s.\n",
356 mout_bus_pll_div2
->name
, mout_bus_pll_user
->name
);
357 goto err_clk_set_parent
;
360 rate
= clk_get_rate(mout_bus_pll_user
) / 1000;
362 fout_apollo_pll
= clk_get(NULL
, "fout_kfc_pll");
363 if (IS_ERR(fout_apollo_pll
)) {
364 pr_err("failed get fout_apollo_pll clk\n");
365 goto err_fout_apollo_pll
;
368 clk_put(mout_bus_pll_div2
);
370 info
->mpll_freq_khz
= rate
;
371 info
->pll_safe_idx
= L12
;
372 info
->max_support_idx
= max_support_idx_CA53
;
373 info
->min_support_idx
= min_support_idx_CA53
;
374 info
->boost_freq
= exynos5433_freq_table_CA53
[L10
].frequency
;
375 /* booting frequency is 1.3GHz */
376 info
->boot_cpu_min_qos
= exynos5433_freq_table_CA53
[L7
].frequency
;
377 info
->boot_cpu_max_qos
= exynos5433_freq_table_CA53
[L7
].frequency
;
378 info
->bus_table
= exynos5433_bus_table_CA53
;
379 info
->cpu_clk
= fout_apollo_pll
;
381 info
->volt_table
= exynos5433_volt_table_CA53
;
382 info
->abb_table
= exynos5433_abb_table_CA53
;
383 info
->freq_table
= exynos5433_freq_table_CA53
;
384 info
->set_freq
= exynos5433_set_frequency_CA53
;
385 info
->need_apll_change
= exynos5433_pms_change_CA53
;
386 info
->is_alive
= exynos5433_is_alive_CA53
;
389 /* dividing APOLLO_CLK to 1/16 */
390 tmp
= __raw_readl(EXYNOS5430_CLKOUT_CMU_KFC
);
393 __raw_writel(tmp
, EXYNOS5430_CLKOUT_CMU_KFC
);
400 clk_put(mout_bus_pll_user
);
401 err_mout_bus_pll_user
:
402 clk_put(mout_bus_pll_div2
);
404 clk_put(mout_apollo_pll
);
406 clk_put(mout_apollo
);
408 pr_debug("%s: failed initialization\n", __func__
);