aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTang Yuantian <Yuantian.Tang@freescale.com>2015-03-13 00:39:01 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-03-18 17:35:15 -0400
commita4f207428b53975069d12d49a509b440c707d691 (patch)
tree0d8d3ad1a61076c8a9166c0543115211af5deded
parent06e5801b8cb3fc057d88cb4dc03c0b64b2744cda (diff)
cpufreq: qoriq: Make the driver usable on all QorIQ platforms
Freescale introduced new ARM core-based SoCs which support dynamic frequency switch feature. DFS on new SoCs are compatible with current PowerPC CoreNet platforms. In order to support those new platforms, this driver needs to be updated. The main changes include: 1. Changed the names of functions in driver. 2. Added two new functions get_cpu_physical_id() and get_bus_freq(). 3. Used a new way to get the CPU mask which share clock wire. Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.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/ppc-corenet-cpufreq.c161
1 files changed, 99 insertions, 62 deletions
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
index 7cb4b766cf94..9fd51c860308 100644
--- a/drivers/cpufreq/ppc-corenet-cpufreq.c
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Copyright 2013 Freescale Semiconductor, Inc. 2 * Copyright 2013 Freescale Semiconductor, Inc.
3 * 3 *
4 * CPU Frequency Scaling driver for Freescale PowerPC corenet SoCs. 4 * CPU Frequency Scaling driver for Freescale QorIQ SoCs.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 7 * it under the terms of the GNU General Public License version 2 as
@@ -20,12 +20,11 @@
20#include <linux/of.h> 20#include <linux/of.h>
21#include <linux/slab.h> 21#include <linux/slab.h>
22#include <linux/smp.h> 22#include <linux/smp.h>
23#include <sysdev/fsl_soc.h>
24 23
25#include <asm/smp.h> /* for get_hard_smp_processor_id() in UP configs */ 24#include <asm/smp.h> /* for get_hard_smp_processor_id() in UP configs */
26 25
27/** 26/**
28 * struct cpu_data - per CPU data struct 27 * struct cpu_data
29 * @parent: the parent node of cpu clock 28 * @parent: the parent node of cpu clock
30 * @table: frequency table 29 * @table: frequency table
31 */ 30 */
@@ -69,17 +68,78 @@ static const struct soc_data sdata[] = {
69static u32 min_cpufreq; 68static u32 min_cpufreq;
70static const u32 *fmask; 69static const u32 *fmask;
71 70
72static DEFINE_PER_CPU(struct cpu_data *, cpu_data); 71#if defined(CONFIG_ARM)
72static int get_cpu_physical_id(int cpu)
73{
74 return topology_core_id(cpu);
75}
76#else
77static int get_cpu_physical_id(int cpu)
78{
79 return get_hard_smp_processor_id(cpu);
80}
81#endif
82
83static u32 get_bus_freq(void)
84{
85 struct device_node *soc;
86 u32 sysfreq;
87
88 soc = of_find_node_by_type(NULL, "soc");
89 if (!soc)
90 return 0;
91
92 if (of_property_read_u32(soc, "bus-frequency", &sysfreq))
93 sysfreq = 0;
94
95 of_node_put(soc);
73 96
74/* cpumask in a cluster */ 97 return sysfreq;
75static DEFINE_PER_CPU(cpumask_var_t, cpu_mask); 98}
76 99
77#ifndef CONFIG_SMP 100static struct device_node *cpu_to_clk_node(int cpu)
78static inline const struct cpumask *cpu_core_mask(int cpu)
79{ 101{
80 return cpumask_of(0); 102 struct device_node *np, *clk_np;
103
104 if (!cpu_present(cpu))
105 return NULL;
106
107 np = of_get_cpu_node(cpu, NULL);
108 if (!np)
109 return NULL;
110
111 clk_np = of_parse_phandle(np, "clocks", 0);
112 if (!clk_np)
113 return NULL;
114
115 of_node_put(np);
116
117 return clk_np;
118}
119
120/* traverse cpu nodes to get cpu mask of sharing clock wire */
121static void set_affected_cpus(struct cpufreq_policy *policy)
122{
123 struct device_node *np, *clk_np;
124 struct cpumask *dstp = policy->cpus;
125 int i;
126
127 np = cpu_to_clk_node(policy->cpu);
128 if (!np)
129 return;
130
131 for_each_present_cpu(i) {
132 clk_np = cpu_to_clk_node(i);
133 if (!clk_np)
134 continue;
135
136 if (clk_np == np)
137 cpumask_set_cpu(i, dstp);
138
139 of_node_put(clk_np);
140 }
141 of_node_put(np);
81} 142}
82#endif
83 143
84/* reduce the duplicated frequencies in frequency table */ 144/* reduce the duplicated frequencies in frequency table */
85static void freq_table_redup(struct cpufreq_frequency_table *freq_table, 145static void freq_table_redup(struct cpufreq_frequency_table *freq_table,
@@ -107,6 +167,7 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
107 int i, j, ind; 167 int i, j, ind;
108 unsigned int freq, max_freq; 168 unsigned int freq, max_freq;
109 struct cpufreq_frequency_table table; 169 struct cpufreq_frequency_table table;
170
110 for (i = 0; i < count - 1; i++) { 171 for (i = 0; i < count - 1; i++) {
111 max_freq = freq_table[i].frequency; 172 max_freq = freq_table[i].frequency;
112 ind = i; 173 ind = i;
@@ -131,7 +192,7 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table,
131 } 192 }
132} 193}
133 194
134static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) 195static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy)
135{ 196{
136 struct device_node *np; 197 struct device_node *np;
137 int i, count, ret; 198 int i, count, ret;
@@ -147,10 +208,8 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
147 return -ENODEV; 208 return -ENODEV;
148 209
149 data = kzalloc(sizeof(*data), GFP_KERNEL); 210 data = kzalloc(sizeof(*data), GFP_KERNEL);
150 if (!data) { 211 if (!data)
151 pr_err("%s: no memory\n", __func__);
152 goto err_np; 212 goto err_np;
153 }
154 213
155 policy->clk = of_clk_get(np, 0); 214 policy->clk = of_clk_get(np, 0);
156 if (IS_ERR(policy->clk)) { 215 if (IS_ERR(policy->clk)) {
@@ -172,7 +231,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
172 } 231 }
173 232
174 if (fmask) 233 if (fmask)
175 mask = fmask[get_hard_smp_processor_id(cpu)]; 234 mask = fmask[get_cpu_physical_id(cpu)];
176 else 235 else
177 mask = 0x0; 236 mask = 0x0;
178 237
@@ -203,13 +262,12 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
203 data->table = table; 262 data->table = table;
204 263
205 /* update ->cpus if we have cluster, no harm if not */ 264 /* update ->cpus if we have cluster, no harm if not */
206 cpumask_copy(policy->cpus, per_cpu(cpu_mask, cpu)); 265 set_affected_cpus(policy);
207 for_each_cpu(i, per_cpu(cpu_mask, cpu)) 266 policy->driver_data = data;
208 per_cpu(cpu_data, i) = data;
209 267
210 /* Minimum transition latency is 12 platform clocks */ 268 /* Minimum transition latency is 12 platform clocks */
211 u64temp = 12ULL * NSEC_PER_SEC; 269 u64temp = 12ULL * NSEC_PER_SEC;
212 do_div(u64temp, fsl_get_sys_freq()); 270 do_div(u64temp, get_bus_freq());
213 policy->cpuinfo.transition_latency = u64temp + 1; 271 policy->cpuinfo.transition_latency = u64temp + 1;
214 272
215 of_node_put(np); 273 of_node_put(np);
@@ -221,7 +279,7 @@ err_nomem1:
221err_node: 279err_node:
222 of_node_put(data->parent); 280 of_node_put(data->parent);
223err_nomem2: 281err_nomem2:
224 per_cpu(cpu_data, cpu) = NULL; 282 policy->driver_data = NULL;
225 kfree(data); 283 kfree(data);
226err_np: 284err_np:
227 of_node_put(np); 285 of_node_put(np);
@@ -229,43 +287,40 @@ err_np:
229 return -ENODEV; 287 return -ENODEV;
230} 288}
231 289
232static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy) 290static int __exit qoriq_cpufreq_cpu_exit(struct cpufreq_policy *policy)
233{ 291{
234 struct cpu_data *data = per_cpu(cpu_data, policy->cpu); 292 struct cpu_data *data = policy->driver_data;
235 unsigned int cpu;
236 293
237 of_node_put(data->parent); 294 of_node_put(data->parent);
238 kfree(data->table); 295 kfree(data->table);
239 kfree(data); 296 kfree(data);
240 297 policy->driver_data = NULL;
241 for_each_cpu(cpu, per_cpu(cpu_mask, policy->cpu))
242 per_cpu(cpu_data, cpu) = NULL;
243 298
244 return 0; 299 return 0;
245} 300}
246 301
247static int corenet_cpufreq_target(struct cpufreq_policy *policy, 302static int qoriq_cpufreq_target(struct cpufreq_policy *policy,
248 unsigned int index) 303 unsigned int index)
249{ 304{
250 struct clk *parent; 305 struct clk *parent;
251 struct cpu_data *data = per_cpu(cpu_data, policy->cpu); 306 struct cpu_data *data = policy->driver_data;
252 307
253 parent = of_clk_get(data->parent, data->table[index].driver_data); 308 parent = of_clk_get(data->parent, data->table[index].driver_data);
254 return clk_set_parent(policy->clk, parent); 309 return clk_set_parent(policy->clk, parent);
255} 310}
256 311
257static struct cpufreq_driver ppc_corenet_cpufreq_driver = { 312static struct cpufreq_driver qoriq_cpufreq_driver = {
258 .name = "ppc_cpufreq", 313 .name = "qoriq_cpufreq",
259 .flags = CPUFREQ_CONST_LOOPS, 314 .flags = CPUFREQ_CONST_LOOPS,
260 .init = corenet_cpufreq_cpu_init, 315 .init = qoriq_cpufreq_cpu_init,
261 .exit = __exit_p(corenet_cpufreq_cpu_exit), 316 .exit = __exit_p(qoriq_cpufreq_cpu_exit),
262 .verify = cpufreq_generic_frequency_table_verify, 317 .verify = cpufreq_generic_frequency_table_verify,
263 .target_index = corenet_cpufreq_target, 318 .target_index = qoriq_cpufreq_target,
264 .get = cpufreq_generic_get, 319 .get = cpufreq_generic_get,
265 .attr = cpufreq_generic_attr, 320 .attr = cpufreq_generic_attr,
266}; 321};
267 322
268static const struct of_device_id node_matches[] __initdata = { 323static const struct of_device_id node_matches[] __initconst = {
269 { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], }, 324 { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], },
270 { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], }, 325 { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], },
271 { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], }, 326 { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], },
@@ -275,61 +330,43 @@ static const struct of_device_id node_matches[] __initdata = {
275 {} 330 {}
276}; 331};
277 332
278static int __init ppc_corenet_cpufreq_init(void) 333static int __init qoriq_cpufreq_init(void)
279{ 334{
280 int ret; 335 int ret;
281 struct device_node *np; 336 struct device_node *np;
282 const struct of_device_id *match; 337 const struct of_device_id *match;
283 const struct soc_data *data; 338 const struct soc_data *data;
284 unsigned int cpu;
285 339
286 np = of_find_matching_node(NULL, node_matches); 340 np = of_find_matching_node(NULL, node_matches);
287 if (!np) 341 if (!np)
288 return -ENODEV; 342 return -ENODEV;
289 343
290 for_each_possible_cpu(cpu) {
291 if (!alloc_cpumask_var(&per_cpu(cpu_mask, cpu), GFP_KERNEL))
292 goto err_mask;
293 cpumask_copy(per_cpu(cpu_mask, cpu), cpu_core_mask(cpu));
294 }
295
296 match = of_match_node(node_matches, np); 344 match = of_match_node(node_matches, np);
297 data = match->data; 345 data = match->data;
298 if (data) { 346 if (data) {
299 if (data->flag) 347 if (data->flag)
300 fmask = data->freq_mask; 348 fmask = data->freq_mask;
301 min_cpufreq = fsl_get_sys_freq(); 349 min_cpufreq = get_bus_freq();
302 } else { 350 } else {
303 min_cpufreq = fsl_get_sys_freq() / 2; 351 min_cpufreq = get_bus_freq() / 2;
304 } 352 }
305 353
306 of_node_put(np); 354 of_node_put(np);
307 355
308 ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver); 356 ret = cpufreq_register_driver(&qoriq_cpufreq_driver);
309 if (!ret) 357 if (!ret)
310 pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n"); 358 pr_info("Freescale QorIQ CPU frequency scaling driver\n");
311 359
312 return ret; 360 return ret;
313
314err_mask:
315 for_each_possible_cpu(cpu)
316 free_cpumask_var(per_cpu(cpu_mask, cpu));
317
318 return -ENOMEM;
319} 361}
320module_init(ppc_corenet_cpufreq_init); 362module_init(qoriq_cpufreq_init);
321 363
322static void __exit ppc_corenet_cpufreq_exit(void) 364static void __exit qoriq_cpufreq_exit(void)
323{ 365{
324 unsigned int cpu; 366 cpufreq_unregister_driver(&qoriq_cpufreq_driver);
325
326 for_each_possible_cpu(cpu)
327 free_cpumask_var(per_cpu(cpu_mask, cpu));
328
329 cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
330} 367}
331module_exit(ppc_corenet_cpufreq_exit); 368module_exit(qoriq_cpufreq_exit);
332 369
333MODULE_LICENSE("GPL"); 370MODULE_LICENSE("GPL");
334MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>"); 371MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
335MODULE_DESCRIPTION("cpufreq driver for Freescale e500mc series SoCs"); 372MODULE_DESCRIPTION("cpufreq driver for Freescale QorIQ series SoCs");