aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r--arch/arm/mach-tegra/Kconfig8
-rw-r--r--arch/arm/mach-tegra/Makefile1
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c293
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra114.c28
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c72
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra30.c29
6 files changed, 27 insertions, 404 deletions
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index d1c4893894ce..dbc653ea851c 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -18,8 +18,8 @@ config ARCH_TEGRA_2x_SOC
18 select PL310_ERRATA_727915 if CACHE_L2X0 18 select PL310_ERRATA_727915 if CACHE_L2X0
19 select PL310_ERRATA_769419 if CACHE_L2X0 19 select PL310_ERRATA_769419 if CACHE_L2X0
20 select USB_ARCH_HAS_EHCI if USB_SUPPORT 20 select USB_ARCH_HAS_EHCI if USB_SUPPORT
21 select USB_ULPI if USB 21 select USB_ULPI if USB_PHY
22 select USB_ULPI_VIEWPORT if USB_SUPPORT 22 select USB_ULPI_VIEWPORT if USB_PHY
23 help 23 help
24 Support for NVIDIA Tegra AP20 and T20 processors, based on the 24 Support for NVIDIA Tegra AP20 and T20 processors, based on the
25 ARM CortexA9MP CPU and the ARM PL310 L2 cache controller 25 ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
@@ -37,8 +37,8 @@ config ARCH_TEGRA_3x_SOC
37 select PINCTRL_TEGRA30 37 select PINCTRL_TEGRA30
38 select PL310_ERRATA_769419 if CACHE_L2X0 38 select PL310_ERRATA_769419 if CACHE_L2X0
39 select USB_ARCH_HAS_EHCI if USB_SUPPORT 39 select USB_ARCH_HAS_EHCI if USB_SUPPORT
40 select USB_ULPI if USB 40 select USB_ULPI if USB_PHY
41 select USB_ULPI_VIEWPORT if USB_SUPPORT 41 select USB_ULPI_VIEWPORT if USB_PHY
42 help 42 help
43 Support for NVIDIA Tegra T30 processor family, based on the 43 Support for NVIDIA Tegra T30 processor family, based on the
44 ARM CortexA9MP CPU and the ARM PL310 L2 cache controller 44 ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index f6b46ae2b7f8..09b578f9eb84 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -24,7 +24,6 @@ obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += cpuidle-tegra30.o
24endif 24endif
25obj-$(CONFIG_SMP) += platsmp.o headsmp.o 25obj-$(CONFIG_SMP) += platsmp.o headsmp.o
26obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 26obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
27obj-$(CONFIG_CPU_FREQ) += cpu-tegra.o
28obj-$(CONFIG_TEGRA_PCI) += pcie.o 27obj-$(CONFIG_TEGRA_PCI) += pcie.o
29 28
30obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o 29obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += board-dt-tegra20.o
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
deleted file mode 100644
index e3d6e15ff188..000000000000
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ /dev/null
@@ -1,293 +0,0 @@
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#include <linux/suspend.h>
32
33/* Frequency table index must be sequential starting at 0 */
34static struct cpufreq_frequency_table freq_table[] = {
35 { 0, 216000 },
36 { 1, 312000 },
37 { 2, 456000 },
38 { 3, 608000 },
39 { 4, 760000 },
40 { 5, 816000 },
41 { 6, 912000 },
42 { 7, 1000000 },
43 { 8, CPUFREQ_TABLE_END },
44};
45
46#define NUM_CPUS 2
47
48static struct clk *cpu_clk;
49static struct clk *pll_x_clk;
50static struct clk *pll_p_clk;
51static struct clk *emc_clk;
52
53static unsigned long target_cpu_speed[NUM_CPUS];
54static DEFINE_MUTEX(tegra_cpu_lock);
55static bool is_suspended;
56
57static int tegra_verify_speed(struct cpufreq_policy *policy)
58{
59 return cpufreq_frequency_table_verify(policy, freq_table);
60}
61
62static unsigned int tegra_getspeed(unsigned int cpu)
63{
64 unsigned long rate;
65
66 if (cpu >= NUM_CPUS)
67 return 0;
68
69 rate = clk_get_rate(cpu_clk) / 1000;
70 return rate;
71}
72
73static int tegra_cpu_clk_set_rate(unsigned long rate)
74{
75 int ret;
76
77 /*
78 * Take an extra reference to the main pll so it doesn't turn
79 * off when we move the cpu off of it
80 */
81 clk_prepare_enable(pll_x_clk);
82
83 ret = clk_set_parent(cpu_clk, pll_p_clk);
84 if (ret) {
85 pr_err("Failed to switch cpu to clock pll_p\n");
86 goto out;
87 }
88
89 if (rate == clk_get_rate(pll_p_clk))
90 goto out;
91
92 ret = clk_set_rate(pll_x_clk, rate);
93 if (ret) {
94 pr_err("Failed to change pll_x to %lu\n", rate);
95 goto out;
96 }
97
98 ret = clk_set_parent(cpu_clk, pll_x_clk);
99 if (ret) {
100 pr_err("Failed to switch cpu to clock pll_x\n");
101 goto out;
102 }
103
104out:
105 clk_disable_unprepare(pll_x_clk);
106 return ret;
107}
108
109static int tegra_update_cpu_speed(unsigned long rate)
110{
111 int ret = 0;
112 struct cpufreq_freqs freqs;
113
114 freqs.old = tegra_getspeed(0);
115 freqs.new = rate;
116
117 if (freqs.old == freqs.new)
118 return ret;
119
120 /*
121 * Vote on memory bus frequency based on cpu frequency
122 * This sets the minimum frequency, display or avp may request higher
123 */
124 if (rate >= 816000)
125 clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
126 else if (rate >= 456000)
127 clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
128 else
129 clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
130
131 for_each_online_cpu(freqs.cpu)
132 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
133
134#ifdef CONFIG_CPU_FREQ_DEBUG
135 printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
136 freqs.old, freqs.new);
137#endif
138
139 ret = tegra_cpu_clk_set_rate(freqs.new * 1000);
140 if (ret) {
141 pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n",
142 freqs.new);
143 return ret;
144 }
145
146 for_each_online_cpu(freqs.cpu)
147 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
148
149 return 0;
150}
151
152static unsigned long tegra_cpu_highest_speed(void)
153{
154 unsigned long rate = 0;
155 int i;
156
157 for_each_online_cpu(i)
158 rate = max(rate, target_cpu_speed[i]);
159 return rate;
160}
161
162static int tegra_target(struct cpufreq_policy *policy,
163 unsigned int target_freq,
164 unsigned int relation)
165{
166 unsigned int idx;
167 unsigned int freq;
168 int ret = 0;
169
170 mutex_lock(&tegra_cpu_lock);
171
172 if (is_suspended) {
173 ret = -EBUSY;
174 goto out;
175 }
176
177 cpufreq_frequency_table_target(policy, freq_table, target_freq,
178 relation, &idx);
179
180 freq = freq_table[idx].frequency;
181
182 target_cpu_speed[policy->cpu] = freq;
183
184 ret = tegra_update_cpu_speed(tegra_cpu_highest_speed());
185
186out:
187 mutex_unlock(&tegra_cpu_lock);
188 return ret;
189}
190
191static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
192 void *dummy)
193{
194 mutex_lock(&tegra_cpu_lock);
195 if (event == PM_SUSPEND_PREPARE) {
196 is_suspended = true;
197 pr_info("Tegra cpufreq suspend: setting frequency to %d kHz\n",
198 freq_table[0].frequency);
199 tegra_update_cpu_speed(freq_table[0].frequency);
200 } else if (event == PM_POST_SUSPEND) {
201 is_suspended = false;
202 }
203 mutex_unlock(&tegra_cpu_lock);
204
205 return NOTIFY_OK;
206}
207
208static struct notifier_block tegra_cpu_pm_notifier = {
209 .notifier_call = tegra_pm_notify,
210};
211
212static int tegra_cpu_init(struct cpufreq_policy *policy)
213{
214 if (policy->cpu >= NUM_CPUS)
215 return -EINVAL;
216
217 clk_prepare_enable(emc_clk);
218 clk_prepare_enable(cpu_clk);
219
220 cpufreq_frequency_table_cpuinfo(policy, freq_table);
221 cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
222 policy->cur = tegra_getspeed(policy->cpu);
223 target_cpu_speed[policy->cpu] = policy->cur;
224
225 /* FIXME: what's the actual transition time? */
226 policy->cpuinfo.transition_latency = 300 * 1000;
227
228 cpumask_copy(policy->cpus, cpu_possible_mask);
229
230 if (policy->cpu == 0)
231 register_pm_notifier(&tegra_cpu_pm_notifier);
232
233 return 0;
234}
235
236static int tegra_cpu_exit(struct cpufreq_policy *policy)
237{
238 cpufreq_frequency_table_cpuinfo(policy, freq_table);
239 clk_disable_unprepare(emc_clk);
240 return 0;
241}
242
243static struct freq_attr *tegra_cpufreq_attr[] = {
244 &cpufreq_freq_attr_scaling_available_freqs,
245 NULL,
246};
247
248static struct cpufreq_driver tegra_cpufreq_driver = {
249 .verify = tegra_verify_speed,
250 .target = tegra_target,
251 .get = tegra_getspeed,
252 .init = tegra_cpu_init,
253 .exit = tegra_cpu_exit,
254 .name = "tegra",
255 .attr = tegra_cpufreq_attr,
256};
257
258static int __init tegra_cpufreq_init(void)
259{
260 cpu_clk = clk_get_sys(NULL, "cpu");
261 if (IS_ERR(cpu_clk))
262 return PTR_ERR(cpu_clk);
263
264 pll_x_clk = clk_get_sys(NULL, "pll_x");
265 if (IS_ERR(pll_x_clk))
266 return PTR_ERR(pll_x_clk);
267
268 pll_p_clk = clk_get_sys(NULL, "pll_p_cclk");
269 if (IS_ERR(pll_p_clk))
270 return PTR_ERR(pll_p_clk);
271
272 emc_clk = clk_get_sys("cpu", "emc");
273 if (IS_ERR(emc_clk)) {
274 clk_put(cpu_clk);
275 return PTR_ERR(emc_clk);
276 }
277
278 return cpufreq_register_driver(&tegra_cpufreq_driver);
279}
280
281static void __exit tegra_cpufreq_exit(void)
282{
283 cpufreq_unregister_driver(&tegra_cpufreq_driver);
284 clk_put(emc_clk);
285 clk_put(cpu_clk);
286}
287
288
289MODULE_AUTHOR("Colin Cross <ccross@android.com>");
290MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
291MODULE_LICENSE("GPL");
292module_init(tegra_cpufreq_init);
293module_exit(tegra_cpufreq_exit);
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c
index 0f4e8c483b34..1d1c6023f4a2 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra114.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra114.c
@@ -23,39 +23,13 @@
23static struct cpuidle_driver tegra_idle_driver = { 23static struct cpuidle_driver tegra_idle_driver = {
24 .name = "tegra_idle", 24 .name = "tegra_idle",
25 .owner = THIS_MODULE, 25 .owner = THIS_MODULE,
26 .en_core_tk_irqen = 1,
27 .state_count = 1, 26 .state_count = 1,
28 .states = { 27 .states = {
29 [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), 28 [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
30 }, 29 },
31}; 30};
32 31
33static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
34
35int __init tegra114_cpuidle_init(void) 32int __init tegra114_cpuidle_init(void)
36{ 33{
37 int ret; 34 return cpuidle_register(&tegra_idle_driver, NULL);
38 unsigned int cpu;
39 struct cpuidle_device *dev;
40 struct cpuidle_driver *drv = &tegra_idle_driver;
41
42 ret = cpuidle_register_driver(&tegra_idle_driver);
43 if (ret) {
44 pr_err("CPUidle driver registration failed\n");
45 return ret;
46 }
47
48 for_each_possible_cpu(cpu) {
49 dev = &per_cpu(tegra_idle_device, cpu);
50 dev->cpu = cpu;
51
52 dev->state_count = drv->state_count;
53 ret = cpuidle_register_device(dev);
54 if (ret) {
55 pr_err("CPU%u: CPUidle device registration failed\n",
56 cpu);
57 return ret;
58 }
59 }
60 return 0;
61} 35}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index 825ced4f7a40..590ec25855dd 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -43,32 +43,33 @@ static atomic_t abort_barrier;
43static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev, 43static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
44 struct cpuidle_driver *drv, 44 struct cpuidle_driver *drv,
45 int index); 45 int index);
46#define TEGRA20_MAX_STATES 2
47#else
48#define TEGRA20_MAX_STATES 1
46#endif 49#endif
47 50
48static struct cpuidle_state tegra_idle_states[] = {
49 [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
50#ifdef CONFIG_PM_SLEEP
51 [1] = {
52 .enter = tegra20_idle_lp2_coupled,
53 .exit_latency = 5000,
54 .target_residency = 10000,
55 .power_usage = 0,
56 .flags = CPUIDLE_FLAG_TIME_VALID |
57 CPUIDLE_FLAG_COUPLED,
58 .name = "powered-down",
59 .desc = "CPU power gated",
60 },
61#endif
62};
63
64static struct cpuidle_driver tegra_idle_driver = { 51static struct cpuidle_driver tegra_idle_driver = {
65 .name = "tegra_idle", 52 .name = "tegra_idle",
66 .owner = THIS_MODULE, 53 .owner = THIS_MODULE,
67 .en_core_tk_irqen = 1, 54 .states = {
55 ARM_CPUIDLE_WFI_STATE_PWR(600),
56#ifdef CONFIG_PM_SLEEP
57 {
58 .enter = tegra20_idle_lp2_coupled,
59 .exit_latency = 5000,
60 .target_residency = 10000,
61 .power_usage = 0,
62 .flags = CPUIDLE_FLAG_TIME_VALID |
63 CPUIDLE_FLAG_COUPLED,
64 .name = "powered-down",
65 .desc = "CPU power gated",
66 },
67#endif
68 },
69 .state_count = TEGRA20_MAX_STATES,
70 .safe_state_index = 0,
68}; 71};
69 72
70static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
71
72#ifdef CONFIG_PM_SLEEP 73#ifdef CONFIG_PM_SLEEP
73#ifdef CONFIG_SMP 74#ifdef CONFIG_SMP
74static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); 75static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
@@ -217,39 +218,8 @@ static int tegra20_idle_lp2_coupled(struct cpuidle_device *dev,
217 218
218int __init tegra20_cpuidle_init(void) 219int __init tegra20_cpuidle_init(void)
219{ 220{
220 int ret;
221 unsigned int cpu;
222 struct cpuidle_device *dev;
223 struct cpuidle_driver *drv = &tegra_idle_driver;
224
225#ifdef CONFIG_PM_SLEEP 221#ifdef CONFIG_PM_SLEEP
226 tegra_tear_down_cpu = tegra20_tear_down_cpu; 222 tegra_tear_down_cpu = tegra20_tear_down_cpu;
227#endif 223#endif
228 224 return cpuidle_register(&tegra_idle_driver, cpu_possible_mask);
229 drv->state_count = ARRAY_SIZE(tegra_idle_states);
230 memcpy(drv->states, tegra_idle_states,
231 drv->state_count * sizeof(drv->states[0]));
232
233 ret = cpuidle_register_driver(&tegra_idle_driver);
234 if (ret) {
235 pr_err("CPUidle driver registration failed\n");
236 return ret;
237 }
238
239 for_each_possible_cpu(cpu) {
240 dev = &per_cpu(tegra_idle_device, cpu);
241 dev->cpu = cpu;
242#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED
243 dev->coupled_cpus = *cpu_possible_mask;
244#endif
245
246 dev->state_count = drv->state_count;
247 ret = cpuidle_register_device(dev);
248 if (ret) {
249 pr_err("CPU%u: CPUidle device registration failed\n",
250 cpu);
251 return ret;
252 }
253 }
254 return 0;
255} 225}
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index 80445ed33d95..9387daeeadc8 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -43,7 +43,6 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
43static struct cpuidle_driver tegra_idle_driver = { 43static struct cpuidle_driver tegra_idle_driver = {
44 .name = "tegra_idle", 44 .name = "tegra_idle",
45 .owner = THIS_MODULE, 45 .owner = THIS_MODULE,
46 .en_core_tk_irqen = 1,
47#ifdef CONFIG_PM_SLEEP 46#ifdef CONFIG_PM_SLEEP
48 .state_count = 2, 47 .state_count = 2,
49#else 48#else
@@ -65,8 +64,6 @@ static struct cpuidle_driver tegra_idle_driver = {
65 }, 64 },
66}; 65};
67 66
68static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
69
70#ifdef CONFIG_PM_SLEEP 67#ifdef CONFIG_PM_SLEEP
71static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, 68static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
72 struct cpuidle_driver *drv, 69 struct cpuidle_driver *drv,
@@ -153,32 +150,8 @@ static int tegra30_idle_lp2(struct cpuidle_device *dev,
153 150
154int __init tegra30_cpuidle_init(void) 151int __init tegra30_cpuidle_init(void)
155{ 152{
156 int ret;
157 unsigned int cpu;
158 struct cpuidle_device *dev;
159 struct cpuidle_driver *drv = &tegra_idle_driver;
160
161#ifdef CONFIG_PM_SLEEP 153#ifdef CONFIG_PM_SLEEP
162 tegra_tear_down_cpu = tegra30_tear_down_cpu; 154 tegra_tear_down_cpu = tegra30_tear_down_cpu;
163#endif 155#endif
164 156 return cpuidle_register(&tegra_idle_driver, NULL);
165 ret = cpuidle_register_driver(&tegra_idle_driver);
166 if (ret) {
167 pr_err("CPUidle driver registration failed\n");
168 return ret;
169 }
170
171 for_each_possible_cpu(cpu) {
172 dev = &per_cpu(tegra_idle_device, cpu);
173 dev->cpu = cpu;
174
175 dev->state_count = drv->state_count;
176 ret = cpuidle_register_device(dev);
177 if (ret) {
178 pr_err("CPU%u: CPUidle device registration failed\n",
179 cpu);
180 return ret;
181 }
182 }
183 return 0;
184} 157}