ARM: tegra: power: Don't change mode of uninitialized DFLL
Alex Frid [Tue, 15 Oct 2013 01:37:13 +0000 (18:37 -0700)]
If DFLL has not initialized, yet, or initialization failed:
- do not change DFLL mode from sysfs callback
- do not resume DFLL bypass mode after CPU rail gating/cluster switch

Change-Id: Ife68679b942e9af30cdc7dddbec1abf15f42dd66
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/299264
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>

arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/pm.c
arch/arm/mach-tegra/tegra11_clocks.c
arch/arm/mach-tegra/tegra12_clocks.c
arch/arm/mach-tegra/tegra14_clocks.c

index 25d7566..38a5a56 100644 (file)
@@ -156,6 +156,11 @@ unsigned long clk_get_min_rate(struct clk *c)
                return c->min_rate;
 }
 
+bool tegra_is_clk_initialized(struct clk *c)
+{
+       return c->state != UNINITIALIZED;
+}
+
 /* Must be called with clk_lock(c) held */
 unsigned long clk_get_rate_locked(struct clk *c)
 {
index f789da4..438f279 100644 (file)
@@ -370,6 +370,8 @@ void tegra_clk_init_cbus_plls_from_table(struct tegra_clk_init_table *table);
 void clk_set_cansleep(struct clk *c);
 unsigned long clk_get_min_rate(struct clk *c);
 unsigned long clk_get_max_rate(struct clk *c);
+bool tegra_is_clk_initialized(struct clk *c);
+
 int clk_set_rate_locked(struct clk *c, unsigned long rate);
 int clk_rate_change_notify(struct clk *c, unsigned long rate);
 int clk_set_parent_locked(struct clk *c, struct clk *parent);
index b4a3bbc..97b2b80 100644 (file)
@@ -400,6 +400,7 @@ static void resume_cpu_dfll_mode(unsigned int flags)
 #ifdef CONFIG_ARCH_TEGRA_HAS_CL_DVFS
        /* If DFLL is Not used and resume on G restore bypass mode */
        if (pdata && pdata->resume_dfll_bypass && !is_lp_cluster() &&
+           tegra_is_clk_initialized(tegra_dfll) &&
            !tegra_dvfs_rail_is_dfll_mode(tegra_cpu_rail))
                pdata->resume_dfll_bypass();
 
index 1a85b98..5994e44 100644 (file)
@@ -3668,11 +3668,17 @@ static int tegra11_use_dfll_cb(const char *arg, const struct kernel_param *kp)
        unsigned long c_flags, p_flags;
        unsigned int old_use_dfll;
        struct clk *c = tegra_get_clock_by_name("cpu");
+       struct clk *dfll = tegra_get_clock_by_name("dfll_cpu");
 
-       if (!c->parent || !c->parent->dvfs)
+       if (!c->parent || !c->parent->dvfs || !dfll)
                return -ENOSYS;
 
        clk_lock_save(c, &c_flags);
+       if (dfll->state == UNINITIALIZED) {
+               pr_err("%s: DFLL is not initialized\n", __func__);
+               clk_unlock_restore(c, &c_flags);
+               return -ENOSYS;
+       }
        if (c->parent->u.cpu.mode == MODE_LP) {
                pr_err("%s: DFLL is not used on LP CPU\n", __func__);
                clk_unlock_restore(c, &c_flags);
index 98dc99d..e53c5d5 100644 (file)
@@ -4083,11 +4083,17 @@ static int tegra12_use_dfll_cb(const char *arg, const struct kernel_param *kp)
        unsigned long c_flags, p_flags;
        unsigned int old_use_dfll;
        struct clk *c = tegra_get_clock_by_name("cpu");
+       struct clk *dfll = tegra_get_clock_by_name("dfll_cpu");
 
-       if (!c->parent || !c->parent->dvfs)
+       if (!c->parent || !c->parent->dvfs || !dfll)
                return -ENOSYS;
 
        clk_lock_save(c, &c_flags);
+       if (dfll->state == UNINITIALIZED) {
+               pr_err("%s: DFLL is not initialized\n", __func__);
+               clk_unlock_restore(c, &c_flags);
+               return -ENOSYS;
+       }
        if (c->parent->u.cpu.mode == MODE_LP) {
                pr_err("%s: DFLL is not used on LP CPU\n", __func__);
                clk_unlock_restore(c, &c_flags);
index 07e766a..960f247 100644 (file)
@@ -3282,11 +3282,17 @@ static int tegra14_use_dfll_cb(const char *arg, const struct kernel_param *kp)
        unsigned long c_flags, p_flags;
        unsigned int old_use_dfll;
        struct clk *c = tegra_get_clock_by_name("cpu");
+       struct clk *dfll = tegra_get_clock_by_name("dfll_cpu");
 
-       if (!c->parent || !c->parent->dvfs)
+       if (!c->parent || !c->parent->dvfs || !dfll)
                return -ENOSYS;
 
        clk_lock_save(c, &c_flags);
+       if (dfll->state == UNINITIALIZED) {
+               pr_err("%s: DFLL is not initialized\n", __func__);
+               clk_unlock_restore(c, &c_flags);
+               return -ENOSYS;
+       }
        if (c->parent->u.cpu.mode == MODE_LP) {
                pr_err("%s: DFLL is not used on LP CPU\n", __func__);
                clk_unlock_restore(c, &c_flags);