diff options
author | Gary King <gking@nvidia.com> | 2010-05-27 15:14:06 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-05-27 21:40:53 -0700 |
commit | 3ef10ea5a7707480519eb04b6602e38f2d006b36 (patch) | |
tree | a87a51131bb5f61e5c0ba0f5cd2d05543f2a2b82 /arch | |
parent | 8a4c20e35a435e8744618a19fd51d3d23ac5d16b (diff) |
[ARM/tegra] suspend: add suspend support for clock and reset block
EMC clock source is not saved, because the final low-power entry and
BootROM restore (out of LP0) preserves this itself.
Change-Id: I34d16a362ba58c9ea50715ef6dd103ab854b1251
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/clock_nvrm.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/clock_nvrm.c b/arch/arm/mach-tegra/clock_nvrm.c index 1d32c71dd5bc..69a5c8aeb8dd 100644 --- a/arch/arm/mach-tegra/clock_nvrm.c +++ b/arch/arm/mach-tegra/clock_nvrm.c @@ -411,3 +411,101 @@ void __init tegra_init_clock(void) on_each_cpu(twd_set_prescaler, NULL, true); #endif } + +#ifdef CONFIG_PM +#define CLK_RESET_RST_DEVICES_L 0x04 +#define CLK_RESET_RST_DEVICES_NUM 3 + +#define CLK_RESET_CLK_OUT_ENB_L 0x10 +#define CLK_RESET_CLK_OUT_ENB_H 0x14 +#define CLK_RESET_CLK_OUT_ENB_U 0x18 +#define CLK_RESET_CLK_OUT_ENB_L_ALL 0xbffffff9ul +#define CLK_RESET_CLK_OUT_ENB_H_ALL 0xfefffff7ul +#define CLK_RESET_CLK_OUT_ENB_U_ALL 0x77f01bfful +#define CLK_RESET_CLK_OUT_ENB_NUM 3 + +#define CLK_RESET_CLK_MASK_ARM 0x44 +#define CLK_RESET_MISC_CLK_ENB 0x48 +#define CLK_RESET_OSC_CTRL 0x50 +#define CLK_RESET_OSC_CTRL_MASK 0x3f2 /* drive strength & bypass */ + +#define CLK_RESET_CLK_SOURCE_I2S1 0x100 +#define CLK_RESET_CLK_SOURCE_EMC 0x19c +#define CLK_RESET_CLK_SOURCE_OSC 0x1fc +#define CLK_RESET_CLK_SOURCE_NUM \ + (((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_CLK_SOURCE_NUM + 3]; + +void tegra_clk_suspend(void) +{ + void __iomem *car = IO_ADDRESS(TEGRA_CLK_RESET_BASE); + unsigned long offs, i; + u32 *ctx = clk_rst; + + *ctx++ = readl(car + CLK_RESET_OSC_CTRL) & CLK_RESET_OSC_CTRL_MASK; + + for (offs=CLK_RESET_CLK_SOURCE_I2S1; + offs<=CLK_RESET_CLK_SOURCE_OSC; offs+=4) { + + if (offs==CLK_RESET_CLK_SOURCE_EMC) + continue; + + *ctx++ = readl(car + offs); + } + + offs = CLK_RESET_RST_DEVICES_L; + for (i=0; i<CLK_RESET_RST_DEVICES_NUM; i++) + *ctx++ = readl(car + offs + i*4); + + offs = CLK_RESET_CLK_OUT_ENB_L; + for (i=0; i<CLK_RESET_CLK_OUT_ENB_NUM; i++) + *ctx++ = readl(car + offs + i*4); + + *ctx++ = readl(car + CLK_RESET_MISC_CLK_ENB); + *ctx++ = readl(car + CLK_RESET_CLK_MASK_ARM); + + BUG_ON(ctx-clk_rst != ARRAY_SIZE(clk_rst)); +} + +void tegra_clk_resume(void) +{ + void __iomem *car = IO_ADDRESS(TEGRA_CLK_RESET_BASE); + unsigned long offs, i; + u32 *ctx = clk_rst; + u32 temp; + + temp = readl(car + CLK_RESET_OSC_CTRL) & ~CLK_RESET_OSC_CTRL_MASK; + temp |= *ctx++; + writel(temp, car + CLK_RESET_OSC_CTRL); + + 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); + writel(CLK_RESET_CLK_OUT_ENB_U_ALL, car + CLK_RESET_CLK_OUT_ENB_U); + wmb(); + + for (offs=CLK_RESET_CLK_SOURCE_I2S1; + offs<=CLK_RESET_CLK_SOURCE_OSC; offs+=4) { + if (offs==CLK_RESET_CLK_SOURCE_EMC) + continue; + writel(*ctx++, car + offs); + } + wmb(); + + offs = CLK_RESET_RST_DEVICES_L; + for (i=0; i<CLK_RESET_RST_DEVICES_NUM; i++) + writel(*ctx++, car + offs + i*4); + wmb(); + + offs = CLK_RESET_CLK_OUT_ENB_L; + for (i=0; i<CLK_RESET_CLK_OUT_ENB_NUM; i++) + writel(*ctx++, car + offs + i*4); + wmb(); + + writel(*ctx++, car + CLK_RESET_MISC_CLK_ENB); + writel(*ctx++, car + CLK_RESET_CLK_MASK_ARM); + BUG_ON(ctx-clk_rst != ARRAY_SIZE(clk_rst)); +} + +#endif |