ralink: various i2c related fixes
[oweals/openwrt.git] / target / linux / ipq806x / patches / 0172-cpufreq-Add-a-cpufreq-krait-based-on-cpufreq-cpu0.patch
1 From 5cf343c60d7557aefb468603065cac5062f11b8d 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 172/182] 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  drivers/cpufreq/Kconfig         |   13 +++
16  drivers/cpufreq/Makefile        |    1 +
17  drivers/cpufreq/cpufreq-krait.c |  190 +++++++++++++++++++++++++++++++++++++++
18  3 files changed, 204 insertions(+)
19  create mode 100644 drivers/cpufreq/cpufreq-krait.c
20
21 --- a/drivers/cpufreq/Kconfig
22 +++ b/drivers/cpufreq/Kconfig
23 @@ -194,6 +194,19 @@ config GENERIC_CPUFREQ_CPU0
24  
25           If in doubt, say N.
26  
27 +config GENERIC_CPUFREQ_KRAIT
28 +       tristate "Krait cpufreq driver"
29 +       depends on HAVE_CLK && OF
30 +       # if CPU_THERMAL is on and THERMAL=m, CPU0 cannot be =y:
31 +       depends on !CPU_THERMAL || THERMAL
32 +       select PM_OPP
33 +       help
34 +         This adds a generic cpufreq driver for CPU0 frequency management.
35 +         It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
36 +         systems which share clock and voltage across all CPUs.
37 +
38 +         If in doubt, say N.
39 +
40  menu "x86 CPU frequency scaling drivers"
41  depends on X86
42  source "drivers/cpufreq/Kconfig.x86"
43 --- a/drivers/cpufreq/Makefile
44 +++ b/drivers/cpufreq/Makefile
45 @@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)
46  obj-$(CONFIG_CPU_FREQ_GOV_COMMON)              += cpufreq_governor.o
47  
48  obj-$(CONFIG_GENERIC_CPUFREQ_CPU0)     += cpufreq-cpu0.o
49 +obj-$(CONFIG_GENERIC_CPUFREQ_KRAIT)    += cpufreq-krait.o
50  
51  ##################################################################################
52  # x86 drivers.
53 --- /dev/null
54 +++ b/drivers/cpufreq/cpufreq-krait.c
55 @@ -0,0 +1,190 @@
56 +/*
57 + * Copyright (C) 2012 Freescale Semiconductor, Inc.
58 + * Copyright (c) 2014, The Linux Foundation. All rights reserved.
59 + *
60 + * The OPP code in function krait_set_target() is reused from
61 + * drivers/cpufreq/omap-cpufreq.c
62 + *
63 + * This program is free software; you can redistribute it and/or modify
64 + * it under the terms of the GNU General Public License version 2 as
65 + * published by the Free Software Foundation.
66 + */
67 +
68 +#include <linux/clk.h>
69 +#include <linux/cpu.h>
70 +#include <linux/cpu_cooling.h>
71 +#include <linux/cpufreq.h>
72 +#include <linux/cpumask.h>
73 +#include <linux/err.h>
74 +#include <linux/module.h>
75 +#include <linux/of.h>
76 +#include <linux/pm_opp.h>
77 +#include <linux/platform_device.h>
78 +#include <linux/slab.h>
79 +#include <linux/thermal.h>
80 +
81 +static unsigned int transition_latency;
82 +
83 +static struct device *cpu_dev;
84 +static DEFINE_PER_CPU(struct clk *, krait_cpu_clks);
85 +static struct cpufreq_frequency_table *freq_table;
86 +static struct thermal_cooling_device *cdev;
87 +
88 +static int krait_set_target(struct cpufreq_policy *policy, unsigned int index)
89 +{
90 +       unsigned long volt = 0, volt_old = 0;
91 +       unsigned int old_freq, new_freq;
92 +       long freq_Hz, freq_exact;
93 +       int ret;
94 +       struct clk *cpu_clk;
95 +
96 +       cpu_clk = per_cpu(krait_cpu_clks, policy->cpu);
97 +
98 +       freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
99 +       if (freq_Hz <= 0)
100 +               freq_Hz = freq_table[index].frequency * 1000;
101 +
102 +       freq_exact = freq_Hz;
103 +       new_freq = freq_Hz / 1000;
104 +       old_freq = clk_get_rate(cpu_clk) / 1000;
105 +
106 +       pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
107 +                old_freq / 1000, volt_old ? volt_old / 1000 : -1,
108 +                new_freq / 1000, volt ? volt / 1000 : -1);
109 +
110 +       ret = clk_set_rate(cpu_clk, freq_exact);
111 +       if (ret)
112 +               pr_err("failed to set clock rate: %d\n", ret);
113 +
114 +       return ret;
115 +}
116 +
117 +static int krait_cpufreq_init(struct cpufreq_policy *policy)
118 +{
119 +       int ret;
120 +
121 +       policy->clk = per_cpu(krait_cpu_clks, policy->cpu);
122 +
123 +       ret = cpufreq_table_validate_and_show(policy, freq_table);
124 +       if (ret) {
125 +               pr_err("%s: invalid frequency table: %d\n", __func__, ret);
126 +               return ret;
127 +       }
128 +
129 +       policy->cpuinfo.transition_latency = transition_latency;
130 +
131 +       return 0;
132 +}
133 +
134 +static struct cpufreq_driver krait_cpufreq_driver = {
135 +       .flags = CPUFREQ_STICKY,
136 +       .verify = cpufreq_generic_frequency_table_verify,
137 +       .target_index = krait_set_target,
138 +       .get = cpufreq_generic_get,
139 +       .init = krait_cpufreq_init,
140 +       .name = "generic_krait",
141 +       .attr = cpufreq_generic_attr,
142 +};
143 +
144 +static int krait_cpufreq_probe(struct platform_device *pdev)
145 +{
146 +       struct device_node *np;
147 +       int ret;
148 +       unsigned int cpu;
149 +       struct device *dev;
150 +       struct clk *clk;
151 +
152 +       cpu_dev = get_cpu_device(0);
153 +       if (!cpu_dev) {
154 +               pr_err("failed to get krait device\n");
155 +               return -ENODEV;
156 +       }
157 +
158 +       np = of_node_get(cpu_dev->of_node);
159 +       if (!np) {
160 +               pr_err("failed to find krait node\n");
161 +               return -ENOENT;
162 +       }
163 +
164 +       for_each_possible_cpu(cpu) {
165 +               dev = get_cpu_device(cpu);
166 +               if (!dev) {
167 +                       pr_err("failed to get krait device\n");
168 +                       ret = -ENOENT;
169 +                       goto out_put_node;
170 +               }
171 +               per_cpu(krait_cpu_clks, cpu) = clk = devm_clk_get(dev, NULL);
172 +               if (IS_ERR(clk)) {
173 +                       ret = PTR_ERR(clk);
174 +                       goto out_put_node;
175 +               }
176 +       }
177 +
178 +       ret = of_init_opp_table(cpu_dev);
179 +       if (ret) {
180 +               pr_err("failed to init OPP table: %d\n", ret);
181 +               goto out_put_node;
182 +       }
183 +
184 +       ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
185 +       if (ret) {
186 +               pr_err("failed to init cpufreq table: %d\n", ret);
187 +               goto out_put_node;
188 +       }
189 +
190 +       if (of_property_read_u32(np, "clock-latency", &transition_latency))
191 +               transition_latency = CPUFREQ_ETERNAL;
192 +
193 +       ret = cpufreq_register_driver(&krait_cpufreq_driver);
194 +       if (ret) {
195 +               pr_err("failed register driver: %d\n", ret);
196 +               goto out_free_table;
197 +       }
198 +       of_node_put(np);
199 +
200 +       /*
201 +        * For now, just loading the cooling device;
202 +        * thermal DT code takes care of matching them.
203 +        */
204 +       for_each_possible_cpu(cpu) {
205 +               dev = get_cpu_device(cpu);
206 +               np = of_node_get(dev->of_node);
207 +               if (of_find_property(np, "#cooling-cells", NULL)) {
208 +                       cdev = of_cpufreq_cooling_register(np, cpumask_of(cpu));
209 +                       if (IS_ERR(cdev))
210 +                               pr_err("running cpufreq without cooling device: %ld\n",
211 +                                      PTR_ERR(cdev));
212 +               }
213 +               of_node_put(np);
214 +       }
215 +
216 +       return 0;
217 +
218 +out_free_table:
219 +       dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
220 +out_put_node:
221 +       of_node_put(np);
222 +       return ret;
223 +}
224 +
225 +static int krait_cpufreq_remove(struct platform_device *pdev)
226 +{
227 +       cpufreq_cooling_unregister(cdev);
228 +       cpufreq_unregister_driver(&krait_cpufreq_driver);
229 +       dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
230 +
231 +       return 0;
232 +}
233 +
234 +static struct platform_driver krait_cpufreq_platdrv = {
235 +       .driver = {
236 +               .name   = "cpufreq-krait",
237 +               .owner  = THIS_MODULE,
238 +       },
239 +       .probe          = krait_cpufreq_probe,
240 +       .remove         = krait_cpufreq_remove,
241 +};
242 +module_platform_driver(krait_cpufreq_platdrv);
243 +
244 +MODULE_DESCRIPTION("Krait CPUfreq driver");
245 +MODULE_LICENSE("GPL v2");