summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra3_clocks.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2012-02-05 00:12:59 -0800
committerLokesh Pathak <lpathak@nvidia.com>2012-02-23 22:40:23 -0800
commit3e39a36eb51fb4f755bf9d3229e91c3a58663b97 (patch)
treef51d0d55c248c3f8514e79606cff9e08ff582c72 /arch/arm/mach-tegra/tegra3_clocks.c
parent199850ff2eec72260d84768e273c808ccc068b4c (diff)
ARM: tegra: clock: Update secondary pll dividers resume
During resume from LP0 on Tegra3 always enable pll secondary dividers before clocks restoration (to make sure clock sources are enabled). Restore actual secondary dividers settings after clocks are restored. Remove pllp secondary dividers restoration from cpu complex restore, and add them to common clock restoration procedure. These dividers are not affected by CPU complex suspend, only by LP0 core suspend. Signed-off-by: Alex Frid <afrid@nvidia.com> (cherry picked from commit 1f631436717c0602ef30770f7976615150114afe) Change-Id: I45777ca0535f51a39c35e9d360ac6e97a13ea92c Reviewed-on: http://git-master/r/84712 Reviewed-by: Lokesh Pathak <lpathak@nvidia.com> Tested-by: Lokesh Pathak <lpathak@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_clocks.c')
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c40
1 files changed, 33 insertions, 7 deletions
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index 97e7aa2bb976..1ecf1bacfaf3 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -4750,7 +4750,7 @@ int tegra_update_mselect_rate(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)
{
@@ -4759,6 +4759,10 @@ static int tegra_clk_suspend(void)
*ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
*ctx++ = clk_readl(CPU_SOFTRST_CTRL);
+
+ *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);
@@ -4822,6 +4826,8 @@ static void tegra_clk_resume(void)
u32 plla_base;
u32 plld_base;
u32 plld2_base;
+ u32 pll_p_out12, pll_p_out34;
+ u32 pll_a_out0, pll_m_out1, pll_c_out1;
struct clk *p;
val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK;
@@ -4829,9 +4835,18 @@ static void tegra_clk_resume(void)
clk_writel(val, OSC_CTRL);
clk_writel(*ctx++, CPU_SOFTRST_CTRL);
- /* Since we are going to reset devices in this function, pllc/a is
- * required to be enabled. The actual value will be restore back later.
+ /* 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);
+
pllc_base = *ctx++;
clk_writel(pllc_base | PLL_BASE_ENABLE, tegra_pll_c.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_c.reg + PLL_MISC(&tegra_pll_c));
@@ -4850,9 +4865,13 @@ static void tegra_clk_resume(void)
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_g.reg);
clk_writel(*ctx++, tegra_clk_cclk_g.reg + SUPER_CLK_DIVIDER);
@@ -4913,14 +4932,21 @@ static void tegra_clk_resume(void)
clk_writel(*ctx++, MISC_CLK_ENB);
clk_writel(*ctx++, CLK_MASK_ARM);
- /* Restore back the actual pllc/a value */
+ /* Restore back the actual pll and secondary divider values */
/* FIXME: need to root cause why pllc is required to be on
* clk_writel(pllc_base, tegra_pll_c.reg + PLL_BASE);
*/
+ clk_writel(pll_p_out12, tegra_pll_p_out1.reg);
+ clk_writel(pll_p_out34, tegra_pll_p_out3.reg);
+
clk_writel(plla_base, tegra_pll_a.reg + PLL_BASE);
clk_writel(plld_base, tegra_pll_d.reg + PLL_BASE);
clk_writel(plld2_base, tegra_pll_d2.reg + PLL_BASE);
+ 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);
+
/* Since EMC clock is not restored, and may not preserve parent across
suspend, update current state, and mark EMC DFS as out of sync */
p = tegra_clk_emc.parent;