ipq806x: fix uninitialized variable usage in cpufreq-krait
[openwrt.git] / target / linux / ipq806x / patches-4.1 / 145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch
1 From dd77db4143290689d3a5e1ec61627233d0711b66 Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Fri, 30 May 2014 16:36:11 -0700
4 Subject: [PATCH] FROMLIST: cpufreq: Add a cpufreq-krait based on cpufreq-cpu0
5
6 Krait processors have individual clocks for each CPU that can
7 scale independently from one another. cpufreq-cpu0 is fairly
8 close to this, but assumes that there is only one clock for all
9 CPUs. Add a driver to support the Krait configuration.
10
11 TODO: Merge into cpufreq-cpu0? Or make generic?
12
13 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
14
15 ---
16  drivers/cpufreq/Kconfig         |  13 +++
17  drivers/cpufreq/Makefile        |   1 +
18  drivers/cpufreq/cpufreq-krait.c | 190 ++++++++++++++++++++++++++++++++++++++++
19  3 files changed, 204 insertions(+)
20  create mode 100644 drivers/cpufreq/cpufreq-krait.c
21
22 --- a/drivers/cpufreq/Kconfig
23 +++ b/drivers/cpufreq/Kconfig
24 @@ -198,6 +198,19 @@ config CPUFREQ_DT
25  
26           If in doubt, say N.
27  
28 +config GENERIC_CPUFREQ_KRAIT
29 +       tristate "Krait cpufreq driver"
30 +       depends on HAVE_CLK && OF
31 +       # if CPU_THERMAL is on and THERMAL=m, CPU0 cannot be =y:
32 +       depends on !CPU_THERMAL || THERMAL
33 +       select PM_OPP
34 +       help
35 +         This adds a generic cpufreq driver for CPU0 frequency management.
36 +         It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
37 +         systems which share clock and voltage across all CPUs.
38 +
39 +         If in doubt, say N.
40 +
41  if X86
42  source "drivers/cpufreq/Kconfig.x86"
43  endif
44 --- a/drivers/cpufreq/Makefile
45 +++ b/drivers/cpufreq/Makefile
46 @@ -14,6 +14,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)
47  obj-$(CONFIG_CPU_FREQ_GOV_COMMON)              += cpufreq_governor.o
48  
49  obj-$(CONFIG_CPUFREQ_DT)               += cpufreq-dt.o
50 +obj-$(CONFIG_GENERIC_CPUFREQ_KRAIT)    += cpufreq-krait.o
51  
52  ##################################################################################
53  # x86 drivers.
54 --- /dev/null
55 +++ b/drivers/cpufreq/cpufreq-krait.c
56 @@ -0,0 +1,390 @@
57 +/*
58 + * Copyright (C) 2012 Freescale Semiconductor, Inc.
59 + * Copyright (c) 2014, The Linux Foundation. All rights reserved.
60 + *
61 + * The OPP code in function krait_set_target() is reused from
62 + * drivers/cpufreq/omap-cpufreq.c
63 + *
64 + * This program is free software; you can redistribute it and/or modify
65 + * it under the terms of the GNU General Public License version 2 as
66 + * published by the Free Software Foundation.
67 + */
68 +
69 +#include <linux/clk.h>
70 +#include <linux/cpu.h>
71 +#include <linux/cpu_cooling.h>
72 +#include <linux/cpufreq.h>
73 +#include <linux/cpumask.h>
74 +#include <linux/err.h>
75 +#include <linux/module.h>
76 +#include <linux/of.h>
77 +#include <linux/pm_opp.h>
78 +#include <linux/platform_device.h>
79 +#include <linux/regulator/consumer.h>
80 +#include <linux/slab.h>
81 +#include <linux/thermal.h>
82 +
83 +static unsigned int transition_latency;
84 +static unsigned int voltage_tolerance; /* in percentage */
85 +
86 +static struct device *cpu_dev;
87 +static DEFINE_PER_CPU(struct clk *, krait_cpu_clks);
88 +static DEFINE_PER_CPU(struct regulator *, krait_supply_core);
89 +static struct cpufreq_frequency_table *freq_table;
90 +static struct thermal_cooling_device *cdev;
91 +
92 +struct cache_points {
93 +       unsigned long cache_freq;
94 +       unsigned int cache_volt;
95 +       unsigned long cpu_freq;
96 +};
97 +
98 +static struct regulator *krait_l2_reg;
99 +static struct clk *krait_l2_clk;
100 +static struct cache_points *krait_l2_points;
101 +static int nr_krait_l2_points;
102 +
103 +static int krait_parse_cache_points(struct device *dev,
104 +               struct device_node *of_node)
105 +{
106 +       const struct property *prop;
107 +       const __be32 *val;
108 +       int nr, i;
109 +
110 +       prop = of_find_property(of_node, "cache-points-kHz", NULL);
111 +       if (!prop)
112 +               return -ENODEV;
113 +       if (!prop->value)
114 +               return -ENODATA;
115 +
116 +       /*
117 +        * Each OPP is a set of tuples consisting of frequency and
118 +        * cpu-frequency like <freq-kHz volt-uV freq-kHz>.
119 +        */
120 +       nr = prop->length / sizeof(u32);
121 +       if (nr % 3) {
122 +               dev_err(dev, "%s: Invalid cache points\n", __func__);
123 +               return -EINVAL;
124 +       }
125 +       nr /= 3;
126 +
127 +       krait_l2_points = devm_kcalloc(dev, nr, sizeof(*krait_l2_points),
128 +                                      GFP_KERNEL);
129 +       if (!krait_l2_points)
130 +               return -ENOMEM;
131 +       nr_krait_l2_points = nr;
132 +
133 +       for (i = 0, val = prop->value; i < nr; i++) {
134 +               unsigned long cache_freq = be32_to_cpup(val++) * 1000;
135 +               unsigned int cache_volt = be32_to_cpup(val++);
136 +               unsigned long cpu_freq = be32_to_cpup(val++) * 1000;
137 +
138 +               krait_l2_points[i].cache_freq = cache_freq;
139 +               krait_l2_points[i].cache_volt = cache_volt;
140 +               krait_l2_points[i].cpu_freq = cpu_freq;
141 +       }
142 +
143 +       return 0;
144 +}
145 +
146 +static int krait_set_target(struct cpufreq_policy *policy, unsigned int index)
147 +{
148 +       struct dev_pm_opp *opp;
149 +       unsigned long volt = 0, volt_old = 0, tol = 0;
150 +       unsigned long freq, max_cpu_freq = 0;
151 +       unsigned int old_freq, new_freq;
152 +       long freq_Hz, freq_exact;
153 +       int ret, i;
154 +       struct clk *cpu_clk;
155 +       struct regulator *core;
156 +       unsigned int cpu;
157 +
158 +       cpu_clk = per_cpu(krait_cpu_clks, policy->cpu);
159 +
160 +       freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
161 +       if (freq_Hz <= 0)
162 +               freq_Hz = freq_table[index].frequency * 1000;
163 +
164 +       freq_exact = freq_Hz;
165 +       new_freq = freq_Hz / 1000;
166 +       old_freq = clk_get_rate(cpu_clk) / 1000;
167 +
168 +       core = per_cpu(krait_supply_core, policy->cpu);
169 +
170 +       rcu_read_lock();
171 +       opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
172 +       if (IS_ERR(opp)) {
173 +               rcu_read_unlock();
174 +               pr_err("failed to find OPP for %ld\n", freq_Hz);
175 +               return PTR_ERR(opp);
176 +       }
177 +       volt = dev_pm_opp_get_voltage(opp);
178 +       rcu_read_unlock();
179 +       tol = volt * voltage_tolerance / 100;
180 +       volt_old = regulator_get_voltage(core);
181 +
182 +       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
183 +                old_freq / 1000, volt_old ? volt_old / 1000 : -1,
184 +                new_freq / 1000, volt ? volt / 1000 : -1);
185 +
186 +       /* scaling up?  scale voltage before frequency */
187 +       if (new_freq > old_freq) {
188 +               ret = regulator_set_voltage_tol(core, volt, tol);
189 +               if (ret) {
190 +                       pr_err("failed to scale voltage up: %d\n", ret);
191 +                       return ret;
192 +               }
193 +       }
194 +
195 +       ret = clk_set_rate(cpu_clk, freq_exact);
196 +       if (ret) {
197 +               pr_err("failed to set clock rate: %d\n", ret);
198 +               return ret;
199 +       }
200 +
201 +       /* scaling down?  scale voltage after frequency */
202 +       if (new_freq < old_freq) {
203 +               ret = regulator_set_voltage_tol(core, volt, tol);
204 +               if (ret) {
205 +                       pr_err("failed to scale voltage down: %d\n", ret);
206 +                       clk_set_rate(cpu_clk, old_freq * 1000);
207 +               }
208 +       }
209 +
210 +       for_each_possible_cpu(cpu) {
211 +               freq = clk_get_rate(per_cpu(krait_cpu_clks, cpu));
212 +               max_cpu_freq = max(max_cpu_freq, freq);
213 +       }
214 +
215 +       for (i = 0; i < nr_krait_l2_points; i++) {
216 +               if (max_cpu_freq >= krait_l2_points[i].cpu_freq) {
217 +                       if (krait_l2_reg) {
218 +                               ret = regulator_set_voltage_tol(krait_l2_reg,
219 +                                               krait_l2_points[i].cache_volt,
220 +                                               tol);
221 +                               if (ret) {
222 +                                       pr_err("failed to scale l2 voltage: %d\n",
223 +                                               ret);
224 +                               }
225 +                       }
226 +                       ret = clk_set_rate(krait_l2_clk,
227 +                                       krait_l2_points[i].cache_freq);
228 +                       if (ret)
229 +                               pr_err("failed to scale l2 clk: %d\n", ret);
230 +                       break;
231 +               }
232 +
233 +       }
234 +
235 +       return ret;
236 +}
237 +
238 +static int krait_cpufreq_init(struct cpufreq_policy *policy)
239 +{
240 +       int ret;
241 +
242 +       policy->clk = per_cpu(krait_cpu_clks, policy->cpu);
243 +
244 +       ret = cpufreq_table_validate_and_show(policy, freq_table);
245 +       if (ret) {
246 +               pr_err("%s: invalid frequency table: %d\n", __func__, ret);
247 +               return ret;
248 +       }
249 +
250 +       policy->cpuinfo.transition_latency = transition_latency;
251 +
252 +       return 0;
253 +}
254 +
255 +static struct cpufreq_driver krait_cpufreq_driver = {
256 +       .flags = CPUFREQ_STICKY,
257 +       .verify = cpufreq_generic_frequency_table_verify,
258 +       .target_index = krait_set_target,
259 +       .get = cpufreq_generic_get,
260 +       .init = krait_cpufreq_init,
261 +       .name = "generic_krait",
262 +       .attr = cpufreq_generic_attr,
263 +};
264 +
265 +static int krait_cpufreq_probe(struct platform_device *pdev)
266 +{
267 +       struct device_node *np, *cache;
268 +       int ret, i;
269 +       unsigned int cpu;
270 +       struct device *dev;
271 +       struct clk *clk;
272 +       struct regulator *core;
273 +       unsigned long freq_Hz, freq, max_cpu_freq = 0;
274 +       struct dev_pm_opp *opp;
275 +       unsigned long volt, tol;
276 +
277 +       cpu_dev = get_cpu_device(0);
278 +       if (!cpu_dev) {
279 +               pr_err("failed to get krait device\n");
280 +               return -ENODEV;
281 +       }
282 +
283 +       np = of_node_get(cpu_dev->of_node);
284 +       if (!np) {
285 +               pr_err("failed to find krait node\n");
286 +               return -ENOENT;
287 +       }
288 +
289 +       ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
290 +       if (ret) {
291 +               pr_err("failed to init cpufreq table: %d\n", ret);
292 +               goto out_put_node;
293 +       }
294 +
295 +       of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
296 +
297 +       if (of_property_read_u32(np, "clock-latency", &transition_latency))
298 +               transition_latency = CPUFREQ_ETERNAL;
299 +
300 +       cache = of_find_next_cache_node(np);
301 +       if (cache) {
302 +               struct device_node *vdd;
303 +
304 +               vdd = of_parse_phandle(cache, "vdd_dig-supply", 0);
305 +               if (vdd) {
306 +                       krait_l2_reg = regulator_get(NULL, vdd->name);
307 +                       if (IS_ERR(krait_l2_reg)) {
308 +                               pr_warn("failed to get l2 vdd_dig supply\n");
309 +                               krait_l2_reg = NULL;
310 +                       }
311 +                       of_node_put(vdd);
312 +               }
313 +
314 +               krait_l2_clk = of_clk_get(cache, 0);
315 +               if (!IS_ERR(krait_l2_clk)) {
316 +                       ret = krait_parse_cache_points(&pdev->dev, cache);
317 +                       if (ret)
318 +                               clk_put(krait_l2_clk);
319 +               }
320 +               if (IS_ERR(krait_l2_clk) || ret)
321 +                       krait_l2_clk = NULL;
322 +       }
323 +
324 +       for_each_possible_cpu(cpu) {
325 +               dev = get_cpu_device(cpu);
326 +               if (!dev) {
327 +                       pr_err("failed to get krait device\n");
328 +                       ret = -ENOENT;
329 +                       goto out_free_table;
330 +               }
331 +               per_cpu(krait_cpu_clks, cpu) = clk = devm_clk_get(dev, NULL);
332 +               if (IS_ERR(clk)) {
333 +                       ret = PTR_ERR(clk);
334 +                       goto out_free_table;
335 +               }
336 +               core = devm_regulator_get(dev, "core");
337 +               if (IS_ERR(core)) {
338 +                       pr_debug("failed to get core regulator\n");
339 +                       ret = PTR_ERR(core);
340 +                       goto out_free_table;
341 +               }
342 +               per_cpu(krait_supply_core, cpu) = core;
343 +
344 +               freq = freq_Hz = clk_get_rate(clk);
345 +
346 +               rcu_read_lock();
347 +               opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
348 +               if (IS_ERR(opp)) {
349 +                       rcu_read_unlock();
350 +                       pr_err("failed to find OPP for %ld\n", freq_Hz);
351 +                       ret = PTR_ERR(opp);
352 +                       goto out_free_table;
353 +               }
354 +               volt = dev_pm_opp_get_voltage(opp);
355 +               rcu_read_unlock();
356 +
357 +               tol = volt * voltage_tolerance / 100;
358 +               ret = regulator_set_voltage_tol(core, volt, tol);
359 +               if (ret) {
360 +                       pr_err("failed to scale voltage up: %d\n", ret);
361 +                       goto out_free_table;
362 +               }
363 +               ret = regulator_enable(core);
364 +               if (ret) {
365 +                       pr_err("failed to enable regulator: %d\n", ret);
366 +                       goto out_free_table;
367 +               }
368 +               max_cpu_freq = max(max_cpu_freq, freq);
369 +       }
370 +
371 +       for (i = 0; i < nr_krait_l2_points; i++) {
372 +               if (max_cpu_freq >= krait_l2_points[i].cpu_freq) {
373 +                       if (krait_l2_reg) {
374 +                               ret = regulator_set_voltage_tol(krait_l2_reg,
375 +                                               krait_l2_points[i].cache_volt,
376 +                                               tol);
377 +                               if (ret)
378 +                                       pr_err("failed to scale l2 voltage: %d\n",
379 +                                                       ret);
380 +                               ret = regulator_enable(krait_l2_reg);
381 +                               if (ret)
382 +                                       pr_err("failed to enable l2 voltage: %d\n",
383 +                                                       ret);
384 +                       }
385 +                       break;
386 +               }
387 +
388 +       }
389 +
390 +       ret = cpufreq_register_driver(&krait_cpufreq_driver);
391 +       if (ret) {
392 +               pr_err("failed register driver: %d\n", ret);
393 +               goto out_free_table;
394 +       }
395 +       of_node_put(np);
396 +
397 +       /*
398 +        * For now, just loading the cooling device;
399 +        * thermal DT code takes care of matching them.
400 +        */
401 +       for_each_possible_cpu(cpu) {
402 +               dev = get_cpu_device(cpu);
403 +               np = of_node_get(dev->of_node);
404 +               if (of_find_property(np, "#cooling-cells", NULL)) {
405 +                       cdev = of_cpufreq_cooling_register(np, cpumask_of(cpu));
406 +                       if (IS_ERR(cdev))
407 +                               pr_err("running cpufreq without cooling device: %ld\n",
408 +                                      PTR_ERR(cdev));
409 +               }
410 +               of_node_put(np);
411 +       }
412 +
413 +       return 0;
414 +
415 +out_free_table:
416 +       regulator_put(krait_l2_reg);
417 +       clk_put(krait_l2_clk);
418 +       dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
419 +out_put_node:
420 +       of_node_put(np);
421 +       return ret;
422 +}
423 +
424 +static int krait_cpufreq_remove(struct platform_device *pdev)
425 +{
426 +       cpufreq_cooling_unregister(cdev);
427 +       cpufreq_unregister_driver(&krait_cpufreq_driver);
428 +       dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
429 +       clk_put(krait_l2_clk);
430 +       regulator_put(krait_l2_reg);
431 +
432 +       return 0;
433 +}
434 +
435 +static struct platform_driver krait_cpufreq_platdrv = {
436 +       .driver = {
437 +               .name   = "cpufreq-krait",
438 +               .owner  = THIS_MODULE,
439 +       },
440 +       .probe          = krait_cpufreq_probe,
441 +       .remove         = krait_cpufreq_remove,
442 +};
443 +module_platform_driver(krait_cpufreq_platdrv);
444 +
445 +MODULE_DESCRIPTION("Krait CPUfreq driver");
446 +MODULE_LICENSE("GPL v2");
447 --- a/drivers/cpufreq/qcom-cpufreq.c
448 +++ b/drivers/cpufreq/qcom-cpufreq.c
449 @@ -168,11 +168,8 @@ static int __init qcom_cpufreq_populate_
450  
451  static int __init qcom_cpufreq_driver_init(void)
452  {
453 -       struct cpufreq_dt_platform_data pdata = { .independent_clocks = true };
454         struct platform_device_info devinfo = {
455 -               .name = "cpufreq-dt",
456 -               .data = &pdata,
457 -               .size_data = sizeof(pdata),
458 +               .name = "cpufreq-krait",
459         };
460         struct device *cpu_dev;
461         struct device_node *np;