summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-10-23 14:56:27 -0700
committerColin Cross <ccross@android.com>2010-10-25 18:46:19 -0700
commit1d583e43c3280477060bce90a2489084904f4e4b (patch)
tree1724598ebb72d7c3b4bcfc7512fdebfb6adf0bdc
parentb1a196f10ad69c13e688cc8a27f7b9fb301d3ffe (diff)
ARM: tegra: cpuidle: Fix compile issues with CONFIG_SMP=n
Change-Id: Id02744bcdfc079a6091be2e8a736bcd3a6cc0ba6 Signed-off-by: Colin Cross <ccross@android.com>
-rw-r--r--arch/arm/mach-tegra/cpuidle.c138
1 files changed, 89 insertions, 49 deletions
diff --git a/arch/arm/mach-tegra/cpuidle.c b/arch/arm/mach-tegra/cpuidle.c
index e8b9dcb5649e..fc1d2ab2cdda 100644
--- a/arch/arm/mach-tegra/cpuidle.c
+++ b/arch/arm/mach-tegra/cpuidle.c
@@ -38,6 +38,7 @@
#include <linux/tick.h>
#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
#include <mach/iomap.h>
@@ -63,7 +64,7 @@ static bool lp2_in_idle __read_mostly = true;
static bool lp2_disabled_by_suspend;
module_param(lp2_in_idle, bool, 0644);
-static s64 tegra_cpu1_idle_time;
+static s64 tegra_cpu1_idle_time = LLONG_MAX;;
static int tegra_lp2_exit_latency;
static int tegra_lp2_power_off_time;
@@ -146,6 +147,7 @@ static inline void tegra_flow_wfi(struct cpuidle_device *dev)
reg = __raw_readl(flow_ctrl);
}
+#ifdef CONFIG_SMP
static inline bool tegra_wait_for_both_idle(struct cpuidle_device *dev)
{
int wake_int;
@@ -183,18 +185,90 @@ static inline bool tegra_cpu_in_reset(int cpu)
return !!(readl(CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET) & (1 << cpu));
}
+static int tegra_tear_down_cpu1(void)
+{
+ u32 reg;
+
+ /* Signal to CPU1 to tear down */
+ tegra_legacy_force_irq_set(TEGRA_CPUIDLE_TEAR_DOWN);
+
+ /* At this point, CPU0 can no longer abort LP2, but CP1 can */
+ /* TODO: any way not to poll here? Use the LP2 timer to wfi? */
+ /* takes ~80 us */
+ while (!tegra_cpu_in_reset(1) &&
+ tegra_legacy_force_irq_status(TEGRA_CPUIDLE_BOTH_IDLE))
+ cpu_relax();
+
+ tegra_legacy_force_irq_clr(TEGRA_CPUIDLE_TEAR_DOWN);
+
+ /* If CPU1 aborted LP2, restart the process */
+ if (!tegra_legacy_force_irq_status(TEGRA_CPUIDLE_BOTH_IDLE))
+ return -EAGAIN;
+
+ /* CPU1 is ready for LP2, clock gate it */
+ reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+ writel(reg | (1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+
+ return 0;
+}
+
+static void tegra_wake_cpu1(void)
+{
+ unsigned long boot_vector;
+ unsigned long old_boot_vector;
+ unsigned long timeout;
+ u32 reg;
+
+ boot_vector = virt_to_phys(tegra_hotplug_startup);
+ old_boot_vector = readl(EVP_CPU_RESET_VECTOR);
+ writel(boot_vector, EVP_CPU_RESET_VECTOR);
+
+ /* enable cpu clock on cpu */
+ reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+ writel(reg & ~(1 << (8 + 1)), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
+
+ reg = 0x1111 << 1;
+ writel(reg, CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
+
+ /* unhalt the cpu */
+ writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x14);
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (time_before(jiffies, timeout)) {
+ if (readl(EVP_CPU_RESET_VECTOR) != boot_vector)
+ break;
+ udelay(10);
+ }
+
+ /* put the old boot vector back */
+ writel(old_boot_vector, EVP_CPU_RESET_VECTOR);
+
+ /* CPU1 is now started */
+}
+#else
+static inline bool tegra_wait_for_both_idle(struct cpuidle_device *dev)
+{
+ return true;
+}
+
+static inline int tegra_tear_down_cpu1(void)
+{
+ return 0;
+}
+
+static inline void tegra_wake_cpu1(void)
+{
+}
+#endif
+
static void tegra_idle_enter_lp2_cpu0(struct cpuidle_device *dev,
struct cpuidle_state *state)
{
s64 request;
- u32 reg;
ktime_t enter;
ktime_t exit;
bool sleep_completed = false;
int bin;
- unsigned long boot_vector;
- unsigned long old_boot_vector;
- unsigned long timeout;
restart:
if (!tegra_wait_for_both_idle(dev))
@@ -208,41 +282,24 @@ restart:
/* CPU1 woke CPU0 because both are idle */
request = ktime_to_us(tick_nohz_get_sleep_length());
- if (request < tegra_lp2_exit_latency) {
+ if (request < state->target_residency) {
/* Not enough time left to enter LP2 */
tegra_flow_wfi(dev);
return;
}
- /* Signal to CPU1 to tear down */
- tegra_legacy_force_irq_set(TEGRA_CPUIDLE_TEAR_DOWN);
-
- /* At this point, CPU0 can no longer abort LP2, but CP1 can */
- /* TODO: any way not to poll here? Use the LP2 timer to wfi? */
- /* takes ~80 us */
- while (!tegra_cpu_in_reset(1) &&
- tegra_legacy_force_irq_status(TEGRA_CPUIDLE_BOTH_IDLE))
- cpu_relax();
-
- tegra_legacy_force_irq_clr(TEGRA_CPUIDLE_TEAR_DOWN);
-
idle_stats.tear_down_count++;
- /* If CPU1 aborted LP2, restart the process */
- if (!tegra_legacy_force_irq_status(TEGRA_CPUIDLE_BOTH_IDLE))
+ if (tegra_tear_down_cpu1())
goto restart;
- /* CPU1 is ready for LP2, clock gate it */
- reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
- writel(reg | (1<<9), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-
/* Enter LP2 */
request = ktime_to_us(tick_nohz_get_sleep_length());
smp_rmb();
request = min_t(s64, request, tegra_cpu1_idle_time);
enter = ktime_get();
- if (request > tegra_lp2_exit_latency + state->target_residency) {
+ if (request > state->target_residency) {
s64 sleep_time = request - tegra_lp2_exit_latency;
bin = time_to_bin((u32)request / 1000);
@@ -259,31 +316,8 @@ restart:
/* set the reset vector to point to the secondary_startup routine */
smp_wmb();
- boot_vector = virt_to_phys(tegra_hotplug_startup);
- old_boot_vector = readl(EVP_CPU_RESET_VECTOR);
- writel(boot_vector, EVP_CPU_RESET_VECTOR);
- /* enable cpu clock on cpu */
- reg = readl(CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
- writel(reg & ~(1 << (8 + 1)), CLK_RST_CONTROLLER_CLK_CPU_CMPLX);
-
- reg = 0x1111 << 1;
- writel(reg, CLK_RST_CONTROLLER_RST_CPU_CMPLX_CLR);
-
- /* unhalt the cpu */
- writel(0, IO_ADDRESS(TEGRA_FLOW_CTRL_BASE) + 0x14);
-
- timeout = jiffies + msecs_to_jiffies(1000);
- while (time_before(jiffies, timeout)) {
- if (readl(EVP_CPU_RESET_VECTOR) != boot_vector)
- break;
- udelay(10);
- }
-
- /* put the old boot vector back */
- writel(old_boot_vector, EVP_CPU_RESET_VECTOR);
-
- /* CPU1 is now started */
+ tegra_wake_cpu1();
/*
* TODO: is it worth going back to wfi if no interrupt is pending
@@ -312,6 +346,7 @@ restart:
}
}
+#ifdef CONFIG_SMP
static void tegra_idle_enter_lp2_cpu1(struct cpuidle_device *dev,
struct cpuidle_state *state)
{
@@ -380,6 +415,7 @@ static void tegra_idle_enter_lp2_cpu1(struct cpuidle_device *dev,
out:
tegra_legacy_force_irq_clr(TEGRA_CPUIDLE_BOTH_IDLE);
}
+#endif
static int tegra_idle_enter_lp3(struct cpuidle_device *dev,
struct cpuidle_state *state)
@@ -416,10 +452,14 @@ static int tegra_idle_enter_lp2(struct cpuidle_device *dev,
idle_stats.cpu_ready_count[dev->cpu]++;
+#ifdef CONFIG_SMP
if (dev->cpu == 0)
tegra_idle_enter_lp2_cpu0(dev, state);
else
tegra_idle_enter_lp2_cpu1(dev, state);
+#else
+ tegra_idle_enter_lp2_cpu0(dev, state);
+#endif
exit = ktime_sub(ktime_get(), enter);
us = ktime_to_us(exit);