提交 60e49ca6 编写于 作者: J Jongpill Lee 提交者: Kukjin Kim

ARM: EXYNOS: Support suspend and resume for EXYNOS5250

This patch adds function for suspend and resume of Exynos5250.
Signed-off-by: NJongpill Lee <boyko.lee@samsung.com>
[kgene.kim@samsung.com: re-worked on top of v3.4-rc7]
Signed-off-by: NKukjin Kim <kgene.kim@samsung.com>
上级 a2fa3041
...@@ -62,6 +62,8 @@ config SOC_EXYNOS5250 ...@@ -62,6 +62,8 @@ config SOC_EXYNOS5250
default y default y
depends on ARCH_EXYNOS5 depends on ARCH_EXYNOS5
select SAMSUNG_DMADEV select SAMSUNG_DMADEV
select S5P_PM if PM
select S5P_SLEEP if PM
help help
Enable EXYNOS5250 SoC support Enable EXYNOS5250 SoC support
......
...@@ -33,7 +33,7 @@ static inline void s3c_pm_arch_prepare_irqs(void) ...@@ -33,7 +33,7 @@ static inline void s3c_pm_arch_prepare_irqs(void)
__raw_writel(tmp, S5P_WAKEUP_MASK); __raw_writel(tmp, S5P_WAKEUP_MASK);
__raw_writel(s3c_irqwake_intmask, 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) static inline void s3c_pm_arch_stop_clocks(void)
......
...@@ -77,7 +77,9 @@ static unsigned int save_arm_register[2]; ...@@ -77,7 +77,9 @@ static unsigned int save_arm_register[2];
static int exynos_cpu_suspend(unsigned long arg) static int exynos_cpu_suspend(unsigned long arg)
{ {
#ifdef CONFIG_CACHE_L2X0
outer_flush_all(); outer_flush_all();
#endif
/* issue the standby signal into the pm unit. */ /* issue the standby signal into the pm unit. */
cpu_do_idle(); cpu_do_idle();
...@@ -88,13 +90,19 @@ static int exynos_cpu_suspend(unsigned long arg) ...@@ -88,13 +90,19 @@ static int exynos_cpu_suspend(unsigned long arg)
static void exynos_pm_prepare(void) 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(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 */ /* Set value of power down register for sleep mode */
...@@ -107,7 +115,8 @@ static void exynos_pm_prepare(void) ...@@ -107,7 +115,8 @@ static void exynos_pm_prepare(void)
/* Before enter central sequence mode, clock src register have to set */ /* 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()) if (soc_is_exynos4210())
s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc)); s3c_pm_do_restore_core(exynos4210_set_clksrc, ARRAY_SIZE(exynos4210_set_clksrc));
...@@ -190,7 +199,7 @@ static void exynos4_restore_pll(void) ...@@ -190,7 +199,7 @@ static void exynos4_restore_pll(void)
} }
static struct subsys_interface exynos_pm_interface = { static struct subsys_interface exynos_pm_interface = {
.name = "exynos4_pm", .name = "exynos_pm",
.subsys = &exynos_subsys, .subsys = &exynos_subsys,
.add_dev = exynos_pm_add, .add_dev = exynos_pm_add,
}; };
...@@ -231,22 +240,22 @@ static int exynos_pm_suspend(void) ...@@ -231,22 +240,22 @@ static int exynos_pm_suspend(void)
tmp &= ~S5P_CENTRAL_LOWPWR_CFG; tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
__raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); __raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
if (soc_is_exynos4212() || soc_is_exynos4412()) { /* Setting SEQ_OPTION register */
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);
}
/* Save Power control register */ tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
asm ("mrc p15, 0, %0, c15, c0, 0" __raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
: "=r" (tmp) : : "cc");
save_arm_register[0] = tmp;
/* Save Diagnostic register */ if (!soc_is_exynos5250()) {
asm ("mrc p15, 0, %0, c15, c0, 1" /* Save Power control register */
: "=r" (tmp) : : "cc"); asm ("mrc p15, 0, %0, c15, c0, 0"
save_arm_register[1] = tmp; : "=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; return 0;
} }
...@@ -268,17 +277,19 @@ static void exynos_pm_resume(void) ...@@ -268,17 +277,19 @@ static void exynos_pm_resume(void)
/* No need to perform below restore code */ /* No need to perform below restore code */
goto early_wakeup; goto early_wakeup;
} }
/* Restore Power control register */ if (!soc_is_exynos5250()) {
tmp = save_arm_register[0]; /* Restore Power control register */
asm volatile ("mcr p15, 0, %0, c15, c0, 0" tmp = save_arm_register[0];
: : "r" (tmp) asm volatile ("mcr p15, 0, %0, c15, c0, 0"
: "cc"); : : "r" (tmp)
: "cc");
/* Restore Diagnostic register */
tmp = save_arm_register[1]; /* Restore Diagnostic register */
asm volatile ("mcr p15, 0, %0, c15, c0, 1" tmp = save_arm_register[1];
: : "r" (tmp) asm volatile ("mcr p15, 0, %0, c15, c0, 1"
: "cc"); : : "r" (tmp)
: "cc");
}
/* For release retention */ /* For release retention */
...@@ -292,11 +303,13 @@ static void exynos_pm_resume(void) ...@@ -292,11 +303,13 @@ static void exynos_pm_resume(void)
s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); 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 #ifdef CONFIG_SMP
scu_enable(S5P_VA_SCU); scu_enable(S5P_VA_SCU);
#endif #endif
}
early_wakeup: early_wakeup:
return; return;
...@@ -307,9 +320,9 @@ static struct syscore_ops exynos_pm_syscore_ops = { ...@@ -307,9 +320,9 @@ static struct syscore_ops exynos_pm_syscore_ops = {
.resume = exynos_pm_resume, .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); register_syscore_ops(&exynos_pm_syscore_ops);
return 0; return 0;
} }
arch_initcall(exynos4_pm_syscore_init); arch_initcall(exynos_pm_syscore_init);
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/bug.h>
#include <mach/regs-clock.h> #include <mach/regs-clock.h>
#include <mach/pmu.h> #include <mach/pmu.h>
...@@ -314,10 +315,68 @@ static struct exynos_pmu_conf exynos5250_pmu_config[] = { ...@@ -314,10 +315,68 @@ static struct exynos_pmu_conf exynos5250_pmu_config[] = {
{ PMU_TABLE_END,}, { 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) void exynos_sys_powerdown_conf(enum sys_powerdown mode)
{ {
unsigned int i; unsigned int i;
if (soc_is_exynos5250())
exynos5_init_pmu();
for (i = 0; (exynos_pmu_config[i].reg != PMU_TABLE_END) ; i++) for (i = 0; (exynos_pmu_config[i].reg != PMU_TABLE_END) ; i++)
__raw_writel(exynos_pmu_config[i].val[mode], __raw_writel(exynos_pmu_config[i].val[mode],
exynos_pmu_config[i].reg); exynos_pmu_config[i].reg);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册