ARM: tegra: clock: Update secondary pll dividers resume
Prashant Gaikwad [Fri, 25 May 2012 05:18:09 +0000 (10:18 +0530)]
During resume from LP0 on Tegra2 always enable pll secondary dividers
before clocks restoration (to make sure clock sources are enabled).
Restore actual secondary dividers settings after clocks are restored.

Bug 965928
Bug 953030

Change-Id: Id0cd99b601f90ad9fe8452817810969e41002199
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>

Reviewed on http://git-master/r/#change,104661
(cherry picked from commit 6350d1fd475373779cf5110403717b2c84e723ba)

Change-Id: Ic50477603b97a99d2ac2c926df1728faa107b108
Reviewed-on: http://git-master/r/104668
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Tested-by: Prashant Gaikwad <pgaikwad@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
GVS: Gerrit_Virtual_Submit

arch/arm/mach-tegra/tegra2_clocks.c

index af30cf2..135ae6a 100644 (file)
@@ -2771,7 +2771,7 @@ unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate)
 
 #ifdef CONFIG_PM_SLEEP
 static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
-                          PERIPH_CLK_SOURCE_NUM + 22];
+                          PERIPH_CLK_SOURCE_NUM + 24];
 
 static int tegra_clk_suspend(void)
 {
@@ -2779,6 +2779,8 @@ static int tegra_clk_suspend(void)
        u32 *ctx = clk_rst_suspend;
 
        *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
+       *ctx++ = clk_readl(tegra_pll_p_out1.reg);
+       *ctx++ = clk_readl(tegra_pll_p_out3.reg);
        *ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE);
        *ctx++ = clk_readl(tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
        *ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
@@ -2831,11 +2833,26 @@ static void tegra_clk_resume(void)
        unsigned long off, i;
        const u32 *ctx = clk_rst_suspend;
        u32 val;
+       u32 pll_p_out12, pll_p_out34;
+       u32 pll_m_out1, pll_a_out0, pll_c_out1;
 
        val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
        val |= *ctx++;
        clk_writel(val, OSC_CTRL);
 
+       /* Since we are going to reset devices and switch clock sources in this
+        * function, plls and secondary dividers is required to be enabled. The
+        * actual value will be restored back later. Note that boot plls: pllm,
+        * pllp, and pllu are already configured and enabled.
+        */
+
+       val = PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+       val |= val << 16;
+       pll_p_out12 = *ctx++;
+       clk_writel(pll_p_out12 | val, tegra_pll_p_out1.reg);
+       pll_p_out34 = *ctx++;
+       clk_writel(pll_p_out34 | val, tegra_pll_p_out3.reg);
+
        clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE);
        clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
        clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
@@ -2848,9 +2865,13 @@ static void tegra_clk_resume(void)
        clk_writel(*ctx++, tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
        udelay(1000);
 
-       clk_writel(*ctx++, tegra_pll_m_out1.reg);
-       clk_writel(*ctx++, tegra_pll_a_out0.reg);
-       clk_writel(*ctx++, tegra_pll_c_out1.reg);
+       val = PLL_OUT_CLKEN | PLL_OUT_RESET_DISABLE;
+       pll_m_out1 = *ctx++;
+       clk_writel(pll_m_out1 | val, tegra_pll_m_out1.reg);
+       pll_a_out0 = *ctx++;
+       clk_writel(pll_a_out0 | val, tegra_pll_a_out0.reg);
+       pll_c_out1 = *ctx++;
+       clk_writel(pll_c_out1 | val, tegra_pll_c_out1.reg);
 
        clk_writel(*ctx++, tegra_clk_cclk.reg);
        clk_writel(*ctx++, tegra_clk_cclk.reg + SUPER_CLK_DIVIDER);
@@ -2887,6 +2908,13 @@ static void tegra_clk_resume(void)
 
        clk_writel(*ctx++, MISC_CLK_ENB);
        clk_writel(*ctx++, CLK_MASK_ARM);
+
+       /* Restore back the actual pll and secondary divider values */
+       clk_writel(pll_p_out12, tegra_pll_p_out1.reg);
+       clk_writel(pll_p_out34, tegra_pll_p_out3.reg);
+       clk_writel(pll_m_out1, tegra_pll_m_out1.reg);
+       clk_writel(pll_a_out0, tegra_pll_a_out0.reg);
+       clk_writel(pll_c_out1, tegra_pll_c_out1.reg);
 }
 
 #else