aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTang Yuantian <Yuantian.Tang@nxp.com>2017-02-08 21:33:02 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-02-09 08:33:02 -0500
commitb1e9a64972bfecd2f3dc5eb816781fa4ef28007a (patch)
treecea31356df78c285f2be94f04050b40f64cf91c6
parent5026ac23145eb63f5208eb843ce3a6a7a596c2ee (diff)
cpufreq: qoriq: Don't look at clock implementation details
Get the CPU clock's potential parent clocks from the clock interface itself, rather than manually parsing the clocks property to find a phandle, looking at the clock-names property of that, and assuming that those are valid parent clocks for the cpu clock. This is necessary now that the clocks are generated based on the clock driver's knowledge of the chip rather than a fragile device-tree description of the mux options. We can now rely on the clock driver to ensure that the mux only exposes options that are valid. The cpufreq driver was currently being overly conservative in some cases -- for example, the "min_cpufreq = get_bus_freq()" restriction only applies to chips with erratum A-004510, and whether the freq_mask used on p5020 is needed depends on the actual frequencies of the PLLs (FWIW, p5040 has a similar limitation but its .freq_mask was zero) -- and the frequency mask mechanism made assumptions about particular parent clock indices that are no longer valid. Signed-off-by: Scott Wood <scottwood@nxp.com> Signed-off-by: Tang Yuantian <yuantian.tang@nxp.com> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/cpufreq/qoriq-cpufreq.c148
1 files changed, 49 insertions, 99 deletions
diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c
index 53d8c3fb16f6..a6fefac8afe4 100644
--- a/drivers/cpufreq/qoriq-cpufreq.c
+++ b/drivers/cpufreq/qoriq-cpufreq.c
@@ -11,6 +11,7 @@
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12 12
13#include <linux/clk.h> 13#include <linux/clk.h>
14#include <linux/clk-provider.h>
14#include <linux/cpufreq.h> 15#include <linux/cpufreq.h>
15#include <linux/cpu_cooling.h> 16#include <linux/cpu_cooling.h>
16#include <linux/errno.h> 17#include <linux/errno.h>
@@ -37,53 +38,20 @@ struct cpu_data {
37 struct thermal_cooling_device *cdev; 38 struct thermal_cooling_device *cdev;
38}; 39};
39 40
41/*
42 * Don't use cpufreq on this SoC -- used when the SoC would have otherwise
43 * matched a more generic compatible.
44 */
45#define SOC_BLACKLIST 1
46
40/** 47/**
41 * struct soc_data - SoC specific data 48 * struct soc_data - SoC specific data
42 * @freq_mask: mask the disallowed frequencies 49 * @flags: SOC_xxx
43 * @flag: unique flags
44 */ 50 */
45struct soc_data { 51struct soc_data {
46 u32 freq_mask[4]; 52 u32 flags;
47 u32 flag;
48};
49
50#define FREQ_MASK 1
51/* see hardware specification for the allowed frqeuencies */
52static const struct soc_data sdata[] = {
53 { /* used by p2041 and p3041 */
54 .freq_mask = {0x8, 0x8, 0x2, 0x2},
55 .flag = FREQ_MASK,
56 },
57 { /* used by p5020 */
58 .freq_mask = {0x8, 0x2},
59 .flag = FREQ_MASK,
60 },
61 { /* used by p4080, p5040 */
62 .freq_mask = {0},
63 .flag = 0,
64 },
65}; 53};
66 54
67/*
68 * the minimum allowed core frequency, in Hz
69 * for chassis v1.0, >= platform frequency
70 * for chassis v2.0, >= platform frequency / 2
71 */
72static u32 min_cpufreq;
73static const u32 *fmask;
74
75#if defined(CONFIG_ARM)
76static int get_cpu_physical_id(int cpu)
77{
78 return topology_core_id(cpu);
79}
80#else
81static int get_cpu_physical_id(int cpu)
82{
83 return get_hard_smp_processor_id(cpu);
84}
85#endif
86
87static u32 get_bus_freq(void) 55static u32 get_bus_freq(void)
88{ 56{
89 struct device_node *soc; 57 struct device_node *soc;
@@ -101,9 +69,10 @@ static u32 get_bus_freq(void)
101 return sysfreq; 69 return sysfreq;
102} 70}
103 71
104static struct device_node *cpu_to_clk_node(int cpu) 72static struct clk *cpu_to_clk(int cpu)
105{ 73{
106 struct device_node *np, *clk_np; 74 struct device_node *np;
75 struct clk *clk;
107 76
108 if (!cpu_present(cpu)) 77 if (!cpu_present(cpu))
109 return NULL; 78 return NULL;
@@ -112,37 +81,28 @@ static struct device_node *cpu_to_clk_node(int cpu)
112 if (!np) 81 if (!np)
113 return NULL; 82 return NULL;
114 83
115 clk_np = of_parse_phandle(np, "clocks", 0); 84 clk = of_clk_get(np, 0);
116 if (!clk_np)
117 return NULL;
118
119 of_node_put(np); 85 of_node_put(np);
120 86 return clk;
121 return clk_np;
122} 87}
123 88
124/* traverse cpu nodes to get cpu mask of sharing clock wire */ 89/* traverse cpu nodes to get cpu mask of sharing clock wire */
125static void set_affected_cpus(struct cpufreq_policy *policy) 90static void set_affected_cpus(struct cpufreq_policy *policy)
126{ 91{
127 struct device_node *np, *clk_np;
128 struct cpumask *dstp = policy->cpus; 92 struct cpumask *dstp = policy->cpus;
93 struct clk *clk;
129 int i; 94 int i;
130 95
131 np = cpu_to_clk_node(policy->cpu);
132 if (!np)
133 return;
134
135 for_each_present_cpu(i) { 96 for_each_present_cpu(i) {
136 clk_np = cpu_to_clk_node(i); 97 clk = cpu_to_clk(i);
137 if (!clk_np) 98 if (IS_ERR(clk)) {
99 pr_err("%s: no clock for cpu %d\n", __func__, i);
138 continue; 100 continue;
101 }
139 102
140 if (clk_np == np) 103 if (clk_is_match(policy->clk, clk))
141 cpumask_set_cpu(i, dstp); 104 cpumask_set_cpu(i, dstp);
142
143 of_node_put(clk_np);
144 } 105 }
145 of_node_put(np);
146} 106}
147 107
148/* reduce the duplicated frequencies in frequency table */ 108/* reduce the duplicated frequencies in frequency table */
@@ -198,10 +158,11 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
198 158
199static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) 159static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
200{ 160{
201 struct device_node *np, *pnode; 161 struct device_node *np;
202 int i, count, ret; 162 int i, count, ret;
203 u32 freq, mask; 163 u32 freq;
204 struct clk *clk; 164 struct clk *clk;
165 const struct clk_hw *hwclk;
205 struct cpufreq_frequency_table *table; 166 struct cpufreq_frequency_table *table;
206 struct cpu_data *data; 167 struct cpu_data *data;
207 unsigned int cpu = policy->cpu; 168 unsigned int cpu = policy->cpu;
@@ -221,17 +182,13 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
221 goto err_nomem2; 182 goto err_nomem2;
222 } 183 }
223 184
224 pnode = of_parse_phandle(np, "clocks", 0); 185 hwclk = __clk_get_hw(policy->clk);
225 if (!pnode) { 186 count = clk_hw_get_num_parents(hwclk);
226 pr_err("%s: could not get clock information\n", __func__);
227 goto err_nomem2;
228 }
229 187
230 count = of_property_count_strings(pnode, "clock-names");
231 data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL); 188 data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
232 if (!data->pclk) { 189 if (!data->pclk) {
233 pr_err("%s: no memory\n", __func__); 190 pr_err("%s: no memory\n", __func__);
234 goto err_node; 191 goto err_nomem2;
235 } 192 }
236 193
237 table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL); 194 table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL);
@@ -240,23 +197,11 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
240 goto err_pclk; 197 goto err_pclk;
241 } 198 }
242 199
243 if (fmask)
244 mask = fmask[get_cpu_physical_id(cpu)];
245 else
246 mask = 0x0;
247
248 for (i = 0; i < count; i++) { 200 for (i = 0; i < count; i++) {
249 clk = of_clk_get(pnode, i); 201 clk = clk_hw_get_parent_by_index(hwclk, i)->clk;
250 data->pclk[i] = clk; 202 data->pclk[i] = clk;
251 freq = clk_get_rate(clk); 203 freq = clk_get_rate(clk);
252 /* 204 table[i].frequency = freq / 1000;
253 * the clock is valid if its frequency is not masked
254 * and large than minimum allowed frequency.
255 */
256 if (freq < min_cpufreq || (mask & (1 << i)))
257 table[i].frequency = CPUFREQ_ENTRY_INVALID;
258 else
259 table[i].frequency = freq / 1000;
260 table[i].driver_data = i; 205 table[i].driver_data = i;
261 } 206 }
262 freq_table_redup(table, count); 207 freq_table_redup(table, count);
@@ -282,7 +227,6 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
282 policy->cpuinfo.transition_latency = u64temp + 1; 227 policy->cpuinfo.transition_latency = u64temp + 1;
283 228
284 of_node_put(np); 229 of_node_put(np);
285 of_node_put(pnode);
286 230
287 return 0; 231 return 0;
288 232
@@ -290,10 +234,7 @@ err_nomem1:
290 kfree(table); 234 kfree(table);
291err_pclk: 235err_pclk:
292 kfree(data->pclk); 236 kfree(data->pclk);
293err_node:
294 of_node_put(pnode);
295err_nomem2: 237err_nomem2:
296 policy->driver_data = NULL;
297 kfree(data); 238 kfree(data);
298err_np: 239err_np:
299 of_node_put(np); 240 of_node_put(np);
@@ -357,12 +298,25 @@ static struct cpufreq_driver qoriq_cpufreq_driver = {
357 .attr = cpufreq_generic_attr, 298 .attr = cpufreq_generic_attr,
358}; 299};
359 300
301static const struct soc_data blacklist = {
302 .flags = SOC_BLACKLIST,
303};
304
360static const struct of_device_id node_matches[] __initconst = { 305static const struct of_device_id node_matches[] __initconst = {
361 { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], }, 306 /* e6500 cannot use cpufreq due to erratum A-008083 */
362 { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], }, 307 { .compatible = "fsl,b4420-clockgen", &blacklist },
363 { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], }, 308 { .compatible = "fsl,b4860-clockgen", &blacklist },
364 { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], }, 309 { .compatible = "fsl,t2080-clockgen", &blacklist },
365 { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], }, 310 { .compatible = "fsl,t4240-clockgen", &blacklist },
311
312 { .compatible = "fsl,ls1012a-clockgen", },
313 { .compatible = "fsl,ls1021a-clockgen", },
314 { .compatible = "fsl,ls1043a-clockgen", },
315 { .compatible = "fsl,ls1046a-clockgen", },
316 { .compatible = "fsl,ls1088a-clockgen", },
317 { .compatible = "fsl,ls2080a-clockgen", },
318 { .compatible = "fsl,p4080-clockgen", },
319 { .compatible = "fsl,qoriq-clockgen-1.0", },
366 { .compatible = "fsl,qoriq-clockgen-2.0", }, 320 { .compatible = "fsl,qoriq-clockgen-2.0", },
367 {} 321 {}
368}; 322};
@@ -380,16 +334,12 @@ static int __init qoriq_cpufreq_init(void)
380 334
381 match = of_match_node(node_matches, np); 335 match = of_match_node(node_matches, np);
382 data = match->data; 336 data = match->data;
383 if (data) {
384 if (data->flag)
385 fmask = data->freq_mask;
386 min_cpufreq = get_bus_freq();
387 } else {
388 min_cpufreq = get_bus_freq() / 2;
389 }
390 337
391 of_node_put(np); 338 of_node_put(np);
392 339
340 if (data && data->flags & SOC_BLACKLIST)
341 return -ENODEV;
342
393 ret = cpufreq_register_driver(&qoriq_cpufreq_driver); 343 ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
394 if (!ret) 344 if (!ret)
395 pr_info("Freescale QorIQ CPU frequency scaling driver\n"); 345 pr_info("Freescale QorIQ CPU frequency scaling driver\n");