ARM: tegra11: Use CPU private timer for LP2
Bo Yan [Wed, 25 Jul 2012 01:32:12 +0000 (18:32 -0700)]
There is no new change for T20 and T30. For SoCs with arch timer
support, arch timer is used for LP2 accounting.

Also removed ARM_SMP_TWD option from Kconfig, it's no longer
necessary and deprecated.

Change-Id: I4292e333df97da296318224e0aa1411330f67900
Signed-off-by: Bo Yan <byan@nvidia.com>
Reviewed-on: http://git-master/r/118365
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Aleksandr Frid <afrid@nvidia.com>

Rebase-Id: Rdcf0ab5bd8ed3cba9d22b624914be5adf79ebe36

arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/cpuidle-t3.c
arch/arm/mach-tegra/timer.c
arch/arm/mach-tegra/timer.h

index 124b538..d7e7fa6 100644 (file)
@@ -18,7 +18,6 @@ config ARCH_TEGRA_2x_SOC
        select ARM_ERRATA_754327 if SMP
        select ARM_ERRATA_764369 if SMP
        select ARM_GIC
-       select ARM_SMP_TWD
        select ARM_SAVE_DEBUG_CONTEXT if PM_SLEEP
        select COMMON_CLK
        select CPA
@@ -51,7 +50,6 @@ config ARCH_TEGRA_3x_SOC
        select ARM_ERRATA_754322
        select ARM_ERRATA_764369 if SMP
        select ARM_GIC
-       select ARM_SMP_TWD
        select ARM_SAVE_DEBUG_CONTEXT if PM_SLEEP
        select COMMON_CLK
        select CPA
@@ -87,6 +85,7 @@ config ARCH_TEGRA_11x_SOC
        select REPORT_PRESENT_CPUS if TEGRA_AUTO_HOTPLUG
        select TEGRA_DUAL_CBUS
        select TEGRA_DYNAMIC_CBUS
+       select TEGRA_LP2_CPU_TIMER if !TEGRA_RAIL_OFF_MULTIPLE_CPUS
        select USB_ARCH_HAS_EHCI if USB_SUPPORT
        select USB_EHCI_TEGRA if USB_SUPPORT
        select USB_ULPI if USB_SUPPORT
index 05e4b4a..b215b3e 100644 (file)
@@ -70,6 +70,9 @@
 #define PMC_POWERGATE_STATUS \
        (IO_ADDRESS(TEGRA_PMC_BASE) + 0x038)
 
+#define ARCH_TIMER_CTRL_ENABLE          (1 << 0)
+#define ARCH_TIMER_CTRL_IT_MASK         (1 << 1)
+
 #ifdef CONFIG_SMP
 static s64 tegra_cpu_wake_by_time[4] = {
        LLONG_MAX, LLONG_MAX, LLONG_MAX, LLONG_MAX };
@@ -362,13 +365,19 @@ static bool tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
 #ifdef CONFIG_SMP
        s64 sleep_time;
        ktime_t entry_time;
+#ifdef CONFIG_HAVE_ARM_TWD
        struct tegra_twd_context twd_context;
+#endif
+#ifdef CONFIG_ARM_ARCH_TIMER
+       struct arch_timer_context timer_context;
+#endif
        bool sleep_completed = false;
        struct tick_sched *ts = tick_get_tick_sched(dev->cpu);
-#ifdef CONFIG_TEGRA_LP2_CPU_TIMER
+#if defined(CONFIG_TEGRA_LP2_CPU_TIMER) && defined(CONFIG_HAVE_ARM_TWD)
        void __iomem *twd_base = IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x600);
 #endif
 
+#ifdef CONFIG_HAVE_ARM_TWD
        if (!tegra_twd_get_state(&twd_context)) {
                unsigned long twd_rate = clk_get_rate(twd_clk);
 
@@ -386,6 +395,26 @@ static bool tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
 #endif
                }
        }
+#endif
+#ifdef CONFIG_ARM_ARCH_TIMER
+       if (!arch_timer_get_state(&timer_context)) {
+               if ((timer_context.cntp_ctl & ARCH_TIMER_CTRL_ENABLE) &&
+                   ~(timer_context.cntp_ctl & ARCH_TIMER_CTRL_IT_MASK)) {
+                       request = div_u64((u64)timer_context.cntp_tval *
+                                       1000000, timer_context.cntfrq);
+#ifdef CONFIG_TEGRA_LP2_CPU_TIMER
+                       if (request >= state->target_residency) {
+                               timer_context.cntp_tval -= state->exit_latency *
+                                       (timer_context.cntfrq / 1000000);
+                               __asm__("mcr p15, 0, %0, c14, c2, 0\n"
+                                       :
+                                       :
+                                       "r"(timer_context.cntp_tval));
+                       }
+#endif
+               }
+       }
+#endif
 
        if (!tegra_is_lp2_timer_ready(dev->cpu) ||
            (request < state->target_residency) ||
@@ -397,12 +426,20 @@ static bool tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
                return false;
        }
 
-#ifndef CONFIG_TEGRA_LP2_CPU_TIMER
+#if !defined(CONFIG_TEGRA_LP2_CPU_TIMER)
+#ifdef CONFIG_HAVE_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
+#ifdef CONFIG_ARM_ARCH_TIMER
+       sleep_time = request - state->exit_latency;
+       clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
+       arch_timer_suspend(&timer_context);
+       tegra_lp2_set_trigger(sleep_time);
+#endif
+#endif
        idle_stats.tear_down_count[cpu_number(dev->cpu)]++;
 
        trace_power_start(POWER_CSTATE, 2, dev->cpu);
@@ -426,12 +463,23 @@ static bool tegra3_idle_enter_lp2_cpu_n(struct cpuidle_device *dev,
        tegra_cpu_wake_by_time[dev->cpu] = LLONG_MAX;
 
 #ifdef CONFIG_TEGRA_LP2_CPU_TIMER
+#ifdef CONFIG_HAVE_ARM_TWD
        if (!tegra_twd_get_state(&twd_context))
                sleep_completed = (twd_context.twd_cnt == 0);
+#endif
+#ifdef CONFIG_ARM_ARCH_TIMER
+       if (!arch_timer_get_state(&timer_context))
+               sleep_completed = (timer_context.cntp_tval == 0);
+#endif
 #else
        sleep_completed = !tegra_lp2_timer_remain();
        tegra_lp2_set_trigger(0);
+#ifdef CONFIG_HAVE_ARM_TWD
        tegra_twd_resume(&twd_context);
+#endif
+#ifdef CONFIG_ARM_ARCH_TIMER
+       arch_timer_resume(&timer_context);
+#endif
        clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
 #endif
        sleep_time = ktime_to_us(ktime_sub(ktime_get(), entry_time));
index fb20466..8ef462f 100644 (file)
@@ -275,6 +275,19 @@ static void __init tegra_init_late_timer(void)
 #endif
 
 #ifdef CONFIG_ARM_ARCH_TIMER
+int arch_timer_get_state(struct arch_timer_context *context)
+{
+       u32 val;
+
+       asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
+       context->cntp_tval = val;
+       asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
+       context->cntp_ctl = val;
+       asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
+       context->cntfrq = val;
+       return 0;
+}
+
 void arch_timer_suspend(struct arch_timer_context *context)
 {
        u32 val;
@@ -295,6 +308,7 @@ void arch_timer_resume(struct arch_timer_context *context)
        asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r"(val));
 }
 #else
+#define arch_timer_get_state do {} while(0)
 #define arch_timer_suspend do {} while(0)
 #define arch_timer_resume do {} while(0)
 #endif
index 385c3d7..77edfbf 100644 (file)
@@ -64,8 +64,10 @@ static inline void tegra_twd_resume(struct tegra_twd_context *context) {}
 struct arch_timer_context {
        u32 cntp_tval;
        u32 cntp_ctl;
+       u32 cntfrq;
 };
 
+int arch_timer_get_state(struct arch_timer_context *);
 void arch_timer_suspend(struct arch_timer_context *);
 void arch_timer_resume(struct arch_timer_context *);
 #endif