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:17 -0400
committerStephen Warren <swarren@nvidia.com>2012-11-15 17:09:21 -0500
commitd457ef358f3c7179c428becda45b1dfd2b8cf98a (patch)
tree90299ea88a7fb8ebe02cb2cd45160db13afe6775 /arch/arm/mach-tegra/cpuidle-tegra30.c
parentd3f293656c07a1147c11e8c8774d7955a903cee0 (diff)
ARM: tegra30: cpuidle: add powered-down state for secondary CPUs
This supports power-gated idle on secondary CPUs for Tegra30. The secondary CPUs can go into powered-down state independently. When CPU goes into this state, it saves it's contexts and puts itself to flow controlled WFI state. After that, it will been power gated. 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". Based 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.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index 37e75512f697..cc48d7fa3358 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -22,21 +22,107 @@
22#include <linux/kernel.h> 22#include <linux/kernel.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/cpuidle.h> 24#include <linux/cpuidle.h>
25#include <linux/cpu_pm.h>
26#include <linux/clockchips.h>
25 27
26#include <asm/cpuidle.h> 28#include <asm/cpuidle.h>
29#include <asm/proc-fns.h>
30#include <asm/suspend.h>
31#include <asm/smp_plat.h>
32
33#include "pm.h"
34#include "sleep.h"
35
36#ifdef CONFIG_PM_SLEEP
37static int tegra30_idle_lp2(struct cpuidle_device *dev,
38 struct cpuidle_driver *drv,
39 int index);
40#endif
27 41
28static struct cpuidle_driver tegra_idle_driver = { 42static struct cpuidle_driver tegra_idle_driver = {
29 .name = "tegra_idle", 43 .name = "tegra_idle",
30 .owner = THIS_MODULE, 44 .owner = THIS_MODULE,
31 .en_core_tk_irqen = 1, 45 .en_core_tk_irqen = 1,
46#ifdef CONFIG_PM_SLEEP
47 .state_count = 2,
48#else
32 .state_count = 1, 49 .state_count = 1,
50#endif
33 .states = { 51 .states = {
34 [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), 52 [0] = ARM_CPUIDLE_WFI_STATE_PWR(600),
53#ifdef CONFIG_PM_SLEEP
54 [1] = {
55 .enter = tegra30_idle_lp2,
56 .exit_latency = 2000,
57 .target_residency = 2200,
58 .power_usage = 0,
59 .flags = CPUIDLE_FLAG_TIME_VALID,
60 .name = "powered-down",
61 .desc = "CPU power gated",
62 },
63#endif
35 }, 64 },
36}; 65};
37 66
38static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device); 67static DEFINE_PER_CPU(struct cpuidle_device, tegra_idle_device);
39 68
69#ifdef CONFIG_PM_SLEEP
70#ifdef CONFIG_SMP
71static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
72 struct cpuidle_driver *drv,
73 int index)
74{
75 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
76
77 smp_wmb();
78
79 save_cpu_arch_register();
80
81 cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
82
83 restore_cpu_arch_register();
84
85 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
86
87 return true;
88}
89#else
90static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
91 struct cpuidle_driver *drv,
92 int index)
93{
94 return true;
95}
96#endif
97
98static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev,
99 struct cpuidle_driver *drv,
100 int index)
101{
102 u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu;
103 bool entered_lp2 = false;
104
105 local_fiq_disable();
106
107 tegra_set_cpu_in_lp2(cpu);
108 cpu_pm_enter();
109
110 if (cpu == 0)
111 cpu_do_idle();
112 else
113 entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index);
114
115 cpu_pm_exit();
116 tegra_clear_cpu_in_lp2(cpu);
117
118 local_fiq_enable();
119
120 smp_rmb();
121
122 return (entered_lp2) ? index : 0;
123}
124#endif
125
40int __init tegra30_cpuidle_init(void) 126int __init tegra30_cpuidle_init(void)
41{ 127{
42 int ret; 128 int ret;