aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/cpu-tegra.c
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-04-22 23:30:13 -0400
committerColin Cross <ccross@android.com>2010-10-21 21:12:28 -0400
commit7056d423f16103f6700569f60ca842d91bfaabab (patch)
treeafb545ce216c1e35387d41e3a02b864d054db016 /arch/arm/mach-tegra/cpu-tegra.c
parent8486bddc09c84606fb22cf30c6282335275d4dfa (diff)
[ARM] tegra: Add cpufreq support
Implement cpufreq support for the Tegra SOC. DVFS is handled by the core virtual cpu clock. The frequencies of the two cores are tied together, the highest frequency requested by either core determines the actual frequency. Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/cpu-tegra.c')
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c185
1 files changed, 185 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
new file mode 100644
index 000000000000..fea5719c7072
--- /dev/null
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -0,0 +1,185 @@
1/*
2 * arch/arm/mach-tegra/cpu-tegra.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 *
6 * Author:
7 * Colin Cross <ccross@google.com>
8 * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
9 *
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.
13 *
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.
18 *
19 */
20
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>
30#include <linux/io.h>
31
32#include <asm/system.h>
33
34#include <mach/hardware.h>
35#include <mach/clk.h>
36
37/* Frequency table index must be sequential starting at 0 */
38static struct cpufreq_frequency_table freq_table[] = {
39 { 0, 312000 },
40 { 1, 456000 },
41 { 2, 608000 },
42 { 3, 760000 },
43 { 4, 816000 },
44 { 5, 912000 },
45 { 6, 1000000 },
46 { 7, CPUFREQ_TABLE_END },
47};
48
49#define NUM_CPUS 2
50
51static struct clk *cpu_clk;
52
53static unsigned long target_cpu_speed[NUM_CPUS];
54
55int tegra_verify_speed(struct cpufreq_policy *policy)
56{
57 return cpufreq_frequency_table_verify(policy, freq_table);
58}
59
60unsigned int tegra_getspeed(unsigned int cpu)
61{
62 unsigned long rate;
63
64 if (cpu >= NUM_CPUS)
65 return 0;
66
67 rate = clk_get_rate(cpu_clk) / 1000;
68 return rate;
69}
70
71static int tegra_update_cpu_speed(void)
72{
73 int i;
74 unsigned long rate = 0;
75 int ret = 0;
76 struct cpufreq_freqs freqs;
77
78 for_each_online_cpu(i)
79 rate = max(rate, target_cpu_speed[i]);
80
81 freqs.old = tegra_getspeed(0);
82 freqs.new = rate;
83
84 if (freqs.old == freqs.new)
85 return ret;
86
87 for_each_online_cpu(freqs.cpu)
88 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
89
90#ifdef CONFIG_CPU_FREQ_DEBUG
91 printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
92 freqs.old, freqs.new);
93#endif
94
95 ret = clk_set_rate_cansleep(cpu_clk, freqs.new * 1000);
96 if (ret) {
97 pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
98 freqs.new);
99 return ret;
100 }
101
102 for_each_online_cpu(freqs.cpu)
103 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
104
105 return 0;
106}
107
108static int tegra_target(struct cpufreq_policy *policy,
109 unsigned int target_freq,
110 unsigned int relation)
111{
112 int idx;
113 unsigned int freq;
114
115 cpufreq_frequency_table_target(policy, freq_table, target_freq,
116 relation, &idx);
117
118 freq = freq_table[idx].frequency;
119
120 target_cpu_speed[policy->cpu] = freq;
121
122 return tegra_update_cpu_speed();
123}
124
125static int tegra_cpu_init(struct cpufreq_policy *policy)
126{
127 if (policy->cpu >= NUM_CPUS)
128 return -EINVAL;
129
130 cpu_clk = clk_get_sys(NULL, "cpu");
131 if (IS_ERR(cpu_clk))
132 return PTR_ERR(cpu_clk);
133
134 cpufreq_frequency_table_cpuinfo(policy, freq_table);
135 cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
136 policy->cur = tegra_getspeed(policy->cpu);
137 target_cpu_speed[policy->cpu] = policy->cur;
138
139 /* FIXME: what's the actual transition time? */
140 policy->cpuinfo.transition_latency = 300 * 1000;
141
142 policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
143 cpumask_copy(policy->related_cpus, cpu_possible_mask);
144
145 return 0;
146}
147
148static int tegra_cpu_exit(struct cpufreq_policy *policy)
149{
150 cpufreq_frequency_table_cpuinfo(policy, freq_table);
151 clk_put(cpu_clk);
152 return 0;
153}
154
155static struct freq_attr *tegra_cpufreq_attr[] = {
156 &cpufreq_freq_attr_scaling_available_freqs,
157 NULL,
158};
159
160static struct cpufreq_driver tegra_cpufreq_driver = {
161 .verify = tegra_verify_speed,
162 .target = tegra_target,
163 .get = tegra_getspeed,
164 .init = tegra_cpu_init,
165 .exit = tegra_cpu_exit,
166 .name = "tegra",
167 .attr = tegra_cpufreq_attr,
168};
169
170static int __init tegra_cpufreq_init(void)
171{
172 return cpufreq_register_driver(&tegra_cpufreq_driver);
173}
174
175static void __exit tegra_cpufreq_exit(void)
176{
177 cpufreq_unregister_driver(&tegra_cpufreq_driver);
178}
179
180
181MODULE_AUTHOR("Colin Cross <ccross@android.com>");
182MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
183MODULE_LICENSE("GPL");
184module_init(tegra_cpufreq_init);
185module_exit(tegra_cpufreq_exit);