ARM: tegra: timer: Update twd suspend/resume
Alex Frid [Wed, 21 Sep 2011 06:37:36 +0000 (23:37 -0700)]
- Preserve twd periodic load register across suspend and LP2 on main
CPU. Keep timer disabled on resume, since it will be re-configured
later when timekeeping switches from global system timer.

- Generate "load equal zero" warning in twd suspend/resume code only
when timer is in periodic mode.

Change-Id: If7df8be08c0ef4e355f315e3f0b7e3cf1b358f0f
Reviewed-on: http://git-master/r/55068
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

Rebase-Id: R75f3950a915e0953a098620dea9ea32a7d5e9482

arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/timer.c

index 94d8e0b..50740b0 100644 (file)
@@ -413,9 +413,14 @@ static void restore_cpu_complex(u32 mode)
        flowctrl_write_cpu_csr(cpu, reg);
 
        /* If an immedidate cluster switch is being perfomed, restore the
-          local timer registers. See save_cpu_complex() for the details. */
-       if (mode & (TEGRA_POWER_CLUSTER_MASK | TEGRA_POWER_CLUSTER_IMMEDIATE))
-               tegra_twd_resume(&tegra_sctx.twd);
+          local timer registers. For calls resulting from CPU LP2 in
+          idle or system suspend, the local timer was shut down and
+          timekeeping switched over to the global system timer. In this
+          case keep local timer disabled, and restore only periodic load. */
+       if (!(mode & (TEGRA_POWER_CLUSTER_MASK |
+                     TEGRA_POWER_CLUSTER_IMMEDIATE)))
+               tegra_sctx.twd.twd_ctrl = 0;
+       tegra_twd_resume(&tegra_sctx.twd);
 }
 
 /*
@@ -447,12 +452,7 @@ static void suspend_cpu_complex(u32 mode)
        tegra_sctx.pllp_misc = readl(clk_rst + CLK_RESET_PLLP_MISC);
        tegra_sctx.cclk_divider = readl(clk_rst + CLK_RESET_CCLK_DIVIDER);
 
-       /* If an immedidate cluster switch is being perfomed, save the
-          local timer registers. For calls resulting from CPU LP2 in
-          idle or system suspend, the local timer is shut down and
-          timekeeping switches over to the global system timer. */
-       if (mode & (TEGRA_POWER_CLUSTER_MASK | TEGRA_POWER_CLUSTER_IMMEDIATE))
-               tegra_twd_suspend(&tegra_sctx.twd);
+       tegra_twd_suspend(&tegra_sctx.twd);
 
        reg = flowctrl_read_cpu_csr(cpu);
        reg &= ~FLOW_CTRL_CSR_WFE_BITMAP;       /* clear wfe bitmap */
index ba4ad7a..db0d186 100644 (file)
@@ -204,8 +204,10 @@ void tegra_twd_suspend(struct tegra_twd_context *context)
 {
        context->twd_ctrl = readl(twd_base + TWD_TIMER_CONTROL);
        context->twd_load = readl(twd_base + TWD_TIMER_LOAD);
-       if ((context->twd_load == 0) && (context->twd_ctrl &
-               (TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE))) {
+       if ((context->twd_load == 0) &&
+           (context->twd_ctrl & TWD_TIMER_CONTROL_PERIODIC) &&
+           (context->twd_ctrl & (TWD_TIMER_CONTROL_ENABLE |
+                                 TWD_TIMER_CONTROL_IT_ENABLE))) {
                WARN("%s: TWD enabled but counter was 0\n", __func__);
                context->twd_load = 1;
        }
@@ -214,8 +216,10 @@ void tegra_twd_suspend(struct tegra_twd_context *context)
 
 void tegra_twd_resume(struct tegra_twd_context *context)
 {
-       BUG_ON((context->twd_load == 0) && (context->twd_ctrl &
-               (TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE)));
+       BUG_ON((context->twd_load == 0) &&
+              (context->twd_ctrl & TWD_TIMER_CONTROL_PERIODIC) &&
+              (context->twd_ctrl & (TWD_TIMER_CONTROL_ENABLE |
+                                    TWD_TIMER_CONTROL_IT_ENABLE)));
        writel(context->twd_load, twd_base + TWD_TIMER_LOAD);
        writel(context->twd_ctrl, twd_base + TWD_TIMER_CONTROL);
 }