Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60e49ca6 authored by Jongpill Lee's avatar Jongpill Lee Committed by Kukjin Kim
Browse files

ARM: EXYNOS: Support suspend and resume for EXYNOS5250



This patch adds function for suspend and resume of Exynos5250.

Signed-off-by: default avatarJongpill Lee <boyko.lee@samsung.com>
[kgene.kim@samsung.com: re-worked on top of v3.4-rc7]
Signed-off-by: default avatarKukjin Kim <kgene.kim@samsung.com>
parent a2fa3041
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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

+1 −1
Original line number Diff line number Diff line
@@ -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)
+48 −35
Original line number Diff line number Diff line
@@ -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));

	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));

	tmp = __raw_readl(S5P_INFORM1);
	} 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,6 +115,7 @@ static void exynos_pm_prepare(void)

	/* Before enter central sequence mode, clock src register have to set */

	if (!soc_is_exynos5250())
		s3c_pm_do_restore_core(exynos4_set_clksrc, ARRAY_SIZE(exynos4_set_clksrc));

	if (soc_is_exynos4210())
@@ -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,13 +240,12 @@ 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);
	/* 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");
@@ -247,6 +255,7 @@ static int exynos_pm_suspend(void)
		asm ("mrc p15, 0, %0, c15, c0, 1"
		     : "=r" (tmp) : : "cc");
		save_arm_register[1] = tmp;
	}

	return 0;
}
@@ -268,6 +277,7 @@ static void exynos_pm_resume(void)
		/* No need to perform below restore code */
		goto early_wakeup;
	}
	if (!soc_is_exynos5250()) {
		/* Restore Power control register */
		tmp = save_arm_register[0];
		asm volatile ("mcr p15, 0, %0, c15, c0, 0"
@@ -279,6 +289,7 @@ static void exynos_pm_resume(void)
		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));

	if (!soc_is_exynos5250()) {
		exynos4_restore_pll();

#ifdef CONFIG_SMP
		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);
+59 −0
Original line number Diff line number Diff line
@@ -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);