aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/cpuidle-tegra30.c
diff options
context:
space:
mode:
authorJoseph Lo <josephl@nvidia.com>2012-10-31 05:41:21 -0400
committerStephen Warren <swarren@nvidia.com>2012-11-15 17:09:22 -0500
commitd552920a02759cdc45d8507868de10ac2f5b9a18 (patch)
tree2c3c5f805e1657f64088631e63c145cc43739608 /arch/arm/mach-tegra/cpuidle-tegra30.c
parent01459c69dd48badeb7833c3293e43f7b8ae75e31 (diff)
ARM: tegra30: cpuidle: add powered-down state for CPU0
This is a power gating idle mode. It support power gating vdd_cpu rail after all cpu cores in "powered-down" status. For Tegra30, the CPU0 can enter this state only when all secondary CPU is offline. We need to take care and make sure whole secondary CPUs were offline and checking the CPU power gate status. After that, the CPU0 can go into "powered-down" state safely. Then shut off the CPU rail. Be aware of that, you may see the legacy power state "LP2" in the code which is exactly the same meaning of "CPU power down". Base on the work by: Scott Williams <scwilliams@nvidia.com> Signed-off-by: Joseph Lo <josephl@nvidia.com> Signed-off-by: Stephen Warren <swarren@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/cpuidle-tegra30.c')
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra30.c44
1 files changed, 40 insertions, 4 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index cc48d7fa3358..5e8cbf5b799f 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -32,6 +32,7 @@
32 32
33#include "pm.h" 33#include "pm.h"
34#include "sleep.h" 34#include "sleep.h"
35#include "tegra_cpu_car.h"
35 36
36#ifdef CONFIG_PM_SLEEP 37#ifdef CONFIG_PM_SLEEP
37static int tegra30_idle_lp2(struct cpuidle_device *dev, 38static int tegra30_idle_lp2(struct cpuidle_device *dev,
@@ -67,6 +68,31 @@ static struct cpuidle_driver tegra_idle_driver = {
67static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); 68static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
68 69
69#ifdef CONFIG_PM_SLEEP 70#ifdef CONFIG_PM_SLEEP
71static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
72 struct cpuidle_driver *drv,
73 int index)
74{
75 struct cpuidle_state *state = &drv->states[index];
76 u32 cpu_on_time = state->exit_latency;
77 u32 cpu_off_time = state->target_residency - state->exit_latency;
78
79 /* All CPUs entering LP2 is not working.
80 * Don't let CPU0 enter LP2 when any secondary CPU is online.
81 */
82 if (num_online_cpus() > 1 || !tegra_cpu_rail_off_ready()) {
83 cpu_do_idle();
84 return false;
85 }
86
87 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
88
89 tegra_idle_lp2_last(cpu_on_time, cpu_off_time);
90
91 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
92
93 return true;
94}
95
70#ifdef CONFIG_SMP 96#ifdef CONFIG_SMP
71static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, 97static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
72 struct cpuidle_driver *drv, 98 struct cpuidle_driver *drv,
@@ -101,16 +127,22 @@ static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev,
101{ 127{
102 u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; 128 u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
103 bool entered_lp2 = false; 129 bool entered_lp2 = false;
130 bool last_cpu;
104 131
105 local_fiq_disable(); 132 local_fiq_disable();
106 133
107 tegra_set_cpu_in_lp2(cpu); 134 last_cpu = tegra_set_cpu_in_lp2(cpu);
108 cpu_pm_enter(); 135 cpu_pm_enter();
109 136
110 if (cpu == 0) 137 if (cpu == 0) {
111 cpu_do_idle(); 138 if (last_cpu)
112 else 139 entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv,
140 index);
141 else
142 cpu_do_idle();
143 } else {
113 entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index); 144 entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index);
145 }
114 146
115 cpu_pm_exit(); 147 cpu_pm_exit();
116 tegra_clear_cpu_in_lp2(cpu); 148 tegra_clear_cpu_in_lp2(cpu);
@@ -130,6 +162,10 @@ int __init tegra30_cpuidle_init(void)
130 struct cpuidle_device *dev; 162 struct cpuidle_device *dev;
131 struct cpuidle_driver *drv = &tegra_idle_driver; 163 struct cpuidle_driver *drv = &tegra_idle_driver;
132 164
165#ifdef CONFIG_PM_SLEEP
166 tegra_tear_down_cpu = tegra30_tear_down_cpu;
167#endif
168
133 ret = cpuidle_register_driver(&tegra_idle_driver); 169 ret = cpuidle_register_driver(&tegra_idle_driver);
134 if (ret) { 170 if (ret) {
135 pr_err("CPUidle driver registration failed\n"); 171 pr_err("CPUidle driver registration failed\n");