From 0e52d7fe25b11a656c376a37890be219470661fb Mon Sep 17 00:00:00 2001 From: Alex Frid Date: Sat, 21 Aug 2010 22:38:44 -0700 Subject: [ARM/tegra] power: Added non-boot PLL restoration. Added non-boot PLL (PLLC/PLLA/PLLD) restoration during clock resume before clock dividers are restored. (Current restoration in RM happens late after clock dividers are restored). Change-Id: I9661f5ddba0ba4b25d5a00c78820792791777429 Reviewed-on: http://git-master/r/5515 Tested-by: Aleksandr Frid Reviewed-by: Iqbal Bhinderwala Reviewed-by: Rajkumar Jayaraman Reviewed-by: Yu-Huan Hsu --- arch/arm/mach-tegra/clock_nvrm.c | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/arch/arm/mach-tegra/clock_nvrm.c b/arch/arm/mach-tegra/clock_nvrm.c index cc4dde9be1e6..598c001179a2 100644 --- a/arch/arm/mach-tegra/clock_nvrm.c +++ b/arch/arm/mach-tegra/clock_nvrm.c @@ -455,6 +455,7 @@ void __init tegra_init_clock(void) #ifdef CONFIG_PM #define CLK_RESET_RST_DEVICES_L 0x04 #define CLK_RESET_RST_DEVICES_NUM 3 +#define CLK_RESET_PROPAGATION_US 10 #define CLK_RESET_CLK_OUT_ENB_L 0x10 #define CLK_RESET_CLK_OUT_ENB_H 0x14 @@ -469,6 +470,17 @@ void __init tegra_init_clock(void) #define CLK_RESET_OSC_CTRL 0x50 #define CLK_RESET_OSC_CTRL_MASK 0x3f2 /* drive strength & bypass */ +#define CLK_RESET_PLLC_BASE 0x80 +#define CLK_RESET_PLLC_MISC 0x8C +#define CLK_RESET_PLLA_BASE 0xB0 +#define CLK_RESET_PLLA_MISC 0xBC +#define CLK_RESET_PLLD_BASE 0xD0 +#define CLK_RESET_PLLD_MISC 0xDC +#define CLK_RESET_NON_BOOT_PLLS_NUM 3 +#define CLK_RESET_PLL_ENABLE_MASK (0x1 << 30) +#define CLK_RESET_PLL_STAB_US 300 +#define CLK_RESET_PLL_STAB_LONG_US 1000 + #define CLK_RESET_CLK_SOURCE_I2S1 0x100 #define CLK_RESET_CLK_SOURCE_EMC 0x19c #define CLK_RESET_CLK_SOURCE_OSC 0x1fc @@ -476,6 +488,7 @@ void __init tegra_init_clock(void) (((CLK_RESET_CLK_SOURCE_OSC - CLK_RESET_CLK_SOURCE_I2S1) / 4) + 1 - 1) static u32 clk_rst[CLK_RESET_RST_DEVICES_NUM + CLK_RESET_CLK_OUT_ENB_NUM + + (CLK_RESET_NON_BOOT_PLLS_NUM * 2) + CLK_RESET_CLK_SOURCE_NUM + 3]; void tegra_clk_suspend(void) @@ -486,6 +499,13 @@ void tegra_clk_suspend(void) *ctx++ = readl(car + CLK_RESET_OSC_CTRL) & CLK_RESET_OSC_CTRL_MASK; + *ctx++ = readl(car + CLK_RESET_PLLC_MISC); + *ctx++ = readl(car + CLK_RESET_PLLC_BASE); + *ctx++ = readl(car + CLK_RESET_PLLA_MISC); + *ctx++ = readl(car + CLK_RESET_PLLA_BASE); + *ctx++ = readl(car + CLK_RESET_PLLD_MISC); + *ctx++ = readl(car + CLK_RESET_PLLD_BASE); + for (offs=CLK_RESET_CLK_SOURCE_I2S1; offs<=CLK_RESET_CLK_SOURCE_OSC; offs+=4) { @@ -519,6 +539,30 @@ void tegra_clk_resume(void) temp = readl(car + CLK_RESET_OSC_CTRL) & ~CLK_RESET_OSC_CTRL_MASK; temp |= *ctx++; writel(temp, car + CLK_RESET_OSC_CTRL); + wmb(); + + writel(*ctx++, car + CLK_RESET_PLLC_MISC); + temp = *ctx & (~CLK_RESET_PLL_ENABLE_MASK); + writel(temp, car + CLK_RESET_PLLC_BASE); + wmb(); + writel(*ctx++, car + CLK_RESET_PLLC_BASE); + + writel(*ctx++, car + CLK_RESET_PLLA_MISC); + temp = *ctx & (~CLK_RESET_PLL_ENABLE_MASK); + writel(temp, car + CLK_RESET_PLLA_BASE); + wmb(); + writel(*ctx++, car + CLK_RESET_PLLA_BASE); + + writel(*ctx++, car + CLK_RESET_PLLD_MISC); + temp = *ctx & (~CLK_RESET_PLL_ENABLE_MASK); + writel(temp, car + CLK_RESET_PLLD_BASE); + wmb(); + temp = *ctx++; + if (temp & CLK_RESET_PLL_ENABLE_MASK) { + writel(temp, car + CLK_RESET_PLLD_BASE); + udelay(CLK_RESET_PLL_STAB_LONG_US); + } else + udelay(CLK_RESET_PLL_STAB_US); writel(CLK_RESET_CLK_OUT_ENB_L_ALL, car + CLK_RESET_CLK_OUT_ENB_L); writel(CLK_RESET_CLK_OUT_ENB_H_ALL, car + CLK_RESET_CLK_OUT_ENB_H); @@ -532,6 +576,7 @@ void tegra_clk_resume(void) writel(*ctx++, car + offs); } wmb(); + udelay(CLK_RESET_PROPAGATION_US); offs = CLK_RESET_RST_DEVICES_L; for (i=0; i