2 * CPU frequency scaling for Zynq
4 * Based on drivers/cpufreq/omap-cpufreq.c,
5 * Copyright (C) 2005 Nokia Corporation
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 #include <linux/kernel.h>
17 #include <linux/cpufreq.h>
18 #include <linux/delay.h>
19 #include <linux/init.h>
20 #include <linux/err.h>
21 #include <linux/clk.h>
22 #include <linux/cpu.h>
23 #include <linux/cpumask.h>
24 #include <linux/module.h>
25 #include <linux/opp.h>
26 #include <linux/platform_device.h>
27 #include <asm/smp_plat.h>
30 static atomic_t freq_table_users = ATOMIC_INIT(0);
31 static struct cpufreq_frequency_table *freq_table;
32 static struct device *mpu_dev;
33 static struct clk *cpuclk;
35 static int zynq_verify_speed(struct cpufreq_policy *policy)
39 return cpufreq_frequency_table_verify(policy, freq_table);
42 static unsigned int zynq_getspeed(unsigned int cpu)
46 if (cpu >= num_present_cpus())
49 rate = clk_get_rate(cpuclk) / 1000;
53 static int zynq_target(struct cpufreq_policy *policy,
54 unsigned int target_freq,
55 unsigned int relation)
59 struct cpufreq_freqs freqs;
62 dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
67 ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
70 dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n",
71 __func__, policy->cpu, target_freq, ret);
74 freqs.new = freq_table[i].frequency;
76 dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__,
77 policy->cpu, target_freq);
81 freqs.old = zynq_getspeed(policy->cpu);
82 freqs.cpu = policy->cpu;
84 if (freqs.old == freqs.new && policy->cur == freqs.new)
88 for_each_cpu(i, policy->cpus) {
90 cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE);
93 dev_dbg(mpu_dev, "cpufreq-zynq: %u MHz --> %u MHz\n",
94 freqs.old / 1000, freqs.new / 1000);
96 ret = clk_set_rate(cpuclk, freqs.new * 1000);
98 freqs.new = zynq_getspeed(policy->cpu);
101 for_each_cpu(i, policy->cpus) {
103 cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE);
109 static inline void freq_table_free(void)
111 if (atomic_dec_and_test(&freq_table_users))
112 opp_free_cpufreq_table(mpu_dev, &freq_table);
115 static int __cpuinit zynq_cpu_init(struct cpufreq_policy *policy)
119 cpuclk = clk_get_sys("CPU_6OR4X_CLK", NULL);
120 if (IS_ERR(cpuclk)) {
121 pr_warn("Xilinx: cpufreq: Clock not found.");
122 return PTR_ERR(cpuclk);
125 if (policy->cpu >= num_possible_cpus()) {
130 policy->cur = policy->min = policy->max = zynq_getspeed(policy->cpu);
133 result = opp_init_cpufreq_table(mpu_dev, &freq_table);
136 dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n",
137 __func__, policy->cpu, result);
141 atomic_inc(&freq_table_users);
143 result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
147 cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
149 policy->min = policy->cpuinfo.min_freq;
150 policy->max = policy->cpuinfo.max_freq;
151 policy->cur = zynq_getspeed(policy->cpu);
154 * On Zynq configuartion, both processors share the voltage
155 * and clock. So both CPUs needs to be scaled together and hence
156 * needs software co-ordination. Use cpufreq affected_cpus
157 * interface to handle this scenario. Additional is_smp() check
158 * is to keep SMP_ON_UP build working.
161 policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
162 cpumask_setall(policy->cpus);
165 /* FIXME: what's the actual transition time? */
166 policy->cpuinfo.transition_latency = 300 * 1000;
177 static int zynq_cpu_exit(struct cpufreq_policy *policy)
184 static struct freq_attr *zynq_cpufreq_attr[] = {
185 &cpufreq_freq_attr_scaling_available_freqs,
189 static struct cpufreq_driver zynq_cpufreq_driver = {
190 .flags = CPUFREQ_STICKY,
191 .verify = zynq_verify_speed,
192 .target = zynq_target,
193 .get = zynq_getspeed,
194 .init = zynq_cpu_init,
195 .exit = zynq_cpu_exit,
196 .name = "Zynq cpufreq",
197 .attr = zynq_cpufreq_attr,
200 static int __init zynq_cpufreq_init(void)
202 struct device *dev = get_cpu_device(0);
205 pr_warn("%s: Error: device not found.", __func__);
209 return cpufreq_register_driver(&zynq_cpufreq_driver);
212 static void __exit zynq_cpufreq_exit(void)
214 cpufreq_unregister_driver(&zynq_cpufreq_driver);
217 MODULE_DESCRIPTION("cpufreq driver for Zynq");
218 MODULE_LICENSE("GPL");
219 module_init(zynq_cpufreq_init);
220 module_exit(zynq_cpufreq_exit);