video: tegra: gk20a: protect clk reg accesses
Prashant Malani [Sun, 8 Sep 2013 04:07:56 +0000 (21:07 -0700)]
Use clk mutex to protect and prevent accesses
of clock registers when gk20a is powergated by
nvhost.

Bug 1363292

Change-Id: Id96181ee31993e3479a61284031d3a31f1fe528b
Signed-off-by: Prashant Malani <pmalani@nvidia.com>
Reviewed-on: http://git-master/r/271850
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>

drivers/video/tegra/host/gk20a/clk_gk20a.c
drivers/video/tegra/host/gk20a/clk_gk20a.h
drivers/video/tegra/host/gk20a/gk20a.c

index 489e146..810ff75 100644 (file)
@@ -424,9 +424,7 @@ static int set_pll_freq(struct gk20a *g, u32 freq, u32 old_freq)
                return 0;
 
        /* change frequency only if power is on */
-       /* FIXME: Need a lock to protect power gating state during
-          clk_program_gpc_pll(g, clk) */
-       if (g->power_on)
+       if (g->clk.clk_hw_on)
                err = clk_program_gpc_pll(g, clk);
 
        /* Just report error but not restore PLL since dvfs could already change
@@ -475,7 +473,7 @@ static void gk20a_clk_export_disable(void *data)
        struct clk_gk20a *clk = &g->clk;
 
        mutex_lock(&clk->clk_mutex);
-       if (g->power_on)
+       if (g->clk.clk_hw_on)
                clk_disable_gpcpll(g);
        mutex_unlock(&clk->clk_mutex);
 }
@@ -540,7 +538,12 @@ int gk20a_init_clk_support(struct gk20a *g)
        if (err)
                return err;
 
+       mutex_lock(&clk->clk_mutex);
+       clk->clk_hw_on = true;
+
        err = gk20a_init_clk_setup_hw(g);
+       mutex_unlock(&clk->clk_mutex);
+
        if (err)
                return err;
 
@@ -626,9 +629,15 @@ int gk20a_clk_init_cap_freqs(struct gk20a *g)
        return 0;
 }
 
-int gk20a_clk_disable_gpcpll(struct gk20a *g)
+int gk20a_suspend_clk_support(struct gk20a *g)
 {
-       return clk_disable_gpcpll(g);
+       int ret;
+
+       mutex_lock(&g->clk.clk_mutex);
+       ret = clk_disable_gpcpll(g);
+       g->clk.clk_hw_on = false;
+       mutex_unlock(&g->clk.clk_mutex);
+       return ret;
 }
 
 #ifdef CONFIG_DEBUG_FS
@@ -685,8 +694,10 @@ static int pll_reg_show(struct seq_file *s, void *data)
        struct gk20a *g = s->private;
        u32 reg, m, n, pl, f;
 
-       if (!g->power_on) {
+       mutex_lock(&g->clk.clk_mutex);
+       if (!g->clk.clk_hw_on) {
                seq_printf(s, "gk20a powered down - no access to registers\n");
+               mutex_unlock(&g->clk.clk_mutex);
                return 0;
        }
 
@@ -702,6 +713,7 @@ static int pll_reg_show(struct seq_file *s, void *data)
        f = g->clk.gpc_pll.clk_in * n / (m * pl_to_div[pl]);
        seq_printf(s, "coef = 0x%x : m = %u : n = %u : pl = %u", reg, m, n, pl);
        seq_printf(s, " : pll_f(gpu_f) = %u(%u) MHz\n", f, f/2);
+       mutex_unlock(&g->clk.clk_mutex);
        return 0;
 }
 
index fa60bd5..430e4c1 100644 (file)
@@ -57,6 +57,7 @@ struct clk_gk20a {
        bool sw_ready;
        u32 cap_freq;
        u32 cap_freq_thermal;
+       bool clk_hw_on;
 };
 
 struct gpufreq_table_data {
@@ -73,7 +74,7 @@ int gk20a_init_clk_support(struct gk20a *g);
 int gk20a_clk_init_cap_freqs(struct gk20a *g);
 u32 gk20a_clk_get_rate(struct gk20a *g);
 int gk20a_clk_set_rate(struct gk20a *g, u32 rate);
-int gk20a_clk_disable_gpcpll(struct gk20a *g);
+int gk20a_suspend_clk_support(struct gk20a *g);
 struct clk *gk20a_clk_get(struct gk20a *g);
 int gk20a_clk_round_rate(struct gk20a *g, u32 rate);
 
index 01b793a..8be8f4b 100644 (file)
@@ -667,12 +667,8 @@ int nvhost_gk20a_prepare_poweroff(struct platform_device *dev)
        ret |= gk20a_gr_suspend(g);
        ret |= gk20a_mm_suspend(g);
 
-       /* Disable GPCPLL.
-        * TODO: Remove this once gk20a clock driver is moved to
-        * common clock framework
-        */
-       ret |= gk20a_clk_disable_gpcpll(g);
-
+       /* Disable GPCPLL */
+       ret |= gk20a_suspend_clk_support(g);
        g->power_on = false;
 
        return ret;