[PATCH 2/4] ARM: S5P64X0: Add Power Management support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Abhilash Kesavan <a.kesavan@xxxxxxxxxxx>

Add suspend-to-ram support for SMDK6440/50

Signed-off-by: Abhilash Kesavan <a.kesavan@xxxxxxxxxxx>
Signed-off-by: Sangbeom Kim <sbkim73@xxxxxxxxxxx>
---
 arch/arm/mach-s5p64x0/Kconfig                   |    2 +
 arch/arm/mach-s5p64x0/Makefile                  |    1 +
 arch/arm/mach-s5p64x0/include/mach/map.h        |    1 +
 arch/arm/mach-s5p64x0/include/mach/pm-core.h    |   92 ++++++++++++
 arch/arm/mach-s5p64x0/include/mach/regs-clock.h |   31 ++++
 arch/arm/mach-s5p64x0/include/mach/regs-gpio.h  |   12 ++
 arch/arm/mach-s5p64x0/irq-pm.c                  |   93 ++++++++++++
 arch/arm/mach-s5p64x0/mach-smdk6440.c           |    4 +
 arch/arm/mach-s5p64x0/mach-smdk6450.c           |    4 +
 arch/arm/mach-s5p64x0/pm.c                      |  181 +++++++++++++++++++++++
 arch/arm/mach-s5p64x0/sleep.S                   |  129 ++++++++++++++++
 11 files changed, 550 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-s5p64x0/include/mach/pm-core.h
 create mode 100644 arch/arm/mach-s5p64x0/irq-pm.c
 create mode 100644 arch/arm/mach-s5p64x0/pm.c
 create mode 100644 arch/arm/mach-s5p64x0/sleep.S

diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
index 164d278..f9532dd 100644
--- a/arch/arm/mach-s5p64x0/Kconfig
+++ b/arch/arm/mach-s5p64x0/Kconfig
@@ -36,6 +36,7 @@ config MACH_SMDK6440
 	select SAMSUNG_DEV_ADC
 	select SAMSUNG_DEV_TS
 	select S5P64X0_SETUP_I2C1
+	select SAMSUNG_WAKEMASK if PM
 	help
 	  Machine support for the Samsung SMDK6440
 
@@ -49,6 +50,7 @@ config MACH_SMDK6450
 	select SAMSUNG_DEV_ADC
 	select SAMSUNG_DEV_TS
 	select S5P64X0_SETUP_I2C1
+	select SAMSUNG_WAKEMASK if PM
 	help
 	  Machine support for the Samsung SMDK6450
 
diff --git a/arch/arm/mach-s5p64x0/Makefile b/arch/arm/mach-s5p64x0/Makefile
index 669f470..44b563c 100644
--- a/arch/arm/mach-s5p64x0/Makefile
+++ b/arch/arm/mach-s5p64x0/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_ARCH_S5P64X0)	+= setup-i2c0.o
 obj-$(CONFIG_ARCH_S5P64X0)	+= irq-eint.o
 obj-$(CONFIG_CPU_S5P6440)	+= clock-s5p6440.o
 obj-$(CONFIG_CPU_S5P6450)	+= clock-s5p6450.o
+obj-$(CONFIG_PM)		+= pm.o sleep.o irq-pm.o
 
 # machine support
 
diff --git a/arch/arm/mach-s5p64x0/include/mach/map.h b/arch/arm/mach-s5p64x0/include/mach/map.h
index 31e5341..c961025 100644
--- a/arch/arm/mach-s5p64x0/include/mach/map.h
+++ b/arch/arm/mach-s5p64x0/include/mach/map.h
@@ -49,6 +49,7 @@
 #define S5P_PA_UART5		S5P6450_PA_UART(5)
 
 #define S5P_SZ_UART		SZ_256
+#define S3C_VA_UARTx(x)		(S3C_VA_UART + ((x) * S3C_UART_OFFSET))
 
 #define S5P6440_PA_IIC0		(0xEC104000)
 #define S5P6440_PA_IIC1		(0xEC20F000)
diff --git a/arch/arm/mach-s5p64x0/include/mach/pm-core.h b/arch/arm/mach-s5p64x0/include/mach/pm-core.h
new file mode 100644
index 0000000..40d9fa0
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/include/mach/pm-core.h
@@ -0,0 +1,92 @@
+/* linux/arch/arm/mach-s5p64X0/include/mach/pm-core.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - PM core support for arch/arm/plat-samsung/pm.c
+ *
+ * Based on PM core support for S3C64XX by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <mach/regs-gpio.h>
+
+static inline void s3c_pm_debug_init_uart(void)
+{
+	u32 tmp = __raw_readl(S5P64X0_CLK_GATE_PCLK);
+
+	tmp |= S5P64X0_CLKCON_PCLK_UART0;
+	tmp |= S5P64X0_CLKCON_PCLK_UART1;
+	tmp |= S5P64X0_CLKCON_PCLK_UART2;
+	tmp |= S5P64X0_CLKCON_PCLK_UART3;
+
+	__raw_writel(tmp, S5P64X0_CLK_GATE_PCLK);
+	udelay(10);
+}
+
+static inline void s3c_pm_arch_prepare_irqs(void)
+{
+	/* VIC should have already been taken care of */
+
+	/* clear any pending EINT0 interrupts */
+	__raw_writel(__raw_readl(S5P64X0_EINT0PEND), S5P64X0_EINT0PEND);
+}
+
+static inline void s3c_pm_arch_stop_clocks(void)
+{
+}
+
+static inline void s3c_pm_arch_show_resume_irqs(void)
+{
+}
+
+/* make these defines, we currently do not have any need to change
+ * the IRQ wake controls depending on the CPU we are running on */
+
+#define s3c_irqwake_eintallow	((1 << 16) - 1)
+#define s3c_irqwake_intallow	(0)
+
+static inline void s3c_pm_arch_update_uart(void __iomem *regs,
+					   struct pm_uart_save *save)
+{
+	u32 ucon = __raw_readl(regs + S3C2410_UCON);
+	u32 ucon_clk = ucon & S3C6400_UCON_CLKMASK;
+	u32 save_clk = save->ucon & S3C6400_UCON_CLKMASK;
+	u32 new_ucon;
+	u32 delta;
+
+	/* S5P64XX UART blocks only support level interrupts, so ensure that
+	 * when we restore unused UART blocks we force the level interrupt
+	 * settigs. */
+	save->ucon |= S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL;
+
+	/* We have a constraint on changing the clock type of the UART
+	 * between UCLKx and PCLK, so ensure that when we restore UCON
+	 * that the CLK field is correctly modified if the bootloader
+	 * has changed anything.
+	 */
+	if (ucon_clk != save_clk) {
+		new_ucon = save->ucon;
+		delta = ucon_clk ^ save_clk;
+
+		/* change from UCLKx => wrong PCLK,
+		 * either UCLK can be tested for by a bit-test
+		 * with UCLK0 */
+		if (ucon_clk & S3C6400_UCON_UCLK0 &&
+		    !(save_clk & S3C6400_UCON_UCLK0) &&
+		    delta & S3C6400_UCON_PCLK2) {
+			new_ucon &= ~S3C6400_UCON_UCLK0;
+		} else if (delta == S3C6400_UCON_PCLK2) {
+			/* as an precaution, don't change from
+			 * PCLK2 => PCLK or vice-versa */
+			new_ucon ^= S3C6400_UCON_PCLK2;
+		}
+
+		S3C_PMDBG("ucon change %04x => %04x (save=%04x)\n",
+			  ucon, new_ucon, save->ucon);
+		save->ucon = new_ucon;
+	}
+}
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
index a133f22..1d23f9a 100644
--- a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
@@ -41,17 +41,48 @@
 #define S5P6450_DPLL_CON		S5P_CLKREG(0x50)
 #define S5P6450_DPLL_CON_K		S5P_CLKREG(0x54)
 
+#define S5P64X0_AHB_CON0		S5P_CLKREG(0x100)
 #define S5P64X0_CLK_SRC1		S5P_CLKREG(0x10C)
 
 #define S5P64X0_SYS_ID			S5P_CLKREG(0x118)
 #define S5P64X0_SYS_OTHERS		S5P_CLKREG(0x11C)
+#define S5P64X0_WAKEUP_STAT		S5P_CLKREG(0x908)
 
 #define S5P64X0_PWR_CFG			S5P_CLKREG(0x804)
+#define S5P64X0_EINT_WAKEUP_MASK	S5P_CLKREG(0x808)
+#define S5P64X0_SLEEP_CFG		S5P_CLKREG(0x818)
+#define S5P64X0_PWR_STABLE		S5P_CLKREG(0x828)
+
 #define S5P64X0_OTHERS			S5P_CLKREG(0x900)
+#define S5P64X0_INFORM0			S5P_CLKREG(0xA00)
 
 #define S5P64X0_CLKDIV0_HCLK_SHIFT	(8)
 #define S5P64X0_CLKDIV0_HCLK_MASK	(0xF << S5P64X0_CLKDIV0_HCLK_SHIFT)
 
+/* HCLK GATE Registers */
+#define S5P64X0_CLKCON_HCLK1_FIMGVG	(1<<2)
+#define S5P64X0_CLKCON_SCLK1_FIMGVG	(1<<2)
+
+/* PCLK GATE Registers */
+#define S5P64X0_CLKCON_PCLK_UART3	(1<<4)
+#define S5P64X0_CLKCON_PCLK_UART2	(1<<3)
+#define S5P64X0_CLKCON_PCLK_UART1	(1<<2)
+#define S5P64X0_CLKCON_PCLK_UART0	(1<<1)
+
+#define S5P64X0_PWRCFG_MMC1_DISABLE	(1 << 15)
+#define S5P64X0_PWRCFG_MMC0_DISABLE	(1 << 14)
+#define S5P64X0_PWRCFG_RTC_TICK_DISABLE	(1 << 11)
+#define S5P64X0_PWRCFG_RTC_ALRM_DISABLE	(1 << 10)
+#define S5P64X0_PWRCFG_CFG_WFI_MASK	(3 << 5)
+#define S5P64X0_PWRCFG_CFG_WFI_SLEEP	(3 << 5)
+
+#define S5P64X0_SLEEP_CFG_OSC_EN	(1 << 0)
+#define S5P64X0_PWR_STABLE_CNT_VAL_4	(4 << 0)
+
+#define S5P6450_OTHERS_DISABLE_INT	(1 << 31)
+#define S5P6450_OTHERS_RET_UART		(1 << 26)
+#define S5P6450_OTHERS_RET_MMC1		(1 << 25)
+#define S5P6450_OTHERS_RET_MMC0		(1 << 24)
 #define S5P64X0_OTHERS_USB_SIG_MASK	(1 << 16)
 
 /* Compatibility defines */
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h b/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
index ce64863..eeb539d 100644
--- a/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
@@ -52,6 +52,18 @@
 #define S5P64X0_EINT12FLTCON		(S5P_VA_GPIO + 0x220)
 #define S5P64X0_EINT12MASK		(S5P_VA_GPIO + 0x240)
 
+#define S5P64X0_SPCON0			(S5P_VA_GPIO + 0x1A0)
+#define S5P64X0_SPCON1			(S5P_VA_GPIO + 0x2B0)
+
+#define S5P64X0_MEM0CONSLP0		(S5P_VA_GPIO + 0x1C0)
+#define S5P64X0_MEM0CONSLP1		(S5P_VA_GPIO + 0x1C4)
+#define S5P64X0_MEM0DRVCON		(S5P_VA_GPIO + 0x1D0)
+#define S5P64X0_MEM1DRVCON		(S5P_VA_GPIO + 0x1D4)
+
+#define S5P64X0_EINT12CON		(S5P_VA_GPIO + 0x200)
+#define S5P64X0_EINT12FLTCON		(S5P_VA_GPIO + 0x220)
+#define S5P64X0_EINT12MASK		(S5P_VA_GPIO + 0x240)
+
 /* for LCD */
 
 #define S5P64X0_SPCON_LCD_SEL_RGB	(1 << 0)
diff --git a/arch/arm/mach-s5p64x0/irq-pm.c b/arch/arm/mach-s5p64x0/irq-pm.c
new file mode 100644
index 0000000..32ee74c
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/irq-pm.c
@@ -0,0 +1,93 @@
+/* arch/arm/mach-s5p64x0/irq-pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 - Interrupt handling Power Management
+ *
+ * Based on arch/arm/mach-s3c64xx/irq-pm.c by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/sysdev.h>
+#include <linux/serial_core.h>
+#include <linux/io.h>
+
+#include <plat/regs-serial.h>
+#include <plat/cpu.h>
+#include <plat/pm.h>
+
+#include <mach/regs-gpio.h>
+
+static struct sleep_save irq_save[] = {
+	SAVE_ITEM(S5P64X0_EINT0CON0),
+	SAVE_ITEM(S5P64X0_EINT0FLTCON0),
+	SAVE_ITEM(S5P64X0_EINT0FLTCON1),
+	SAVE_ITEM(S5P64X0_EINT0MASK),
+};
+
+static struct irq_grp_save {
+	u32	con;
+	u32	fltcon;
+	u32	mask;
+} eint_grp_save[4];
+
+static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS];
+
+static int s5p64x0_irq_pm_suspend(struct sys_device *dev, pm_message_t state)
+{
+	struct irq_grp_save *grp = eint_grp_save;
+	int i;
+
+	S3C_PMDBG("%s: suspending IRQs\n", __func__);
+
+	s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
+
+	for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
+		irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM);
+
+	for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
+		grp->con = __raw_readl(S5P64X0_EINT12CON + (i * 4));
+		grp->mask = __raw_readl(S5P64X0_EINT12MASK + (i * 4));
+		grp->fltcon = __raw_readl(S5P64X0_EINT12FLTCON + (i * 4));
+	}
+
+	return 0;
+}
+
+static int s5p64x0_irq_pm_resume(struct sys_device *dev)
+{
+	struct irq_grp_save *grp = eint_grp_save;
+	int i;
+
+	S3C_PMDBG("%s: resuming IRQs\n", __func__);
+
+	s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+
+	for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
+		__raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM);
+
+	for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
+		__raw_writel(grp->con, S5P64X0_EINT12CON + (i * 4));
+		__raw_writel(grp->mask, S5P64X0_EINT12MASK + (i * 4));
+		__raw_writel(grp->fltcon, S5P64X0_EINT12FLTCON + (i * 4));
+	}
+
+	S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
+	return 0;
+}
+
+static struct sysdev_driver s5p64x0_irq_driver = {
+	.suspend = s5p64x0_irq_pm_suspend,
+	.resume	 = s5p64x0_irq_pm_resume,
+};
+
+static int __init s5p64x0_irq_pm_init(void)
+{
+	return sysdev_driver_register(&s5p64x0_sysclass, &s5p64x0_irq_driver);
+}
+
+arch_initcall(s5p64x0_irq_pm_init);
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6440.c b/arch/arm/mach-s5p64x0/mach-smdk6440.c
index 87c3f03..ddf1898 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6440.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6440.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
+#include <linux/sysdev.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -43,6 +44,7 @@
 #include <plat/pll.h>
 #include <plat/adc.h>
 #include <plat/ts.h>
+#include <plat/pm.h>
 
 #define SMDK6440_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
 				S3C2410_UCON_RXILEVEL |		\
@@ -147,6 +149,8 @@ static void __init smdk6440_machine_init(void)
 	i2c_register_board_info(1, smdk6440_i2c_devs1,
 			ARRAY_SIZE(smdk6440_i2c_devs1));
 
+	s3c_pm_init();
+
 	platform_add_devices(smdk6440_devices, ARRAY_SIZE(smdk6440_devices));
 }
 
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
index d609f5a..969b6c3 100644
--- a/arch/arm/mach-s5p64x0/mach-smdk6450.c
+++ b/arch/arm/mach-s5p64x0/mach-smdk6450.c
@@ -22,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
+#include <linux/sysdev.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -43,6 +44,7 @@
 #include <plat/pll.h>
 #include <plat/adc.h>
 #include <plat/ts.h>
+#include <plat/pm.h>
 
 #define SMDK6450_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
 				S3C2410_UCON_RXILEVEL |		\
@@ -166,6 +168,8 @@ static void __init smdk6450_machine_init(void)
 	i2c_register_board_info(1, smdk6450_i2c_devs1,
 			ARRAY_SIZE(smdk6450_i2c_devs1));
 
+	s3c_pm_init();
+
 	platform_add_devices(smdk6450_devices, ARRAY_SIZE(smdk6450_devices));
 }
 
diff --git a/arch/arm/mach-s5p64x0/pm.c b/arch/arm/mach-s5p64x0/pm.c
new file mode 100644
index 0000000..fb964af
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/pm.c
@@ -0,0 +1,181 @@
+/* linux/arch/arm/mach-s5p64x0/pm.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *
+ * S5P64X0 Power Management Support
+ *
+ * Based on arch/arm/mach-s3c64xx/pm.c by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/suspend.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <plat/pm.h>
+#include <plat/cpu.h>
+#include <plat/regs-timer.h>
+#include <plat/wakeup-mask.h>
+
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
+#include <mach/irqs.h>
+
+static struct sleep_save core_save[] = {
+	SAVE_ITEM(S5P64X0_APLL_CON),
+	SAVE_ITEM(S5P64X0_MPLL_CON),
+	SAVE_ITEM(S5P64X0_EPLL_CON),
+	SAVE_ITEM(S5P64X0_EPLL_CON_K),
+	SAVE_ITEM(S5P64X0_CLK_SRC0),
+	SAVE_ITEM(S5P64X0_CLK_SRC1),
+	SAVE_ITEM(S5P64X0_CLK_DIV0),
+	SAVE_ITEM(S5P64X0_CLK_DIV1),
+	SAVE_ITEM(S5P64X0_CLK_DIV2),
+	SAVE_ITEM(S5P64X0_CLK_DIV3),
+	SAVE_ITEM(S5P64X0_CLK_GATE_MEM0),
+	SAVE_ITEM(S5P64X0_CLK_GATE_HCLK1),
+	SAVE_ITEM(S5P64X0_CLK_GATE_SCLK1),
+
+	SAVE_ITEM(S5P6450_DPLL_CON),
+	SAVE_ITEM(S5P6450_DPLL_CON_K),
+
+	SAVE_ITEM(S3C64XX_TINT_CSTAT),
+};
+
+static struct sleep_save misc_save[] = {
+	SAVE_ITEM(S5P64X0_AHB_CON0),
+
+	SAVE_ITEM(S5P64X0_SPCON0),
+	SAVE_ITEM(S5P64X0_SPCON1),
+
+	SAVE_ITEM(S5P64X0_MEM0CONSLP0),
+	SAVE_ITEM(S5P64X0_MEM0CONSLP1),
+	SAVE_ITEM(S5P64X0_MEM0DRVCON),
+	SAVE_ITEM(S5P64X0_MEM1DRVCON),
+};
+
+void s3c_pm_configure_extint(void)
+{
+	__raw_writel(s3c_irqwake_eintmask, S5P64X0_EINT_WAKEUP_MASK);
+}
+
+void s3c_pm_restore_core(void)
+{
+	__raw_writel(0, S5P64X0_EINT_WAKEUP_MASK);
+
+	s3c_pm_do_restore(core_save, ARRAY_SIZE(core_save));
+	s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save));
+}
+
+void s3c_pm_save_core(void)
+{
+	s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save));
+	s3c_pm_do_save(core_save, ARRAY_SIZE(core_save));
+}
+
+static void s5p64x0_cpu_suspend(void)
+{
+	unsigned long tmp;
+
+	/* issue the standby signal into the pm unit. Note, we
+	 * issue a write-buffer drain just in case */
+
+	tmp = 0;
+
+	asm("b 1f\n\t"
+	    ".align 5\n\t"
+	    "1:\n\t"
+	    "mcr p15, 0, %0, c7, c10, 5\n\t"
+	    "mcr p15, 0, %0, c7, c10, 4\n\t"
+	    "mcr p15, 0, %0, c7, c0, 4" : : "r" (tmp));
+
+	/* we should never get past here */
+
+	panic("sleep resumed to originator?");
+}
+
+/* mapping of interrupts to parts of the wakeup mask */
+static struct samsung_wakeup_mask wake_irqs[] = {
+	{ .irq = IRQ_RTC_ALARM,	.bit = S5P64X0_PWRCFG_RTC_ALRM_DISABLE, },
+	{ .irq = IRQ_RTC_TIC,	.bit = S5P64X0_PWRCFG_RTC_TICK_DISABLE, },
+	{ .irq = IRQ_HSMMC0,	.bit = S5P64X0_PWRCFG_MMC0_DISABLE, },
+	{ .irq = IRQ_HSMMC1,	.bit = S5P64X0_PWRCFG_MMC1_DISABLE, },
+};
+
+static void s5p64x0_pm_prepare(void)
+{
+	unsigned long tmp;
+
+	samsung_sync_wakemask(S5P64X0_PWR_CFG,
+			wake_irqs, ARRAY_SIZE(wake_irqs));
+
+	/* store the resume address in INFORM0 register */
+	__raw_writel(virt_to_phys(s3c_cpu_resume), S5P64X0_INFORM0);
+
+	/* setup clock gating for FIMGVG block */
+	__raw_writel((__raw_readl(S5P64X0_CLK_GATE_HCLK1) | \
+		(S5P64X0_CLKCON_HCLK1_FIMGVG)), S5P64X0_CLK_GATE_HCLK1);
+	__raw_writel((__raw_readl(S5P64X0_CLK_GATE_SCLK1) | \
+		(S5P64X0_CLKCON_SCLK1_FIMGVG)), S5P64X0_CLK_GATE_SCLK1);
+
+	/* Configure the stabilization counter with wait time required */
+	__raw_writel(S5P64X0_PWR_STABLE_CNT_VAL_4, S5P64X0_PWR_STABLE);
+
+	/* set WFI to SLEEP mode configuration */
+	tmp = __raw_readl(S5P64X0_SLEEP_CFG);
+	tmp &= ~(S5P64X0_SLEEP_CFG_OSC_EN);
+	__raw_writel(tmp, S5P64X0_SLEEP_CFG);
+
+	tmp = __raw_readl(S5P64X0_PWR_CFG);
+	tmp &= ~S5P64X0_PWRCFG_CFG_WFI_MASK;
+	tmp |= S5P64X0_PWRCFG_CFG_WFI_SLEEP;
+	__raw_writel(tmp, S5P64X0_PWR_CFG);
+
+	/* set OTHERS register to disable interrupt before going to
+	 * sleep. This register is present only in S5P6450.
+	 */
+	tmp = __raw_readl(S5P64X0_OTHERS);
+	tmp |= S5P6450_OTHERS_DISABLE_INT;
+	__raw_writel(tmp, S5P64X0_OTHERS);
+
+	/* ensure previous wakeup state is cleared before sleeping */
+	__raw_writel(__raw_readl(S5P64X0_WAKEUP_STAT), S5P64X0_WAKEUP_STAT);
+
+}
+
+static int s5p64x0_pm_add(struct sys_device *sysdev)
+{
+	pm_cpu_prep = s5p64x0_pm_prepare;
+	pm_cpu_sleep = s5p64x0_cpu_suspend;
+	pm_uart_udivslot = 1;
+
+	return 0;
+}
+
+static int s5p64x0_pm_resume(struct sys_device *dev)
+{
+	u32 tmp;
+
+	tmp = __raw_readl(S5P64X0_OTHERS);
+	tmp |= (S5P6450_OTHERS_RET_MMC0 | S5P6450_OTHERS_RET_MMC1 | \
+			S5P6450_OTHERS_RET_UART);
+	__raw_writel(tmp , S5P64X0_OTHERS);
+
+	return 0;
+}
+
+static struct sysdev_driver s5p64x0_pm_driver = {
+	.add		= s5p64x0_pm_add,
+	.resume		= s5p64x0_pm_resume,
+};
+
+static __init int s5p64x0_pm_drvinit(void)
+{
+	return sysdev_driver_register(&s5p64x0_sysclass, &s5p64x0_pm_driver);
+}
+
+arch_initcall(s5p64x0_pm_drvinit);
diff --git a/arch/arm/mach-s5p64x0/sleep.S b/arch/arm/mach-s5p64x0/sleep.S
new file mode 100644
index 0000000..d2bab06
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/sleep.S
@@ -0,0 +1,129 @@
+/* linux/arch/arm/mach-s5p64x0/sleep.S
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P64X0 Power Manager (Suspend-to-RAM) code
+ * Based on S3C64XX sleep code by:
+ *     Ben Dooks, (c) 2008 Simtec Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <mach/map.h>
+
+	.text
+
+	/* s3c_cpu_save
+	 *
+	 * Save enough processor state to allow the restart of the pm.c
+	 * code after resume.
+	 *
+	 * entry:
+	 *	r0 = pointer to the save block
+	*/
+
+ENTRY(s3c_cpu_save)
+	stmfd	sp!, { r4 - r12, lr }
+
+	mrc	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mrc	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mrc	p15, 0, r6, c2, c0, 0	@ Translation Table BASE0
+	mrc	p15, 0, r7, c2, c0, 1	@ Translation Table BASE1
+	mrc	p15, 0, r8, c2, c0, 2	@ Translation Table Control
+	mrc	p15, 0, r9, c1, c0, 0	@ Control register
+	mrc	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
+	mrc	p15, 0, r11, c1, c0, 2	@ Co-processor access controls
+
+	stmia	r0, { r4 - r13 }	@ Save CP registers and SP
+
+	@@ save our state to ram
+	bl	s3c_pm_cb_flushcache
+
+	@@ call final suspend code
+	ldr	r0, =pm_cpu_sleep
+	ldr	pc, [r0]
+
+	@@ return to the caller, after the MMU is turned on.
+	@@ restore the last bits of the stack and return.
+resume_with_mmu:
+	ldmfd	sp!, { r4 - r12, pc }	@ return, from sp from s3c_cpu_save
+
+	.data
+
+	/* the next bit is code, but it requires easy access to the
+	 * s3c_sleep_save_phys data before the MMU is switched on, so
+	 * we store the code that needs this variable in the .data where
+	 * the value can be written to (the .text segment is RO).
+	*/
+
+	.global	s3c_sleep_save_phys
+s3c_sleep_save_phys:
+	.word	0
+
+       /* sleep magic, to allow the bootloader to check for an valid
+        * image to resume to. Must be the first word before the
+        * s3c_cpu_resume entry.
+       */
+
+       .word   0x2bedf00d
+
+       /* s3c_cpu_resume
+        *
+        * resume code entry for bootloader to call
+        *
+        * we must put this code here in the data segment as we have no
+        * other way of restoring the stack pointer after sleep, and we
+        * must not write to the code segment (code is read-only)
+       */
+
+
+ENTRY(s3c_cpu_resume)
+	msr	cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE
+
+	/* __v6_setup from arch/arm/mm/proc-v6.S, ensure that the caches
+	 * are thoroughly cleaned just in case the bootloader didn't do it
+	 * for us. */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0		@ clean+invalidate D cache
+	mcr	p15, 0, r0, c7, c5, 0		@ invalidate I cache
+	mcr	p15, 0, r0, c7, c15, 0		@ clean+invalidate cache
+	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer
+	@@mcr	p15, 0, r0, c8, c7, 0		@ invalidate I + D TLBs
+	@@mcr	p15, 0, r0, c7, c7, 0		@ Invalidate I + D caches
+
+	ldr	r0, s3c_sleep_save_phys
+	ldmia	r0, { r4 - r13 }
+
+	mcr	p15, 0, r4, c13, c0, 0	@ FCSE/PID
+	mcr	p15, 0, r5, c3, c0, 0	@ Domain ID
+	mcr	p15, 0, r6, c2, c0, 0	@ Translation Table BASE0
+	mcr	p15, 0, r7, c2, c0, 1	@ Translation Table BASE1
+	mcr	p15, 0, r8, c2, c0, 2	@ Translation Table Control
+	mcr	p15, 0, r10, c1, c0, 1	@ Auxiliary control register
+
+	mov	r0, #0			@ restore copro access controls
+	mcr	p15, 0, r11, c1, c0, 2	@ Co-processor access controls
+	mcr 	p15, 0, r0, c7, c5, 4
+
+	ldr	r2, =resume_with_mmu
+	mcr	p15, 0, r9, c1, c0, 0		/* turn mmu back on */
+	nop
+	mov	pc, r2				/* jump back */
+
+	.end
-- 
1.6.6.1

--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux SoC Development]     [Linux Rockchip Development]     [Linux USB Development]     [Video for Linux]     [Linux Audio Users]     [Linux SCSI]     [Yosemite News]

  Powered by Linux