aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2013-08-16 13:19:16 -0400
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 09:01:16 -0400
commitf2c66915dcc5a6ce309ed3c78efd930786373125 (patch)
tree36744bccbbd6f3672314d97db123640bc756b264 /drivers/cpufreq
parent2a7b3ac19150caeee1eac35e2dcc2fefd6155d0a (diff)
ENGR00273792-1 Cpufreq:iMX6x:Improve CPUFREQ driver.
Add support for VDDSOC/VDDPU operating points that track the VDDARM cap to the device tree. Add the description for soc-operating-points that need to be added to the device tree files. Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c184
1 files changed, 144 insertions, 40 deletions
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index b78bc35973ba..23c0125e8253 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -15,10 +15,7 @@
15#include <linux/opp.h> 15#include <linux/opp.h>
16#include <linux/platform_device.h> 16#include <linux/platform_device.h>
17#include <linux/regulator/consumer.h> 17#include <linux/regulator/consumer.h>
18 18#include <linux/slab.h>
19#define PU_SOC_VOLTAGE_NORMAL 1250000
20#define PU_SOC_VOLTAGE_HIGH 1275000
21#define FREQ_1P2_GHZ 1200000000
22 19
23static struct regulator *arm_reg; 20static struct regulator *arm_reg;
24static struct regulator *pu_reg; 21static struct regulator *pu_reg;
@@ -33,6 +30,13 @@ static struct clk *pll2_pfd2_396m_clk;
33static struct device *cpu_dev; 30static struct device *cpu_dev;
34static struct cpufreq_frequency_table *freq_table; 31static struct cpufreq_frequency_table *freq_table;
35static unsigned int transition_latency; 32static unsigned int transition_latency;
33struct soc_opp {
34 u32 arm_freq;
35 u32 soc_volt;
36};
37
38static struct soc_opp *imx6q_soc_opp;
39static u32 soc_opp_count;
36 40
37static int imx6q_verify_speed(struct cpufreq_policy *policy) 41static int imx6q_verify_speed(struct cpufreq_policy *policy)
38{ 42{
@@ -50,7 +54,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
50 struct cpufreq_freqs freqs; 54 struct cpufreq_freqs freqs;
51 struct opp *opp; 55 struct opp *opp;
52 unsigned long freq_hz, volt, volt_old; 56 unsigned long freq_hz, volt, volt_old;
53 unsigned int index; 57 unsigned int index, soc_opp_index = 0;
54 int ret; 58 int ret;
55 59
56 ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, 60 ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
@@ -82,28 +86,46 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
82 rcu_read_unlock(); 86 rcu_read_unlock();
83 volt_old = regulator_get_voltage(arm_reg); 87 volt_old = regulator_get_voltage(arm_reg);
84 88
89 /* Find the matching VDDSOC/VDDPU operating voltage */
90 while (soc_opp_index < soc_opp_count) {
91 if (freqs.new == imx6q_soc_opp[soc_opp_index].arm_freq)
92 break;
93 soc_opp_index++;
94 }
95 if (soc_opp_index >= soc_opp_count) {
96 dev_err(cpu_dev,
97 "Cannot find matching imx6q_soc_opp voltage\n");
98 return -EINVAL;
99 }
100
85 dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", 101 dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
86 freqs.old / 1000, volt_old / 1000, 102 freqs.old / 1000, volt_old / 1000,
87 freqs.new / 1000, volt / 1000); 103 freqs.new / 1000, volt / 1000);
88 104
89 /* scaling up? scale voltage before frequency */ 105 /* scaling up? scale voltage before frequency */
90 if (freqs.new > freqs.old) { 106 if (freqs.new > freqs.old) {
107 if (regulator_is_enabled(pu_reg)) {
108 ret = regulator_set_voltage_tol(pu_reg,
109 imx6q_soc_opp[soc_opp_index].soc_volt,
110 0);
111 if (ret) {
112 dev_err(cpu_dev,
113 "failed to scale vddpu up: %d\n", ret);
114 goto err1;
115 }
116 }
117 ret = regulator_set_voltage_tol(soc_reg,
118 imx6q_soc_opp[soc_opp_index].soc_volt, 0);
119 if (ret) {
120 dev_err(cpu_dev,
121 "failed to scale vddsoc up: %d\n", ret);
122 goto err1;
123 }
91 ret = regulator_set_voltage_tol(arm_reg, volt, 0); 124 ret = regulator_set_voltage_tol(arm_reg, volt, 0);
92 if (ret) { 125 if (ret) {
93 dev_err(cpu_dev, 126 dev_err(cpu_dev,
94 "failed to scale vddarm up: %d\n", ret); 127 "failed to scale vddarm up: %d\n", ret);
95 return ret; 128 goto err1;
96 }
97
98 /*
99 * Need to increase vddpu and vddsoc for safety
100 * if we are about to run at 1.2 GHz.
101 */
102 if (freqs.new == FREQ_1P2_GHZ / 1000) {
103 regulator_set_voltage_tol(pu_reg,
104 PU_SOC_VOLTAGE_HIGH, 0);
105 regulator_set_voltage_tol(soc_reg,
106 PU_SOC_VOLTAGE_HIGH, 0);
107 } 129 }
108 } 130 }
109 131
@@ -144,28 +166,43 @@ static int imx6q_set_target(struct cpufreq_policy *policy,
144 ret = clk_set_rate(arm_clk, freqs.new * 1000); 166 ret = clk_set_rate(arm_clk, freqs.new * 1000);
145 if (ret) { 167 if (ret) {
146 dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); 168 dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
147 regulator_set_voltage_tol(arm_reg, volt_old, 0); 169 goto err1;
148 return ret;
149 } 170 }
150 171
151 /* scaling down? scale voltage after frequency */ 172 /* scaling down? scale voltage after frequency */
152 if (freqs.new < freqs.old) { 173 if (freqs.new < freqs.old) {
153 ret = regulator_set_voltage_tol(arm_reg, volt, 0); 174 ret = regulator_set_voltage_tol(arm_reg, volt, 0);
154 if (ret) 175 if (ret) {
155 dev_warn(cpu_dev, 176 dev_warn(cpu_dev,
156 "failed to scale vddarm down: %d\n", ret); 177 "failed to scale vddarm down: %d\n", ret);
178 goto err1;
179 }
157 180
158 if (freqs.old == FREQ_1P2_GHZ / 1000) { 181 ret = regulator_set_voltage_tol(soc_reg,
159 regulator_set_voltage_tol(pu_reg, 182 imx6q_soc_opp[soc_opp_index].soc_volt, 0);
160 PU_SOC_VOLTAGE_NORMAL, 0); 183 if (ret) {
161 regulator_set_voltage_tol(soc_reg, 184 dev_err(cpu_dev,
162 PU_SOC_VOLTAGE_NORMAL, 0); 185 "failed to scale vddsoc down: %d\n", ret);
186 goto err1;
163 } 187 }
164 }
165 188
189 if (regulator_is_enabled(pu_reg)) {
190 ret = regulator_set_voltage_tol(pu_reg,
191 imx6q_soc_opp[soc_opp_index].soc_volt,
192 0);
193 if (ret) {
194 dev_err(cpu_dev,
195 "failed to scale vddpu down: %d\n", ret);
196 goto err1;
197 }
198 }
199
200 }
166 cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); 201 cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
167 202
168 return 0; 203 return 0;
204err1:
205 return -1;
169} 206}
170 207
171static int imx6q_cpufreq_init(struct cpufreq_policy *policy) 208static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
@@ -211,8 +248,11 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
211{ 248{
212 struct device_node *np; 249 struct device_node *np;
213 struct opp *opp; 250 struct opp *opp;
214 unsigned long min_volt, max_volt; 251 unsigned long min_volt = 0, max_volt = 0;
215 int num, ret; 252 int num, ret;
253 const struct property *prop;
254 const __be32 *val;
255 u32 nr, i;
216 256
217 cpu_dev = &pdev->dev; 257 cpu_dev = &pdev->dev;
218 258
@@ -259,10 +299,86 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
259 goto put_node; 299 goto put_node;
260 } 300 }
261 301
302 prop = of_find_property(np, "fsl,soc-operating-points", NULL);
303 if (!prop) {
304 dev_err(cpu_dev,
305 "fsl,soc-operating-points node not found\n");
306 goto free_freq_table;
307 }
308 if (!prop->value) {
309 dev_err(cpu_dev,
310 "No entries in fsl-soc-operating-points node.\n");
311 goto free_freq_table;
312 }
313
314 /*
315 * Each OPP is a set of tuples consisting of frequency and
316 * voltage like <freq-kHz vol-uV>.
317 */
318 nr = prop->length / sizeof(u32);
319 if (nr % 2) {
320 dev_err(cpu_dev, "Invalid fsl-soc-operating-points list\n");
321 goto free_freq_table;
322 }
323
324 /* Get the VDDSOC/VDDPU voltages that need to track the CPU voltages. */
325 imx6q_soc_opp = devm_kzalloc(cpu_dev,
326 sizeof(struct soc_opp) * (nr / 2),
327 GFP_KERNEL);
328
329 if (imx6q_soc_opp == NULL) {
330 dev_err(cpu_dev, "No Memory for VDDSOC/PU table\n");
331 goto free_freq_table;
332 }
333
334 rcu_read_lock();
335 val = prop->value;
336
337 for (i = 0; i < nr / 2; i++) {
338 unsigned long freq = be32_to_cpup(val++);
339 unsigned long volt = be32_to_cpup(val++);
340
341 if (i == 0)
342 min_volt = max_volt = volt;
343 if (volt < min_volt)
344 min_volt = volt;
345 if (volt > max_volt)
346 max_volt = volt;
347 opp = opp_find_freq_exact(cpu_dev,
348 freq * 1000, true);
349 if (IS_ERR(opp)) {
350 opp = opp_find_freq_exact(cpu_dev,
351 freq * 1000, false);
352 if (IS_ERR(opp)) {
353 dev_err(cpu_dev,
354 "freq in soc-operating-points does not \
355 match cpufreq table\n");
356 rcu_read_unlock();
357 goto free_freq_table;
358 }
359 }
360 imx6q_soc_opp[i].arm_freq = freq;
361 imx6q_soc_opp[i].soc_volt = volt;
362 soc_opp_count++;
363 }
364 rcu_read_unlock();
365
262 if (of_property_read_u32(np, "clock-latency", &transition_latency)) 366 if (of_property_read_u32(np, "clock-latency", &transition_latency))
263 transition_latency = CPUFREQ_ETERNAL; 367 transition_latency = CPUFREQ_ETERNAL;
264 368
265 /* 369 /*
370 * Calculate the ramp time for max voltage change in the
371 * VDDSOC and VDDPU regulators.
372 */
373 ret = regulator_set_voltage_time(soc_reg, min_volt, max_volt);
374 if (ret > 0)
375 transition_latency += ret * 1000;
376
377 ret = regulator_set_voltage_time(pu_reg, min_volt, max_volt);
378 if (ret > 0)
379 transition_latency += ret * 1000;
380
381 /*
266 * OPP is maintained in order of increasing frequency, and 382 * OPP is maintained in order of increasing frequency, and
267 * freq_table initialised from OPP is therefore sorted in the 383 * freq_table initialised from OPP is therefore sorted in the
268 * same order. 384 * same order.
@@ -272,25 +388,13 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
272 freq_table[0].frequency * 1000, true); 388 freq_table[0].frequency * 1000, true);
273 min_volt = opp_get_voltage(opp); 389 min_volt = opp_get_voltage(opp);
274 opp = opp_find_freq_exact(cpu_dev, 390 opp = opp_find_freq_exact(cpu_dev,
275 freq_table[--num].frequency * 1000, true); 391 freq_table[num - 1].frequency * 1000, true);
276 max_volt = opp_get_voltage(opp); 392 max_volt = opp_get_voltage(opp);
277 rcu_read_unlock(); 393 rcu_read_unlock();
278 ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt); 394 ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
279 if (ret > 0) 395 if (ret > 0)
280 transition_latency += ret * 1000; 396 transition_latency += ret * 1000;
281 397
282 /* Count vddpu and vddsoc latency in for 1.2 GHz support */
283 if (freq_table[num].frequency == FREQ_1P2_GHZ / 1000) {
284 ret = regulator_set_voltage_time(pu_reg, PU_SOC_VOLTAGE_NORMAL,
285 PU_SOC_VOLTAGE_HIGH);
286 if (ret > 0)
287 transition_latency += ret * 1000;
288 ret = regulator_set_voltage_time(soc_reg, PU_SOC_VOLTAGE_NORMAL,
289 PU_SOC_VOLTAGE_HIGH);
290 if (ret > 0)
291 transition_latency += ret * 1000;
292 }
293
294 ret = cpufreq_register_driver(&imx6q_cpufreq_driver); 398 ret = cpufreq_register_driver(&imx6q_cpufreq_driver);
295 if (ret) { 399 if (ret) {
296 dev_err(cpu_dev, "failed register driver: %d\n", ret); 400 dev_err(cpu_dev, "failed register driver: %d\n", ret);