summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/cpuidle-t3.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2012-01-31 22:48:34 -0800
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-02-17 07:14:44 -0800
commit676518dbd35c737a59205e9611a92e32146d461b (patch)
tree9f762e0f90bdd1372713f62900e9a91a1435e44e /arch/arm/mach-tegra/cpuidle-t3.c
parent39af9f4c2c3cf0d9b8026986db5d73b9ad3ffe11 (diff)
ARM: tegra: power: Add external LP2 wake timers on secondary CPUs
Add an option to use external timer as Tegra3 secondary CPU wake source from lp2 (power gated) state. This is a follow up to commit 51e6be9ce103fbeb2b73fa2a9d2b6528a6941e81 that disabled wake from external timer, since its interrupt is registered too late - after secondary CPU is brought on-line, and already had a chance to enter lp2. With this commit, secondary CPU is not allowed to enter lp2 in idle until wake timer is registered (clock-gated lp3 state is entered instead). External timer wake up mechanism is enabled on Tegra3 only if option HAVE_ARM_TWD is not selected. Otherwise, continue to use local CPU timers as lp2 wake sources. Change-Id: Ic8c33f55e77174717bfa6525041e1263d3232dd5 Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/83546 Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/cpuidle-t3.c')
-rw-r--r--arch/arm/mach-tegra/cpuidle-t3.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/cpuidle-t3.c b/arch/arm/mach-tegra/cpuidle-t3.c
index e75ded720198..4cdfbf2abbc0 100644
--- a/arch/arm/mach-tegra/cpuidle-t3.c
+++ b/arch/arm/mach-tegra/cpuidle-t3.c
@@ -314,23 +314,32 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
(twd_context.twd_ctrl & TWD_TIMER_CONTROL_IT_ENABLE)) {
request = div_u64((u64)twd_context.twd_cnt * 1000000,
twd_rate);
+#ifdef CONFIG_TEGRA_LP2_ARM_TWD
if (request >= state->target_residency) {
twd_context.twd_cnt -= state->exit_latency *
(twd_rate / 1000000);
writel(twd_context.twd_cnt,
twd_base + TWD_TIMER_COUNTER);
}
+#endif
}
}
- if (request < state->target_residency) {
+ if (!tegra_is_lp2_timer_ready(dev->cpu) ||
+ (request < state->target_residency)) {
/*
- * Not enough time left to enter LP2
+ * Not enough time left to enter LP2, or wake timer not ready
*/
tegra3_lp3_fall_back(dev);
return;
}
+#ifndef CONFIG_TEGRA_LP2_ARM_TWD
+ sleep_time = request - state->exit_latency;
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
+ tegra_twd_suspend(&twd_context);
+ tegra_lp2_set_trigger(sleep_time);
+#endif
idle_stats.tear_down_count[cpu_number(dev->cpu)]++;
trace_power_start(POWER_CSTATE, 2, dev->cpu);
@@ -344,9 +353,16 @@ static void tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
tegra3_sleep_cpu_secondary(PLAT_PHYS_OFFSET - PAGE_OFFSET);
tegra_cpu_wake_by_time[dev->cpu] = LLONG_MAX;
+
+#ifdef CONFIG_TEGRA_LP2_ARM_TWD
if (!tegra_twd_get_state(&twd_context))
sleep_completed = (twd_context.twd_cnt == 0);
-
+#else
+ sleep_completed = !tegra_lp2_timer_remain();
+ tegra_lp2_set_trigger(0);
+ tegra_twd_resume(&twd_context);
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
+#endif
sleep_time = ktime_to_us(ktime_sub(ktime_get(), entry_time));
idle_stats.in_lp2_time[cpu_number(dev->cpu)] += sleep_time;
if (sleep_completed) {