Branch data Line data Source code
1 : : /*
2 : : * ARM big.LITTLE Platforms CPUFreq support
3 : : *
4 : : * Copyright (C) 2013 ARM Ltd.
5 : : * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
6 : : *
7 : : * Copyright (C) 2013 Linaro.
8 : : * Viresh Kumar <viresh.kumar@linaro.org>
9 : : *
10 : : * This program is free software; you can redistribute it and/or modify
11 : : * it under the terms of the GNU General Public License version 2 as
12 : : * published by the Free Software Foundation.
13 : : *
14 : : * This program is distributed "as is" WITHOUT ANY WARRANTY of any
15 : : * kind, whether express or implied; without even the implied warranty
16 : : * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : : * GNU General Public License for more details.
18 : : */
19 : :
20 : : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21 : :
22 : : #include <linux/clk.h>
23 : : #include <linux/cpu.h>
24 : : #include <linux/cpufreq.h>
25 : : #include <linux/cpumask.h>
26 : : #include <linux/export.h>
27 : : #include <linux/mutex.h>
28 : : #include <linux/of_platform.h>
29 : : #include <linux/pm_opp.h>
30 : : #include <linux/slab.h>
31 : : #include <linux/topology.h>
32 : : #include <linux/types.h>
33 : : #include <asm/bL_switcher.h>
34 : :
35 : : #include "arm_big_little.h"
36 : :
37 : : /* Currently we support only two clusters */
38 : : #define A15_CLUSTER 0
39 : : #define A7_CLUSTER 1
40 : : #define MAX_CLUSTERS 2
41 : :
42 : : #ifdef CONFIG_BL_SWITCHER
43 : : static bool bL_switching_enabled;
44 : : #define is_bL_switching_enabled() bL_switching_enabled
45 : : #define set_switching_enabled(x) (bL_switching_enabled = (x))
46 : : #else
47 : : #define is_bL_switching_enabled() false
48 : : #define set_switching_enabled(x) do { } while (0)
49 : : #endif
50 : :
51 : : #define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq)
52 : : #define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq)
53 : :
54 : : static struct cpufreq_arm_bL_ops *arm_bL_ops;
55 : : static struct clk *clk[MAX_CLUSTERS];
56 : : static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1];
57 : : static atomic_t cluster_usage[MAX_CLUSTERS + 1];
58 : :
59 : : static unsigned int clk_big_min; /* (Big) clock frequencies */
60 : : static unsigned int clk_little_max; /* Maximum clock frequency (Little) */
61 : :
62 : : static DEFINE_PER_CPU(unsigned int, physical_cluster);
63 : : static DEFINE_PER_CPU(unsigned int, cpu_last_req_freq);
64 : :
65 : : static struct mutex cluster_lock[MAX_CLUSTERS];
66 : :
67 : : static inline int raw_cpu_to_cluster(int cpu)
68 : : {
69 : 0 : return topology_physical_package_id(cpu);
70 : : }
71 : :
72 : : static inline int cpu_to_cluster(int cpu)
73 : : {
74 : 12944 : return is_bL_switching_enabled() ?
75 [ # # ][ # # ]: 12944 : MAX_CLUSTERS : raw_cpu_to_cluster(cpu);
[ # # ][ - + ]
76 : : }
77 : :
78 : 0 : static unsigned int find_cluster_maxfreq(int cluster)
79 : : {
80 : : int j;
81 : : u32 max_freq = 0, cpu_freq;
82 : :
83 [ + + ]: 71271 : for_each_online_cpu(j) {
84 : 35634 : cpu_freq = per_cpu(cpu_last_req_freq, j);
85 : :
86 [ + + ][ + + ]: 35634 : if ((cluster == per_cpu(physical_cluster, j)) &&
87 : : (max_freq < cpu_freq))
88 : : max_freq = cpu_freq;
89 : : }
90 : :
91 : : pr_debug("%s: cluster: %d, max freq: %d\n", __func__, cluster,
92 : : max_freq);
93 : :
94 : 17816 : return max_freq;
95 : : }
96 : :
97 : 0 : static unsigned int clk_get_cpu_rate(unsigned int cpu)
98 : : {
99 : 0 : u32 cur_cluster = per_cpu(physical_cluster, cpu);
100 : 0 : u32 rate = clk_get_rate(clk[cur_cluster]) / 1000;
101 : :
102 : : /* For switcher we use virtual A7 clock rates */
103 [ # # ]: 0 : if (is_bL_switching_enabled())
104 [ # # ]: 0 : rate = VIRT_FREQ(cur_cluster, rate);
105 : :
106 : : pr_debug("%s: cpu: %d, cluster: %d, freq: %u\n", __func__, cpu,
107 : : cur_cluster, rate);
108 : :
109 : 0 : return rate;
110 : : }
111 : :
112 : 0 : static unsigned int bL_cpufreq_get_rate(unsigned int cpu)
113 : : {
114 [ # # ]: 0 : if (is_bL_switching_enabled()) {
115 : 0 : pr_debug("%s: freq: %d\n", __func__, per_cpu(cpu_last_req_freq,
116 : : cpu));
117 : :
118 : 0 : return per_cpu(cpu_last_req_freq, cpu);
119 : : } else {
120 : 0 : return clk_get_cpu_rate(cpu);
121 : : }
122 : : }
123 : :
124 : : static unsigned int
125 : 0 : bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
126 : : {
127 : : u32 new_rate, prev_rate;
128 : : int ret;
129 : 12938 : bool bLs = is_bL_switching_enabled();
130 : :
131 : 12938 : mutex_lock(&cluster_lock[new_cluster]);
132 : :
133 [ + - ]: 12938 : if (bLs) {
134 : 12938 : prev_rate = per_cpu(cpu_last_req_freq, cpu);
135 : 12938 : per_cpu(cpu_last_req_freq, cpu) = rate;
136 : 12938 : per_cpu(physical_cluster, cpu) = new_cluster;
137 : :
138 : 12938 : new_rate = find_cluster_maxfreq(new_cluster);
139 [ + + ]: 12943 : new_rate = ACTUAL_FREQ(new_cluster, new_rate);
140 : : } else {
141 : : new_rate = rate;
142 : : }
143 : :
144 : : pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d, freq: %d\n",
145 : : __func__, cpu, old_cluster, new_cluster, new_rate);
146 : :
147 : 12943 : ret = clk_set_rate(clk[new_cluster], new_rate * 1000);
148 [ - + ][ - + ]: 12944 : if (WARN_ON(ret)) {
149 : 0 : pr_err("clk_set_rate failed: %d, new cluster: %d\n", ret,
150 : : new_cluster);
151 [ # # ]: 0 : if (bLs) {
152 : 0 : per_cpu(cpu_last_req_freq, cpu) = prev_rate;
153 : 0 : per_cpu(physical_cluster, cpu) = old_cluster;
154 : : }
155 : :
156 : 0 : mutex_unlock(&cluster_lock[new_cluster]);
157 : :
158 : 0 : return ret;
159 : : }
160 : :
161 : 12944 : mutex_unlock(&cluster_lock[new_cluster]);
162 : :
163 : : /* Recalc freq for old cluster when switching clusters */
164 [ + + ]: 12944 : if (old_cluster != new_cluster) {
165 : : pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d\n",
166 : : __func__, cpu, old_cluster, new_cluster);
167 : :
168 : : /* Switch cluster */
169 : : bL_switch_request(cpu, new_cluster);
170 : :
171 : 4877 : mutex_lock(&cluster_lock[old_cluster]);
172 : :
173 : : /* Set freq of old cluster if there are cpus left on it */
174 : 4878 : new_rate = find_cluster_maxfreq(old_cluster);
175 [ + + ]: 4876 : new_rate = ACTUAL_FREQ(old_cluster, new_rate);
176 : :
177 [ + + ]: 4876 : if (new_rate) {
178 : : pr_debug("%s: Updating rate of old cluster: %d, to freq: %d\n",
179 : : __func__, old_cluster, new_rate);
180 : :
181 [ - + ]: 2547 : if (clk_set_rate(clk[old_cluster], new_rate * 1000))
182 : 0 : pr_err("%s: clk_set_rate failed: %d, old cluster: %d\n",
183 : : __func__, ret, old_cluster);
184 : : }
185 : 4881 : mutex_unlock(&cluster_lock[old_cluster]);
186 : : }
187 : :
188 : : return 0;
189 : : }
190 : :
191 : : /* Set clock frequency */
192 : 0 : static int bL_cpufreq_set_target(struct cpufreq_policy *policy,
193 : : unsigned int index)
194 : : {
195 : 12944 : u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster;
196 : : unsigned int freqs_new;
197 : :
198 : 25888 : cur_cluster = cpu_to_cluster(cpu);
199 : 12944 : new_cluster = actual_cluster = per_cpu(physical_cluster, cpu);
200 : :
201 : 12944 : freqs_new = freq_table[cur_cluster][index].frequency;
202 : :
203 [ + + ]: 12944 : if (is_bL_switching_enabled()) {
204 [ + + ][ + + ]: 12906 : if ((actual_cluster == A15_CLUSTER) &&
205 : 6013 : (freqs_new < clk_big_min)) {
206 : : new_cluster = A7_CLUSTER;
207 [ + + ][ + + ]: 10470 : } else if ((actual_cluster == A7_CLUSTER) &&
208 : 6886 : (freqs_new > clk_little_max)) {
209 : : new_cluster = A15_CLUSTER;
210 : : }
211 : : }
212 : :
213 : 12944 : return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new);
214 : : }
215 : :
216 : : static inline u32 get_table_count(struct cpufreq_frequency_table *table)
217 : : {
218 : : int count;
219 : :
220 [ # # ]: 0 : for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++)
221 : : ;
222 : :
223 : : return count;
224 : : }
225 : :
226 : : /* get the minimum frequency in the cpufreq_frequency_table */
227 : : static inline u32 get_table_min(struct cpufreq_frequency_table *table)
228 : : {
229 : : int i;
230 : : uint32_t min_freq = ~0;
231 [ # # ]: 0 : for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
232 [ # # ]: 0 : if (table[i].frequency < min_freq)
233 : : min_freq = table[i].frequency;
234 : : return min_freq;
235 : : }
236 : :
237 : : /* get the maximum frequency in the cpufreq_frequency_table */
238 : : static inline u32 get_table_max(struct cpufreq_frequency_table *table)
239 : : {
240 : : int i;
241 : : uint32_t max_freq = 0;
242 [ # # ]: 0 : for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
243 [ # # ]: 0 : if (table[i].frequency > max_freq)
244 : : max_freq = table[i].frequency;
245 : : return max_freq;
246 : : }
247 : :
248 : 0 : static int merge_cluster_tables(void)
249 : : {
250 : : int i, j, k = 0, count = 1;
251 : : struct cpufreq_frequency_table *table;
252 : :
253 [ # # ]: 0 : for (i = 0; i < MAX_CLUSTERS; i++)
254 : 0 : count += get_table_count(freq_table[i]);
255 : :
256 : 0 : table = kzalloc(sizeof(*table) * count, GFP_KERNEL);
257 [ # # ]: 0 : if (!table)
258 : : return -ENOMEM;
259 : :
260 : 0 : freq_table[MAX_CLUSTERS] = table;
261 : :
262 : : /* Add in reverse order to get freqs in increasing order */
263 [ # # ]: 0 : for (i = MAX_CLUSTERS - 1; i >= 0; i--) {
264 [ # # ]: 0 : for (j = 0; freq_table[i][j].frequency != CPUFREQ_TABLE_END;
265 : 0 : j++) {
266 [ # # ]: 0 : table[k].frequency = VIRT_FREQ(i,
267 : : freq_table[i][j].frequency);
268 : : pr_debug("%s: index: %d, freq: %d\n", __func__, k,
269 : : table[k].frequency);
270 : 0 : k++;
271 : : }
272 : : }
273 : :
274 : 0 : table[k].driver_data = k;
275 : 0 : table[k].frequency = CPUFREQ_TABLE_END;
276 : :
277 : : pr_debug("%s: End, table: %p, count: %d\n", __func__, table, k);
278 : :
279 : 0 : return 0;
280 : : }
281 : :
282 : 0 : static void _put_cluster_clk_and_freq_table(struct device *cpu_dev)
283 : : {
284 : 0 : u32 cluster = raw_cpu_to_cluster(cpu_dev->id);
285 : :
286 [ # # ]: 0 : if (!freq_table[cluster])
287 : 0 : return;
288 : :
289 : 0 : clk_put(clk[cluster]);
290 : 0 : dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
291 : : dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster);
292 : : }
293 : :
294 : 0 : static void put_cluster_clk_and_freq_table(struct device *cpu_dev)
295 : : {
296 : 0 : u32 cluster = cpu_to_cluster(cpu_dev->id);
297 : : int i;
298 : :
299 [ # # ]: 0 : if (atomic_dec_return(&cluster_usage[cluster]))
300 : : return;
301 : :
302 [ # # ]: 0 : if (cluster < MAX_CLUSTERS)
303 : 0 : return _put_cluster_clk_and_freq_table(cpu_dev);
304 : :
305 [ # # ]: 0 : for_each_present_cpu(i) {
306 : 0 : struct device *cdev = get_cpu_device(i);
307 [ # # ]: 0 : if (!cdev) {
308 : 0 : pr_err("%s: failed to get cpu%d device\n", __func__, i);
309 : 0 : return;
310 : : }
311 : :
312 : 0 : _put_cluster_clk_and_freq_table(cdev);
313 : : }
314 : :
315 : : /* free virtual table */
316 : 0 : kfree(freq_table[cluster]);
317 : : }
318 : :
319 : 0 : static int _get_cluster_clk_and_freq_table(struct device *cpu_dev)
320 : : {
321 : 0 : u32 cluster = raw_cpu_to_cluster(cpu_dev->id);
322 : 0 : char name[14] = "cpu-cluster.";
323 : : int ret;
324 : :
325 [ # # ]: 0 : if (freq_table[cluster])
326 : : return 0;
327 : :
328 : 0 : ret = arm_bL_ops->init_opp_table(cpu_dev);
329 [ # # ]: 0 : if (ret) {
330 : 0 : dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n",
331 : : __func__, cpu_dev->id, ret);
332 : 0 : goto out;
333 : : }
334 : :
335 : 0 : ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]);
336 [ # # ]: 0 : if (ret) {
337 : 0 : dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
338 : : __func__, cpu_dev->id, ret);
339 : 0 : goto out;
340 : : }
341 : :
342 : 0 : name[12] = cluster + '0';
343 : 0 : clk[cluster] = clk_get(cpu_dev, name);
344 [ # # ]: 0 : if (!IS_ERR(clk[cluster])) {
345 : : dev_dbg(cpu_dev, "%s: clk: %p & freq table: %p, cluster: %d\n",
346 : : __func__, clk[cluster], freq_table[cluster],
347 : : cluster);
348 : : return 0;
349 : : }
350 : :
351 : 0 : dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d, cluster: %d\n",
352 : : __func__, cpu_dev->id, cluster);
353 : 0 : ret = PTR_ERR(clk[cluster]);
354 : 0 : dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
355 : :
356 : : out:
357 : 0 : dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
358 : : cluster);
359 : 0 : return ret;
360 : : }
361 : :
362 : 0 : static int get_cluster_clk_and_freq_table(struct device *cpu_dev)
363 : : {
364 : 0 : u32 cluster = cpu_to_cluster(cpu_dev->id);
365 : : int i, ret;
366 : :
367 [ # # ]: 0 : if (atomic_inc_return(&cluster_usage[cluster]) != 1)
368 : : return 0;
369 : :
370 [ # # ]: 0 : if (cluster < MAX_CLUSTERS) {
371 : 0 : ret = _get_cluster_clk_and_freq_table(cpu_dev);
372 [ # # ]: 0 : if (ret)
373 : : atomic_dec(&cluster_usage[cluster]);
374 : 0 : return ret;
375 : : }
376 : :
377 : : /*
378 : : * Get data for all clusters and fill virtual cluster with a merge of
379 : : * both
380 : : */
381 [ # # ]: 0 : for_each_present_cpu(i) {
382 : 0 : struct device *cdev = get_cpu_device(i);
383 [ # # ]: 0 : if (!cdev) {
384 : 0 : pr_err("%s: failed to get cpu%d device\n", __func__, i);
385 : 0 : return -ENODEV;
386 : : }
387 : :
388 : 0 : ret = _get_cluster_clk_and_freq_table(cdev);
389 [ # # ]: 0 : if (ret)
390 : : goto put_clusters;
391 : : }
392 : :
393 : 0 : ret = merge_cluster_tables();
394 [ # # ]: 0 : if (ret)
395 : : goto put_clusters;
396 : :
397 : : /* Assuming 2 cluster, set clk_big_min and clk_little_max */
398 : 0 : clk_big_min = get_table_min(freq_table[0]);
399 : 0 : clk_little_max = VIRT_FREQ(1, get_table_max(freq_table[1]));
400 : :
401 : : pr_debug("%s: cluster: %d, clk_big_min: %d, clk_little_max: %d\n",
402 : : __func__, cluster, clk_big_min, clk_little_max);
403 : :
404 : 0 : return 0;
405 : :
406 : : put_clusters:
407 [ # # ]: 0 : for_each_present_cpu(i) {
408 : 0 : struct device *cdev = get_cpu_device(i);
409 [ # # ]: 0 : if (!cdev) {
410 : 0 : pr_err("%s: failed to get cpu%d device\n", __func__, i);
411 : 0 : return -ENODEV;
412 : : }
413 : :
414 : 0 : _put_cluster_clk_and_freq_table(cdev);
415 : : }
416 : :
417 : : atomic_dec(&cluster_usage[cluster]);
418 : :
419 : 0 : return ret;
420 : : }
421 : :
422 : : /* Per-CPU initialization */
423 : 0 : static int bL_cpufreq_init(struct cpufreq_policy *policy)
424 : : {
425 : 0 : u32 cur_cluster = cpu_to_cluster(policy->cpu);
426 : : struct device *cpu_dev;
427 : : int ret;
428 : :
429 : 0 : cpu_dev = get_cpu_device(policy->cpu);
430 [ # # ]: 0 : if (!cpu_dev) {
431 : 0 : pr_err("%s: failed to get cpu%d device\n", __func__,
432 : : policy->cpu);
433 : 0 : return -ENODEV;
434 : : }
435 : :
436 : 0 : ret = get_cluster_clk_and_freq_table(cpu_dev);
437 [ # # ]: 0 : if (ret)
438 : : return ret;
439 : :
440 : 0 : ret = cpufreq_table_validate_and_show(policy, freq_table[cur_cluster]);
441 [ # # ]: 0 : if (ret) {
442 : 0 : dev_err(cpu_dev, "CPU %d, cluster: %d invalid freq table\n",
443 : : policy->cpu, cur_cluster);
444 : 0 : put_cluster_clk_and_freq_table(cpu_dev);
445 : 0 : return ret;
446 : : }
447 : :
448 [ # # ]: 0 : if (cur_cluster < MAX_CLUSTERS) {
449 : 0 : cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu));
450 : :
451 : 0 : per_cpu(physical_cluster, policy->cpu) = cur_cluster;
452 : : } else {
453 : : /* Assumption: during init, we are always running on A15 */
454 : 0 : per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER;
455 : : }
456 : :
457 [ # # ]: 0 : if (arm_bL_ops->get_transition_latency)
458 : 0 : policy->cpuinfo.transition_latency =
459 : 0 : arm_bL_ops->get_transition_latency(cpu_dev);
460 : : else
461 : 0 : policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
462 : :
463 [ # # ]: 0 : if (is_bL_switching_enabled())
464 : 0 : per_cpu(cpu_last_req_freq, policy->cpu) = clk_get_cpu_rate(policy->cpu);
465 : :
466 : 0 : dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu);
467 : 0 : return 0;
468 : : }
469 : :
470 : 0 : static int bL_cpufreq_exit(struct cpufreq_policy *policy)
471 : : {
472 : : struct device *cpu_dev;
473 : :
474 : 0 : cpu_dev = get_cpu_device(policy->cpu);
475 [ # # ]: 0 : if (!cpu_dev) {
476 : 0 : pr_err("%s: failed to get cpu%d device\n", __func__,
477 : : policy->cpu);
478 : 0 : return -ENODEV;
479 : : }
480 : :
481 : 0 : cpufreq_frequency_table_put_attr(policy->cpu);
482 : 0 : put_cluster_clk_and_freq_table(cpu_dev);
483 : : dev_dbg(cpu_dev, "%s: Exited, cpu: %d\n", __func__, policy->cpu);
484 : :
485 : 0 : return 0;
486 : : }
487 : :
488 : : static struct cpufreq_driver bL_cpufreq_driver = {
489 : : .name = "arm-big-little",
490 : : .flags = CPUFREQ_STICKY |
491 : : CPUFREQ_HAVE_GOVERNOR_PER_POLICY,
492 : : .verify = cpufreq_generic_frequency_table_verify,
493 : : .target_index = bL_cpufreq_set_target,
494 : : .get = bL_cpufreq_get_rate,
495 : : .init = bL_cpufreq_init,
496 : : .exit = bL_cpufreq_exit,
497 : : .attr = cpufreq_generic_attr,
498 : : };
499 : :
500 : 0 : static int bL_cpufreq_switcher_notifier(struct notifier_block *nfb,
501 : : unsigned long action, void *_arg)
502 : : {
503 : : pr_debug("%s: action: %ld\n", __func__, action);
504 : :
505 [ # # # # ]: 0 : switch (action) {
506 : : case BL_NOTIFY_PRE_ENABLE:
507 : : case BL_NOTIFY_PRE_DISABLE:
508 : 0 : cpufreq_unregister_driver(&bL_cpufreq_driver);
509 : 0 : break;
510 : :
511 : : case BL_NOTIFY_POST_ENABLE:
512 : 0 : set_switching_enabled(true);
513 : 0 : cpufreq_register_driver(&bL_cpufreq_driver);
514 : 0 : break;
515 : :
516 : : case BL_NOTIFY_POST_DISABLE:
517 : 0 : set_switching_enabled(false);
518 : 0 : cpufreq_register_driver(&bL_cpufreq_driver);
519 : 0 : break;
520 : :
521 : : default:
522 : : return NOTIFY_DONE;
523 : : }
524 : :
525 : : return NOTIFY_OK;
526 : : }
527 : :
528 : : static struct notifier_block bL_switcher_notifier = {
529 : : .notifier_call = bL_cpufreq_switcher_notifier,
530 : : };
531 : :
532 : 0 : int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
533 : : {
534 : : int ret, i;
535 : :
536 [ # # ]: 0 : if (arm_bL_ops) {
537 : : pr_debug("%s: Already registered: %s, exiting\n", __func__,
538 : : arm_bL_ops->name);
539 : : return -EBUSY;
540 : : }
541 : :
542 [ # # ][ # # ]: 0 : if (!ops || !strlen(ops->name) || !ops->init_opp_table) {
[ # # ]
543 : 0 : pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__);
544 : 0 : return -ENODEV;
545 : : }
546 : :
547 : 0 : arm_bL_ops = ops;
548 : :
549 : 0 : ret = bL_switcher_get_enabled();
550 : 0 : set_switching_enabled(ret);
551 : :
552 [ # # ]: 0 : for (i = 0; i < MAX_CLUSTERS; i++)
553 : 0 : mutex_init(&cluster_lock[i]);
554 : :
555 : 0 : ret = cpufreq_register_driver(&bL_cpufreq_driver);
556 [ # # ]: 0 : if (ret) {
557 : 0 : pr_info("%s: Failed registering platform driver: %s, err: %d\n",
558 : : __func__, ops->name, ret);
559 : 0 : arm_bL_ops = NULL;
560 : : } else {
561 : 0 : ret = bL_switcher_register_notifier(&bL_switcher_notifier);
562 [ # # ]: 0 : if (ret) {
563 : 0 : cpufreq_unregister_driver(&bL_cpufreq_driver);
564 : 0 : arm_bL_ops = NULL;
565 : : } else {
566 : 0 : pr_info("%s: Registered platform driver: %s\n",
567 : : __func__, ops->name);
568 : : }
569 : : }
570 : :
571 : 0 : bL_switcher_put_enabled();
572 : 0 : return ret;
573 : : }
574 : : EXPORT_SYMBOL_GPL(bL_cpufreq_register);
575 : :
576 : 0 : void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops)
577 : : {
578 [ # # ]: 0 : if (arm_bL_ops != ops) {
579 : 0 : pr_err("%s: Registered with: %s, can't unregister, exiting\n",
580 : : __func__, arm_bL_ops->name);
581 : 0 : return;
582 : : }
583 : :
584 : 0 : bL_switcher_get_enabled();
585 : 0 : bL_switcher_unregister_notifier(&bL_switcher_notifier);
586 : 0 : cpufreq_unregister_driver(&bL_cpufreq_driver);
587 : 0 : bL_switcher_put_enabled();
588 : 0 : pr_info("%s: Un-registered platform driver: %s\n", __func__,
589 : : arm_bL_ops->name);
590 : 0 : arm_bL_ops = NULL;
591 : : }
592 : : EXPORT_SYMBOL_GPL(bL_cpufreq_unregister);
|