2 * arch/arm/mach-tegra/cpu-tegra.c
4 * Copyright (C) 2010 Google, Inc.
7 * Colin Cross <ccross@google.com>
8 * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
10 * This software is licensed under the terms of the GNU General Public
11 * License version 2, as published by the Free Software Foundation, and
12 * may be copied, distributed, and modified under those terms.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/types.h>
24 #include <linux/sched.h>
25 #include <linux/cpufreq.h>
26 #include <linux/delay.h>
27 #include <linux/init.h>
28 #include <linux/err.h>
29 #include <linux/clk.h>
31 #include <linux/suspend.h>
32 #include <linux/debugfs.h>
34 #include <asm/smp_twd.h>
35 #include <asm/system.h>
37 #include <mach/hardware.h>
40 /* Frequency table index must be sequential starting at 0 and frequencies must be ascending*/
41 static struct cpufreq_frequency_table freq_table[] = {
50 { 8, CPUFREQ_TABLE_END },
53 /* CPU frequency is gradually lowered when throttling is enabled */
54 #define THROTTLE_START_INDEX 2
55 #define THROTTLE_END_INDEX 6
56 #define THROTTLE_DELAY msecs_to_jiffies(2000)
57 #define NO_DELAY msecs_to_jiffies(0)
61 static struct clk *cpu_clk;
63 static struct workqueue_struct *workqueue;
65 static unsigned long target_cpu_speed[NUM_CPUS];
66 static DEFINE_MUTEX(tegra_cpu_lock);
67 static bool is_suspended;
69 static DEFINE_MUTEX(throttling_lock);
70 static bool is_throttling;
71 static struct delayed_work throttle_work;
74 int tegra_verify_speed(struct cpufreq_policy *policy)
76 return cpufreq_frequency_table_verify(policy, freq_table);
79 unsigned int tegra_getspeed(unsigned int cpu)
86 rate = clk_get_rate(cpu_clk) / 1000;
90 #ifdef CONFIG_HAVE_ARM_TWD
91 static void tegra_cpufreq_rescale_twd_other_cpu(void *data) {
92 unsigned long new_rate = *(unsigned long *)data;
93 twd_recalc_prescaler(new_rate);
96 static void tegra_cpufreq_rescale_twds(unsigned long new_rate)
98 twd_recalc_prescaler(new_rate);
99 smp_call_function(tegra_cpufreq_rescale_twd_other_cpu, &new_rate, 1);
102 static inline void tegra_cpufreq_rescale_twds(unsigned long new_rate)
107 static int tegra_update_cpu_speed(unsigned long rate)
110 struct cpufreq_freqs freqs;
112 freqs.old = tegra_getspeed(0);
115 if (freqs.old == freqs.new)
118 for_each_online_cpu(freqs.cpu)
119 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
121 if (freqs.new > freqs.old)
122 tegra_cpufreq_rescale_twds(freqs.new * 1000);
124 #ifdef CONFIG_CPU_FREQ_DEBUG
125 printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
126 freqs.old, freqs.new);
129 ret = clk_set_rate(cpu_clk, freqs.new * 1000);
131 pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
136 if (freqs.new < freqs.old)
137 tegra_cpufreq_rescale_twds(freqs.new * 1000);
139 for_each_online_cpu(freqs.cpu)
140 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
145 static unsigned long tegra_cpu_highest_speed(void) {
146 unsigned long rate = 0;
149 for_each_online_cpu(i)
150 rate = max(rate, target_cpu_speed[i]);
154 static int tegra_target(struct cpufreq_policy *policy,
155 unsigned int target_freq,
156 unsigned int relation)
160 unsigned int highest_speed;
161 unsigned int limit_when_throttling;
164 mutex_lock(&tegra_cpu_lock);
171 cpufreq_frequency_table_target(policy, freq_table, target_freq,
174 freq = freq_table[idx].frequency;
176 target_cpu_speed[policy->cpu] = freq;
178 highest_speed = tegra_cpu_highest_speed();
180 /* Do not go above this frequency when throttling */
181 limit_when_throttling = freq_table[THROTTLE_START_INDEX].frequency;
183 if (is_throttling && highest_speed > limit_when_throttling) {
184 if (tegra_getspeed(0) < limit_when_throttling) {
185 ret = tegra_update_cpu_speed(limit_when_throttling);
193 ret = tegra_update_cpu_speed(highest_speed);
195 mutex_unlock(&tegra_cpu_lock);
199 static bool tegra_throttling_needed(unsigned long *rate)
201 unsigned int current_freq = tegra_getspeed(0);
204 for (i = THROTTLE_END_INDEX; i >= THROTTLE_START_INDEX; i--) {
205 if (freq_table[i].frequency < current_freq) {
206 *rate = freq_table[i].frequency;
214 static void tegra_throttle_work_func(struct work_struct *work)
218 mutex_lock(&tegra_cpu_lock);
220 if (tegra_throttling_needed(&rate) && tegra_update_cpu_speed(rate) == 0) {
221 queue_delayed_work(workqueue, &throttle_work, THROTTLE_DELAY);
224 mutex_unlock(&tegra_cpu_lock);
228 * tegra_throttling_enable
229 * This functions may sleep
231 void tegra_throttling_enable(void)
233 mutex_lock(&throttling_lock);
235 if (!is_throttling) {
236 is_throttling = true;
237 queue_delayed_work(workqueue, &throttle_work, NO_DELAY);
240 mutex_unlock(&throttling_lock);
242 EXPORT_SYMBOL_GPL(tegra_throttling_enable);
245 * tegra_throttling_disable
246 * This functions may sleep
248 void tegra_throttling_disable(void)
250 mutex_lock(&throttling_lock);
253 cancel_delayed_work_sync(&throttle_work);
254 is_throttling = false;
257 mutex_unlock(&throttling_lock);
259 EXPORT_SYMBOL_GPL(tegra_throttling_disable);
261 #ifdef CONFIG_DEBUG_FS
262 static int throttle_debug_set(void *data, u64 val)
265 tegra_throttling_enable();
267 tegra_throttling_disable();
272 static int throttle_debug_get(void *data, u64 *val)
274 *val = (u64) is_throttling;
278 DEFINE_SIMPLE_ATTRIBUTE(throttle_fops, throttle_debug_get, throttle_debug_set, "%llu\n");
280 static struct dentry *cpu_tegra_debugfs_root;
282 static int __init tegra_cpu_debug_init(void)
284 cpu_tegra_debugfs_root = debugfs_create_dir("cpu-tegra", 0);
286 if (!cpu_tegra_debugfs_root)
289 if (!debugfs_create_file("throttle", 0644, cpu_tegra_debugfs_root, NULL, &throttle_fops))
295 debugfs_remove_recursive(cpu_tegra_debugfs_root);
300 static void __exit tegra_cpu_debug_exit(void)
302 debugfs_remove_recursive(cpu_tegra_debugfs_root);
305 late_initcall(tegra_cpu_debug_init);
306 module_exit(tegra_cpu_debug_exit);
309 static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
312 mutex_lock(&tegra_cpu_lock);
313 if (event == PM_SUSPEND_PREPARE) {
315 pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
316 freq_table[0].frequency);
317 tegra_update_cpu_speed(freq_table[0].frequency);
318 } else if (event == PM_POST_SUSPEND) {
319 is_suspended = false;
321 mutex_unlock(&tegra_cpu_lock);
326 static struct notifier_block tegra_cpu_pm_notifier = {
327 .notifier_call = tegra_pm_notify,
330 static int tegra_cpu_init(struct cpufreq_policy *policy)
332 if (policy->cpu >= NUM_CPUS)
335 cpu_clk = clk_get_sys(NULL, "cpu");
337 return PTR_ERR(cpu_clk);
339 cpufreq_frequency_table_cpuinfo(policy, freq_table);
340 cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
341 policy->cur = tegra_getspeed(policy->cpu);
342 target_cpu_speed[policy->cpu] = policy->cur;
344 /* FIXME: what's the actual transition time? */
345 policy->cpuinfo.transition_latency = 300 * 1000;
347 policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
348 cpumask_copy(policy->related_cpus, cpu_possible_mask);
350 if (policy->cpu == 0) {
351 INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
352 register_pm_notifier(&tegra_cpu_pm_notifier);
358 static int tegra_cpu_exit(struct cpufreq_policy *policy)
360 cpufreq_frequency_table_cpuinfo(policy, freq_table);
365 static struct freq_attr *tegra_cpufreq_attr[] = {
366 &cpufreq_freq_attr_scaling_available_freqs,
370 static struct cpufreq_driver tegra_cpufreq_driver = {
371 .verify = tegra_verify_speed,
372 .target = tegra_target,
373 .get = tegra_getspeed,
374 .init = tegra_cpu_init,
375 .exit = tegra_cpu_exit,
377 .attr = tegra_cpufreq_attr,
380 static int __init tegra_cpufreq_init(void)
382 workqueue = create_singlethread_workqueue("cpu-tegra");
385 return cpufreq_register_driver(&tegra_cpufreq_driver);
388 static void __exit tegra_cpufreq_exit(void)
390 destroy_workqueue(workqueue);
391 cpufreq_unregister_driver(&tegra_cpufreq_driver);
395 MODULE_AUTHOR("Colin Cross <ccross@android.com>");
396 MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
397 MODULE_LICENSE("GPL");
398 module_init(tegra_cpufreq_init);
399 module_exit(tegra_cpufreq_exit);