summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-05-27 15:14:06 -0700
committerGary King <gking@nvidia.com>2010-05-27 21:40:53 -0700
commit3ef10ea5a7707480519eb04b6602e38f2d006b36 (patch)
treea87a51131bb5f61e5c0ba0f5cd2d05543f2a2b82 /arch
parent8a4c20e35a435e8744618a19fd51d3d23ac5d16b (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.c98
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