2 * ARM big.LITTLE Platforms CPUFreq support
4 * Copyright (C) 2013 ARM Ltd.
5 * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
7 * Copyright (C) 2013 Linaro.
8 * Viresh Kumar <viresh.kumar@linaro.org>
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.
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.
20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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/of_platform.h>
28 #include <linux/opp.h>
29 #include <linux/slab.h>
30 #include <linux/topology.h>
31 #include <linux/types.h>
33 #include "arm_big_little.h"
35 /* Currently we support only two clusters */
36 #define MAX_CLUSTERS 2
38 static struct cpufreq_arm_bL_ops
*arm_bL_ops
;
39 static struct clk
*clk
[MAX_CLUSTERS
];
40 static struct cpufreq_frequency_table
*freq_table
[MAX_CLUSTERS
];
41 static atomic_t cluster_usage
[MAX_CLUSTERS
] = {ATOMIC_INIT(0), ATOMIC_INIT(0)};
43 static unsigned int bL_cpufreq_get(unsigned int cpu
)
45 u32 cur_cluster
= cpu_to_cluster(cpu
);
47 return clk_get_rate(clk
[cur_cluster
]) / 1000;
50 /* Validate policy frequency range */
51 static int bL_cpufreq_verify_policy(struct cpufreq_policy
*policy
)
53 u32 cur_cluster
= cpu_to_cluster(policy
->cpu
);
55 return cpufreq_frequency_table_verify(policy
, freq_table
[cur_cluster
]);
58 /* Set clock frequency */
59 static int bL_cpufreq_set_target(struct cpufreq_policy
*policy
,
60 unsigned int target_freq
, unsigned int relation
)
62 struct cpufreq_freqs freqs
;
63 u32 cpu
= policy
->cpu
, freq_tab_idx
, cur_cluster
;
66 cur_cluster
= cpu_to_cluster(policy
->cpu
);
68 freqs
.old
= bL_cpufreq_get(policy
->cpu
);
70 /* Determine valid target frequency using freq_table */
71 cpufreq_frequency_table_target(policy
, freq_table
[cur_cluster
],
72 target_freq
, relation
, &freq_tab_idx
);
73 freqs
.new = freq_table
[cur_cluster
][freq_tab_idx
].frequency
;
75 pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n",
76 __func__
, cpu
, cur_cluster
, freqs
.old
, target_freq
,
79 if (freqs
.old
== freqs
.new)
82 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_PRECHANGE
);
84 ret
= clk_set_rate(clk
[cur_cluster
], freqs
.new * 1000);
86 pr_err("clk_set_rate failed: %d\n", ret
);
90 policy
->cur
= freqs
.new;
92 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_POSTCHANGE
);
97 static void put_cluster_clk_and_freq_table(struct device
*cpu_dev
)
99 u32 cluster
= cpu_to_cluster(cpu_dev
->id
);
101 if (!atomic_dec_return(&cluster_usage
[cluster
])) {
102 clk_put(clk
[cluster
]);
103 opp_free_cpufreq_table(cpu_dev
, &freq_table
[cluster
]);
104 dev_dbg(cpu_dev
, "%s: cluster: %d\n", __func__
, cluster
);
108 static int get_cluster_clk_and_freq_table(struct device
*cpu_dev
)
110 u32 cluster
= cpu_to_cluster(cpu_dev
->id
);
111 char name
[14] = "cpu-cluster.";
114 if (atomic_inc_return(&cluster_usage
[cluster
]) != 1)
117 ret
= arm_bL_ops
->init_opp_table(cpu_dev
);
119 dev_err(cpu_dev
, "%s: init_opp_table failed, cpu: %d, err: %d\n",
120 __func__
, cpu_dev
->id
, ret
);
124 ret
= opp_init_cpufreq_table(cpu_dev
, &freq_table
[cluster
]);
126 dev_err(cpu_dev
, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
127 __func__
, cpu_dev
->id
, ret
);
131 name
[12] = cluster
+ '0';
132 clk
[cluster
] = clk_get_sys(name
, NULL
);
133 if (!IS_ERR(clk
[cluster
])) {
134 dev_dbg(cpu_dev
, "%s: clk: %p & freq table: %p, cluster: %d\n",
135 __func__
, clk
[cluster
], freq_table
[cluster
],
140 dev_err(cpu_dev
, "%s: Failed to get clk for cpu: %d, cluster: %d\n",
141 __func__
, cpu_dev
->id
, cluster
);
142 ret
= PTR_ERR(clk
[cluster
]);
143 opp_free_cpufreq_table(cpu_dev
, &freq_table
[cluster
]);
146 atomic_dec(&cluster_usage
[cluster
]);
147 dev_err(cpu_dev
, "%s: Failed to get data for cluster: %d\n", __func__
,
152 /* Per-CPU initialization */
153 static int bL_cpufreq_init(struct cpufreq_policy
*policy
)
155 u32 cur_cluster
= cpu_to_cluster(policy
->cpu
);
156 struct device
*cpu_dev
;
159 cpu_dev
= get_cpu_device(policy
->cpu
);
161 pr_err("%s: failed to get cpu%d device\n", __func__
,
166 ret
= get_cluster_clk_and_freq_table(cpu_dev
);
170 ret
= cpufreq_frequency_table_cpuinfo(policy
, freq_table
[cur_cluster
]);
172 dev_err(cpu_dev
, "CPU %d, cluster: %d invalid freq table\n",
173 policy
->cpu
, cur_cluster
);
174 put_cluster_clk_and_freq_table(cpu_dev
);
178 cpufreq_frequency_table_get_attr(freq_table
[cur_cluster
], policy
->cpu
);
180 if (arm_bL_ops
->get_transition_latency
)
181 policy
->cpuinfo
.transition_latency
=
182 arm_bL_ops
->get_transition_latency(cpu_dev
);
184 policy
->cpuinfo
.transition_latency
= CPUFREQ_ETERNAL
;
186 policy
->cur
= bL_cpufreq_get(policy
->cpu
);
188 cpumask_copy(policy
->cpus
, topology_core_cpumask(policy
->cpu
));
190 dev_info(cpu_dev
, "%s: CPU %d initialized\n", __func__
, policy
->cpu
);
194 static int bL_cpufreq_exit(struct cpufreq_policy
*policy
)
196 struct device
*cpu_dev
;
198 cpu_dev
= get_cpu_device(policy
->cpu
);
200 pr_err("%s: failed to get cpu%d device\n", __func__
,
205 put_cluster_clk_and_freq_table(cpu_dev
);
206 dev_dbg(cpu_dev
, "%s: Exited, cpu: %d\n", __func__
, policy
->cpu
);
211 /* Export freq_table to sysfs */
212 static struct freq_attr
*bL_cpufreq_attr
[] = {
213 &cpufreq_freq_attr_scaling_available_freqs
,
217 static struct cpufreq_driver bL_cpufreq_driver
= {
218 .name
= "arm-big-little",
219 .flags
= CPUFREQ_STICKY
,
220 .verify
= bL_cpufreq_verify_policy
,
221 .target
= bL_cpufreq_set_target
,
222 .get
= bL_cpufreq_get
,
223 .init
= bL_cpufreq_init
,
224 .exit
= bL_cpufreq_exit
,
225 .have_governor_per_policy
= true,
226 .attr
= bL_cpufreq_attr
,
229 int bL_cpufreq_register(struct cpufreq_arm_bL_ops
*ops
)
234 pr_debug("%s: Already registered: %s, exiting\n", __func__
,
239 if (!ops
|| !strlen(ops
->name
) || !ops
->init_opp_table
) {
240 pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__
);
246 ret
= cpufreq_register_driver(&bL_cpufreq_driver
);
248 pr_info("%s: Failed registering platform driver: %s, err: %d\n",
249 __func__
, ops
->name
, ret
);
252 pr_info("%s: Registered platform driver: %s\n", __func__
,
258 EXPORT_SYMBOL_GPL(bL_cpufreq_register
);
260 void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops
*ops
)
262 if (arm_bL_ops
!= ops
) {
263 pr_err("%s: Registered with: %s, can't unregister, exiting\n",
264 __func__
, arm_bL_ops
->name
);
268 cpufreq_unregister_driver(&bL_cpufreq_driver
);
269 pr_info("%s: Un-registered platform driver: %s\n", __func__
,
273 EXPORT_SYMBOL_GPL(bL_cpufreq_unregister
);