[PATCH 5/5] ARM: S5P64X0: Add Power Management support

Abhilash Kesavan kesavan.abhilash at gmail.com
Wed Sep 7 02:33:52 EDT 2011


Hi Mr Kim,

On Wed, Sep 7, 2011 at 11:31 AM, Kukjin Kim <kgene.kim at samsung.com> wrote:
> Abhilash Kesavan wrote:
>>
>> Add suspend-to-ram support for SMDK6440/50
>>
>> Signed-off-by: Abhilash Kesavan <a.kesavan at samsung.com>
>> ---
>>  arch/arm/Kconfig                                |    2 +-
>>  arch/arm/mach-s5p64x0/Kconfig                   |    4 +
>>  arch/arm/mach-s5p64x0/Makefile                  |    1 +
>>  arch/arm/mach-s5p64x0/include/mach/map.h        |    1 +
>>  arch/arm/mach-s5p64x0/include/mach/pm-core.h    |  117 +++++++++++++
>>  arch/arm/mach-s5p64x0/include/mach/regs-clock.h |   33 ++++
>>  arch/arm/mach-s5p64x0/include/mach/regs-gpio.h  |   19 ++
>>  arch/arm/mach-s5p64x0/irq-eint.c                |    2 +
>>  arch/arm/mach-s5p64x0/irq-pm.c                  |   92 ++++++++++
>>  arch/arm/mach-s5p64x0/pm.c                      |  204
>> +++++++++++++++++++++++
>>  10 files changed, 474 insertions(+), 1 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
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 2c71a8f..47aed0d 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -2071,7 +2071,7 @@ menu "Power management options"
>>  source "kernel/power/Kconfig"
>>
>>  config ARCH_SUSPEND_POSSIBLE
>> -     depends on !ARCH_S5P64X0 && !ARCH_S5PC100
>> +     depends on !ARCH_S5PC100
>>       depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
>>               CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
>>       def_bool y
>> diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
>> index 65c7518..d7f034a 100644
>> --- a/arch/arm/mach-s5p64x0/Kconfig
>> +++ b/arch/arm/mach-s5p64x0/Kconfig
>> @@ -11,6 +11,8 @@ config CPU_S5P6440
>>       bool
>>       select S3C_PL330_DMA
>>       select S5P_HRT
>> +     select SAMSUNG_SLEEP if PM
>> +     select SAMSUNG_WAKEMASK if PM
>>       help
>>         Enable S5P6440 CPU support
>>
>> @@ -18,6 +20,8 @@ config CPU_S5P6450
>>       bool
>>       select S3C_PL330_DMA
>>       select S5P_HRT
>> +     select SAMSUNG_SLEEP if PM
>> +     select SAMSUNG_WAKEMASK if PM
>>       help
>>         Enable S5P6450 CPU support
>>
>> diff --git a/arch/arm/mach-s5p64x0/Makefile
> b/arch/arm/mach-s5p64x0/Makefile
>> index 5f6afdf..acfebb7 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 gpiolib.o
>>  obj-$(CONFIG_ARCH_S5P64X0)   += setup-i2c0.o irq-eint.o
>>  obj-$(CONFIG_CPU_S5P6440)    += clock-s5p6440.o
>>  obj-$(CONFIG_CPU_S5P6450)    += clock-s5p6450.o
>> +obj-$(CONFIG_PM)             += pm.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 95c9125..6138f7c 100644
>> --- a/arch/arm/mach-s5p64x0/include/mach/map.h
>> +++ b/arch/arm/mach-s5p64x0/include/mach/map.h
>> @@ -85,5 +85,6 @@
>>  #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))
>>
>>  #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 0000000..aee9d85
>> --- /dev/null
>> +++ b/arch/arm/mach-s5p64x0/include/mach/pm-core.h
>> @@ -0,0 +1,117 @@
>> +/* linux/arch/arm/mach-s5p64x0/include/mach/pm-core.h
>> + *
>> + * Copyright (c) 2011 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);
>> +
>> +     /*
>> +      * As a note, since the S5P64X0 UARTs generally have multiple
>> +      * clock sources, we simply enable PCLK at the moment and hope
>> +      * that the resume settings for the UART are suitable for the
>> +      * use with 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;
>> +
>> +     /*
>> +      * S5P64X0 UART blocks only support level interrupts, so ensure that
>> +      * when we restore unused UART blocks we force the level interrupt
>> +      * settings.
>> +      */
>> +     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 a 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;
>> +     }
>> +}
>> +
>> +static inline void s3c_pm_restored_gpios(void)
>> +{
>> +     /* ensure sleep mode has been cleared from the system */
>> +     __raw_writel(0, S5P64X0_SLPEN);
>> +}
>> +
>> +static inline void s3c_pm_saved_gpios(void)
>> +{
>> +     /*
>> +      * turn on the sleep mode and keep it there, as it seems that during
>> +      * suspend the xCON registers get re-set and thus you can end up
> with
>> +      * problems between going to sleep and resuming.
>> +      */
>> +     __raw_writel(S5P64X0_SLPEN_USE_xSLP, S5P64X0_SLPEN);
>> +}
>> diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
> b/arch/arm/mach-
>> s5p64x0/include/mach/regs-clock.h
>> index a133f22..75f66a9 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 @@
>>  #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_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_WAKEUP_STAT          S5P_CLKREG(0x908)
>> +
>> +#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)
>
> Should be added blank around "<<" like (1 << 2).
> And if possible, the name should be same with datasheet like
> ...CLK_GATE_HCLK1_FIMGVG.
>
> Please don't make new name.
OK..will change
>
>> +#define S5P64X0_CLKCON_SCLK1_FIMGVG  (1<<2)
>
> Same as above.
OK..will change
> ...CLK_GATE_SCLK1_FIMGVG
>
>> +
>> +/* 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)
>
> Same as above.
OK..will change
>
>> +
>> +#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)
>
> Same...please use same name with datasheet.
would you like it to be PWR_STABLE_PWR_CNT_VAL_4 ?
>
>> +
>> +#define S5P6450_OTHERS_DISABLE_INT   (1 << 31)
>> +#define S5P64X0_OTHERS_RET_UART              (1 << 26)
>> +#define S5P64X0_OTHERS_RET_MMC1              (1 << 25)
>> +#define S5P64X0_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 6ce2547..27a2230 100644
>> --- a/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
>> +++ b/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
>> @@ -34,14 +34,33 @@
>>  #define S5P6450_GPQ_BASE             (S5P_VA_GPIO + 0x0180)
>>  #define S5P6450_GPS_BASE             (S5P_VA_GPIO + 0x0300)
>>
>> +#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)
>> +
>>  /* External interrupt control registers for group0 */
>>
>>  #define EINT0CON0_OFFSET             (0x900)
>> +#define EINT0FLTCON0_OFFSET          (0x910)
>> +#define EINT0FLTCON1_OFFSET          (0x914)
>>  #define EINT0MASK_OFFSET             (0x920)
>>  #define EINT0PEND_OFFSET             (0x924)
>>
>>  #define S5P64X0_EINT0CON0            (S5P_VA_GPIO +
>> EINT0CON0_OFFSET)
>> +#define S5P64X0_EINT0FLTCON0         (S5P_VA_GPIO +
>> EINT0FLTCON0_OFFSET)
>> +#define S5P64X0_EINT0FLTCON1         (S5P_VA_GPIO +
>> EINT0FLTCON1_OFFSET)
>>  #define S5P64X0_EINT0MASK            (S5P_VA_GPIO +
>> EINT0MASK_OFFSET)
>>  #define S5P64X0_EINT0PEND            (S5P_VA_GPIO +
>> EINT0PEND_OFFSET)
>>
>> +#define S5P64X0_SLPEN                        (S5P_VA_GPIO + 0x930)
>> +#define S5P64X0_SLPEN_USE_xSLP               (1 << 0)
>> +
>>  #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 fe7380f..3b94c6c 100644
>> --- a/arch/arm/mach-s5p64x0/irq-eint.c
>> +++ b/arch/arm/mach-s5p64x0/irq-eint.c
>> @@ -19,6 +19,7 @@
>>
>>  #include <plat/regs-irqtype.h>
>>  #include <plat/gpio-cfg.h>
>> +#include <plat/pm.h>
>>
>>  #include <mach/regs-gpio.h>
>>  #include <mach/regs-clock.h>
>> @@ -133,6 +134,7 @@ static int s5p64x0_alloc_gc(void)
>>       ct->chip.irq_mask = irq_gc_mask_set_bit;
>>       ct->chip.irq_unmask = irq_gc_mask_clr_bit;
>>       ct->chip.irq_set_type = s5p64x0_irq_eint_set_type;
>> +     ct->chip.irq_set_wake = s3c_irqext_wake;
>>       ct->regs.ack = EINT0PEND_OFFSET;
>>       ct->regs.mask = EINT0MASK_OFFSET;
>>       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 0000000..3e6f245
>> --- /dev/null
>> +++ b/arch/arm/mach-s5p64x0/irq-pm.c
>> @@ -0,0 +1,92 @@
>> +/* linux/arch/arm/mach-s5p64x0/irq-pm.c
>> + *
>> + * Copyright (c) 2011 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/syscore_ops.h>
>> +#include <linux/serial_core.h>
>> +#include <linux/io.h>
>> +
>> +#include <plat/regs-serial.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(void)
>> +{
>> +     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 void s5p64x0_irq_pm_resume(void)
>> +{
>> +     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__);
>> +}
>> +
>> +static struct syscore_ops s5p64x0_irq_syscore_ops = {
>> +     .suspend = s5p64x0_irq_pm_suspend,
>> +     .resume  = s5p64x0_irq_pm_resume,
>> +};
>> +
>> +static int __init s5p64x0_syscore_init(void)
>> +{
>> +     register_syscore_ops(&s5p64x0_irq_syscore_ops);
>> +
>> +     return 0;
>> +}
>> +core_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 0000000..cced4fb
>> --- /dev/null
>> +++ b/arch/arm/mach-s5p64x0/pm.c
>> @@ -0,0 +1,204 @@
>> +/* linux/arch/arm/mach-s5p64x0/pm.c
>> + *
>> + * Copyright (c) 2011 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/syscore_ops.h>
>> +#include <linux/io.h>
>> +
>> +#include <plat/cpu.h>
>> +#include <plat/pm.h>
>> +#include <plat/regs-timer.h>
>> +#include <plat/wakeup-mask.h>
>> +
>> +#include <mach/regs-clock.h>
>> +#include <mach/regs-gpio.h>
>> +
>> +static struct sleep_save s5p64x0_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),
>> +};
>> +
>> +static struct sleep_save s5p64x0_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),
>> +
>> +     SAVE_ITEM(S3C64XX_TINT_CSTAT),
>> +};
>> +
>> +/* DPLL is present only in S5P6450 */
>> +static struct sleep_save s5p6450_core_save[] = {
>> +     SAVE_ITEM(S5P6450_DPLL_CON),
>> +     SAVE_ITEM(S5P6450_DPLL_CON_K),
>> +};
>> +
>> +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(s5p64x0_core_save,
>> +                             ARRAY_SIZE(s5p64x0_core_save));
>> +
>> +     if ((__raw_readl(S5P64X0_SYS_ID) & 0xFF000) == 0x50000)
>> +             s3c_pm_do_restore_core(s5p6450_core_save,
>> +                             ARRAY_SIZE(s5p6450_core_save));
>
> You can use soc_is_xxx() here.
Yep, wasn't there when I posted the series. Will change.
>
>> +
>> +     s3c_pm_do_restore(s5p64x0_misc_save,
>> ARRAY_SIZE(s5p64x0_misc_save));
>> +}
>> +
>> +void s3c_pm_save_core(void)
>> +{
>> +     s3c_pm_do_save(s5p64x0_misc_save,
>> ARRAY_SIZE(s5p64x0_misc_save));
>> +
>> +     if ((__raw_readl(S5P64X0_SYS_ID) & 0xFF000) == 0x50000)
>> +             s3c_pm_do_save(s5p6450_core_save,
>> +                             ARRAY_SIZE(s5p6450_core_save));
>
> Same.
>
>> +
>> +     s3c_pm_do_save(s5p64x0_core_save,
>> ARRAY_SIZE(s5p64x0_core_save));
>> +}
>> +
>> +static int s5p64x0_cpu_suspend(unsigned long arg)
>> +{
>> +     unsigned long tmp = 0;
>> +
>> +     /*
>> +      * Issue the standby signal into the pm unit. Note, we
>> +      * issue a write-buffer drain just in case.
>> +      */
>> +     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 s5p64x0_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)
>> +{
>> +     u32 tmp;
>> +
>> +     samsung_sync_wakemask(S5P64X0_PWR_CFG,
>> +                     s5p64x0_wake_irqs, ARRAY_SIZE(s5p64x0_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 bit is present only in S5P6450, it is reserved
>> +      * in S5P6440.
>> +      */
>> +     if ((__raw_readl(S5P64X0_SYS_ID) & 0xFF000) == 0x50000) {
>> +             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;
>
> If pm_uart_udivslot has value, the UDIVSLOT3 is used...is this right on
> S5P64X0?
UDIVSLOT at an offset of 2C seems fine for 64X0.
>
>> +
>> +     return 0;
>> +}
>> +
>> +static struct sysdev_driver s5p64x0_pm_driver = {
>> +     .add            = s5p64x0_pm_add,
>> +};
>> +
>> +static __init int s5p64x0_pm_drvinit(void)
>> +{
>> +     s3c_pm_init();
>> +
>> +     return sysdev_driver_register(&s5p64x0_sysclass,
> &s5p64x0_pm_driver);
>> +}
>> +arch_initcall(s5p64x0_pm_drvinit);
>> +
>> +static void s5p64x0_pm_resume(void)
>> +{
>> +     u32 tmp;
>> +
>> +     tmp = __raw_readl(S5P64X0_OTHERS);
>> +     tmp |= (S5P64X0_OTHERS_RET_MMC0 |
>> S5P64X0_OTHERS_RET_MMC1 | \
>> +                     S5P64X0_OTHERS_RET_UART);
>> +     __raw_writel(tmp , S5P64X0_OTHERS);
>> +}
>> +
>> +static struct syscore_ops s5p64x0_pm_syscore_ops = {
>> +     .resume         = s5p64x0_pm_resume,
>> +};
>> +
>> +static __init int s5p64x0_pm_syscore_init(void)
>> +{
>> +     register_syscore_ops(&s5p64x0_pm_syscore_ops);
>> +
>> +     return 0;
>> +}
>> +arch_initcall(s5p64x0_pm_syscore_init);
>> --
>> 1.7.4.1
>
> Basically, this codes need small fixing. I mean if this codes have been
> tested on board and it works fine, it's ok to me.
>
> But as you said, s5p64x0 pm is almost same with s3c64xx, so we need to clean
> them up next time :)
Has been tested for 6440 and 6450. Thanks for the review.
>
> Thanks.
>
> Best regards,
> Kgene.
Abhilash
> --
> Kukjin Kim <kgene.kim at samsung.com>, Senior Engineer,
> SW Solution Development Team, Samsung Electronics Co., Ltd.
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>



More information about the linux-arm-kernel mailing list