Commit c2f44a9d authored by Colin Cross's avatar Colin Cross

ARM: tegra: clock: Fix clock issues in suspend

The PLLP registers are now being restored by the low-level resume code,
and the CPU may be running off PLLP, so don't touch them during clock
resume.

Save plld, plls, pllu, and audio clock during suspend (originally
fixed by Mayuresh Kulkarni <mkulkarni@nvidia.com>)

The lock time for plld is 1000 us, so increase the delay after
setting the PLLs.

Add a BUG_ON to ensure the size of the suspend context area is
correct.
Acked-by: default avatarOlof Johansson <olof@lixom.net>
Signed-off-by: default avatarColin Cross <ccross@android.com>
parent 9743b389
...@@ -2236,7 +2236,7 @@ void __init tegra2_init_clocks(void) ...@@ -2236,7 +2236,7 @@ void __init tegra2_init_clocks(void)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM + static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM +
PERIPH_CLK_SOURCE_NUM + 19]; PERIPH_CLK_SOURCE_NUM + 22];
void tegra_clk_suspend(void) void tegra_clk_suspend(void)
{ {
...@@ -2244,16 +2244,18 @@ void tegra_clk_suspend(void) ...@@ -2244,16 +2244,18 @@ void tegra_clk_suspend(void)
u32 *ctx = clk_rst_suspend; u32 *ctx = clk_rst_suspend;
*ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK; *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK;
*ctx++ = clk_readl(tegra_pll_p.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_p.reg + PLL_MISC(&tegra_pll_p));
*ctx++ = clk_readl(tegra_pll_c.reg + PLL_BASE); *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_c.reg + PLL_MISC(&tegra_pll_c));
*ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE); *ctx++ = clk_readl(tegra_pll_a.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a)); *ctx++ = clk_readl(tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
*ctx++ = clk_readl(tegra_pll_s.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
*ctx++ = clk_readl(tegra_pll_d.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
*ctx++ = clk_readl(tegra_pll_u.reg + PLL_BASE);
*ctx++ = clk_readl(tegra_pll_u.reg + PLL_MISC(&tegra_pll_u));
*ctx++ = clk_readl(tegra_pll_m_out1.reg); *ctx++ = clk_readl(tegra_pll_m_out1.reg);
*ctx++ = clk_readl(tegra_pll_p_out1.reg);
*ctx++ = clk_readl(tegra_pll_p_out3.reg);
*ctx++ = clk_readl(tegra_pll_a_out0.reg); *ctx++ = clk_readl(tegra_pll_a_out0.reg);
*ctx++ = clk_readl(tegra_pll_c_out1.reg); *ctx++ = clk_readl(tegra_pll_c_out1.reg);
...@@ -2264,6 +2266,8 @@ void tegra_clk_suspend(void) ...@@ -2264,6 +2266,8 @@ void tegra_clk_suspend(void)
*ctx++ = clk_readl(tegra_clk_sclk.reg + SUPER_CLK_DIVIDER); *ctx++ = clk_readl(tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
*ctx++ = clk_readl(tegra_clk_pclk.reg); *ctx++ = clk_readl(tegra_clk_pclk.reg);
*ctx++ = clk_readl(tegra_clk_audio.reg);
for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC; for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC;
off += 4) { off += 4) {
if (off == PERIPH_CLK_SOURCE_EMC) if (off == PERIPH_CLK_SOURCE_EMC)
...@@ -2281,6 +2285,8 @@ void tegra_clk_suspend(void) ...@@ -2281,6 +2285,8 @@ void tegra_clk_suspend(void)
*ctx++ = clk_readl(MISC_CLK_ENB); *ctx++ = clk_readl(MISC_CLK_ENB);
*ctx++ = clk_readl(CLK_MASK_ARM); *ctx++ = clk_readl(CLK_MASK_ARM);
BUG_ON(ctx - clk_rst_suspend != ARRAY_SIZE(clk_rst_suspend));
} }
void tegra_clk_resume(void) void tegra_clk_resume(void)
...@@ -2293,17 +2299,19 @@ void tegra_clk_resume(void) ...@@ -2293,17 +2299,19 @@ void tegra_clk_resume(void)
val |= *ctx++; val |= *ctx++;
clk_writel(val, OSC_CTRL); clk_writel(val, OSC_CTRL);
clk_writel(*ctx++, tegra_pll_p.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_p.reg + PLL_MISC(&tegra_pll_p));
clk_writel(*ctx++, tegra_pll_c.reg + PLL_BASE); 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_c.reg + PLL_MISC(&tegra_pll_c));
clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE); clk_writel(*ctx++, tegra_pll_a.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_a.reg + PLL_MISC(&tegra_pll_a)); clk_writel(*ctx++, tegra_pll_a.reg + PLL_MISC(&tegra_pll_a));
udelay(300); clk_writel(*ctx++, tegra_pll_s.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_s.reg + PLL_MISC(&tegra_pll_s));
clk_writel(*ctx++, tegra_pll_d.reg + PLL_BASE);
clk_writel(*ctx++, tegra_pll_d.reg + PLL_MISC(&tegra_pll_d));
clk_writel(*ctx++, tegra_pll_u.reg + PLL_BASE);
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_m_out1.reg);
clk_writel(*ctx++, tegra_pll_p_out1.reg);
clk_writel(*ctx++, tegra_pll_p_out3.reg);
clk_writel(*ctx++, tegra_pll_a_out0.reg); clk_writel(*ctx++, tegra_pll_a_out0.reg);
clk_writel(*ctx++, tegra_pll_c_out1.reg); clk_writel(*ctx++, tegra_pll_c_out1.reg);
...@@ -2314,6 +2322,8 @@ void tegra_clk_resume(void) ...@@ -2314,6 +2322,8 @@ void tegra_clk_resume(void)
clk_writel(*ctx++, tegra_clk_sclk.reg + SUPER_CLK_DIVIDER); clk_writel(*ctx++, tegra_clk_sclk.reg + SUPER_CLK_DIVIDER);
clk_writel(*ctx++, tegra_clk_pclk.reg); clk_writel(*ctx++, tegra_clk_pclk.reg);
clk_writel(*ctx++, tegra_clk_audio.reg);
/* enable all clocks before configuring clock sources */ /* enable all clocks before configuring clock sources */
clk_writel(0xbffffff9ul, CLK_OUT_ENB); clk_writel(0xbffffff9ul, CLK_OUT_ENB);
clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4); clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment