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
);
87 freqs
.new = freqs
.old
;
90 cpufreq_notify_transition(policy
, &freqs
, CPUFREQ_POSTCHANGE
);
95 static void put_cluster_clk_and_freq_table(struct device
*cpu_dev
)
97 u32 cluster
= cpu_to_cluster(cpu_dev
->id
);
99 if (!atomic_dec_return(&cluster_usage
[cluster
])) {
100 clk_put(clk
[cluster
]);
101 opp_free_cpufreq_table(cpu_dev
, &freq_table
[cluster
]);
102 dev_dbg(cpu_dev
, "%s: cluster: %d\n", __func__
, cluster
);
106 static int get_cluster_clk_and_freq_table(struct device
*cpu_dev
)
108 u32 cluster
= cpu_to_cluster(cpu_dev
->id
);
109 char name
[14] = "cpu-cluster.";
112 if (atomic_inc_return(&cluster_usage
[cluster
]) != 1)
115 ret
= arm_bL_ops
->init_opp_table(cpu_dev
);
117 dev_err(cpu_dev
, "%s: init_opp_table failed, cpu: %d, err: %d\n",
118 __func__
, cpu_dev
->id
, ret
);
122 ret
= opp_init_cpufreq_table(cpu_dev
, &freq_table
[cluster
]);
124 dev_err(cpu_dev
, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
125 __func__
, cpu_dev
->id
, ret
);
129 name
[12] = cluster
+ '0';
130 clk
[cluster
] = clk_get_sys(name
, NULL
);
131 if (!IS_ERR(clk
[cluster
])) {
132 dev_dbg(cpu_dev
, "%s: clk: %p & freq table: %p, cluster: %d\n",
133 __func__
, clk
[cluster
], freq_table
[cluster
],
138 dev_err(cpu_dev
, "%s: Failed to get clk for cpu: %d, cluster: %d\n",
139 __func__
, cpu_dev
->id
, cluster
);
140 ret
= PTR_ERR(clk
[cluster
]);
141 opp_free_cpufreq_table(cpu_dev
, &freq_table
[cluster
]);
144 atomic_dec(&cluster_usage
[cluster
]);
145 dev_err(cpu_dev
, "%s: Failed to get data for cluster: %d\n", __func__
,
150 /* Per-CPU initialization */
151 static int bL_cpufreq_init(struct cpufreq_policy
*policy
)
153 u32 cur_cluster
= cpu_to_cluster(policy
->cpu
);
154 struct device
*cpu_dev
;
157 cpu_dev
= get_cpu_device(policy
->cpu
);
159 pr_err("%s: failed to get cpu%d device\n", __func__
,
164 ret
= get_cluster_clk_and_freq_table(cpu_dev
);
168 ret
= cpufreq_frequency_table_cpuinfo(policy
, freq_table
[cur_cluster
]);
170 dev_err(cpu_dev
, "CPU %d, cluster: %d invalid freq table\n",
171 policy
->cpu
, cur_cluster
);
172 put_cluster_clk_and_freq_table(cpu_dev
);
176 cpufreq_frequency_table_get_attr(freq_table
[cur_cluster
], policy
->cpu
);
178 if (arm_bL_ops
->get_transition_latency
)
179 policy
->cpuinfo
.transition_latency
=
180 arm_bL_ops
->get_transition_latency(cpu_dev
);
182 policy
->cpuinfo
.transition_latency
= CPUFREQ_ETERNAL
;
184 policy
->cur
= bL_cpufreq_get(policy
->cpu
);
186 cpumask_copy(policy
->cpus
, topology_core_cpumask(policy
->cpu
));
188 dev_info(cpu_dev
, "%s: CPU %d initialized\n", __func__
, policy
->cpu
);
192 static int bL_cpufreq_exit(struct cpufreq_policy
*policy
)
194 struct device
*cpu_dev
;
196 cpu_dev
= get_cpu_device(policy
->cpu
);
198 pr_err("%s: failed to get cpu%d device\n", __func__
,
203 put_cluster_clk_and_freq_table(cpu_dev
);
204 dev_dbg(cpu_dev
, "%s: Exited, cpu: %d\n", __func__
, policy
->cpu
);
209 /* Export freq_table to sysfs */
210 static struct freq_attr
*bL_cpufreq_attr
[] = {
211 &cpufreq_freq_attr_scaling_available_freqs
,
215 static struct cpufreq_driver bL_cpufreq_driver
= {
216 .name
= "arm-big-little",
217 .flags
= CPUFREQ_STICKY
,
218 .verify
= bL_cpufreq_verify_policy
,
219 .target
= bL_cpufreq_set_target
,
220 .get
= bL_cpufreq_get
,
221 .init
= bL_cpufreq_init
,
222 .exit
= bL_cpufreq_exit
,
223 .have_governor_per_policy
= true,
224 .attr
= bL_cpufreq_attr
,
227 int bL_cpufreq_register(struct cpufreq_arm_bL_ops
*ops
)
232 pr_debug("%s: Already registered: %s, exiting\n", __func__
,
237 if (!ops
|| !strlen(ops
->name
) || !ops
->init_opp_table
) {
238 pr_err("%s: Invalid arm_bL_ops, exiting\n", __func__
);
244 ret
= cpufreq_register_driver(&bL_cpufreq_driver
);
246 pr_info("%s: Failed registering platform driver: %s, err: %d\n",
247 __func__
, ops
->name
, ret
);
250 pr_info("%s: Registered platform driver: %s\n", __func__
,
256 EXPORT_SYMBOL_GPL(bL_cpufreq_register
);
258 void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops
*ops
)
260 if (arm_bL_ops
!= ops
) {
261 pr_err("%s: Registered with: %s, can't unregister, exiting\n",
262 __func__
, arm_bL_ops
->name
);
266 cpufreq_unregister_driver(&bL_cpufreq_driver
);
267 pr_info("%s: Un-registered platform driver: %s\n", __func__
,
271 EXPORT_SYMBOL_GPL(bL_cpufreq_unregister
);