diff options
author | Colin Cross <ccross@android.com> | 2010-10-23 14:56:27 -0700 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-10-25 18:46:19 -0700 |
commit | 1d583e43c3280477060bce90a2489084904f4e4b (patch) | |
tree | 1724598ebb72d7c3b4bcfc7512fdebfb6adf0bdc | |
parent | b1a196f10ad69c13e688cc8a27f7b9fb301d3ffe (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.c | 138 |
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); |