1 /*
2  * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
3  *		http://www.samsung.com
4  *
5  * EXYNOS5250 - CPU 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/module.h>
13 #include <linux/kernel.h>
14 #include <linux/err.h>
15 #include <linux/clk.h>
16 #include <linux/io.h>
17 #include <linux/slab.h>
18 #include <linux/cpufreq.h>
19 
20 #include <mach/map.h>
21 #include <mach/regs-clock.h>
22 #include <mach/cpufreq.h>
23 
24 #define CPUFREQ_LEVEL_END	(L15 + 1)
25 
26 static int max_support_idx;
27 static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
28 static struct clk *cpu_clk;
29 static struct clk *moutcore;
30 static struct clk *mout_mpll;
31 static struct clk *mout_apll;
32 
33 struct cpufreq_clkdiv {
34 	unsigned int	index;
35 	unsigned int	clkdiv;
36 	unsigned int	clkdiv1;
37 };
38 
39 static unsigned int exynos5250_volt_table[CPUFREQ_LEVEL_END];
40 
41 static struct cpufreq_frequency_table exynos5250_freq_table[] = {
42 	{L0, 1700 * 1000},
43 	{L1, 1600 * 1000},
44 	{L2, 1500 * 1000},
45 	{L3, 1400 * 1000},
46 	{L4, 1300 * 1000},
47 	{L5, 1200 * 1000},
48 	{L6, 1100 * 1000},
49 	{L7, 1000 * 1000},
50 	{L8, 900 * 1000},
51 	{L9, 800 * 1000},
52 	{L10, 700 * 1000},
53 	{L11, 600 * 1000},
54 	{L12, 500 * 1000},
55 	{L13, 400 * 1000},
56 	{L14, 300 * 1000},
57 	{L15, 200 * 1000},
58 	{0, CPUFREQ_TABLE_END},
59 };
60 
61 static struct cpufreq_clkdiv exynos5250_clkdiv_table[CPUFREQ_LEVEL_END];
62 
63 static unsigned int clkdiv_cpu0_5250[CPUFREQ_LEVEL_END][8] = {
64 	/*
65 	 * Clock divider value for following
66 	 * { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 }
67 	 */
68 	{ 0, 3, 7, 7, 6, 1, 3, 0 },	/* 1700 MHz - N/A */
69 	{ 0, 3, 7, 7, 6, 1, 3, 0 },	/* 1600 MHz - N/A */
70 	{ 0, 3, 7, 7, 5, 1, 3, 0 },	/* 1500 MHz - N/A */
71 	{ 0, 3, 7, 7, 6, 1, 3, 0 },	/* 1400 MHz */
72 	{ 0, 3, 7, 7, 6, 1, 3, 0 },	/* 1300 MHz */
73 	{ 0, 3, 7, 7, 5, 1, 3, 0 },	/* 1200 MHz */
74 	{ 0, 2, 7, 7, 5, 1, 2, 0 },	/* 1100 MHz */
75 	{ 0, 2, 7, 7, 4, 1, 2, 0 },	/* 1000 MHz */
76 	{ 0, 2, 7, 7, 4, 1, 2, 0 },	/* 900 MHz */
77 	{ 0, 2, 7, 7, 3, 1, 1, 0 },	/* 800 MHz */
78 	{ 0, 1, 7, 7, 3, 1, 1, 0 },	/* 700 MHz */
79 	{ 0, 1, 7, 7, 2, 1, 1, 0 },	/* 600 MHz */
80 	{ 0, 1, 7, 7, 2, 1, 1, 0 },	/* 500 MHz */
81 	{ 0, 1, 7, 7, 1, 1, 1, 0 },	/* 400 MHz */
82 	{ 0, 1, 7, 7, 1, 1, 1, 0 },	/* 300 MHz */
83 	{ 0, 1, 7, 7, 1, 1, 1, 0 },	/* 200 MHz */
84 };
85 
86 static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
87 	/* Clock divider value for following
88 	 * { COPY, HPM }
89 	 */
90 	{ 0, 2 },	/* 1700 MHz - N/A */
91 	{ 0, 2 },	/* 1600 MHz - N/A */
92 	{ 0, 2 },	/* 1500 MHz - N/A */
93 	{ 0, 2 },	/* 1400 MHz */
94 	{ 0, 2 },	/* 1300 MHz */
95 	{ 0, 2 },	/* 1200 MHz */
96 	{ 0, 2 },	/* 1100 MHz */
97 	{ 0, 2 },	/* 1000 MHz */
98 	{ 0, 2 },	/* 900 MHz */
99 	{ 0, 2 },	/* 800 MHz */
100 	{ 0, 2 },	/* 700 MHz */
101 	{ 0, 2 },	/* 600 MHz */
102 	{ 0, 2 },	/* 500 MHz */
103 	{ 0, 2 },	/* 400 MHz */
104 	{ 0, 2 },	/* 300 MHz */
105 	{ 0, 2 },	/* 200 MHz */
106 };
107 
108 static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
109 	(0),				/* 1700 MHz - N/A */
110 	(0),				/* 1600 MHz - N/A */
111 	(0),				/* 1500 MHz - N/A */
112 	(0),				/* 1400 MHz */
113 	((325 << 16) | (6 << 8) | 0),	/* 1300 MHz */
114 	((200 << 16) | (4 << 8) | 0),	/* 1200 MHz */
115 	((275 << 16) | (6 << 8) | 0),	/* 1100 MHz */
116 	((125 << 16) | (3 << 8) | 0),	/* 1000 MHz */
117 	((150 << 16) | (4 << 8) | 0),	/* 900 MHz */
118 	((100 << 16) | (3 << 8) | 0),	/* 800 MHz */
119 	((175 << 16) | (3 << 8) | 1),	/* 700 MHz */
120 	((200 << 16) | (4 << 8) | 1),	/* 600 MHz */
121 	((125 << 16) | (3 << 8) | 1),	/* 500 MHz */
122 	((100 << 16) | (3 << 8) | 1),	/* 400 MHz */
123 	((200 << 16) | (4 << 8) | 2),	/* 300 MHz */
124 	((100 << 16) | (3 << 8) | 2),	/* 200 MHz */
125 };
126 
127 /* ASV group voltage table */
128 static const unsigned int asv_voltage_5250[CPUFREQ_LEVEL_END] = {
129 	0, 0, 0, 0, 0, 0, 0,	/* 1700 MHz ~ 1100 MHz Not supported */
130 	1175000, 1125000, 1075000, 1050000, 1000000,
131 	950000, 925000, 925000, 900000
132 };
133 
set_clkdiv(unsigned int div_index)134 static void set_clkdiv(unsigned int div_index)
135 {
136 	unsigned int tmp;
137 
138 	/* Change Divider - CPU0 */
139 
140 	tmp = exynos5250_clkdiv_table[div_index].clkdiv;
141 
142 	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
143 
144 	while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
145 		cpu_relax();
146 
147 	/* Change Divider - CPU1 */
148 	tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
149 
150 	__raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
151 
152 	while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
153 		cpu_relax();
154 }
155 
set_apll(unsigned int new_index,unsigned int old_index)156 static void set_apll(unsigned int new_index,
157 			     unsigned int old_index)
158 {
159 	unsigned int tmp, pdiv;
160 
161 	/* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
162 	clk_set_parent(moutcore, mout_mpll);
163 
164 	do {
165 		cpu_relax();
166 		tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
167 		tmp &= 0x7;
168 	} while (tmp != 0x2);
169 
170 	/* 2. Set APLL Lock time */
171 	pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
172 
173 	__raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
174 
175 	/* 3. Change PLL PMS values */
176 	tmp = __raw_readl(EXYNOS5_APLL_CON0);
177 	tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
178 	tmp |= exynos5_apll_pms_table[new_index];
179 	__raw_writel(tmp, EXYNOS5_APLL_CON0);
180 
181 	/* 4. wait_lock_time */
182 	do {
183 		cpu_relax();
184 		tmp = __raw_readl(EXYNOS5_APLL_CON0);
185 	} while (!(tmp & (0x1 << 29)));
186 
187 	/* 5. MUX_CORE_SEL = APLL */
188 	clk_set_parent(moutcore, mout_apll);
189 
190 	do {
191 		cpu_relax();
192 		tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
193 		tmp &= (0x7 << 16);
194 	} while (tmp != (0x1 << 16));
195 
196 }
197 
exynos5250_pms_change(unsigned int old_index,unsigned int new_index)198 bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
199 {
200 	unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
201 	unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
202 
203 	return (old_pm == new_pm) ? 0 : 1;
204 }
205 
exynos5250_set_frequency(unsigned int old_index,unsigned int new_index)206 static void exynos5250_set_frequency(unsigned int old_index,
207 				  unsigned int new_index)
208 {
209 	unsigned int tmp;
210 
211 	if (old_index > new_index) {
212 		if (!exynos5250_pms_change(old_index, new_index)) {
213 			/* 1. Change the system clock divider values */
214 			set_clkdiv(new_index);
215 			/* 2. Change just s value in apll m,p,s value */
216 			tmp = __raw_readl(EXYNOS5_APLL_CON0);
217 			tmp &= ~(0x7 << 0);
218 			tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
219 			__raw_writel(tmp, EXYNOS5_APLL_CON0);
220 
221 		} else {
222 			/* Clock Configuration Procedure */
223 			/* 1. Change the system clock divider values */
224 			set_clkdiv(new_index);
225 			/* 2. Change the apll m,p,s value */
226 			set_apll(new_index, old_index);
227 		}
228 	} else if (old_index < new_index) {
229 		if (!exynos5250_pms_change(old_index, new_index)) {
230 			/* 1. Change just s value in apll m,p,s value */
231 			tmp = __raw_readl(EXYNOS5_APLL_CON0);
232 			tmp &= ~(0x7 << 0);
233 			tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
234 			__raw_writel(tmp, EXYNOS5_APLL_CON0);
235 			/* 2. Change the system clock divider values */
236 			set_clkdiv(new_index);
237 		} else {
238 			/* Clock Configuration Procedure */
239 			/* 1. Change the apll m,p,s value */
240 			set_apll(new_index, old_index);
241 			/* 2. Change the system clock divider values */
242 			set_clkdiv(new_index);
243 		}
244 	}
245 }
246 
set_volt_table(void)247 static void __init set_volt_table(void)
248 {
249 	unsigned int i;
250 
251 	exynos5250_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
252 	exynos5250_freq_table[L1].frequency = CPUFREQ_ENTRY_INVALID;
253 	exynos5250_freq_table[L2].frequency = CPUFREQ_ENTRY_INVALID;
254 	exynos5250_freq_table[L3].frequency = CPUFREQ_ENTRY_INVALID;
255 	exynos5250_freq_table[L4].frequency = CPUFREQ_ENTRY_INVALID;
256 	exynos5250_freq_table[L5].frequency = CPUFREQ_ENTRY_INVALID;
257 	exynos5250_freq_table[L6].frequency = CPUFREQ_ENTRY_INVALID;
258 
259 	max_support_idx = L7;
260 
261 	for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
262 		exynos5250_volt_table[i] = asv_voltage_5250[i];
263 }
264 
exynos5250_cpufreq_init(struct exynos_dvfs_info * info)265 int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
266 {
267 	int i;
268 	unsigned int tmp;
269 	unsigned long rate;
270 
271 	set_volt_table();
272 
273 	cpu_clk = clk_get(NULL, "armclk");
274 	if (IS_ERR(cpu_clk))
275 		return PTR_ERR(cpu_clk);
276 
277 	moutcore = clk_get(NULL, "mout_cpu");
278 	if (IS_ERR(moutcore))
279 		goto err_moutcore;
280 
281 	mout_mpll = clk_get(NULL, "mout_mpll");
282 	if (IS_ERR(mout_mpll))
283 		goto err_mout_mpll;
284 
285 	rate = clk_get_rate(mout_mpll) / 1000;
286 
287 	mout_apll = clk_get(NULL, "mout_apll");
288 	if (IS_ERR(mout_apll))
289 		goto err_mout_apll;
290 
291 	for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
292 
293 		exynos5250_clkdiv_table[i].index = i;
294 
295 		tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
296 
297 		tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
298 			(0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
299 			(0x7 << 24) | (0x7 << 28));
300 
301 		tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
302 			(clkdiv_cpu0_5250[i][1] << 4) |
303 			(clkdiv_cpu0_5250[i][2] << 8) |
304 			(clkdiv_cpu0_5250[i][3] << 12) |
305 			(clkdiv_cpu0_5250[i][4] << 16) |
306 			(clkdiv_cpu0_5250[i][5] << 20) |
307 			(clkdiv_cpu0_5250[i][6] << 24) |
308 			(clkdiv_cpu0_5250[i][7] << 28));
309 
310 		exynos5250_clkdiv_table[i].clkdiv = tmp;
311 
312 		tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
313 
314 		tmp &= ~((0x7 << 0) | (0x7 << 4));
315 
316 		tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
317 			(clkdiv_cpu1_5250[i][1] << 4));
318 
319 		exynos5250_clkdiv_table[i].clkdiv1 = tmp;
320 	}
321 
322 	info->mpll_freq_khz = rate;
323 	/* 1000Mhz */
324 	info->pm_lock_idx = L7;
325 	/* 800Mhz */
326 	info->pll_safe_idx = L9;
327 	info->max_support_idx = max_support_idx;
328 	info->min_support_idx = min_support_idx;
329 	info->cpu_clk = cpu_clk;
330 	info->volt_table = exynos5250_volt_table;
331 	info->freq_table = exynos5250_freq_table;
332 	info->set_freq = exynos5250_set_frequency;
333 	info->need_apll_change = exynos5250_pms_change;
334 
335 	return 0;
336 
337 err_mout_apll:
338 	clk_put(mout_mpll);
339 err_mout_mpll:
340 	clk_put(moutcore);
341 err_moutcore:
342 	clk_put(cpu_clk);
343 
344 	pr_err("%s: failed initialization\n", __func__);
345 	return -EINVAL;
346 }
347 EXPORT_SYMBOL(exynos5250_cpufreq_init);
348