ARM: tegra: power: Suspend/resume cpu dfll mode
Alex Frid [Sat, 29 Sep 2012 02:57:41 +0000 (19:57 -0700)]
If DFLL is used as CPU clock source switch to open loop mode before
cpu rail is turned off when rail-gating during idle (LP2 last), or
suspending the system (entering LP1 or LP0 states). Consolidated this
controls in pm.c file.

Change-Id: I8ed7f29a733225533dd94cce0b14f66dad258310
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/139930
Signed-off-by: Bharat Nihalani <bnihalani@nvidia.com>
Reviewed-on: http://git-master/r/146261
Reviewed-by: Automatic_Commit_Validation_User

Rebase-Id: R2574794d672209fc584361a5fc820ef9cb111d95

arch/arm/mach-tegra/cpuidle-t3.c
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/pm.c

index 774bd78..69117d7 100644 (file)
@@ -86,7 +86,6 @@ module_param(lp2_n_in_idle, bool, 0644);
 
 static struct clk *cpu_clk_for_dvfs;
 static struct clk *twd_clk;
-static struct clk *dfll;
 
 static int lp2_exit_latencies[5];
 
@@ -285,12 +284,8 @@ static bool tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev,
        idle_stats.lp2_count_bin[bin]++;
 
        clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu);
-       if (!is_lp_cluster()) {
+       if (!is_lp_cluster())
                tegra_dvfs_rail_off(tegra_cpu_rail, entry_time);
-               /* If DFLL is used as CPU clock source go to open loop mode */
-               if (clk_get_parent(clk_get_parent(cpu_clk_for_dvfs)) == dfll)
-                       tegra_clk_cfg_ex(dfll, TEGRA_CLK_DFLL_LOCK, 0);
-       }
 
 #if defined(CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE)
        flag = get_power_gating_partition();
@@ -304,12 +299,9 @@ static bool tegra3_idle_enter_lp2_cpu_0(struct cpuidle_device *dev,
 
        clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
        exit_time = ktime_get();
-       if (!is_lp_cluster()) {
+       if (!is_lp_cluster())
                tegra_dvfs_rail_on(tegra_cpu_rail, exit_time);
-               /* If DFLL is used as CPU clock source go to closed loop mode */
-               if (clk_get_parent(clk_get_parent(cpu_clk_for_dvfs)) == dfll)
-                       tegra_clk_cfg_ex(dfll, TEGRA_CLK_DFLL_LOCK, 1);
-       }
+
        idle_stats.in_lp2_time[cpu_number(dev->cpu)] +=
                ktime_to_us(ktime_sub(exit_time, entry_time));
 
@@ -544,7 +536,6 @@ int tegra3_cpudile_init_soc(void)
 
        cpu_clk_for_dvfs = tegra_get_clock_by_name("cpu_g");
        twd_clk = tegra_get_clock_by_name("twd");
-       dfll = tegra_get_clock_by_name("dfll_cpu");
 
        for (i = 0; i < ARRAY_SIZE(lp2_exit_latencies); i++)
                lp2_exit_latencies[i] = tegra_lp2_exit_latency;
index f7a45c4..db595e0 100644 (file)
@@ -183,4 +183,9 @@ static inline int tegra_dvfs_rail_post_enable(struct dvfs_rail *rail)
 { return 0; }
 #endif
 
+static inline bool tegra_dvfs_rail_is_dfll_mode(struct dvfs_rail *rail)
+{
+       return rail->dfll_mode;
+}
+
 #endif
index 61951cc..dc8e7da 100644 (file)
@@ -184,6 +184,7 @@ struct suspend_context tegra_sctx;
 #define MC_SECURITY_SIZE       0x70
 #define MC_SECURITY_CFG2       0x7c
 
+static struct clk *tegra_dfll;
 static struct clk *tegra_pclk;
 static const struct tegra_suspend_platform_data *pdata;
 static enum tegra_suspend_mode current_suspend_mode = TEGRA_SUSPEND_NONE;
@@ -248,6 +249,22 @@ unsigned long tegra_cpu_lp2_min_residency(void)
        return pdata->cpu_lp2_min_residency;
 }
 
+static void suspend_cpu_dfll_mode(void)
+{
+       /* If DFLL is used as CPU clock source go to open loop mode */
+       if (!is_lp_cluster() && tegra_dfll &&
+           tegra_dvfs_rail_is_dfll_mode(tegra_cpu_rail))
+               tegra_clk_cfg_ex(tegra_dfll, TEGRA_CLK_DFLL_LOCK, 0);
+}
+
+static void resume_cpu_dfll_mode(void)
+{
+       /* If DFLL is used as CPU clock source restore closed loop mode */
+       if (!is_lp_cluster() && tegra_dfll &&
+           tegra_dvfs_rail_is_dfll_mode(tegra_cpu_rail))
+               tegra_clk_cfg_ex(tegra_dfll, TEGRA_CLK_DFLL_LOCK, 1);
+}
+
 /*
  * create_suspend_pgtable
  *
@@ -587,6 +604,7 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
                }
                tegra_cluster_switch_prolog(flags);
        } else {
+               suspend_cpu_dfll_mode();
                set_power_timers(pdata->cpu_timer, pdata->cpu_off_timer,
                        clk_get_rate_all_locked(tegra_pclk));
 #if defined(CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE)
@@ -645,6 +663,8 @@ unsigned int tegra_idle_lp2_last(unsigned int sleep_time, unsigned int flags)
                        trace_cpu_cluster_rcuidle(POWER_CPU_CLUSTER_DONE);
                else
                        trace_cpu_cluster(POWER_CPU_CLUSTER_DONE);
+       } else {
+               resume_cpu_dfll_mode();
        }
        tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_epilog);
 
@@ -1071,6 +1091,7 @@ static struct kobject *suspend_kobj;
 static int tegra_pm_enter_suspend(void)
 {
        pr_info("Entering suspend state %s\n", lp_state[current_suspend_mode]);
+       suspend_cpu_dfll_mode();
        if (current_suspend_mode == TEGRA_SUSPEND_LP0)
                tegra_lp0_cpu_mode(true);
        return 0;
@@ -1080,6 +1101,7 @@ static void tegra_pm_enter_resume(void)
 {
        if (current_suspend_mode == TEGRA_SUSPEND_LP0)
                tegra_lp0_cpu_mode(false);
+       resume_cpu_dfll_mode();
        pr_info("Exited suspend state %s\n", lp_state[current_suspend_mode]);
 }
 
@@ -1101,6 +1123,10 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat)
        u32 reg;
        u32 mode;
 
+#ifdef CONFIG_ARCH_TEGRA_HAS_CL_DVFS
+       tegra_dfll = clk_get_sys(NULL, "dfll_cpu");
+       BUG_ON(IS_ERR(tegra_dfll));
+#endif
        tegra_pclk = clk_get_sys(NULL, "pclk");
        BUG_ON(IS_ERR(tegra_pclk));
        pdata = plat;