ARM: EXYNOS: Support suspend and resume for EXYNOS5250

This patch adds function for suspend and resume of Exynos5250.

Signed-off-by: Jongpill Lee <boyko.lee@samsung.com>
[kgene.kim@samsung.com: re-worked on top of v3.4-rc7]
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
This commit is contained in:
Jongpill Lee 2012-02-17 12:23:51 +09:00 committed by Kukjin Kim
parent a2fa3041b6
commit 60e49ca654
4 changed files with 110 additions and 36 deletions

View File

@ -62,6 +62,8 @@ config SOC_EXYNOS5250
default y
depends on ARCH_EXYNOS5
select SAMSUNG_DMADEV
select S5P_PM if PM
select S5P_SLEEP if PM
help
Enable EXYNOS5250 SoC support

View File

@ -33,7 +33,7 @@ static inline void s3c_pm_arch_prepare_irqs(void)
__raw_writel(tmp, S5P_WAKEUP_MASK);
__raw_writel(s3c_irqwake_intmask, S5P_WAKEUP_MASK);
__raw_writel(s3c_irqwake_eintmask, S5P_EINT_WAKEUP_MASK);
__raw_writel(s3c_irqwake_eintmask & 0xFFFFFFFE, S5P_EINT_WAKEUP_MASK);
}
static inline void s3c_pm_arch_stop_clocks(void)

View File

@ -77,7 +77,9 @@ static unsigned int save_arm_register[2];
static int exynos_cpu_suspend(unsigned long arg)
{
#ifdef CONFIG_CACHE_L2X0
outer_flush_all();
#endif
/* issue the standby signal into the pm unit. */
cpu_do_idle();
@ -88,13 +90,19 @@ static int exynos_cpu_suspend(unsigned long arg)
static void exynos_pm_prepare(void)
{
u32 tmp;
unsigned int tmp;
s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
tmp = __raw_readl(S5P_INFORM1);
if (!soc_is_exynos5250()) {
s3c_pm_do_save(exynos4_epll_save, ARRAY_SIZE(exynos4_epll_save));
s3c_pm_do_save(exynos4_vpll_save, ARRAY_SIZE(exynos4_vpll_save));
} else {
/* Disable USE_RETENTION of JPEG_MEM_OPTION */
tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION);
tmp &= ~EXYNOS5_OPTION_USE_RETENTION;
__raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION);
}
/* Set value of power down register for sleep mode */
@ -107,7 +115,8 @@ static void exynos_pm_prepare(void)
/* Before enter central sequence mode, clock src register have to set */
s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc));
if (!soc_is_exynos5250())
s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc));
if (soc_is_exynos4210())
s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc));
@ -190,7 +199,7 @@ static void exynos4_restore_pll(void)
}
static struct subsys_interface exynos_pm_interface = {
.name = "exynos4_pm",
.name = "exynos_pm",
.subsys = &exynos_subsys,
.add_dev = exynos_pm_add,
};
@ -231,23 +240,23 @@ static int exynos_pm_suspend(void)
tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
__raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
if (soc_is_exynos4212() || soc_is_exynos4412()) {
tmp = __raw_readl(S5P_CENTRAL_SEQ_OPTION);
tmp &= ~(S5P_USE_STANDBYWFI_ISP_ARM |
S5P_USE_STANDBYWFE_ISP_ARM);
__raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
/* Setting SEQ_OPTION register */
tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
__raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
if (!soc_is_exynos5250()) {
/* Save Power control register */
asm ("mrc p15, 0, %0, c15, c0, 0"
: "=r" (tmp) : : "cc");
save_arm_register[0] = tmp;
/* Save Diagnostic register */
asm ("mrc p15, 0, %0, c15, c0, 1"
: "=r" (tmp) : : "cc");
save_arm_register[1] = tmp;
}
/* Save Power control register */
asm ("mrc p15, 0, %0, c15, c0, 0"
: "=r" (tmp) : : "cc");
save_arm_register[0] = tmp;
/* Save Diagnostic register */
asm ("mrc p15, 0, %0, c15, c0, 1"
: "=r" (tmp) : : "cc");
save_arm_register[1] = tmp;
return 0;
}
@ -268,17 +277,19 @@ static void exynos_pm_resume(void)
/* No need to perform below restore code */
goto early_wakeup;
}
/* Restore Power control register */
tmp = save_arm_register[0];
asm volatile ("mcr p15, 0, %0, c15, c0, 0"
: : "r" (tmp)
: "cc");
if (!soc_is_exynos5250()) {
/* Restore Power control register */
tmp = save_arm_register[0];
asm volatile ("mcr p15, 0, %0, c15, c0, 0"
: : "r" (tmp)
: "cc");
/* Restore Diagnostic register */
tmp = save_arm_register[1];
asm volatile ("mcr p15, 0, %0, c15, c0, 1"
: : "r" (tmp)
: "cc");
/* Restore Diagnostic register */
tmp = save_arm_register[1];
asm volatile ("mcr p15, 0, %0, c15, c0, 1"
: : "r" (tmp)
: "cc");
}
/* For release retention */
@ -292,11 +303,13 @@ static void exynos_pm_resume(void)
s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
exynos4_restore_pll();
if (!soc_is_exynos5250()) {
exynos4_restore_pll();
#ifdef CONFIG_SMP
scu_enable(S5P_VA_SCU);
scu_enable(S5P_VA_SCU);
#endif
}
early_wakeup:
return;
@ -307,9 +320,9 @@ static struct syscore_ops exynos_pm_syscore_ops = {
.resume = exynos_pm_resume,
};
static __init int exynos4_pm_syscore_init(void)
static __init int exynos_pm_syscore_init(void)
{
register_syscore_ops(&exynos_pm_syscore_ops);
return 0;
}
arch_initcall(exynos4_pm_syscore_init);
arch_initcall(exynos_pm_syscore_init);

View File

@ -11,6 +11,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/bug.h>
#include <mach/regs-clock.h>
#include <mach/pmu.h>
@ -314,10 +315,68 @@ static struct exynos_pmu_conf exynos5250_pmu_config[] = {
{ PMU_TABLE_END,},
};
void __iomem *exynos5_list_both_cnt_feed[] = {
EXYNOS5_ARM_CORE0_OPTION,
EXYNOS5_ARM_CORE1_OPTION,
EXYNOS5_ARM_COMMON_OPTION,
EXYNOS5_GSCL_OPTION,
EXYNOS5_ISP_OPTION,
EXYNOS5_MFC_OPTION,
EXYNOS5_G3D_OPTION,
EXYNOS5_DISP1_OPTION,
EXYNOS5_MAU_OPTION,
EXYNOS5_TOP_PWR_OPTION,
EXYNOS5_TOP_PWR_SYSMEM_OPTION,
};
void __iomem *exynos5_list_diable_wfi_wfe[] = {
EXYNOS5_ARM_CORE1_OPTION,
EXYNOS5_FSYS_ARM_OPTION,
EXYNOS5_ISP_ARM_OPTION,
};
static void exynos5_init_pmu(void)
{
unsigned int i;
unsigned int tmp;
/*
* Enable both SC_FEEDBACK and SC_COUNTER
*/
for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) {
tmp = __raw_readl(exynos5_list_both_cnt_feed[i]);
tmp |= (EXYNOS5_USE_SC_FEEDBACK |
EXYNOS5_USE_SC_COUNTER);
__raw_writel(tmp, exynos5_list_both_cnt_feed[i]);
}
/*
* SKIP_DEACTIVATE_ACEACP_IN_PWDN_BITFIELD Enable
* MANUAL_L2RSTDISABLE_CONTROL_BITFIELD Enable
*/
tmp = __raw_readl(EXYNOS5_ARM_COMMON_OPTION);
tmp |= (EXYNOS5_MANUAL_L2RSTDISABLE_CONTROL |
EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN);
__raw_writel(tmp, EXYNOS5_ARM_COMMON_OPTION);
/*
* Disable WFI/WFE on XXX_OPTION
*/
for (i = 0 ; i < ARRAY_SIZE(exynos5_list_diable_wfi_wfe) ; i++) {
tmp = __raw_readl(exynos5_list_diable_wfi_wfe[i]);
tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE |
EXYNOS5_OPTION_USE_STANDBYWFI);
__raw_writel(tmp, exynos5_list_diable_wfi_wfe[i]);
}
}
void exynos_sys_powerdown_conf(enum sys_powerdown mode)
{
unsigned int i;
if (soc_is_exynos5250())
exynos5_init_pmu();
for (i = 0; (exynos_pmu_config[i].reg != PMU_TABLE_END) ; i++)
__raw_writel(exynos_pmu_config[i].val[mode],
exynos_pmu_config[i].reg);