aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s5p64x0
diff options
context:
space:
mode:
authorAbhilash Kesavan <a.kesavan@samsung.com>2011-10-04 07:30:22 -0400
committerKukjin Kim <kgene.kim@samsung.com>2011-10-04 07:31:24 -0400
commit6b6844dd54e4196dd9818bc63b319f93c37a08be (patch)
treec01749ce969969da4273a51cc054a089d60eb83b /arch/arm/mach-s5p64x0
parente2e13621b267f88f69917780e107725d2c0ecad9 (diff)
ARM: S5P64X0: Add Power Management support
Add suspend-to-ram support for SMDK6440/50 Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'arch/arm/mach-s5p64x0')
-rw-r--r--arch/arm/mach-s5p64x0/Kconfig4
-rw-r--r--arch/arm/mach-s5p64x0/Makefile1
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/map.h1
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/pm-core.h117
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/regs-clock.h33
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/regs-gpio.h17
-rw-r--r--arch/arm/mach-s5p64x0/irq-eint.c2
-rw-r--r--arch/arm/mach-s5p64x0/irq-pm.c92
-rw-r--r--arch/arm/mach-s5p64x0/pm.c204
9 files changed, 471 insertions, 0 deletions
diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
index e361c41314e9..18690c5f99e6 100644
--- a/arch/arm/mach-s5p64x0/Kconfig
+++ b/arch/arm/mach-s5p64x0/Kconfig
@@ -11,6 +11,8 @@ config CPU_S5P6440
11 bool 11 bool
12 select SAMSUNG_DMADEV 12 select SAMSUNG_DMADEV
13 select S5P_HRT 13 select S5P_HRT
14 select S5P_SLEEP if PM
15 select SAMSUNG_WAKEMASK if PM
14 help 16 help
15 Enable S5P6440 CPU support 17 Enable S5P6440 CPU support
16 18
@@ -18,6 +20,8 @@ config CPU_S5P6450
18 bool 20 bool
19 select SAMSUNG_DMADEV 21 select SAMSUNG_DMADEV
20 select S5P_HRT 22 select S5P_HRT
23 select S5P_SLEEP if PM
24 select SAMSUNG_WAKEMASK if PM
21 help 25 help
22 Enable S5P6450 CPU support 26 Enable S5P6450 CPU support
23 27
diff --git a/arch/arm/mach-s5p64x0/Makefile b/arch/arm/mach-s5p64x0/Makefile
index eb7468012a37..a1324d8dc4e0 100644
--- a/arch/arm/mach-s5p64x0/Makefile
+++ b/arch/arm/mach-s5p64x0/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_S5P64X0) += cpu.o init.o clock.o dma.o
16obj-$(CONFIG_ARCH_S5P64X0) += setup-i2c0.o irq-eint.o 16obj-$(CONFIG_ARCH_S5P64X0) += setup-i2c0.o irq-eint.o
17obj-$(CONFIG_CPU_S5P6440) += clock-s5p6440.o 17obj-$(CONFIG_CPU_S5P6440) += clock-s5p6440.o
18obj-$(CONFIG_CPU_S5P6450) += clock-s5p6450.o 18obj-$(CONFIG_CPU_S5P6450) += clock-s5p6450.o
19obj-$(CONFIG_PM) += pm.o irq-pm.o
19 20
20# machine support 21# machine support
21 22
diff --git a/arch/arm/mach-s5p64x0/include/mach/map.h b/arch/arm/mach-s5p64x0/include/mach/map.h
index c5ef50c26291..4d3ac8a3709d 100644
--- a/arch/arm/mach-s5p64x0/include/mach/map.h
+++ b/arch/arm/mach-s5p64x0/include/mach/map.h
@@ -88,5 +88,6 @@
88#define S5P_PA_UART5 S5P6450_PA_UART(5) 88#define S5P_PA_UART5 S5P6450_PA_UART(5)
89 89
90#define S5P_SZ_UART SZ_256 90#define S5P_SZ_UART SZ_256
91#define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
91 92
92#endif /* __ASM_ARCH_MAP_H */ 93#endif /* __ASM_ARCH_MAP_H */
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 000000000000..e52f7545d3aa
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/include/mach/pm-core.h
@@ -0,0 +1,117 @@
1/* linux/arch/arm/mach-s5p64x0/include/mach/pm-core.h
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * S5P64X0 - PM core support for arch/arm/plat-samsung/pm.c
7 *
8 * Based on PM core support for S3C64XX by Ben Dooks
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <mach/regs-gpio.h>
16
17static inline void s3c_pm_debug_init_uart(void)
18{
19 u32 tmp = __raw_readl(S5P64X0_CLK_GATE_PCLK);
20
21 /*
22 * As a note, since the S5P64X0 UARTs generally have multiple
23 * clock sources, we simply enable PCLK at the moment and hope
24 * that the resume settings for the UART are suitable for the
25 * use with PCLK.
26 */
27 tmp |= S5P64X0_CLK_GATE_PCLK_UART0;
28 tmp |= S5P64X0_CLK_GATE_PCLK_UART1;
29 tmp |= S5P64X0_CLK_GATE_PCLK_UART2;
30 tmp |= S5P64X0_CLK_GATE_PCLK_UART3;
31
32 __raw_writel(tmp, S5P64X0_CLK_GATE_PCLK);
33 udelay(10);
34}
35
36static inline void s3c_pm_arch_prepare_irqs(void)
37{
38 /* VIC should have already been taken care of */
39
40 /* clear any pending EINT0 interrupts */
41 __raw_writel(__raw_readl(S5P64X0_EINT0PEND), S5P64X0_EINT0PEND);
42}
43
44static inline void s3c_pm_arch_stop_clocks(void) { }
45static inline void s3c_pm_arch_show_resume_irqs(void) { }
46
47/*
48 * make these defines, we currently do not have any need to change
49 * the IRQ wake controls depending on the CPU we are running on
50 */
51#define s3c_irqwake_eintallow ((1 << 16) - 1)
52#define s3c_irqwake_intallow (~0)
53
54static inline void s3c_pm_arch_update_uart(void __iomem *regs,
55 struct pm_uart_save *save)
56{
57 u32 ucon = __raw_readl(regs + S3C2410_UCON);
58 u32 ucon_clk = ucon & S3C6400_UCON_CLKMASK;
59 u32 save_clk = save->ucon & S3C6400_UCON_CLKMASK;
60 u32 new_ucon;
61 u32 delta;
62
63 /*
64 * S5P64X0 UART blocks only support level interrupts, so ensure that
65 * when we restore unused UART blocks we force the level interrupt
66 * settings.
67 */
68 save->ucon |= S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL;
69
70 /*
71 * We have a constraint on changing the clock type of the UART
72 * between UCLKx and PCLK, so ensure that when we restore UCON
73 * that the CLK field is correctly modified if the bootloader
74 * has changed anything.
75 */
76 if (ucon_clk != save_clk) {
77 new_ucon = save->ucon;
78 delta = ucon_clk ^ save_clk;
79
80 /*
81 * change from UCLKx => wrong PCLK,
82 * either UCLK can be tested for by a bit-test
83 * with UCLK0
84 */
85 if (ucon_clk & S3C6400_UCON_UCLK0 &&
86 !(save_clk & S3C6400_UCON_UCLK0) &&
87 delta & S3C6400_UCON_PCLK2) {
88 new_ucon &= ~S3C6400_UCON_UCLK0;
89 } else if (delta == S3C6400_UCON_PCLK2) {
90 /*
91 * as a precaution, don't change from
92 * PCLK2 => PCLK or vice-versa
93 */
94 new_ucon ^= S3C6400_UCON_PCLK2;
95 }
96
97 S3C_PMDBG("ucon change %04x => %04x (save=%04x)\n",
98 ucon, new_ucon, save->ucon);
99 save->ucon = new_ucon;
100 }
101}
102
103static inline void s3c_pm_restored_gpios(void)
104{
105 /* ensure sleep mode has been cleared from the system */
106 __raw_writel(0, S5P64X0_SLPEN);
107}
108
109static inline void samsung_pm_saved_gpios(void)
110{
111 /*
112 * turn on the sleep mode and keep it there, as it seems that during
113 * suspend the xCON registers get re-set and thus you can end up with
114 * problems between going to sleep and resuming.
115 */
116 __raw_writel(S5P64X0_SLPEN_USE_xSLP, S5P64X0_SLPEN);
117}
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
index a133f22fa155..bd91112c813c 100644
--- a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
@@ -41,17 +41,50 @@
41#define S5P6450_DPLL_CON S5P_CLKREG(0x50) 41#define S5P6450_DPLL_CON S5P_CLKREG(0x50)
42#define S5P6450_DPLL_CON_K S5P_CLKREG(0x54) 42#define S5P6450_DPLL_CON_K S5P_CLKREG(0x54)
43 43
44#define S5P64X0_AHB_CON0 S5P_CLKREG(0x100)
44#define S5P64X0_CLK_SRC1 S5P_CLKREG(0x10C) 45#define S5P64X0_CLK_SRC1 S5P_CLKREG(0x10C)
45 46
46#define S5P64X0_SYS_ID S5P_CLKREG(0x118) 47#define S5P64X0_SYS_ID S5P_CLKREG(0x118)
47#define S5P64X0_SYS_OTHERS S5P_CLKREG(0x11C) 48#define S5P64X0_SYS_OTHERS S5P_CLKREG(0x11C)
48 49
49#define S5P64X0_PWR_CFG S5P_CLKREG(0x804) 50#define S5P64X0_PWR_CFG S5P_CLKREG(0x804)
51#define S5P64X0_EINT_WAKEUP_MASK S5P_CLKREG(0x808)
52#define S5P64X0_SLEEP_CFG S5P_CLKREG(0x818)
53#define S5P64X0_PWR_STABLE S5P_CLKREG(0x828)
54
50#define S5P64X0_OTHERS S5P_CLKREG(0x900) 55#define S5P64X0_OTHERS S5P_CLKREG(0x900)
56#define S5P64X0_WAKEUP_STAT S5P_CLKREG(0x908)
57
58#define S5P64X0_INFORM0 S5P_CLKREG(0xA00)
51 59
52#define S5P64X0_CLKDIV0_HCLK_SHIFT (8) 60#define S5P64X0_CLKDIV0_HCLK_SHIFT (8)
53#define S5P64X0_CLKDIV0_HCLK_MASK (0xF << S5P64X0_CLKDIV0_HCLK_SHIFT) 61#define S5P64X0_CLKDIV0_HCLK_MASK (0xF << S5P64X0_CLKDIV0_HCLK_SHIFT)
54 62
63/* HCLK GATE Registers */
64#define S5P64X0_CLK_GATE_HCLK1_FIMGVG (1 << 2)
65#define S5P64X0_CLK_GATE_SCLK1_FIMGVG (1 << 2)
66
67/* PCLK GATE Registers */
68#define S5P64X0_CLK_GATE_PCLK_UART3 (1 << 4)
69#define S5P64X0_CLK_GATE_PCLK_UART2 (1 << 3)
70#define S5P64X0_CLK_GATE_PCLK_UART1 (1 << 2)
71#define S5P64X0_CLK_GATE_PCLK_UART0 (1 << 1)
72
73#define S5P64X0_PWR_CFG_MMC1_DISABLE (1 << 15)
74#define S5P64X0_PWR_CFG_MMC0_DISABLE (1 << 14)
75#define S5P64X0_PWR_CFG_RTC_TICK_DISABLE (1 << 11)
76#define S5P64X0_PWR_CFG_RTC_ALRM_DISABLE (1 << 10)
77#define S5P64X0_PWR_CFG_WFI_MASK (3 << 5)
78#define S5P64X0_PWR_CFG_WFI_SLEEP (3 << 5)
79
80#define S5P64X0_SLEEP_CFG_OSC_EN (1 << 0)
81
82#define S5P64X0_PWR_STABLE_PWR_CNT_VAL4 (4 << 0)
83
84#define S5P6450_OTHERS_DISABLE_INT (1 << 31)
85#define S5P64X0_OTHERS_RET_UART (1 << 26)
86#define S5P64X0_OTHERS_RET_MMC1 (1 << 25)
87#define S5P64X0_OTHERS_RET_MMC0 (1 << 24)
55#define S5P64X0_OTHERS_USB_SIG_MASK (1 << 16) 88#define S5P64X0_OTHERS_USB_SIG_MASK (1 << 16)
56 89
57/* Compatibility defines */ 90/* 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 88269ec70a38..cfdfa4fdadf2 100644
--- a/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
+++ b/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
@@ -37,15 +37,32 @@
37#define S5P64X0_SPCON0 (S5P_VA_GPIO + 0x1A0) 37#define S5P64X0_SPCON0 (S5P_VA_GPIO + 0x1A0)
38#define S5P64X0_SPCON0_LCD_SEL_MASK (0x3 << 0) 38#define S5P64X0_SPCON0_LCD_SEL_MASK (0x3 << 0)
39#define S5P64X0_SPCON0_LCD_SEL_RGB (0x1 << 0) 39#define S5P64X0_SPCON0_LCD_SEL_RGB (0x1 << 0)
40#define S5P64X0_SPCON1 (S5P_VA_GPIO + 0x2B0)
41
42#define S5P64X0_MEM0CONSLP0 (S5P_VA_GPIO + 0x1C0)
43#define S5P64X0_MEM0CONSLP1 (S5P_VA_GPIO + 0x1C4)
44#define S5P64X0_MEM0DRVCON (S5P_VA_GPIO + 0x1D0)
45#define S5P64X0_MEM1DRVCON (S5P_VA_GPIO + 0x1D4)
46
47#define S5P64X0_EINT12CON (S5P_VA_GPIO + 0x200)
48#define S5P64X0_EINT12FLTCON (S5P_VA_GPIO + 0x220)
49#define S5P64X0_EINT12MASK (S5P_VA_GPIO + 0x240)
40 50
41/* External interrupt control registers for group0 */ 51/* External interrupt control registers for group0 */
42 52
43#define EINT0CON0_OFFSET (0x900) 53#define EINT0CON0_OFFSET (0x900)
54#define EINT0FLTCON0_OFFSET (0x910)
55#define EINT0FLTCON1_OFFSET (0x914)
44#define EINT0MASK_OFFSET (0x920) 56#define EINT0MASK_OFFSET (0x920)
45#define EINT0PEND_OFFSET (0x924) 57#define EINT0PEND_OFFSET (0x924)
46 58
47#define S5P64X0_EINT0CON0 (S5P_VA_GPIO + EINT0CON0_OFFSET) 59#define S5P64X0_EINT0CON0 (S5P_VA_GPIO + EINT0CON0_OFFSET)
60#define S5P64X0_EINT0FLTCON0 (S5P_VA_GPIO + EINT0FLTCON0_OFFSET)
61#define S5P64X0_EINT0FLTCON1 (S5P_VA_GPIO + EINT0FLTCON1_OFFSET)
48#define S5P64X0_EINT0MASK (S5P_VA_GPIO + EINT0MASK_OFFSET) 62#define S5P64X0_EINT0MASK (S5P_VA_GPIO + EINT0MASK_OFFSET)
49#define S5P64X0_EINT0PEND (S5P_VA_GPIO + EINT0PEND_OFFSET) 63#define S5P64X0_EINT0PEND (S5P_VA_GPIO + EINT0PEND_OFFSET)
50 64
65#define S5P64X0_SLPEN (S5P_VA_GPIO + 0x930)
66#define S5P64X0_SLPEN_USE_xSLP (1 << 0)
67
51#endif /* __ASM_ARCH_REGS_GPIO_H */ 68#endif /* __ASM_ARCH_REGS_GPIO_H */
diff --git a/arch/arm/mach-s5p64x0/irq-eint.c b/arch/arm/mach-s5p64x0/irq-eint.c
index 494e1a8f6f6d..275dc74f4a7b 100644
--- a/arch/arm/mach-s5p64x0/irq-eint.c
+++ b/arch/arm/mach-s5p64x0/irq-eint.c
@@ -20,6 +20,7 @@
20#include <plat/cpu.h> 20#include <plat/cpu.h>
21#include <plat/regs-irqtype.h> 21#include <plat/regs-irqtype.h>
22#include <plat/gpio-cfg.h> 22#include <plat/gpio-cfg.h>
23#include <plat/pm.h>
23 24
24#include <mach/regs-gpio.h> 25#include <mach/regs-gpio.h>
25#include <mach/regs-clock.h> 26#include <mach/regs-clock.h>
@@ -134,6 +135,7 @@ static int s5p64x0_alloc_gc(void)
134 ct->chip.irq_mask = irq_gc_mask_set_bit; 135 ct->chip.irq_mask = irq_gc_mask_set_bit;
135 ct->chip.irq_unmask = irq_gc_mask_clr_bit; 136 ct->chip.irq_unmask = irq_gc_mask_clr_bit;
136 ct->chip.irq_set_type = s5p64x0_irq_eint_set_type; 137 ct->chip.irq_set_type = s5p64x0_irq_eint_set_type;
138 ct->chip.irq_set_wake = s3c_irqext_wake;
137 ct->regs.ack = EINT0PEND_OFFSET; 139 ct->regs.ack = EINT0PEND_OFFSET;
138 ct->regs.mask = EINT0MASK_OFFSET; 140 ct->regs.mask = EINT0MASK_OFFSET;
139 irq_setup_generic_chip(gc, IRQ_MSK(16), IRQ_GC_INIT_MASK_CACHE, 141 irq_setup_generic_chip(gc, IRQ_MSK(16), IRQ_GC_INIT_MASK_CACHE,
diff --git a/arch/arm/mach-s5p64x0/irq-pm.c b/arch/arm/mach-s5p64x0/irq-pm.c
new file mode 100644
index 000000000000..3e6f2456ee9d
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/irq-pm.c
@@ -0,0 +1,92 @@
1/* linux/arch/arm/mach-s5p64x0/irq-pm.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * S5P64X0 - Interrupt handling Power Management
7 *
8 * Based on arch/arm/mach-s3c64xx/irq-pm.c by Ben Dooks
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14
15#include <linux/syscore_ops.h>
16#include <linux/serial_core.h>
17#include <linux/io.h>
18
19#include <plat/regs-serial.h>
20#include <plat/pm.h>
21
22#include <mach/regs-gpio.h>
23
24static struct sleep_save irq_save[] = {
25 SAVE_ITEM(S5P64X0_EINT0CON0),
26 SAVE_ITEM(S5P64X0_EINT0FLTCON0),
27 SAVE_ITEM(S5P64X0_EINT0FLTCON1),
28 SAVE_ITEM(S5P64X0_EINT0MASK),
29};
30
31static struct irq_grp_save {
32 u32 con;
33 u32 fltcon;
34 u32 mask;
35} eint_grp_save[4];
36
37static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS];
38
39static int s5p64x0_irq_pm_suspend(void)
40{
41 struct irq_grp_save *grp = eint_grp_save;
42 int i;
43
44 S3C_PMDBG("%s: suspending IRQs\n", __func__);
45
46 s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
47
48 for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
49 irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM);
50
51 for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
52 grp->con = __raw_readl(S5P64X0_EINT12CON + (i * 4));
53 grp->mask = __raw_readl(S5P64X0_EINT12MASK + (i * 4));
54 grp->fltcon = __raw_readl(S5P64X0_EINT12FLTCON + (i * 4));
55 }
56
57 return 0;
58}
59
60static void s5p64x0_irq_pm_resume(void)
61{
62 struct irq_grp_save *grp = eint_grp_save;
63 int i;
64
65 S3C_PMDBG("%s: resuming IRQs\n", __func__);
66
67 s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
68
69 for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++)
70 __raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM);
71
72 for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) {
73 __raw_writel(grp->con, S5P64X0_EINT12CON + (i * 4));
74 __raw_writel(grp->mask, S5P64X0_EINT12MASK + (i * 4));
75 __raw_writel(grp->fltcon, S5P64X0_EINT12FLTCON + (i * 4));
76 }
77
78 S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
79}
80
81static struct syscore_ops s5p64x0_irq_syscore_ops = {
82 .suspend = s5p64x0_irq_pm_suspend,
83 .resume = s5p64x0_irq_pm_resume,
84};
85
86static int __init s5p64x0_syscore_init(void)
87{
88 register_syscore_ops(&s5p64x0_irq_syscore_ops);
89
90 return 0;
91}
92core_initcall(s5p64x0_syscore_init);
diff --git a/arch/arm/mach-s5p64x0/pm.c b/arch/arm/mach-s5p64x0/pm.c
new file mode 100644
index 000000000000..69927243d25f
--- /dev/null
+++ b/arch/arm/mach-s5p64x0/pm.c
@@ -0,0 +1,204 @@
1/* linux/arch/arm/mach-s5p64x0/pm.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * S5P64X0 Power Management Support
7 *
8 * Based on arch/arm/mach-s3c64xx/pm.c by Ben Dooks
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13*/
14
15#include <linux/suspend.h>
16#include <linux/syscore_ops.h>
17#include <linux/io.h>
18
19#include <plat/cpu.h>
20#include <plat/pm.h>
21#include <plat/regs-timer.h>
22#include <plat/wakeup-mask.h>
23
24#include <mach/regs-clock.h>
25#include <mach/regs-gpio.h>
26
27static struct sleep_save s5p64x0_core_save[] = {
28 SAVE_ITEM(S5P64X0_APLL_CON),
29 SAVE_ITEM(S5P64X0_MPLL_CON),
30 SAVE_ITEM(S5P64X0_EPLL_CON),
31 SAVE_ITEM(S5P64X0_EPLL_CON_K),
32 SAVE_ITEM(S5P64X0_CLK_SRC0),
33 SAVE_ITEM(S5P64X0_CLK_SRC1),
34 SAVE_ITEM(S5P64X0_CLK_DIV0),
35 SAVE_ITEM(S5P64X0_CLK_DIV1),
36 SAVE_ITEM(S5P64X0_CLK_DIV2),
37 SAVE_ITEM(S5P64X0_CLK_DIV3),
38 SAVE_ITEM(S5P64X0_CLK_GATE_MEM0),
39 SAVE_ITEM(S5P64X0_CLK_GATE_HCLK1),
40 SAVE_ITEM(S5P64X0_CLK_GATE_SCLK1),
41};
42
43static struct sleep_save s5p64x0_misc_save[] = {
44 SAVE_ITEM(S5P64X0_AHB_CON0),
45 SAVE_ITEM(S5P64X0_SPCON0),
46 SAVE_ITEM(S5P64X0_SPCON1),
47 SAVE_ITEM(S5P64X0_MEM0CONSLP0),
48 SAVE_ITEM(S5P64X0_MEM0CONSLP1),
49 SAVE_ITEM(S5P64X0_MEM0DRVCON),
50 SAVE_ITEM(S5P64X0_MEM1DRVCON),
51
52 SAVE_ITEM(S3C64XX_TINT_CSTAT),
53};
54
55/* DPLL is present only in S5P6450 */
56static struct sleep_save s5p6450_core_save[] = {
57 SAVE_ITEM(S5P6450_DPLL_CON),
58 SAVE_ITEM(S5P6450_DPLL_CON_K),
59};
60
61void s3c_pm_configure_extint(void)
62{
63 __raw_writel(s3c_irqwake_eintmask, S5P64X0_EINT_WAKEUP_MASK);
64}
65
66void s3c_pm_restore_core(void)
67{
68 __raw_writel(0, S5P64X0_EINT_WAKEUP_MASK);
69
70 s3c_pm_do_restore_core(s5p64x0_core_save,
71 ARRAY_SIZE(s5p64x0_core_save));
72
73 if (soc_is_s5p6450())
74 s3c_pm_do_restore_core(s5p6450_core_save,
75 ARRAY_SIZE(s5p6450_core_save));
76
77 s3c_pm_do_restore(s5p64x0_misc_save, ARRAY_SIZE(s5p64x0_misc_save));
78}
79
80void s3c_pm_save_core(void)
81{
82 s3c_pm_do_save(s5p64x0_misc_save, ARRAY_SIZE(s5p64x0_misc_save));
83
84 if (soc_is_s5p6450())
85 s3c_pm_do_save(s5p6450_core_save,
86 ARRAY_SIZE(s5p6450_core_save));
87
88 s3c_pm_do_save(s5p64x0_core_save, ARRAY_SIZE(s5p64x0_core_save));
89}
90
91static int s5p64x0_cpu_suspend(unsigned long arg)
92{
93 unsigned long tmp = 0;
94
95 /*
96 * Issue the standby signal into the pm unit. Note, we
97 * issue a write-buffer drain just in case.
98 */
99 asm("b 1f\n\t"
100 ".align 5\n\t"
101 "1:\n\t"
102 "mcr p15, 0, %0, c7, c10, 5\n\t"
103 "mcr p15, 0, %0, c7, c10, 4\n\t"
104 "mcr p15, 0, %0, c7, c0, 4" : : "r" (tmp));
105
106 /* we should never get past here */
107 panic("sleep resumed to originator?");
108}
109
110/* mapping of interrupts to parts of the wakeup mask */
111static struct samsung_wakeup_mask s5p64x0_wake_irqs[] = {
112 { .irq = IRQ_RTC_ALARM, .bit = S5P64X0_PWR_CFG_RTC_ALRM_DISABLE, },
113 { .irq = IRQ_RTC_TIC, .bit = S5P64X0_PWR_CFG_RTC_TICK_DISABLE, },
114 { .irq = IRQ_HSMMC0, .bit = S5P64X0_PWR_CFG_MMC0_DISABLE, },
115 { .irq = IRQ_HSMMC1, .bit = S5P64X0_PWR_CFG_MMC1_DISABLE, },
116};
117
118static void s5p64x0_pm_prepare(void)
119{
120 u32 tmp;
121
122 samsung_sync_wakemask(S5P64X0_PWR_CFG,
123 s5p64x0_wake_irqs, ARRAY_SIZE(s5p64x0_wake_irqs));
124
125 /* store the resume address in INFORM0 register */
126 __raw_writel(virt_to_phys(s3c_cpu_resume), S5P64X0_INFORM0);
127
128 /* setup clock gating for FIMGVG block */
129 __raw_writel((__raw_readl(S5P64X0_CLK_GATE_HCLK1) | \
130 (S5P64X0_CLK_GATE_HCLK1_FIMGVG)), S5P64X0_CLK_GATE_HCLK1);
131 __raw_writel((__raw_readl(S5P64X0_CLK_GATE_SCLK1) | \
132 (S5P64X0_CLK_GATE_SCLK1_FIMGVG)), S5P64X0_CLK_GATE_SCLK1);
133
134 /* Configure the stabilization counter with wait time required */
135 __raw_writel(S5P64X0_PWR_STABLE_PWR_CNT_VAL4, S5P64X0_PWR_STABLE);
136
137 /* set WFI to SLEEP mode configuration */
138 tmp = __raw_readl(S5P64X0_SLEEP_CFG);
139 tmp &= ~(S5P64X0_SLEEP_CFG_OSC_EN);
140 __raw_writel(tmp, S5P64X0_SLEEP_CFG);
141
142 tmp = __raw_readl(S5P64X0_PWR_CFG);
143 tmp &= ~(S5P64X0_PWR_CFG_WFI_MASK);
144 tmp |= S5P64X0_PWR_CFG_WFI_SLEEP;
145 __raw_writel(tmp, S5P64X0_PWR_CFG);
146
147 /*
148 * set OTHERS register to disable interrupt before going to
149 * sleep. This bit is present only in S5P6450, it is reserved
150 * in S5P6440.
151 */
152 if (soc_is_s5p6450()) {
153 tmp = __raw_readl(S5P64X0_OTHERS);
154 tmp |= S5P6450_OTHERS_DISABLE_INT;
155 __raw_writel(tmp, S5P64X0_OTHERS);
156 }
157
158 /* ensure previous wakeup state is cleared before sleeping */
159 __raw_writel(__raw_readl(S5P64X0_WAKEUP_STAT), S5P64X0_WAKEUP_STAT);
160
161}
162
163static int s5p64x0_pm_add(struct sys_device *sysdev)
164{
165 pm_cpu_prep = s5p64x0_pm_prepare;
166 pm_cpu_sleep = s5p64x0_cpu_suspend;
167 pm_uart_udivslot = 1;
168
169 return 0;
170}
171
172static struct sysdev_driver s5p64x0_pm_driver = {
173 .add = s5p64x0_pm_add,
174};
175
176static __init int s5p64x0_pm_drvinit(void)
177{
178 s3c_pm_init();
179
180 return sysdev_driver_register(&s5p64x0_sysclass, &s5p64x0_pm_driver);
181}
182arch_initcall(s5p64x0_pm_drvinit);
183
184static void s5p64x0_pm_resume(void)
185{
186 u32 tmp;
187
188 tmp = __raw_readl(S5P64X0_OTHERS);
189 tmp |= (S5P64X0_OTHERS_RET_MMC0 | S5P64X0_OTHERS_RET_MMC1 | \
190 S5P64X0_OTHERS_RET_UART);
191 __raw_writel(tmp , S5P64X0_OTHERS);
192}
193
194static struct syscore_ops s5p64x0_pm_syscore_ops = {
195 .resume = s5p64x0_pm_resume,
196};
197
198static __init int s5p64x0_pm_syscore_init(void)
199{
200 register_syscore_ops(&s5p64x0_pm_syscore_ops);
201
202 return 0;
203}
204arch_initcall(s5p64x0_pm_syscore_init);