ARM: tegra2: Move LP2 into cpuidle-t2.c
Scott Williams [Mon, 18 Jul 2011 20:41:32 +0000 (13:41 -0700)]
Move Tegra2 SOC-specific CPU idle functionality to cpuidle-t2.c

Change-Id: I26c94ca74d7a78665c52e23571c5058e3da240a7
Signed-off-by: Scott Williams <scwilliams@nvidia.com>
DW: Split into logical changes
Signed-off-by: Dan Willemsen <dwillemsen@nvidia.com>

Rebase-Id: R1246e3942623458f5121ccdac3e6d4a1d40ad624

arch/arm/mach-tegra/cpuidle-t2.c
arch/arm/mach-tegra/cpuidle.c
arch/arm/mach-tegra/cpuidle.h
arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/pm.h

index 236441a..eefa3b1 100644 (file)
@@ -44,6 +44,7 @@
 #include <mach/irqs.h>
 
 #include "cpuidle.h"
+#include "flowctrl.h"
 #include "pm.h"
 #include "sleep.h"
 
@@ -59,6 +60,128 @@ static struct {
        unsigned int last_lp2_int_count[NR_IRQS];
 } idle_stats;
 
+#ifdef CONFIG_SMP
+
+static void __iomem *clk_rst = IO_ADDRESS(TEGRA_CLK_RESET_BASE);
+static void __iomem *evp_reset = IO_ADDRESS(TEGRA_EXCEPTION_VECTORS_BASE) + 0x100;
+static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+
+static int tegra2_reset_sleeping_cpu(int cpu)
+{
+       int ret = 0;
+
+       BUG_ON(cpu == smp_processor_id());
+       tegra_pen_lock();
+
+       if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE)
+               tegra_cpu_reset(cpu);
+       else
+               ret = -EINVAL;
+
+       tegra_pen_unlock();
+
+       return ret;
+}
+
+static void tegra2_wake_reset_cpu(int cpu)
+{
+       u32 reg;
+
+       writel(virt_to_phys(tegra_secondary_resume), evp_reset);
+
+       /* enable cpu clock on cpu */
+       reg = readl(clk_rst + 0x4c);
+       writel(reg & ~(1 << (8 + cpu)), clk_rst + 0x4c);
+
+       reg = 0x1111 << cpu;
+       writel(reg, clk_rst + 0x344);
+
+       /* unhalt the cpu */
+       flowctrl_write_cpu_halt(1, 0);
+}
+
+static int tegra2_reset_other_cpus(int cpu)
+{
+       int i;
+       int abort = -1;
+
+       for_each_online_cpu(i) {
+               if (i != cpu) {
+                       if (tegra2_reset_sleeping_cpu(i)) {
+                               abort = i;
+                               break;
+                       }
+               }
+       }
+
+       if (abort >= 0) {
+               for_each_online_cpu(i) {
+                       if (i != cpu && i < abort)
+                               tegra2_wake_reset_cpu(i);
+               }
+               return -EINVAL;
+       }
+
+       return 0;
+}
+#else
+static void tegra2_wake_reset_cpu(int cpu)
+{
+}
+
+static int tegra2_reset_other_cpus(int cpu)
+{
+       return 0;
+}
+#endif
+
+static int tegra2_idle_lp2_last(struct cpuidle_device *dev,
+                       struct cpuidle_state *state)
+{
+       int i;
+
+       while (tegra_cpu_is_resettable_soon())
+               cpu_relax();
+
+       if (tegra2_reset_other_cpus(dev->cpu))
+               return -EBUSY;
+
+       tegra_idle_lp2_last(0);
+
+       for_each_online_cpu(i) {
+               if (i != dev->cpu) {
+                       tegra2_wake_reset_cpu(i);
+                       tegra_clear_cpu_in_lp2(i);
+               }
+       }
+
+       return 0;
+}
+
+void tegra2_idle_lp2(struct cpuidle_device *dev,
+                       struct cpuidle_state *state)
+{
+       bool last_cpu = tegra_set_cpu_in_lp2(dev->cpu);
+
+       cpu_pm_enter();
+
+       if (last_cpu) {
+               if (tegra2_idle_lp2_last(dev, state) < 0) {
+                       int i;
+                       for_each_online_cpu(i) {
+                               if (i != dev->cpu) {
+                                       tegra2_wake_reset_cpu(i);
+                                       tegra_clear_cpu_in_lp2(i);
+                               }
+                       }
+               }
+       } else
+               tegra_sleep_wfi(PHYS_OFFSET - PAGE_OFFSET);
+
+       cpu_pm_exit();
+       tegra_clear_cpu_in_lp2(dev->cpu);
+}
+
 void tegra2_cpu_idle_stats_lp2_ready(unsigned int cpu)
 {
        idle_stats.cpu_ready_count[cpu]++;
index d106b44..b12a9fe 100644 (file)
@@ -133,7 +133,7 @@ static int tegra_idle_enter_lp2(struct cpuidle_device *dev,
        tegra_cpu_idle_stats_lp2_ready(dev->cpu);
 
        clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
-       tegra_idle_lp2();
+       tegra_idle_lp2(dev, state);
        clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
 
        exit = ktime_sub(ktime_get(), enter);
index f05d71d..f3f80ad 100644 (file)
 #ifndef __MACH_TEGRA_CPUIDLE_H
 #define __MACH_TEGRA_CPUIDLE_H
 
+#include <linux/cpuidle.h>
+
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
+void tegra2_idle_lp2(struct cpuidle_device *dev, struct cpuidle_state *state);
 void tegra2_cpu_idle_stats_lp2_ready(unsigned int cpu);
 void tegra2_cpu_idle_stats_lp2_time(unsigned int cpu, s64 us);
 #ifdef CONFIG_DEBUG_FS
@@ -41,6 +44,14 @@ static inline void tegra_cpu_idle_stats_lp2_time(unsigned int cpu, s64 us)
 #endif
 }
 
+static inline void tegra_idle_lp2(struct cpuidle_device *dev,
+                       struct cpuidle_state *state)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       tegra2_idle_lp2(dev, state);
+#endif
+}
+
 #ifdef CONFIG_DEBUG_FS
 static inline int tegra_lp2_debug_show(struct seq_file *s, void *data)
 {
index eff724b..f2b2e64 100644 (file)
@@ -88,6 +88,10 @@ static unsigned long iram_save_size;
 
 struct suspend_context tegra_sctx;
 
+#ifdef CONFIG_PM_SLEEP
+static DEFINE_SPINLOCK(tegra_lp2_lock);
+static cpumask_t tegra_in_lp2;
+#endif
 static void __iomem *iram_code = IO_ADDRESS(TEGRA_IRAM_CODE_AREA);
 static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
 #ifdef CONFIG_PM_SLEEP
@@ -155,9 +159,6 @@ static struct clk *tegra_pclk;
 static const struct tegra_suspend_platform_data *pdata;
 static enum tegra_suspend_mode current_suspend_mode = TEGRA_SUSPEND_NONE;
 
-static DEFINE_SPINLOCK(tegra_lp2_lock);
-static cpumask_t tegra_in_lp2;
-
 static struct kobject *suspend_kobj;
 
 static const char *tegra_suspend_name[TEGRA_MAX_SUSPEND_MODE] = {
@@ -298,51 +299,6 @@ static int create_suspend_pgtable(void)
        return 0;
 }
 
-#ifdef CONFIG_SMP
-static int tegra_reset_sleeping_cpu(int cpu)
-{
-       int ret = 0;
-
-       BUG_ON(cpu == smp_processor_id());
-       tegra_pen_lock();
-
-       if (readl(pmc + PMC_SCRATCH41) == CPU_RESETTABLE)
-               tegra_cpu_reset(cpu);
-       else
-               ret = -EINVAL;
-
-       tegra_pen_unlock();
-
-       return ret;
-}
-
-static void tegra_wake_reset_cpu(int cpu)
-{
-       u32 reg;
-
-       writel(virt_to_phys(tegra_secondary_resume), evp_reset);
-
-       /* enable cpu clock on cpu */
-       reg = readl(clk_rst + 0x4c);
-       writel(reg & ~(1 << (8 + cpu)), clk_rst + 0x4c);
-
-       reg = 0x1111 << cpu;
-       writel(reg, clk_rst + 0x344);
-
-       /* unhalt the cpu */
-       flowctrl_write_cpu_halt(1, 0);
-}
-#else
-static int tegra_reset_sleeping_cpu(int cpu)
-{
-       return 0;
-}
-
-static void tegra_wake_reset_cpu(int cpu)
-{
-}
-#endif
-
 #ifdef CONFIG_PM_SLEEP
 /*
  * restore_cpu_complex
@@ -461,50 +417,34 @@ static void suspend_cpu_complex(void)
        }
 }
 
-#ifdef CONFIG_SMP
-int tegra_reset_other_cpus(int cpu)
+void tegra_clear_cpu_in_lp2(int cpu)
 {
-       int i;
-       int abort = -1;
-
-       for_each_online_cpu(i) {
-               if (i != cpu) {
-                       if (tegra_reset_sleeping_cpu(i)) {
-                               abort = i;
-                               break;
-                       }
-               }
-       }
-
-       if (abort >= 0) {
-               for_each_online_cpu(i) {
-                       if (i != cpu && i < abort)
-                               tegra_wake_reset_cpu(i);
-               }
-               return -EINVAL;
-       }
-
-       return 0;
+       spin_lock(&tegra_lp2_lock);
+       cpumask_clear_cpu(cpu, &tegra_in_lp2);
+       spin_unlock(&tegra_lp2_lock);
 }
-#else
-int tegra_reset_other_cpus(int cpu)
+
+bool tegra_set_cpu_in_lp2(int cpu)
 {
-       return 0;
-}
+       bool last_cpu = false;
+
+       spin_lock(&tegra_lp2_lock);
+
+       cpumask_set_cpu(cpu, &tegra_in_lp2);
+       if (cpumask_equal(&tegra_in_lp2, cpu_online_mask))
+               last_cpu = true;
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+       else
+               tegra_cpu_set_resettable_soon();
 #endif
 
-#ifdef CONFIG_SMP
+       spin_unlock(&tegra_lp2_lock);
+       return last_cpu;
+}
+
 void tegra_idle_lp2_last(unsigned int flags)
 {
        u32 reg;
-       int i;
-       int cpu = smp_processor_id();
-
-       while (tegra_cpu_is_resettable_soon())
-               cpu_relax();
-
-       if (tegra_reset_other_cpus(cpu))
-               return;
 
        /* Only the last cpu down does the final suspend steps */
        reg = readl(pmc + PMC_CTRL);
@@ -546,10 +486,6 @@ void tegra_idle_lp2_last(unsigned int flags)
        if (flags & TEGRA_POWER_CLUSTER_MASK)
                tegra_cluster_switch_epilog(reg);
 
-       for_each_online_cpu(i)
-               if (i != cpu)
-                       tegra_wake_reset_cpu(i);
-
        tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_epilog);
 
 #if INSTRUMENT_CLUSTER_SWITCH
@@ -567,55 +503,6 @@ void tegra_idle_lp2_last(unsigned int flags)
        }
 #endif
 }
-#else
-void tegra_idle_lp2_last(unsigned int flags)
-{
-}
-#endif
-
-void tegra_idle_lp2(void)
-{
-       bool last_cpu = false;
-       int cpu = smp_processor_id();
-
-       spin_lock(&tegra_lp2_lock);
-
-       cpumask_set_cpu(cpu, &tegra_in_lp2);
-       if (cpumask_equal(&tegra_in_lp2, cpu_online_mask))
-               last_cpu = true;
-       else
-               tegra_cpu_set_resettable_soon();
-
-       spin_unlock(&tegra_lp2_lock);
-
-       cpu_pm_enter();
-
-#ifdef CONFIG_SMP
-       if (last_cpu)
-               tegra_idle_lp2_last(0);
-       else
-#endif
-               tegra_sleep_wfi(PHYS_OFFSET - PAGE_OFFSET);
-
-       cpu_pm_exit();
-
-       spin_lock(&tegra_lp2_lock);
-       cpumask_clear_cpu(cpu, &tegra_in_lp2);
-
-       /*
-        * cpus coming out of idle muck with page tables that belong to the
-        * last process executed before idle.  Don't release any cpus back to
-        * the scheduler until all cpus have booted to avoid modifying the
-        * page table of a running process on another cpu.
-        */
-       while (!cpumask_empty(&tegra_in_lp2)) {
-               spin_unlock(&tegra_lp2_lock);
-               cpu_relax();
-               spin_lock(&tegra_lp2_lock);
-       }
-
-       spin_unlock(&tegra_lp2_lock);
-}
 
 static int tegra_common_suspend(void)
 {
index b85a8de..86ba81f 100644 (file)
@@ -46,6 +46,8 @@ struct tegra_suspend_platform_data {
 unsigned long tegra_cpu_power_good_time(void);
 unsigned long tegra_cpu_power_off_time(void);
 unsigned long tegra_cpu_lp2_min_residency(void);
+void tegra_clear_cpu_in_lp2(int cpu);
+bool tegra_set_cpu_in_lp2(int cpu);
 
 int tegra_suspend_dram(enum tegra_suspend_mode mode);
 
@@ -74,8 +76,6 @@ static inline void tegra2_lp0_suspend_init(void)
 #endif
 void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat);
 
-void tegra_idle_lp2(void);
-
 unsigned int tegra_count_slow_cpus(unsigned long speed_limit);
 unsigned int tegra_get_slowest_cpu_n(void);
 unsigned long tegra_cpu_lowest_speed(void);