From 61557b8bac9c80a5c14d237d420c246703e5c2e2 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:09 +0900 Subject: [PATCH 01/16] ARM: EXYNOS: Do not resume l2x0 if not enabled before suspend Trying to resume l2x0 if it was not enabled before suspend leads to system crash. This patch prevents this by checking if l2x0_regs_phys is a valid pointer to l2x0 context data saved on initialization. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/s5p-sleep.S | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/arm/plat-samsung/s5p-sleep.S b/arch/arm/plat-samsung/s5p-sleep.S index a030e7301da8..20764bd5518e 100644 --- a/arch/arm/plat-samsung/s5p-sleep.S +++ b/arch/arm/plat-samsung/s5p-sleep.S @@ -59,13 +59,15 @@ ENTRY(s3c_cpu_resume) and r0, r0, r1 ldr r1, =CPU_CORTEX_A9 cmp r0, r1 - bne resume_l2on + bne skip_l2_resume adr r0, l2x0_regs_phys ldr r0, [r0] + cmp r0, #0 + beq skip_l2_resume ldr r1, [r0, #L2X0_R_PHY_BASE] ldr r2, [r1, #L2X0_CTRL] tst r2, #0x1 - bne resume_l2on + bne skip_l2_resume ldr r2, [r0, #L2X0_R_AUX_CTRL] str r2, [r1, #L2X0_AUX_CTRL] ldr r2, [r0, #L2X0_R_TAG_LATENCY] @@ -78,7 +80,7 @@ ENTRY(s3c_cpu_resume) str r2, [r1, #L2X0_POWER_CTRL] mov r2, #1 str r2, [r1, #L2X0_CTRL] -resume_l2on: +skip_l2_resume: #endif b cpu_resume ENDPROC(s3c_cpu_resume) From 04241069617d4f0bfd9f4a3aeefae13e1e5b55e1 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:09 +0900 Subject: [PATCH 02/16] ARM: SAMSUNG: Add soc_is_s3c2410() helper Due to the S3C2410 SoC being quite different from other S3C24xx SoCs in some aspects, such as availability of DIVSLOT register in its UART blocks, there is a need sometimes to check whether we are running on this SoC, not just the S3C24xx series. This patch adds soc_is_s3c2410() helper function for this purpose. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/include/plat/cpu.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h index 31164b34d4c4..d762533b856f 100644 --- a/arch/arm/plat-samsung/include/plat/cpu.h +++ b/arch/arm/plat-samsung/include/plat/cpu.h @@ -20,6 +20,9 @@ extern unsigned long samsung_cpu_id; +#define S3C2410_CPU_ID 0x32410000 +#define S3C2410_CPU_MASK 0xFFFFFFFF + #define S3C24XX_CPU_ID 0x32400000 #define S3C24XX_CPU_MASK 0xFFF00000 @@ -56,6 +59,7 @@ static inline int is_samsung_##name(void) \ return ((samsung_cpu_id & mask) == (id & mask)); \ } +IS_SAMSUNG_CPU(s3c2410, S3C2410_CPU_ID, S3C2410_CPU_MASK) IS_SAMSUNG_CPU(s3c24xx, S3C24XX_CPU_ID, S3C24XX_CPU_MASK) IS_SAMSUNG_CPU(s3c2412, S3C2412_CPU_ID, S3C2412_CPU_MASK) IS_SAMSUNG_CPU(s3c6400, S3C6400_CPU_ID, S3C64XX_CPU_MASK) @@ -76,8 +80,10 @@ IS_SAMSUNG_CPU(exynos5440, EXYNOS5440_SOC_ID, EXYNOS5_SOC_MASK) defined(CONFIG_CPU_S3C2442) || defined(CONFIG_CPU_S3C244X) || \ defined(CONFIG_CPU_S3C2443) # define soc_is_s3c24xx() is_samsung_s3c24xx() +# define soc_is_s3c2410() is_samsung_s3c2410() #else # define soc_is_s3c24xx() 0 +# define soc_is_s3c2410() 0 #endif #if defined(CONFIG_CPU_S3C2412) From de7fe0807c08553b88028d039861a4b8ad04fc62 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:09 +0900 Subject: [PATCH 03/16] ARM: SAMSUNG: Save UART DIVSLOT register based on SoC type The only SoC that does not have DIVSLOT register is S3C2410, so instead of exporting a variable for platforms to set if DIVSLOT register should be preserved, it's enough to simply check whether we are running on a S3C2410 instead. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/pm.c | 1 - arch/arm/mach-s5p64x0/pm.c | 1 - arch/arm/plat-samsung/include/plat/pm.h | 2 -- arch/arm/plat-samsung/pm.c | 19 ++++++------------- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c index b5a66986a529..6b37694fa335 100644 --- a/arch/arm/mach-s3c64xx/pm.c +++ b/arch/arm/mach-s3c64xx/pm.c @@ -332,7 +332,6 @@ static __init int s3c64xx_pm_initcall(void) { pm_cpu_prep = s3c64xx_pm_prepare; pm_cpu_sleep = s3c64xx_cpu_suspend; - pm_uart_udivslot = 1; #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK gpio_request(S3C64XX_GPN(12), "DEBUG_LED0"); diff --git a/arch/arm/mach-s5p64x0/pm.c b/arch/arm/mach-s5p64x0/pm.c index 861e15cea691..ec8229cee716 100644 --- a/arch/arm/mach-s5p64x0/pm.c +++ b/arch/arm/mach-s5p64x0/pm.c @@ -161,7 +161,6 @@ static int s5p64x0_pm_add(struct device *dev, struct subsys_interface *sif) { pm_cpu_prep = s5p64x0_pm_prepare; pm_cpu_sleep = s5p64x0_cpu_suspend; - pm_uart_udivslot = 1; return 0; } diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index ff6063f0d5ea..21758c67bcc0 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -54,8 +54,6 @@ extern int (*pm_cpu_sleep)(unsigned long); extern unsigned long s3c_pm_flags; -extern unsigned char pm_uart_udivslot; /* true to save UART UDIVSLOT */ - /* from sleep.S */ extern int s3c2410_cpu_suspend(unsigned long); diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index ae9baa2d6381..3563421d63ab 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -24,6 +24,8 @@ #include #include +#include + #ifdef CONFIG_SAMSUNG_ATAGS #include #include @@ -70,17 +72,6 @@ static inline void s3c_pm_debug_init(void) s3c_pm_debug_init_uart(); } -#else -#define s3c_pm_debug_init() do { } while(0) - -#endif /* CONFIG_SAMSUNG_PM_DEBUG */ - -/* Save the UART configurations if we are configured for debug. */ - -unsigned char pm_uart_udivslot; - -#ifdef CONFIG_SAMSUNG_PM_DEBUG - static struct pm_uart_save uart_save; static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) @@ -93,7 +84,7 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) save->umcon = __raw_readl(regs + S3C2410_UMCON); save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); - if (pm_uart_udivslot) + if (!soc_is_s3c2410()) save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", @@ -117,7 +108,7 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) __raw_writel(save->umcon, regs + S3C2410_UMCON); __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); - if (pm_uart_udivslot) + if (!soc_is_s3c2410()) __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); } @@ -126,6 +117,8 @@ static void s3c_pm_restore_uarts(void) s3c_pm_restore_uart(CONFIG_DEBUG_S3C_UART, &uart_save); } #else +#define s3c_pm_debug_init() do { } while (0) + static void s3c_pm_save_uarts(void) { } static void s3c_pm_restore_uarts(void) { } #endif From 99b2fc2b8b40256538332769f11f2fe6ee942f6c Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:09 +0900 Subject: [PATCH 04/16] ARM: SAMSUNG: Use debug_ll_addr() to get UART base address This patch modifies Samsung PM debug helpers to use a multiplatform friendly way of getting base address of debug UART port, so instead of using a per-mach static macro, a generic debug_ll_addr() helper is used. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/pm.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index 3563421d63ab..c7fac34de621 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -74,9 +75,19 @@ static inline void s3c_pm_debug_init(void) static struct pm_uart_save uart_save; +static inline void __iomem *s3c_pm_uart_base(void) +{ + unsigned long paddr; + unsigned long vaddr; + + debug_ll_addr(&paddr, &vaddr); + + return (void __iomem *)vaddr; +} + static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) { - void __iomem *regs = S3C_VA_UARTx(uart); + void __iomem *regs = s3c_pm_uart_base(); save->ulcon = __raw_readl(regs + S3C2410_ULCON); save->ucon = __raw_readl(regs + S3C2410_UCON); @@ -98,7 +109,7 @@ static void s3c_pm_save_uarts(void) static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) { - void __iomem *regs = S3C_VA_UARTx(uart); + void __iomem *regs = s3c_pm_uart_base(); s3c_pm_arch_update_uart(regs, save); From d38688a69fd88269eae3c7c66ec34fb02fb04fd1 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:09 +0900 Subject: [PATCH 05/16] ARM: SAMSUNG: Consolidate PM debug functions This patch removes one-line functions that was used just to pass constant arguments to lower level functions. After previous patches the need for those constants has been eliminated, so the main functions can be called directly. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/pm.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index c7fac34de621..dd70337822da 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -85,9 +85,10 @@ static inline void __iomem *s3c_pm_uart_base(void) return (void __iomem *)vaddr; } -static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) +static void s3c_pm_save_uarts(void) { void __iomem *regs = s3c_pm_uart_base(); + struct pm_uart_save *save = &uart_save; save->ulcon = __raw_readl(regs + S3C2410_ULCON); save->ucon = __raw_readl(regs + S3C2410_UCON); @@ -98,18 +99,14 @@ static void s3c_pm_save_uart(unsigned int uart, struct pm_uart_save *save) if (!soc_is_s3c2410()) save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); - S3C_PMDBG("UART[%d]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", - uart, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); + S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", + regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); } -static void s3c_pm_save_uarts(void) -{ - s3c_pm_save_uart(CONFIG_DEBUG_S3C_UART, &uart_save); -} - -static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) +static void s3c_pm_restore_uarts(void) { void __iomem *regs = s3c_pm_uart_base(); + struct pm_uart_save *save = &uart_save; s3c_pm_arch_update_uart(regs, save); @@ -122,11 +119,6 @@ static void s3c_pm_restore_uart(unsigned int uart, struct pm_uart_save *save) if (!soc_is_s3c2410()) __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); } - -static void s3c_pm_restore_uarts(void) -{ - s3c_pm_restore_uart(CONFIG_DEBUG_S3C_UART, &uart_save); -} #else #define s3c_pm_debug_init() do { } while (0) From 72551f6cf13e2f3a1d273b7007b5d7d7fd69c554 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:09 +0900 Subject: [PATCH 06/16] ARM: SAMSUNG: Move Samsung PM debug code into separate file Not all Samsung SoC platforms are going to use the legacy Samsung PM code enabled by CONFIG_SAMSUNG_PM_DEBUG. To allow using Samsung PM debug helpers on such platforms, related code is moved to separate file and a plat/pm-common.h header is added to separate legacy and generic code. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/Makefile | 1 + .../arm/plat-samsung/include/plat/pm-common.h | 70 +++++++++++++ arch/arm/plat-samsung/include/plat/pm.h | 39 +------- arch/arm/plat-samsung/pm-debug.c | 97 +++++++++++++++++++ arch/arm/plat-samsung/pm.c | 84 ---------------- 5 files changed, 169 insertions(+), 122 deletions(-) create mode 100644 arch/arm/plat-samsung/include/plat/pm-common.h create mode 100644 arch/arm/plat-samsung/pm-debug.c diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index 9267d29549b4..ba30a16b3ca8 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o obj-$(CONFIG_SAMSUNG_PM) += pm.o obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o +obj-$(CONFIG_SAMSUNG_PM_DEBUG) += pm-debug.o obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o obj-$(CONFIG_SAMSUNG_WDT_RESET) += watchdog-reset.o diff --git a/arch/arm/plat-samsung/include/plat/pm-common.h b/arch/arm/plat-samsung/include/plat/pm-common.h new file mode 100644 index 000000000000..f72974a762bf --- /dev/null +++ b/arch/arm/plat-samsung/include/plat/pm-common.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Tomasz Figa + * Copyright (c) 2004 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Written 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. +*/ + +#ifndef __PLAT_SAMSUNG_PM_COMMON_H +#define __PLAT_SAMSUNG_PM_COMMON_H __FILE__ + +/* PM debug functions */ + +/** + * struct pm_uart_save - save block for core UART + * @ulcon: Save value for S3C2410_ULCON + * @ucon: Save value for S3C2410_UCON + * @ufcon: Save value for S3C2410_UFCON + * @umcon: Save value for S3C2410_UMCON + * @ubrdiv: Save value for S3C2410_UBRDIV + * + * Save block for UART registers to be held over sleep and restored if they + * are needed (say by debug). +*/ +struct pm_uart_save { + u32 ulcon; + u32 ucon; + u32 ufcon; + u32 umcon; + u32 ubrdiv; + u32 udivslot; +}; + +#ifdef CONFIG_SAMSUNG_PM_DEBUG +/** + * s3c_pm_dbg() - low level debug function for use in suspend/resume. + * @msg: The message to print. + * + * This function is used mainly to debug the resume process before the system + * can rely on printk/console output. It uses the low-level debugging output + * routine printascii() to do its work. + */ +extern void s3c_pm_dbg(const char *msg, ...); + +/** + * s3c_pm_debug_init() - suspend/resume low level debug initialization. + * @base: Virtual base of UART to use for suspend/resume debugging. + * + * This function needs to be called before S3C_PMDBG() can be used, to set up + * UART port base address and configuration. + */ +extern void s3c_pm_debug_init(void); + +#define S3C_PMDBG(fmt...) s3c_pm_dbg(fmt) + +extern void s3c_pm_save_uarts(void); +extern void s3c_pm_restore_uarts(void); +#else +#define S3C_PMDBG(fmt...) pr_debug(fmt) +#define s3c_pm_debug_init() do { } while (0) + +static inline void s3c_pm_save_uarts(void) { } +static inline void s3c_pm_restore_uarts(void) { } +#endif + +#endif diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index 21758c67bcc0..2e04396eb3f3 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -16,6 +16,7 @@ */ #include +#include struct device; @@ -76,26 +77,6 @@ struct sleep_save { #define SAVE_ITEM(x) \ { .reg = (x) } -/** - * struct pm_uart_save - save block for core UART - * @ulcon: Save value for S3C2410_ULCON - * @ucon: Save value for S3C2410_UCON - * @ufcon: Save value for S3C2410_UFCON - * @umcon: Save value for S3C2410_UMCON - * @ubrdiv: Save value for S3C2410_UBRDIV - * - * Save block for UART registers to be held over sleep and restored if they - * are needed (say by debug). -*/ -struct pm_uart_save { - u32 ulcon; - u32 ucon; - u32 ufcon; - u32 umcon; - u32 ubrdiv; - u32 udivslot; -}; - /* helper functions to save/restore lists of registers. */ extern void s3c_pm_do_save(struct sleep_save *ptr, int count); @@ -112,24 +93,6 @@ extern void s3c_cpu_resume(void); #define s3c_cpu_resume NULL #endif -/* PM debug functions */ - -#ifdef CONFIG_SAMSUNG_PM_DEBUG -/** - * s3c_pm_dbg() - low level debug function for use in suspend/resume. - * @msg: The message to print. - * - * This function is used mainly to debug the resume process before the system - * can rely on printk/console output. It uses the low-level debugging output - * routine printascii() to do its work. - */ -extern void s3c_pm_dbg(const char *msg, ...); - -#define S3C_PMDBG(fmt...) s3c_pm_dbg(fmt) -#else -#define S3C_PMDBG(fmt...) printk(KERN_DEBUG fmt) -#endif - #ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK /** * s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs diff --git a/arch/arm/plat-samsung/pm-debug.c b/arch/arm/plat-samsung/pm-debug.c new file mode 100644 index 000000000000..8f19f66388dd --- /dev/null +++ b/arch/arm/plat-samsung/pm-debug.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Tomasz Figa + * Copyright (C) 2008 Openmoko, Inc. + * Copyright (C) 2004-2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * Samsung common power management (suspend to RAM) debug support + * + * 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 +#include + +#include + +#include +#include + +#ifdef CONFIG_SAMSUNG_ATAGS +#include +#else +static inline void s3c_pm_debug_init_uart(void) {} +static inline void s3c_pm_arch_update_uart(void __iomem *regs, + struct pm_uart_save *save) {} +#endif + +static struct pm_uart_save uart_save; + +extern void printascii(const char *); + +void s3c_pm_dbg(const char *fmt, ...) +{ + va_list va; + char buff[256]; + + va_start(va, fmt); + vsnprintf(buff, sizeof(buff), fmt, va); + va_end(va); + + printascii(buff); +} + +void s3c_pm_debug_init(void) +{ + /* restart uart clocks so we can use them to output */ + s3c_pm_debug_init_uart(); +} + +static inline void __iomem *s3c_pm_uart_base(void) +{ + unsigned long paddr; + unsigned long vaddr; + + debug_ll_addr(&paddr, &vaddr); + + return (void __iomem *)vaddr; +} + +void s3c_pm_save_uarts(void) +{ + void __iomem *regs = s3c_pm_uart_base(); + struct pm_uart_save *save = &uart_save; + + save->ulcon = __raw_readl(regs + S3C2410_ULCON); + save->ucon = __raw_readl(regs + S3C2410_UCON); + save->ufcon = __raw_readl(regs + S3C2410_UFCON); + save->umcon = __raw_readl(regs + S3C2410_UMCON); + save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); + + if (!soc_is_s3c2410()) + save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); + + S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", + regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); +} + +void s3c_pm_restore_uarts(void) +{ + void __iomem *regs = s3c_pm_uart_base(); + struct pm_uart_save *save = &uart_save; + + s3c_pm_arch_update_uart(regs, save); + + __raw_writel(save->ulcon, regs + S3C2410_ULCON); + __raw_writel(save->ucon, regs + S3C2410_UCON); + __raw_writel(save->ufcon, regs + S3C2410_UFCON); + __raw_writel(save->umcon, regs + S3C2410_UMCON); + __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); + + if (!soc_is_s3c2410()) + __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); +} diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index dd70337822da..3d523c90202a 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -17,16 +17,12 @@ #include #include #include -#include #include #include #include -#include #include -#include - #ifdef CONFIG_SAMSUNG_ATAGS #include #include @@ -46,86 +42,6 @@ unsigned long s3c_pm_flags; -/* Debug code: - * - * This code supports debug output to the low level UARTs for use on - * resume before the console layer is available. -*/ - -#ifdef CONFIG_SAMSUNG_PM_DEBUG -extern void printascii(const char *); - -void s3c_pm_dbg(const char *fmt, ...) -{ - va_list va; - char buff[256]; - - va_start(va, fmt); - vsnprintf(buff, sizeof(buff), fmt, va); - va_end(va); - - printascii(buff); -} - -static inline void s3c_pm_debug_init(void) -{ - /* restart uart clocks so we can use them to output */ - s3c_pm_debug_init_uart(); -} - -static struct pm_uart_save uart_save; - -static inline void __iomem *s3c_pm_uart_base(void) -{ - unsigned long paddr; - unsigned long vaddr; - - debug_ll_addr(&paddr, &vaddr); - - return (void __iomem *)vaddr; -} - -static void s3c_pm_save_uarts(void) -{ - void __iomem *regs = s3c_pm_uart_base(); - struct pm_uart_save *save = &uart_save; - - save->ulcon = __raw_readl(regs + S3C2410_ULCON); - save->ucon = __raw_readl(regs + S3C2410_UCON); - save->ufcon = __raw_readl(regs + S3C2410_UFCON); - save->umcon = __raw_readl(regs + S3C2410_UMCON); - save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); - - if (!soc_is_s3c2410()) - save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); - - S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", - regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); -} - -static void s3c_pm_restore_uarts(void) -{ - void __iomem *regs = s3c_pm_uart_base(); - struct pm_uart_save *save = &uart_save; - - s3c_pm_arch_update_uart(regs, save); - - __raw_writel(save->ulcon, regs + S3C2410_ULCON); - __raw_writel(save->ucon, regs + S3C2410_UCON); - __raw_writel(save->ufcon, regs + S3C2410_UFCON); - __raw_writel(save->umcon, regs + S3C2410_UMCON); - __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); - - if (!soc_is_s3c2410()) - __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); -} -#else -#define s3c_pm_debug_init() do { } while (0) - -static void s3c_pm_save_uarts(void) { } -static void s3c_pm_restore_uarts(void) { } -#endif - /* The IRQ ext-int code goes here, it is too small to currently bother * with its own file. */ From b27899178c53226a5ff780a17657c84eb5e32338 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:10 +0900 Subject: [PATCH 07/16] ARM: SAMSUNG: Move common save/restore helpers to separate file To separate legacy PM code from generic helpers, this patch moves the generic register save/restore helpers to a new file called pm-common.c that is compiled always when CONFIG_PM_SLEEP is enabled, to allow platforms that do not want to use the legacy PM code use the generic helpers. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/Makefile | 1 + .../arm/plat-samsung/include/plat/pm-common.h | 26 +++++++ arch/arm/plat-samsung/include/plat/pm.h | 25 ------- arch/arm/plat-samsung/pm-common.c | 75 +++++++++++++++++++ arch/arm/plat-samsung/pm.c | 56 -------------- 5 files changed, 102 insertions(+), 81 deletions(-) create mode 100644 arch/arm/plat-samsung/pm-common.c diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile index ba30a16b3ca8..25c826ed3b65 100644 --- a/arch/arm/plat-samsung/Makefile +++ b/arch/arm/plat-samsung/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o # PM support +obj-$(CONFIG_PM_SLEEP) += pm-common.o obj-$(CONFIG_SAMSUNG_PM) += pm.o obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o diff --git a/arch/arm/plat-samsung/include/plat/pm-common.h b/arch/arm/plat-samsung/include/plat/pm-common.h index f72974a762bf..741723eb8cd7 100644 --- a/arch/arm/plat-samsung/include/plat/pm-common.h +++ b/arch/arm/plat-samsung/include/plat/pm-common.h @@ -13,6 +13,32 @@ #ifndef __PLAT_SAMSUNG_PM_COMMON_H #define __PLAT_SAMSUNG_PM_COMMON_H __FILE__ +#include + +/* sleep save info */ + +/** + * struct sleep_save - save information for shared peripherals. + * @reg: Pointer to the register to save. + * @val: Holder for the value saved from reg. + * + * This describes a list of registers which is used by the pm core and + * other subsystem to save and restore register values over suspend. + */ +struct sleep_save { + void __iomem *reg; + unsigned long val; +}; + +#define SAVE_ITEM(x) \ + { .reg = (x) } + +/* helper functions to save/restore lists of registers. */ + +extern void s3c_pm_do_save(struct sleep_save *ptr, int count); +extern void s3c_pm_do_restore(const struct sleep_save *ptr, int count); +extern void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count); + /* PM debug functions */ /** diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index 2e04396eb3f3..4099e8d6f5f9 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -15,7 +15,6 @@ * management */ -#include #include struct device; @@ -59,30 +58,6 @@ extern unsigned long s3c_pm_flags; extern int s3c2410_cpu_suspend(unsigned long); -/* sleep save info */ - -/** - * struct sleep_save - save information for shared peripherals. - * @reg: Pointer to the register to save. - * @val: Holder for the value saved from reg. - * - * This describes a list of registers which is used by the pm core and - * other subsystem to save and restore register values over suspend. - */ -struct sleep_save { - void __iomem *reg; - unsigned long val; -}; - -#define SAVE_ITEM(x) \ - { .reg = (x) } - -/* helper functions to save/restore lists of registers. */ - -extern void s3c_pm_do_save(struct sleep_save *ptr, int count); -extern void s3c_pm_do_restore(const struct sleep_save *ptr, int count); -extern void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count); - #ifdef CONFIG_SAMSUNG_PM extern int s3c_irq_wake(struct irq_data *data, unsigned int state); extern int s3c_irqext_wake(struct irq_data *data, unsigned int state); diff --git a/arch/arm/plat-samsung/pm-common.c b/arch/arm/plat-samsung/pm-common.c new file mode 100644 index 000000000000..515cd53372bd --- /dev/null +++ b/arch/arm/plat-samsung/pm-common.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Tomasz Figa + * Copyright (C) 2008 Openmoko, Inc. + * Copyright (C) 2004-2008 Simtec Electronics + * Ben Dooks + * http://armlinux.simtec.co.uk/ + * + * Samsung common power management helper functions. + * + * 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 +#include + +#include + +/* helper functions to save and restore register state */ + +/** + * s3c_pm_do_save() - save a set of registers for restoration on resume. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * Run through the list of registers given, saving their contents in the + * array for later restoration when we wakeup. + */ +void s3c_pm_do_save(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + ptr->val = __raw_readl(ptr->reg); + S3C_PMDBG("saved %p value %08lx\n", ptr->reg, ptr->val); + } +} + +/** + * s3c_pm_do_restore() - restore register values from the save list. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * Restore the register values saved from s3c_pm_do_save(). + * + * Note, we do not use S3C_PMDBG() in here, as the system may not have + * restore the UARTs state yet +*/ + +void s3c_pm_do_restore(const struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + pr_debug("restore %p (restore %08lx, was %08x)\n", + ptr->reg, ptr->val, __raw_readl(ptr->reg)); + + __raw_writel(ptr->val, ptr->reg); + } +} + +/** + * s3c_pm_do_restore_core() - early restore register values from save list. + * + * This is similar to s3c_pm_do_restore() except we try and minimise the + * side effects of the function in case registers that hardware might need + * to work has been restored. + * + * WARNING: Do not put any debug in here that may effect memory or use + * peripherals, as things may be changing! +*/ + +void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) + __raw_writel(ptr->val, ptr->reg); +} diff --git a/arch/arm/plat-samsung/pm.c b/arch/arm/plat-samsung/pm.c index 3d523c90202a..c08bc51201fc 100644 --- a/arch/arm/plat-samsung/pm.c +++ b/arch/arm/plat-samsung/pm.c @@ -66,62 +66,6 @@ int s3c_irqext_wake(struct irq_data *data, unsigned int state) return 0; } -/* helper functions to save and restore register state */ - -/** - * s3c_pm_do_save() - save a set of registers for restoration on resume. - * @ptr: Pointer to an array of registers. - * @count: Size of the ptr array. - * - * Run through the list of registers given, saving their contents in the - * array for later restoration when we wakeup. - */ -void s3c_pm_do_save(struct sleep_save *ptr, int count) -{ - for (; count > 0; count--, ptr++) { - ptr->val = __raw_readl(ptr->reg); - S3C_PMDBG("saved %p value %08lx\n", ptr->reg, ptr->val); - } -} - -/** - * s3c_pm_do_restore() - restore register values from the save list. - * @ptr: Pointer to an array of registers. - * @count: Size of the ptr array. - * - * Restore the register values saved from s3c_pm_do_save(). - * - * Note, we do not use S3C_PMDBG() in here, as the system may not have - * restore the UARTs state yet -*/ - -void s3c_pm_do_restore(const struct sleep_save *ptr, int count) -{ - for (; count > 0; count--, ptr++) { - printk(KERN_DEBUG "restore %p (restore %08lx, was %08x)\n", - ptr->reg, ptr->val, __raw_readl(ptr->reg)); - - __raw_writel(ptr->val, ptr->reg); - } -} - -/** - * s3c_pm_do_restore_core() - early restore register values from save list. - * - * This is similar to s3c_pm_do_restore() except we try and minimise the - * side effects of the function in case registers that hardware might need - * to work has been restored. - * - * WARNING: Do not put any debug in here that may effect memory or use - * peripherals, as things may be changing! -*/ - -void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count) -{ - for (; count > 0; count--, ptr++) - __raw_writel(ptr->val, ptr->reg); -} - /* s3c2410_pm_show_resume_irqs * * print any IRQs asserted at resume time (ie, we woke from) From f682426630c620a2b8ae488a4f0d85ec6c272d66 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:10 +0900 Subject: [PATCH 08/16] ARM: SAMSUNG: Move s3c_pm_check_* prototypes to plat/pm-common.h To allow using Samsung PM memory check helpers on platforms that do not use the legacy Samsung PM core, this patch moves prototypes of relevant functions to plat/pm-common.h header. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/plat-samsung/include/plat/pm-common.h | 14 ++++++++++++++ arch/arm/plat-samsung/include/plat/pm.h | 14 -------------- arch/arm/plat-samsung/pm-check.c | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/arch/arm/plat-samsung/include/plat/pm-common.h b/arch/arm/plat-samsung/include/plat/pm-common.h index 741723eb8cd7..8705f9e0e288 100644 --- a/arch/arm/plat-samsung/include/plat/pm-common.h +++ b/arch/arm/plat-samsung/include/plat/pm-common.h @@ -93,4 +93,18 @@ static inline void s3c_pm_save_uarts(void) { } static inline void s3c_pm_restore_uarts(void) { } #endif +/* suspend memory checking */ + +#ifdef CONFIG_SAMSUNG_PM_CHECK +extern void s3c_pm_check_prepare(void); +extern void s3c_pm_check_restore(void); +extern void s3c_pm_check_cleanup(void); +extern void s3c_pm_check_store(void); +#else +#define s3c_pm_check_prepare() do { } while (0) +#define s3c_pm_check_restore() do { } while (0) +#define s3c_pm_check_cleanup() do { } while (0) +#define s3c_pm_check_store() do { } while (0) +#endif + #endif diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h index 4099e8d6f5f9..e17d871b934c 100644 --- a/arch/arm/plat-samsung/include/plat/pm.h +++ b/arch/arm/plat-samsung/include/plat/pm.h @@ -80,20 +80,6 @@ extern void s3c_pm_debug_smdkled(u32 set, u32 clear); static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { } #endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */ -/* suspend memory checking */ - -#ifdef CONFIG_SAMSUNG_PM_CHECK -extern void s3c_pm_check_prepare(void); -extern void s3c_pm_check_restore(void); -extern void s3c_pm_check_cleanup(void); -extern void s3c_pm_check_store(void); -#else -#define s3c_pm_check_prepare() do { } while(0) -#define s3c_pm_check_restore() do { } while(0) -#define s3c_pm_check_cleanup() do { } while(0) -#define s3c_pm_check_store() do { } while(0) -#endif - /** * s3c_pm_configure_extint() - ensure pins are correctly set for IRQ * diff --git a/arch/arm/plat-samsung/pm-check.c b/arch/arm/plat-samsung/pm-check.c index 3cbd62666b1e..04aff2c31b46 100644 --- a/arch/arm/plat-samsung/pm-check.c +++ b/arch/arm/plat-samsung/pm-check.c @@ -19,7 +19,7 @@ #include #include -#include +#include #if CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE < 1 #error CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE must be a positive non-zero value From dbc5ca163dc46153a8e5249da627af571ae47c10 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:10 +0900 Subject: [PATCH 09/16] ARM: EXYNOS: Fix abuse of CONFIG_PM CONFIG_PM means that at least one of CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME is enabled, while multiple entries in mach-exynos/Kconfig abused it to enable sleep- and runtime-specific functionality. This patch fixes this abuse by replacing dependencies on CONFIG_PM with appropriate dependencies on either CONFIG_PM_SLEEP or CONFIG_PM_RUNTIME, whichever is appropriate. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/Kconfig | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 4c414af75ef0..0964d97c2fa7 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -24,7 +24,7 @@ config ARCH_EXYNOS4 select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 select PINCTRL - select PM_GENERIC_DOMAINS if PM + select PM_GENERIC_DOMAINS if PM_RUNTIME select S5P_DEV_MFC help Samsung EXYNOS4 SoCs based systems @@ -47,10 +47,10 @@ config CPU_EXYNOS4210 default y depends on ARCH_EXYNOS4 select ARCH_HAS_BANDGAP - select ARM_CPU_SUSPEND if PM + select ARM_CPU_SUSPEND if PM_SLEEP select PINCTRL_EXYNOS - select S5P_PM if PM - select S5P_SLEEP if PM + select S5P_PM if PM_SLEEP + select S5P_SLEEP if PM_SLEEP select SAMSUNG_DMADEV help Enable EXYNOS4210 CPU support @@ -61,8 +61,8 @@ config SOC_EXYNOS4212 depends on ARCH_EXYNOS4 select ARCH_HAS_BANDGAP select PINCTRL_EXYNOS - select S5P_PM if PM - select S5P_SLEEP if PM + select S5P_PM if PM_SLEEP + select S5P_SLEEP if PM_SLEEP select SAMSUNG_DMADEV help Enable EXYNOS4212 SoC support @@ -83,9 +83,9 @@ config SOC_EXYNOS5250 depends on ARCH_EXYNOS5 select ARCH_HAS_BANDGAP select PINCTRL_EXYNOS - select PM_GENERIC_DOMAINS if PM - select S5P_PM if PM - select S5P_SLEEP if PM + select PM_GENERIC_DOMAINS if PM_RUNTIME + select S5P_PM if PM_SLEEP + select S5P_SLEEP if PM_SLEEP select S5P_DEV_MFC select SAMSUNG_DMADEV help @@ -95,9 +95,9 @@ config SOC_EXYNOS5420 bool "SAMSUNG EXYNOS5420" default y depends on ARCH_EXYNOS5 - select PM_GENERIC_DOMAINS if PM - select S5P_PM if PM - select S5P_SLEEP if PM + select PM_GENERIC_DOMAINS if PM_RUNTIME + select S5P_PM if PM_SLEEP + select S5P_SLEEP if PM_SLEEP help Enable EXYNOS5420 SoC support From 559ba237999d723ccba5b4a75cf6b280bac1ab21 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:22 +0900 Subject: [PATCH 10/16] ARM: EXYNOS: Remove PM initcalls and useless indirection This patch simplifies Exynos PM initialization and makes it multiplatform friendly by replacing initcalls used originally to invoke all the initialization code with explicit function calls. In addition, an useless subsys_interface is removed, as all its .add_dev callback did was setting two function pointers. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/common.c | 1 + arch/arm/mach-exynos/common.h | 6 +++++ arch/arm/mach-exynos/pm.c | 50 +++++++++-------------------------- 3 files changed, 19 insertions(+), 38 deletions(-) diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index 025fd8215ca3..e98ddadc5f74 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c @@ -315,6 +315,7 @@ void __init exynos_init_late(void) return; pm_genpd_poweroff_unused(); + exynos_pm_init(); } static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index f76967b1c551..82e08fb83eae 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -27,6 +27,12 @@ void exynos_init_late(void); void exynos_firmware_init(void); +#ifdef CONFIG_PM_SLEEP +extern void __init exynos_pm_init(void); +#else +static inline void exynos_pm_init(void) {} +#endif + extern struct smp_operations exynos_smp_ops; extern void exynos_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index ba18214c9aca..596ed13c4166 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -92,39 +92,6 @@ static void exynos_pm_prepare(void) __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0); } -static int exynos_pm_add(struct device *dev, struct subsys_interface *sif) -{ - pm_cpu_prep = exynos_pm_prepare; - pm_cpu_sleep = exynos_cpu_suspend; - - return 0; -} - -static struct subsys_interface exynos_pm_interface = { - .name = "exynos_pm", - .subsys = &exynos_subsys, - .add_dev = exynos_pm_add, -}; - -static __init int exynos_pm_drvinit(void) -{ - unsigned int tmp; - - if (soc_is_exynos5440()) - return 0; - - s3c_pm_init(); - - /* All wakeup disable */ - - tmp = __raw_readl(S5P_WAKEUP_MASK); - tmp |= ((0xFF << 8) | (0x1F << 1)); - __raw_writel(tmp, S5P_WAKEUP_MASK); - - return subsys_interface_register(&exynos_pm_interface); -} -arch_initcall(exynos_pm_drvinit); - static int exynos_pm_suspend(void) { unsigned long tmp; @@ -220,12 +187,19 @@ static struct syscore_ops exynos_pm_syscore_ops = { .resume = exynos_pm_resume, }; -static __init int exynos_pm_syscore_init(void) +void __init exynos_pm_init(void) { - if (soc_is_exynos5440()) - return 0; + u32 tmp; + + pm_cpu_prep = exynos_pm_prepare; + pm_cpu_sleep = exynos_cpu_suspend; + + s3c_pm_init(); + + /* All wakeup disable */ + tmp = __raw_readl(S5P_WAKEUP_MASK); + tmp |= ((0xFF << 8) | (0x1F << 1)); + __raw_writel(tmp, S5P_WAKEUP_MASK); register_syscore_ops(&exynos_pm_syscore_ops); - return 0; } -arch_initcall(exynos_pm_syscore_init); From d710aa31874e2ff6e656dbd4807f4bd8d659eb93 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:27 +0900 Subject: [PATCH 11/16] ARM: EXYNOS: Stop using legacy Samsung PM code Since Exynos SoCs does not follow most of the semantics of older SoCs when configuring the system to enter sleep, there is no reason to rely on the legacy Samsung PM core anymore. This patch adds local Exynos suspend ops and removes all the code left unnecessary. As a side effect, suspend support on Exynos becomes multiplatform-friendly. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/Kconfig | 8 -- arch/arm/mach-exynos/Makefile | 2 +- arch/arm/mach-exynos/common.h | 8 ++ arch/arm/mach-exynos/include/mach/pm-core.h | 75 ------------------ arch/arm/mach-exynos/pm.c | 79 +++++++++++++++++-- arch/arm/mach-exynos/regs-pmu.h | 2 + arch/arm/mach-exynos/sleep.S | 85 +++++++++++++++++++++ arch/arm/plat-samsung/s5p-sleep.S | 45 ----------- 8 files changed, 167 insertions(+), 137 deletions(-) delete mode 100644 arch/arm/mach-exynos/include/mach/pm-core.h create mode 100644 arch/arm/mach-exynos/sleep.S diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 0964d97c2fa7..fcd78c201c0b 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig @@ -49,8 +49,6 @@ config CPU_EXYNOS4210 select ARCH_HAS_BANDGAP select ARM_CPU_SUSPEND if PM_SLEEP select PINCTRL_EXYNOS - select S5P_PM if PM_SLEEP - select S5P_SLEEP if PM_SLEEP select SAMSUNG_DMADEV help Enable EXYNOS4210 CPU support @@ -61,8 +59,6 @@ config SOC_EXYNOS4212 depends on ARCH_EXYNOS4 select ARCH_HAS_BANDGAP select PINCTRL_EXYNOS - select S5P_PM if PM_SLEEP - select S5P_SLEEP if PM_SLEEP select SAMSUNG_DMADEV help Enable EXYNOS4212 SoC support @@ -84,8 +80,6 @@ config SOC_EXYNOS5250 select ARCH_HAS_BANDGAP select PINCTRL_EXYNOS select PM_GENERIC_DOMAINS if PM_RUNTIME - select S5P_PM if PM_SLEEP - select S5P_SLEEP if PM_SLEEP select S5P_DEV_MFC select SAMSUNG_DMADEV help @@ -96,8 +90,6 @@ config SOC_EXYNOS5420 default y depends on ARCH_EXYNOS5 select PM_GENERIC_DOMAINS if PM_RUNTIME - select S5P_PM if PM_SLEEP - select S5P_SLEEP if PM_SLEEP help Enable EXYNOS5420 SoC support diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 8930b66b4abd..58fe9e6f542f 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile @@ -14,7 +14,7 @@ obj- := obj-$(CONFIG_ARCH_EXYNOS) += common.o -obj-$(CONFIG_S5P_PM) += pm.o +obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 82e08fb83eae..aba6a2ad7d1b 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h @@ -27,12 +27,20 @@ void exynos_init_late(void); void exynos_firmware_init(void); +#ifdef CONFIG_PINCTRL_EXYNOS +extern u32 exynos_get_eint_wake_mask(void); +#else +static inline u32 exynos_get_eint_wake_mask(void) { return 0xffffffff; } +#endif + #ifdef CONFIG_PM_SLEEP extern void __init exynos_pm_init(void); #else static inline void exynos_pm_init(void) {} #endif +extern void exynos_cpu_resume(void); + extern struct smp_operations exynos_smp_ops; extern void exynos_cpu_die(unsigned int cpu); diff --git a/arch/arm/mach-exynos/include/mach/pm-core.h b/arch/arm/mach-exynos/include/mach/pm-core.h deleted file mode 100644 index dc0697c2fa92..000000000000 --- a/arch/arm/mach-exynos/include/mach/pm-core.h +++ /dev/null @@ -1,75 +0,0 @@ -/* linux/arch/arm/mach-exynos4/include/mach/pm-core.h - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Based on arch/arm/mach-s3c2410/include/mach/pm-core.h, - * Copyright 2008 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * EXYNOS4210 - PM core support for arch/arm/plat-s5p/pm.c - * - * 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. -*/ - -#ifndef __ASM_ARCH_PM_CORE_H -#define __ASM_ARCH_PM_CORE_H __FILE__ - -#include -#include - -#define S5P_EINT_WAKEUP_MASK (S5P_VA_PMU + 0x0604) -#define S5P_WAKEUP_MASK (S5P_VA_PMU + 0x0608) - -#ifdef CONFIG_PINCTRL_EXYNOS -extern u32 exynos_get_eint_wake_mask(void); -#else -static inline u32 exynos_get_eint_wake_mask(void) { return 0xffffffff; } -#endif - -static inline void s3c_pm_debug_init_uart(void) -{ - /* nothing here yet */ -} - -static inline void s3c_pm_arch_prepare_irqs(void) -{ - __raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); - __raw_writel(s3c_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); -} - -static inline void s3c_pm_arch_stop_clocks(void) -{ - /* nothing here yet */ -} - -static inline void s3c_pm_arch_show_resume_irqs(void) -{ - /* nothing here yet */ -} - -static inline void s3c_pm_arch_update_uart(void __iomem *regs, - struct pm_uart_save *save) -{ - /* nothing here yet */ -} - -static inline void s3c_pm_restored_gpios(void) -{ - /* nothing here yet */ -} - -static inline void samsung_pm_saved_gpios(void) -{ - /* nothing here yet */ -} - -/* Compatibility definitions to make plat-samsung/pm.c compile */ -#define IRQ_EINT_BIT(x) 1 -#define s3c_irqwake_intallow 0 -#define s3c_irqwake_eintallow 0 - -#endif /* __ASM_ARCH_PM_CORE_H */ diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index 596ed13c4166..ada1c8374b77 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -23,14 +23,14 @@ #include #include #include +#include #include -#include +#include #include #include #include -#include #include "common.h" #include "regs-pmu.h" @@ -48,6 +48,7 @@ static struct sleep_save exynos_core_save[] = { SAVE_ITEM(S5P_SROM_BC3), }; +static u32 exynos_irqwake_intmask = 0xffffffff; /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; @@ -72,6 +73,10 @@ static void exynos_pm_prepare(void) { unsigned int tmp; + /* Set wake-up mask registers */ + __raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); + __raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); + s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); if (soc_is_exynos5250()) { @@ -89,7 +94,7 @@ static void exynos_pm_prepare(void) /* ensure at least INFORM0 has the resume address */ - __raw_writel(virt_to_phys(s3c_cpu_resume), S5P_INFORM0); + __raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); } static int exynos_pm_suspend(void) @@ -187,19 +192,77 @@ static struct syscore_ops exynos_pm_syscore_ops = { .resume = exynos_pm_resume, }; +/* + * Suspend Ops + */ + +static int exynos_suspend_enter(suspend_state_t state) +{ + int ret; + + s3c_pm_debug_init(); + + S3C_PMDBG("%s: suspending the system...\n", __func__); + + S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, + exynos_irqwake_intmask, exynos_get_eint_wake_mask()); + + if (exynos_irqwake_intmask == -1U + && exynos_get_eint_wake_mask() == -1U) { + pr_err("%s: No wake-up sources!\n", __func__); + pr_err("%s: Aborting sleep\n", __func__); + return -EINVAL; + } + + s3c_pm_save_uarts(); + exynos_pm_prepare(); + flush_cache_all(); + s3c_pm_check_store(); + + ret = cpu_suspend(0, exynos_cpu_suspend); + if (ret) + return ret; + + s3c_pm_restore_uarts(); + + S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, + __raw_readl(S5P_WAKEUP_STAT)); + + s3c_pm_check_restore(); + + S3C_PMDBG("%s: resuming the system...\n", __func__); + + return 0; +} + +static int exynos_suspend_prepare(void) +{ + s3c_pm_check_prepare(); + + return 0; +} + +static void exynos_suspend_finish(void) +{ + s3c_pm_check_cleanup(); +} + +static const struct platform_suspend_ops exynos_suspend_ops = { + .enter = exynos_suspend_enter, + .prepare = exynos_suspend_prepare, + .finish = exynos_suspend_finish, + .valid = suspend_valid_only_mem, +}; + void __init exynos_pm_init(void) { u32 tmp; - pm_cpu_prep = exynos_pm_prepare; - pm_cpu_sleep = exynos_cpu_suspend; - - s3c_pm_init(); - /* All wakeup disable */ tmp = __raw_readl(S5P_WAKEUP_MASK); tmp |= ((0xFF << 8) | (0x1F << 1)); __raw_writel(tmp, S5P_WAKEUP_MASK); register_syscore_ops(&exynos_pm_syscore_ops); + suspend_set_ops(&exynos_suspend_ops); } diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 7c029ce27711..2c15a8fbcb5a 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -31,6 +31,8 @@ #define EXYNOS5440_SWRESET S5P_PMUREG(0x00C4) #define S5P_WAKEUP_STAT S5P_PMUREG(0x0600) +#define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604) +#define S5P_WAKEUP_MASK S5P_PMUREG(0x0608) #define S5P_INFORM0 S5P_PMUREG(0x0800) #define S5P_INFORM1 S5P_PMUREG(0x0804) diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S new file mode 100644 index 000000000000..a2613e944e10 --- /dev/null +++ b/arch/arm/mach-exynos/sleep.S @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Exynos low-level resume code + * + * 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. + */ + +#include +#include +#include + +#define CPU_MASK 0xff0ffff0 +#define CPU_CORTEX_A9 0x410fc090 + + /* + * The following code is located into the .data section. This is to + * allow l2x0_regs_phys to be accessed with a relative load while we + * can't rely on any MMU translation. We could have put l2x0_regs_phys + * in the .text section as well, but some setups might insist on it to + * be truly read-only. (Reference from: arch/arm/kernel/sleep.S) + */ + .data + .align + + /* + * sleep magic, to allow the bootloader to check for an valid + * image to resume to. Must be the first word before the + * exynos_cpu_resume entry. + */ + + .word 0x2bedf00d + + /* + * exynos_cpu_resume + * + * resume code entry for bootloader to call + */ + +ENTRY(exynos_cpu_resume) +#ifdef CONFIG_CACHE_L2X0 + mrc p15, 0, r0, c0, c0, 0 + ldr r1, =CPU_MASK + and r0, r0, r1 + ldr r1, =CPU_CORTEX_A9 + cmp r0, r1 + bne skip_l2_resume + adr r0, l2x0_regs_phys + ldr r0, [r0] + cmp r0, #0 + beq skip_l2_resume + ldr r1, [r0, #L2X0_R_PHY_BASE] + ldr r2, [r1, #L2X0_CTRL] + tst r2, #0x1 + bne skip_l2_resume + ldr r2, [r0, #L2X0_R_AUX_CTRL] + str r2, [r1, #L2X0_AUX_CTRL] + ldr r2, [r0, #L2X0_R_TAG_LATENCY] + str r2, [r1, #L2X0_TAG_LATENCY_CTRL] + ldr r2, [r0, #L2X0_R_DATA_LATENCY] + str r2, [r1, #L2X0_DATA_LATENCY_CTRL] + ldr r2, [r0, #L2X0_R_PREFETCH_CTRL] + str r2, [r1, #L2X0_PREFETCH_CTRL] + ldr r2, [r0, #L2X0_R_PWR_CTRL] + str r2, [r1, #L2X0_POWER_CTRL] + mov r2, #1 + str r2, [r1, #L2X0_CTRL] +skip_l2_resume: +#endif + b cpu_resume +ENDPROC(exynos_cpu_resume) +#ifdef CONFIG_CACHE_L2X0 + .globl l2x0_regs_phys +l2x0_regs_phys: + .long 0 +#endif diff --git a/arch/arm/plat-samsung/s5p-sleep.S b/arch/arm/plat-samsung/s5p-sleep.S index 20764bd5518e..c5001659bdf8 100644 --- a/arch/arm/plat-samsung/s5p-sleep.S +++ b/arch/arm/plat-samsung/s5p-sleep.S @@ -23,18 +23,7 @@ #include #include -#include -#define CPU_MASK 0xff0ffff0 -#define CPU_CORTEX_A9 0x410fc090 - -/* - * The following code is located into the .data section. This is to - * allow l2x0_regs_phys to be accessed with a relative load while we - * can't rely on any MMU translation. We could have put l2x0_regs_phys - * in the .text section as well, but some setups might insist on it to - * be truly read-only. (Reference from: arch/arm/kernel/sleep.S) - */ .data .align @@ -53,39 +42,5 @@ */ ENTRY(s3c_cpu_resume) -#ifdef CONFIG_CACHE_L2X0 - mrc p15, 0, r0, c0, c0, 0 - ldr r1, =CPU_MASK - and r0, r0, r1 - ldr r1, =CPU_CORTEX_A9 - cmp r0, r1 - bne skip_l2_resume - adr r0, l2x0_regs_phys - ldr r0, [r0] - cmp r0, #0 - beq skip_l2_resume - ldr r1, [r0, #L2X0_R_PHY_BASE] - ldr r2, [r1, #L2X0_CTRL] - tst r2, #0x1 - bne skip_l2_resume - ldr r2, [r0, #L2X0_R_AUX_CTRL] - str r2, [r1, #L2X0_AUX_CTRL] - ldr r2, [r0, #L2X0_R_TAG_LATENCY] - str r2, [r1, #L2X0_TAG_LATENCY_CTRL] - ldr r2, [r0, #L2X0_R_DATA_LATENCY] - str r2, [r1, #L2X0_DATA_LATENCY_CTRL] - ldr r2, [r0, #L2X0_R_PREFETCH_CTRL] - str r2, [r1, #L2X0_PREFETCH_CTRL] - ldr r2, [r0, #L2X0_R_PWR_CTRL] - str r2, [r1, #L2X0_POWER_CTRL] - mov r2, #1 - str r2, [r1, #L2X0_CTRL] -skip_l2_resume: -#endif b cpu_resume ENDPROC(s3c_cpu_resume) -#ifdef CONFIG_CACHE_L2X0 - .globl l2x0_regs_phys -l2x0_regs_phys: - .long 0 -#endif From dd8ac696b20c1be5ca4728045df10e882e01e91d Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Tue, 18 Mar 2014 07:28:30 +0900 Subject: [PATCH 12/16] ARM: EXYNOS: Allow wake-up using GIC interrupts This patch restores the ability to receive wake-up events from internal GIC interrupts, e.g. RTC tick or alarm interrupts. Signed-off-by: Tomasz Figa Acked-by: Kyungmin Park Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/pm.c | 53 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index ada1c8374b77..15af0ceb0a66 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,16 @@ #include "common.h" #include "regs-pmu.h" +/** + * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping + * @hwirq: Hardware IRQ signal of the GIC + * @mask: Mask in PMU wake-up mask register + */ +struct exynos_wkup_irq { + unsigned int hwirq; + u32 mask; +}; + static struct sleep_save exynos5_sys_save[] = { SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), }; @@ -48,8 +59,47 @@ static struct sleep_save exynos_core_save[] = { SAVE_ITEM(S5P_SROM_BC3), }; +/* + * GIC wake-up support + */ + static u32 exynos_irqwake_intmask = 0xffffffff; +static const struct exynos_wkup_irq exynos4_wkup_irq[] = { + { 76, BIT(1) }, /* RTC alarm */ + { 77, BIT(2) }, /* RTC tick */ + { /* sentinel */ }, +}; + +static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { + { 75, BIT(1) }, /* RTC alarm */ + { 76, BIT(2) }, /* RTC tick */ + { /* sentinel */ }, +}; + +static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) +{ + const struct exynos_wkup_irq *wkup_irq; + + if (soc_is_exynos5250()) + wkup_irq = exynos5250_wkup_irq; + else + wkup_irq = exynos4_wkup_irq; + + while (wkup_irq->mask) { + if (wkup_irq->hwirq == data->hwirq) { + if (!state) + exynos_irqwake_intmask |= wkup_irq->mask; + else + exynos_irqwake_intmask &= ~wkup_irq->mask; + return 0; + } + ++wkup_irq; + } + + return -ENOENT; +} + /* For Cortex-A9 Diagnostic and Power control register */ static unsigned int save_arm_register[2]; @@ -258,6 +308,9 @@ void __init exynos_pm_init(void) { u32 tmp; + /* Platform-specific GIC callback */ + gic_arch_extn.irq_set_wake = exynos_irq_set_wake; + /* All wakeup disable */ tmp = __raw_readl(S5P_WAKEUP_MASK); tmp |= ((0xFF << 8) | (0x1F << 1)); From cf559ab94e058df65c841b4afc8d5346fdda19b3 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Mar 2014 02:55:11 +0900 Subject: [PATCH 13/16] serial: s3c: Fix build of header without serial_core.h preinclusion serial_s3c.h uses upf_t which is defined in serial_core.h but does not include that itself meaning that users which include serial_s3c.h by itself don't build. Signed-off-by: Mark Brown [t.figa: Moved inclusion under #ifndef __ASSEMBLY__ to fix mach-exynos] Signed-off-by: Tomasz Figa Signed-off-by: Kukjin Kim --- include/linux/serial_s3c.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h index 907d9d1d56cf..e6fc9567690b 100644 --- a/include/linux/serial_s3c.h +++ b/include/linux/serial_s3c.h @@ -233,6 +233,8 @@ #ifndef __ASSEMBLY__ +#include + /* configuration structure for per-machine configurations for the * serial port * From e1a9d00c689a5da2d1baf273891507c5fb063f4c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 21 Mar 2014 02:57:18 +0900 Subject: [PATCH 14/16] ARM: S3C64XX: Fix build for implicit serial_s3c.h inclusion Some very recent change appears to have removed an implicit inclusion of serial_s3c.h causing build failures due to references to UART registers in the serial port restore code in next-20140318. Include it explicitly to fix the build. Signed-off-by: Mark Brown Signed-off-by: Kukjin Kim --- arch/arm/mach-s3c64xx/include/mach/pm-core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-s3c64xx/include/mach/pm-core.h b/arch/arm/mach-s3c64xx/include/mach/pm-core.h index c0537f40a3d8..a30a1e3ffc6a 100644 --- a/arch/arm/mach-s3c64xx/include/mach/pm-core.h +++ b/arch/arm/mach-s3c64xx/include/mach/pm-core.h @@ -15,6 +15,8 @@ #ifndef __MACH_S3C64XX_PM_CORE_H #define __MACH_S3C64XX_PM_CORE_H __FILE__ +#include + #include static inline void s3c_pm_debug_init_uart(void) From 58f37b0d47e9839fc8ef90d712594ed55cfcb2c7 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Fri, 21 Mar 2014 03:22:33 +0900 Subject: [PATCH 15/16] ARM: S5P64X0: Explicitly include linux/serial_s3c.h in mach/pm-core.h This patch fixes compilation failure due to missing explicit inclusion of linux/serial_s3c.h in mach/pm-core.h, which contains definitions required for further code in this header. Signed-off-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-s5p64x0/include/mach/pm-core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-s5p64x0/include/mach/pm-core.h b/arch/arm/mach-s5p64x0/include/mach/pm-core.h index e52f7545d3aa..1e0eb65b2b82 100644 --- a/arch/arm/mach-s5p64x0/include/mach/pm-core.h +++ b/arch/arm/mach-s5p64x0/include/mach/pm-core.h @@ -12,6 +12,8 @@ * published by the Free Software Foundation. */ +#include + #include static inline void s3c_pm_debug_init_uart(void) From 8dec067dc9c59f9fdcaf4357c22994cde3647eb8 Mon Sep 17 00:00:00 2001 From: Tomasz Figa Date: Fri, 21 Mar 2014 02:59:30 +0900 Subject: [PATCH 16/16] ARM: EXYNOS: Fix compilation error in cpuidle.c The big series refactoring Exynos suspend to RAM handling missed the cpuidle driver that is disabled in exynos_defconfig, leaving it including old mach/pm_core.h header and using old s3c_cpu_resume symbol instead of new exynos_cpu_resume, resulting in compilation failures with CONFIG_ARCH_EXYNOS and CONFIG_CPU_IDLE enabled. This patch fixes that silly mistake and performs necessary modification to arhc/arm/exynos/cpuidle.c to make it compile again. Signed-off-by: Tomasz Figa Signed-off-by: Kukjin Kim --- arch/arm/mach-exynos/cpuidle.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index f57cb91f02aa..b530231130a0 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c @@ -26,7 +26,6 @@ #include #include -#include #include #include "common.h" @@ -127,7 +126,7 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev, /* Set value of power down register for aftr mode */ exynos_sys_powerdown_conf(SYS_AFTR); - __raw_writel(virt_to_phys(s3c_cpu_resume), REG_DIRECTGO_ADDR); + __raw_writel(virt_to_phys(exynos_cpu_resume), REG_DIRECTGO_ADDR); __raw_writel(S5P_CHECK_AFTR, REG_DIRECTGO_FLAG); save_cpu_arch_register();