ARM: tegra11: power: Keep CPU power On when DFLL mode changing
Alex Frid [Wed, 30 Jan 2013 08:09:47 +0000 (00:09 -0800)]
Don't power down fast CPU cluster when DFLL mode is changing
- during CPU clock source switch between PLL and DFLL
- during CPU cluster switch

Change-Id: I987383a39ce23a19f837eba441c59f9e6513d069
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/195789
(cherry picked from commit b0689c8dec259847087362922d2cf3249fd85c83)
Reviewed-on: http://git-master/r/199165
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/dvfs.c
arch/arm/mach-tegra/dvfs.h
arch/arm/mach-tegra/tegra11_clocks.c

index b9669e4..6f101a1 100644 (file)
@@ -762,7 +762,8 @@ bool tegra_dvfs_rail_updating(struct clk *clk)
        return (!clk ? false :
                (!clk->dvfs ? false :
                 (!clk->dvfs->dvfs_rail ? false :
-                 (clk->dvfs->dvfs_rail->updating))));
+                 (clk->dvfs->dvfs_rail->updating ||
+                  clk->dvfs->dvfs_rail->dfll_mode_updating))));
 }
 
 #ifdef CONFIG_OF
index c5473bc..e060249 100644 (file)
@@ -80,6 +80,7 @@ struct dvfs_rail {
        int offs_millivolts;
        bool suspended;
        bool dfll_mode;
+       bool dfll_mode_updating;
        int thermal_idx;
        struct tegra_cooling_device *pll_mode_cdev;
        struct tegra_cooling_device *dfll_mode_cdev;
@@ -256,6 +257,12 @@ static inline int tegra_dvfs_set_dfll_range(struct dvfs *d, int range)
        d->dfll_data.range = range;
        return 0;
 }
+static inline void tegra_dvfs_rail_mode_updating(struct dvfs_rail *rail,
+                                                bool updating)
+{
+       if (rail)
+               rail->dfll_mode_updating = updating;
+}
 
 static inline int tegra_dvfs_rail_get_nominal_millivolts(struct dvfs_rail *rail)
 {
index 96e9128..4d64d51 100644 (file)
@@ -1149,8 +1149,10 @@ static int tegra11_cpu_clk_dfll_on(struct clk *c, unsigned long rate,
                        }
                }
 
+               tegra_dvfs_rail_mode_updating(tegra_cpu_rail, true);
                ret = clk_set_parent(c->parent, dfll);
                if (ret) {
+                       tegra_dvfs_rail_mode_updating(tegra_cpu_rail, false);
                        pr_err("Failed to switch cpu to %s\n", dfll->name);
                        return ret;
                }
@@ -1159,6 +1161,7 @@ static int tegra11_cpu_clk_dfll_on(struct clk *c, unsigned long rate,
 
                /* prevent legacy dvfs voltage scaling */
                tegra_dvfs_dfll_mode_set(c->dvfs, rate);
+               tegra_dvfs_rail_mode_updating(tegra_cpu_rail, false);
        }
        return 0;
 }
@@ -1174,6 +1177,7 @@ static int tegra11_cpu_clk_dfll_off(struct clk *c, unsigned long rate,
        rate = min(rate, c->max_rate - c->dvfs->dfll_data.max_rate_boost);
        pll = (rate <= c->u.cpu.backup_rate) ? c->u.cpu.backup : c->u.cpu.main;
 
+       tegra_dvfs_rail_mode_updating(tegra_cpu_rail, true);
        ret = tegra_clk_cfg_ex(dfll, TEGRA_CLK_DFLL_LOCK, 0);
        if (ret) {
                pr_err("Failed to unlock %s\n", dfll->name);
@@ -1205,11 +1209,13 @@ static int tegra11_cpu_clk_dfll_off(struct clk *c, unsigned long rate,
        if (old_rate <= rate)
                tegra_dvfs_set_rate(c, rate);
 
+       tegra_dvfs_rail_mode_updating(tegra_cpu_rail, false);
        return 0;
 
 back_to_dfll:
        tegra_clk_cfg_ex(dfll, TEGRA_CLK_DFLL_LOCK, 1);
        tegra_dvfs_dfll_mode_set(c->dvfs, old_rate);
+       tegra_dvfs_rail_mode_updating(tegra_cpu_rail, false);
        return ret;
 }
 
@@ -1387,6 +1393,7 @@ static int tegra11_cpu_cmplx_clk_set_parent(struct clk *c, struct clk *p)
                return 0;       /* already switched - exit */
        }
 
+       tegra_dvfs_rail_mode_updating(tegra_cpu_rail, true);
        if (c->parent->parent->parent == dfll) {
                /* G (DFLL selected as clock source) => LP switch:
                 * turn DFLL into open loop mode ("release" VDD_CPU rail)
@@ -1451,12 +1458,15 @@ static int tegra11_cpu_cmplx_clk_set_parent(struct clk *c, struct clk *p)
        if (p_source == dfll)
                tegra_clk_cfg_ex(dfll, TEGRA_CLK_DFLL_LOCK, 1);
 
+       tegra_dvfs_rail_mode_updating(tegra_cpu_rail, false);
        return 0;
 
 abort:
        /* Re-lock DFLL if necessary after aborted switch */
        if (c->parent->parent->parent == dfll)
                tegra_clk_cfg_ex(dfll, TEGRA_CLK_DFLL_LOCK, 1);
+       tegra_dvfs_rail_mode_updating(tegra_cpu_rail, false);
+
        pr_err("%s: aborted switch from %s to %s\n",
               __func__, c->parent->name, p->name);
        return ret;