Skip to contentSkip to conversation

Adds PMU and S2R support for exynos5420

PATCH Superseded Vikas Sajjan 3 participants 10 messages Jun 26, 2014 – Jul 8, 2014

Subsystems (6)

v5 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v5 cover Adds PMU and S2R support for exynos5420

Rebased on
1] Kukjin Kim's tree, for-next branch
https://git.kernel.org/cgit/linux/kernel/git/kgene/linux-samsung.git/log/?h=for-next
2] Pankaj Dubey's v5 PMU patchset
http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg671625.html

changes since v4:
- Adressed comments from Tomasz figa and rebased on Pankaj Dubey's v5 PMU patchset

changes since v3:
Addressed the following comments from Pankaj Dubey, Bartlomiej Zolnierkiewicz, Tomasz Figa and Alim Akhtar:
- Moved EXYNOS5420_USE_STANDBY_WFI_ALL define to regs-pmu.h.
- Merged exynos5420_set_core_flag function into powerdown_conf.
- Removed XXTI_DURATION3 register setting.
- Updated the commit message and ordered the clock registers in clock patch.
- Removed the code for SYS_DISP1_BLK_CFG handling.
- Modified SoC checks to A9 specific checks in PM code.
- Updated some comments in the code and added macros for register offsets.
- Fixed code which was changing pad retention code for older SoCs.

changes since v2:
- Addressed comments from Tomasz figa
- rebased on Pankaj's V3 patchset https://lkml.org/lkml/2014/5/2/612
- dropped patch "ARM: dts: Add node for GPIO keys on SMDK5420", will be sent separately.

changes since v1:
- Addressed comments from Tomasz figa.
- restructured/consolidated as per Tomasz figa's PM consolidations for exynos

Tested on Kukjin Kim's tree, for-next branch +

	1] http://www.spinics.net/lists/arm-kernel/msg341884.html
	2] http://www.spinics.net/lists/linux-samsung-soc/msg32923.html
	3] http://www.mail-archive.com/linux-samsung-soc at vger.kernel.org/msg33067.html

on Exynos5420 based chromebook (peach-pit board).

NOTE: After system resume we are enabling boot cluster CCI in exynos_cpu_resume in sleep.S.

Below procedures were followed to test S2R:
Procedure A:
1. make multi_v7_defconfig
2 enable MCPM for 5420
3. enable S3C RTC
4. pass "no_console_suspend" in bootargs
5. echo +20 > /sys/class/rtc/rtc0/wakealarm && echo mem > /sys/power/state
Procedure B:
1. make exynos_defconfig
2 enable MCPM for 5420
3 enable CONFIG_PL330_DMA
4. enable CONFIG_PM_RUNTIME
5. pass "no_console_suspend" in bootargs
6. echo +20 > /sys/class/rtc/rtc0/wakealarm && echo mem > /sys/power/state

Abhilash Kesavan (2):
arm: exynos5: Add PMU support for 5420
arm: exynos5: Add Suspend-to-RAM support for 5420

Vikas Sajjan (1):
clk: samsung: exynos5420: Setup clocks before system suspend

 arch/arm/mach-exynos/pm.c            |  150 ++++++++++++++++--
 arch/arm/mach-exynos/pmu.c           |  290 ++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h      |  229 +++++++++++++++++++++++++++
 drivers/clk/samsung/clk-exynos5420.c |   29 ++++
 4 files changed, 682 insertions(+), 16 deletions(-)
Signature · 1 line
1.7.9.5
#1 lore raw

PATCH v5 1/3 arm: exynos5: Add PMU support for 5420

From: Abhilash Kesavan <[email protected]>

Add intial PMU settings for exynos5420. This is required for future S2R and Switching support.

---
 arch/arm/mach-exynos/pmu.c      |  290 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-exynos/regs-pmu.h |  229 +++++++++++++++++++++++++++++++
 2 files changed, 519 insertions(+)
arch/arm/mach-exynos/pmu.c +290 -0
index abaabe5..235d8a4 100644
@@ -9,6 +9,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/of.h>
@@ -17,6 +18,8 @@
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
 
+#include <asm/cputype.h>
+
 #include "exynos-pmu.h"
 #include "regs-pmu.h"
 
@@ -334,6 +337,151 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = {
 	{ PMU_TABLE_END,},
 };
 
+static struct exynos_pmu_conf exynos5420_pmu_config[] = {
+	/* { .offset = offset, .val = { AFTR, LPA, SLEEP } */
+	{ EXYNOS5_ARM_CORE0_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_ARM_CORE1_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_ARM_CORE2_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_ARM_CORE3_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_KFC_CORE0_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_KFC_CORE1_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_KFC_CORE2_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_KFC_CORE3_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_ISP_ARM_SYS_PWR_REG,				{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_ARM_COMMON_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_KFC_COMMON_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_ARM_L2_SYS_PWR_REG,				{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_KFC_L2_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG,			{ 0x1, 0x0, 0x1} },
+	{ EXYNOS5_CMU_RESET_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG,		{ 0x1, 0x0, 0x1} },
+	{ EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG,			{ 0x1, 0x0, 0x1} },
+	{ EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG,			{ 0x1, 0x1, 0x1} },
+	{ EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG,			{ 0x1, 0x0, 0x1} },
+	{ EXYNOS5_APLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_TOP_BUS_SYS_PWR_REG,				{ 0x3, 0x0, 0x0} },
+	{ EXYNOS5_TOP_RETENTION_SYS_PWR_REG,			{ 0x1, 0x1, 0x1} },
+	{ EXYNOS5_TOP_PWR_SYS_PWR_REG,				{ 0x3, 0x3, 0x0} },
+	{ EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG,			{ 0x3, 0x0, 0x0} },
+	{ EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG,		{ 0x1, 0x0, 0x1} },
+	{ EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG,			{ 0x3, 0x0, 0x0} },
+	{ EXYNOS5_LOGIC_RESET_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_OSCCLK_GATE_SYS_PWR_REG,			{ 0x1, 0x0, 0x1} },
+	{ EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_INTRAM_MEM_SYS_PWR_REG,			{ 0x3, 0x0, 0x3} },
+	{ EXYNOS5420_INTROM_MEM_SYS_PWR_REG,			{ 0x3, 0x0, 0x3} },
+	{ EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_PAD_ISOLATION_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_XUSBXTI_SYS_PWR_REG,				{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_XXTI_SYS_PWR_REG,				{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_EXT_REGULATOR_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_GPIO_MODE_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} },
+	{ EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} },
+	{ EXYNOS5_GSCL_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5_ISP_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5_MFC_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5_G3D_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5420_DISP1_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5420_MAU_SYS_PWR_REG,				{ 0x7, 0x7, 0x0} },
+	{ EXYNOS5420_G2D_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5420_MSC_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5420_FSYS_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5420_FSYS2_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5420_PSGEN_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5420_PERIC_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5420_WCORE_SYS_PWR_REG,				{ 0x7, 0x0, 0x0} },
+	{ EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG,			{ 0x0, 0x0, 0x0} },
+	{ EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG,		{ 0x0, 0x0, 0x0} },
+	{ PMU_TABLE_END,},
+};
+
 static unsigned int const exynos5_list_both_cnt_feed[] = {
 	EXYNOS5_ARM_CORE0_OPTION,
 	EXYNOS5_ARM_CORE1_OPTION,
@@ -354,6 +502,74 @@ static unsigned int const exynos5_list_diable_wfi_wfe[] = {
 	EXYNOS5_ISP_ARM_OPTION,
 };
 
+static unsigned int const exynos5420_list_disable_pmu_reg[] = {
+	EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG,
+	EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG,
+	EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG,
+	EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG,
+	EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG,
+	EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG,
+	EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG,
+	EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG,
+	EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG,
+	EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG,
+	EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG,
+	EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG,
+	EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG,
+	EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG,
+	EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG,
+	EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG,
+	EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG,
+	EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG,
+	EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG,
+};
+
+static void exynos5_power_off(void)
+{
+	unsigned int tmp;
+
+	pr_info("Power down.\n");
+	tmp = __raw_readl(pmu_base_addr + EXYNOS_PS_HOLD_CONTROL);
+	tmp ^= (1 << 8);
+	__raw_writel(tmp, pmu_base_addr + EXYNOS_PS_HOLD_CONTROL);
+
+	/* Wait a little so we don't give a false warning below */
+	mdelay(100);
+
+	pr_err("Power down failed, please power off system manually.\n");
+	while (1)
+		;
+}
+
+void exynos5420_powerdown_conf(enum sys_powerdown mode)
+{
+	unsigned int this_cluster;
+	this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+
+	/*
+	 * set the cluster id to IROM register to ensure that we wake
+	 * up with the current cluster.
+	 */
+	__raw_writel(this_cluster, pmu_base_addr + EXYNOS_IROM_DATA2);
+}
+
+
 static void exynos5_powerdown_conf(enum sys_powerdown mode)
 {
 	unsigned int i;
@@ -425,6 +641,70 @@ static void exynos5250_pmu_init(void)
 	__raw_writel(value, pmu_base_addr + EXYNOS5_MASK_WDTRESET_REQUEST);
 }
 
+static void exynos5420_pmu_init(void)
+{
+	unsigned int value;
+	int i;
+
+	/*
+	 * Set the CMU_RESET, CMU_SYSCLK and CMU_CLKSTOP registers
+	 * for local power blocks to Low initially as per Table 8-4:
+	 * "System-Level Power-Down Configuration Registers".
+	 */
+	for (i = 0; i < ARRAY_SIZE(exynos5420_list_disable_pmu_reg); i++)
+		__raw_writel(0, pmu_base_addr + exynos5420_list_disable_pmu_reg[i]);
+
+	/* Enable USE_STANDBY_WFI for all CORE */
+	__raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
+			pmu_base_addr + S5P_CENTRAL_SEQ_OPTION);
+
+	value  = __raw_readl(pmu_base_addr + EXYNOS_L2_OPTION(0));
+	value &= ~EXYNOS5_USE_RETENTION;
+	__raw_writel(value, pmu_base_addr + EXYNOS_L2_OPTION(0));
+
+	value = __raw_readl(pmu_base_addr + EXYNOS_L2_OPTION(1));
+	value &= ~EXYNOS5_USE_RETENTION;
+	__raw_writel(value, pmu_base_addr + EXYNOS_L2_OPTION(1));
+
+	/*
+	 * If L2_COMMON is turned off, clocks related to ATB async
+	 * bridge are gated. Thus, when ISP power is gated, LPI
+	 * may get stuck.
+	 */
+	value = __raw_readl(pmu_base_addr + EXYNOS5420_LPI_MASK);
+	value |= EXYNOS5420_ATB_ISP_ARM;
+	__raw_writel(value, pmu_base_addr + EXYNOS5420_LPI_MASK);
+	value  = __raw_readl(pmu_base_addr + EXYNOS5420_LPI_MASK1);
+	value |= EXYNOS5420_ATB_KFC;
+	__raw_writel(value, pmu_base_addr + EXYNOS5420_LPI_MASK1);
+
+	/* Prevent issue of new bus request from L2 memory */
+	value = __raw_readl(pmu_base_addr + EXYNOS5420_ARM_COMMON_OPTION);
+	value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
+	__raw_writel(value, pmu_base_addr + EXYNOS5420_ARM_COMMON_OPTION);
+
+	value = __raw_readl(pmu_base_addr + EXYNOS5420_KFC_COMMON_OPTION);
+
+	value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
+	__raw_writel(value, pmu_base_addr + EXYNOS5420_KFC_COMMON_OPTION);
+
+	/* This setting is to reduce suspend/resume time */
+	__raw_writel(DUR_WAIT_RESET,
+			pmu_base_addr + EXYNOS5420_LOGIC_RESET_DURATION3);
+
+	/* Serialized CPU wakeup of Eagle */
+	__raw_writel(SPREAD_ENABLE,
+			pmu_base_addr + EXYNOS5420_ARM_INTR_SPREAD_ENABLE);
+
+	__raw_writel(SPREAD_USE_STANDWFI,
+		pmu_base_addr + EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI);
+
+	__raw_writel(0x1, pmu_base_addr + EXYNOS5420_UP_SCHEDULER);
+
+	pm_power_off = exynos5_power_off;
+	pr_info("EXYNOS5420 PMU initialized\n");
+}
+
 static struct exynos_pmu_data exynos4210_pmu_data = {
 	.pmu_config	= exynos4210_pmu_config,
 };
@@ -444,6 +724,12 @@ static struct exynos_pmu_data exynos5250_pmu_data = {
 	.powerdown_conf	= exynos5_powerdown_conf,
 };
 
+static struct exynos_pmu_data exynos5420_pmu_data = {
+	.pmu_config	= exynos5420_pmu_config,
+	.pmu_init	= exynos5420_pmu_init,
+	.powerdown_conf	= exynos5420_powerdown_conf,
+};
+
 static struct regmap_config pmu_regmap_config = {
 	.reg_bits = 32,
 	.val_bits = 32,
@@ -470,6 +756,10 @@ static struct of_device_id exynos_pmu_of_device_ids[] = {
 		.compatible = "samsung,exynos5250-pmu",
 		.data = (void *)&exynos5250_pmu_data,
 	},
+	{
+		.compatible = "samsung,exynos5420-pmu",
+		.data = (void *)&exynos5420_pmu_data,
+	},
 	{},
 };
 
arch/arm/mach-exynos/regs-pmu.h +229 -0

251 lines not on this page · raw message

Signature · 1 line
1.7.9.5
#2 lore raw

PATCH v5 2/3 arm: exynos5: Add Suspend-to-RAM support for 5420

In reply to Vikas Sajjan

From: Abhilash Kesavan <[email protected]>

Adds Suspend-to-RAM support for EXYNOS5420

---
 arch/arm/mach-exynos/pm.c |  150 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 134 insertions(+), 16 deletions(-)
arch/arm/mach-exynos/pm.c +134 -16
index de61d48..bf8564a 100644
@@ -38,9 +38,13 @@
 #include "regs-pmu.h"
 #include "regs-sys.h"
 
+#define EXYNOS5420_CPU_STATE	0x28
+
 #define pmu_raw_writel(val, offset) \
 		__raw_writel(val, pmu_base_addr + offset)
 
+static int exynos5420_cpu_state;
+
 /**
  * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping
  * @hwirq: Hardware IRQ signal of the GIC
@@ -64,6 +68,10 @@ static struct sleep_save exynos_core_save[] = {
 	SAVE_ITEM(S5P_SROM_BC3),
 };
 
+static struct sleep_save exynos5420_pmu_reg_save[] = {
+	SAVE_ITEM((void __iomem *)S5P_PMU_SPARE3),
+};
+
 /*
  * GIC wake-up support
  */
@@ -86,7 +94,7 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
 {
 	const struct exynos_wkup_irq *wkup_irq;
 
-	if (soc_is_exynos5250())
+	if (soc_is_exynos5250() || soc_is_exynos5420())
 		wkup_irq = exynos5250_wkup_irq;
 	else
 		wkup_irq = exynos4_wkup_irq;
@@ -250,7 +258,16 @@ static int exynos_cpu_suspend(unsigned long arg)
 	outer_flush_all();
 #endif
 
-	if (soc_is_exynos5250())
+	/*
+	 * Clear sysram register for cpu state so that primary CPU does
+	 * not enter low power start in U-Boot.
+	 * This is specific to exynos5420 SoC only.
+	 */
+	if (soc_is_exynos5420())
+		__raw_writel(0x0,
+			sysram_base_addr + EXYNOS5420_CPU_STATE);
+
+	if (soc_is_exynos5250() || soc_is_exynos5420())
 		flush_cache_all();
 
 	/* issue the standby signal into the pm unit. */
@@ -276,6 +293,22 @@ static void exynos_pm_prepare(void)
 		tmp = __raw_readl(pmu_base_addr + EXYNOS5_JPEG_MEM_OPTION);
 		tmp &= ~EXYNOS5_OPTION_USE_RETENTION;
 		pmu_raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION);
+	} else if (soc_is_exynos5420()) {
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(exynos5420_pmu_reg_save); i++)
+			exynos5420_pmu_reg_save[i].val =
+				__raw_readl(pmu_base_addr +
+				(unsigned int)exynos5420_pmu_reg_save[i].reg);
+		/*
+		 * The cpu state needs to be saved and restored so that the
+		 * secondary CPUs will enter low power start. Though the U-Boot
+		 * is setting the cpu state with low power flag, the kernel
+		 * needs to restore it back in case, the primary cpu fails to
+		 * suspend for any reason.
+		 */
+		exynos5420_cpu_state =
+		__raw_readl(sysram_base_addr + EXYNOS5420_CPU_STATE);
 	}
 
 	/* Set value of power down register for sleep mode */
@@ -286,6 +319,27 @@ static void exynos_pm_prepare(void)
 	/* ensure@least INFORM0 has the resume address */
 
 	pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
+
+	if (soc_is_exynos5420()) {
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5_ARM_L2_OPTION);
+		tmp &= ~EXYNOS5_USE_RETENTION;
+		pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
+
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_SFR_AXI_CGDIS1);
+		tmp |= EXYNOS5420_UFS;
+		pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
+
+		tmp = __raw_readl(pmu_base_addr +
+				EXYNOS5420_ARM_COMMON_OPTION);
+		tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE;
+		pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION);
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_FSYS2_OPTION);
+		tmp |= EXYNOS5420_EMULATION;
+		pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_PSGEN_OPTION);
+		tmp |= EXYNOS5420_EMULATION;
+		pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
+	}
 }
 
 static void exynos_pm_central_suspend(void)
@@ -301,13 +355,24 @@ static void exynos_pm_central_suspend(void)
 static int exynos_pm_suspend(void)
 {
 	unsigned long tmp;
+	unsigned int  this_cluster;
 
 	exynos_pm_central_suspend();
 
 	/* Setting SEQ_OPTION register */
 
-	tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
-	pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
+	if (soc_is_exynos5420()) {
+		this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+		if (!this_cluster)
+			pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0,
+					S5P_CENTRAL_SEQ_OPTION);
+		else
+			pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0,
+					S5P_CENTRAL_SEQ_OPTION);
+	} else {
+		tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
+		pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
+	}
 
 	if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9)
 		exynos_cpu_save_register();
@@ -340,6 +405,17 @@ static int exynos_pm_central_resume(void)
 
 static void exynos_pm_resume(void)
 {
+	unsigned int tmp;
+
+	if (soc_is_exynos5420()) {
+		/* Restore the sysram cpu state register */
+		__raw_writel(exynos5420_cpu_state,
+		sysram_base_addr + EXYNOS5420_CPU_STATE);
+
+		pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
+				S5P_CENTRAL_SEQ_OPTION);
+	}
+
 	if (exynos_pm_central_resume())
 		goto early_wakeup;
 
@@ -347,18 +423,42 @@ static void exynos_pm_resume(void)
 		exynos_cpu_restore_register();
 
 	/* For release retention */
+	if (soc_is_exynos5420()) {
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_DRAM_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_MAUDIO_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_JTAG_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_GPIO_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_UART_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCA_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCB_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCC_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_HSI_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_EBIA_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_EBIB_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_SPI_OPTION);
+		pmu_raw_writel((1 << 28),
+				EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION);
+	} else {
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
+	}
 
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
-
-	if (soc_is_exynos5250())
+	if (soc_is_exynos5250()) {
 		s3c_pm_do_restore(exynos5_sys_save,
 			ARRAY_SIZE(exynos5_sys_save));
+	} else if (soc_is_exynos5420()) {
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(exynos5420_pmu_reg_save); i++)
+			pmu_raw_writel(
+			(unsigned int)exynos5420_pmu_reg_save[i].val,
+			(unsigned int)exynos5420_pmu_reg_save[i].reg);
+	}
 
 	s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 
@@ -367,6 +467,18 @@ static void exynos_pm_resume(void)
 
 early_wakeup:
 
+	if (soc_is_exynos5420()) {
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_SFR_AXI_CGDIS1);
+		tmp &= ~EXYNOS5420_UFS;
+		pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_FSYS2_OPTION);
+		tmp &= ~EXYNOS5420_EMULATION;
+		pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_PSGEN_OPTION);
+		tmp &= ~EXYNOS5420_EMULATION;
+		pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
+	}
+
 	/* Clear SLEEP mode set in INFORM1 */
 	pmu_raw_writel(0x0, S5P_INFORM1);
 
@@ -483,9 +595,15 @@ void __init exynos_pm_init(void)
 	gic_arch_extn.irq_set_wake = exynos_irq_set_wake;
 
 	/* All wakeup disable */
-	tmp = __raw_readl(pmu_base_addr + S5P_WAKEUP_MASK);
-	tmp |= ((0xFF << 8) | (0x1F << 1));
-	pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
+	if (soc_is_exynos5420()) {
+		tmp = __raw_readl(pmu_base_addr + S5P_WAKEUP_MASK);
+		tmp |= ((0x7F << 7) | (0x1F << 1));
+		pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
+	} else {
+		tmp = __raw_readl(pmu_base_addr + S5P_WAKEUP_MASK);
+		tmp |= ((0xFF << 8) | (0x1F << 1));
+		pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
+	}
 
 	register_syscore_ops(&exynos_pm_syscore_ops);
 	suspend_set_ops(&exynos_suspend_ops);
Signature · 1 line
1.7.9.5
#3 lore raw

PATCH v5 2/3 arm: exynos5: Add Suspend-to-RAM support for 5420

Hi Vikas, Abhilash,

Please see my comments inline.

Quoted 29 lines · Vikas Sajjan

From: Abhilash Kesavan <[email protected]>

Adds Suspend-to-RAM support for EXYNOS5420

---
 arch/arm/mach-exynos/pm.c |  150 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 134 insertions(+), 16 deletions(-)
arch/arm/mach-exynos/pm.c +4 -0
index de61d48..bf8564a 100644
@@ -38,9 +38,13 @@
 #include "regs-pmu.h"
 #include "regs-sys.h"
 
+#define EXYNOS5420_CPU_STATE	0x28
+
 #define pmu_raw_writel(val, offset) \
 		__raw_writel(val, pmu_base_addr + offset)
 
+static int exynos5420_cpu_state;
+
 /**
  * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping
  * @hwirq: Hardware IRQ signal of the GIC

arch/arm/mach-exynos/pm.c static struct sleep_save exynos_core_save[] = { · line 73

Quoted 6 lines
arch/arm/mach-exynos/pm.c +3 -0
@@ -64,6 +68,10 @@ static struct sleep_save exynos_core_save[] = {
 	SAVE_ITEM(S5P_SROM_BC3),
 };
 
+static struct sleep_save exynos5420_pmu_reg_save[] = {
+	SAVE_ITEM((void __iomem *)S5P_PMU_SPARE3),
+};

Do you need a whole array for this single register?

arch/arm/mach-exynos/pm.c static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) · line 97

Quoted 10 lines
arch/arm/mach-exynos/pm.c +2 -1
+
 /*
  * GIC wake-up support
  */
@@ -86,7 +94,7 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
 {
 	const struct exynos_wkup_irq *wkup_irq;
 
-	if (soc_is_exynos5250())
+	if (soc_is_exynos5250() || soc_is_exynos5420())

You should rework this to eliminate the need to use any SoC-specific checks. For example:

1) create a struct where any SoC/family specific data are stored, e.g.

	struct exynos_pm_data {
		const struct exynos_wkup_irq *wkup_irq;
		/* arrays, flags, values, function pointers, etc. */
	};

2) describe supported variants using instances of this struct, e.g.

	static const struct exynos_pm_data exynos5250_pm_data {
		.wkup_irq = exynos5250_wkup_irq,
		/* ... */
	};

	static const struct exynos_pm_data exynos5420_pm_data {
		.wkup_irq = exynos5250_wkup_irq,
		/* ... */
	};

3) put pointers to those structs in DT match table:

	static const struct of_device_id exynos_pm_matches[] = {
		{ .compatible = "samsung,exynos5250-pmu",
			.data = &exynos5250_pm_data },
		{ .compatible = "samsung,exynos5420-pmu",
			.data = &exynos5420_pm_data },
	};

4) find a matching node in DT and use the struct pointed by match data.

Also certain checks could probably be replaced with non-SoC-specific checks, e.g. by CPU part checks.

Quoted 8 lines
arch/arm/mach-exynos/pm.c +0 -1
 		wkup_irq = exynos5250_wkup_irq;
 	else
 		wkup_irq = exynos4_wkup_irq;
@@ -250,7 +258,16 @@ static int exynos_cpu_suspend(unsigned long arg)
 	outer_flush_all();
 #endif
 
-	if (soc_is_exynos5250())

arch/arm/mach-exynos/pm.c static int exynos_cpu_suspend(unsigned long arg) · line 270

Quoted 10 lines
arch/arm/mach-exynos/pm.c +10 -0
+	/*
+	 * Clear sysram register for cpu state so that primary CPU does
+	 * not enter low power start in U-Boot.
+	 * This is specific to exynos5420 SoC only.
+	 */
+	if (soc_is_exynos5420())
+		__raw_writel(0x0,
+			sysram_base_addr + EXYNOS5420_CPU_STATE);
+
+	if (soc_is_exynos5250() || soc_is_exynos5420())

This probably can be replaced with a check for Cortex A15 or A7.

Quoted 34 lines
arch/arm/mach-exynos/pm.c +20 -0
 		flush_cache_all();
 
 	/* issue the standby signal into the pm unit. */
@@ -276,6 +293,22 @@ static void exynos_pm_prepare(void)
 		tmp = __raw_readl(pmu_base_addr + EXYNOS5_JPEG_MEM_OPTION);
 		tmp &= ~EXYNOS5_OPTION_USE_RETENTION;
 		pmu_raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION);
+	} else if (soc_is_exynos5420()) {
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(exynos5420_pmu_reg_save); i++)
+			exynos5420_pmu_reg_save[i].val =
+				__raw_readl(pmu_base_addr +
+				(unsigned int)exynos5420_pmu_reg_save[i].reg);
+		/*
+		 * The cpu state needs to be saved and restored so that the
+		 * secondary CPUs will enter low power start. Though the U-Boot
+		 * is setting the cpu state with low power flag, the kernel
+		 * needs to restore it back in case, the primary cpu fails to
+		 * suspend for any reason.
+		 */
+		exynos5420_cpu_state =
+		__raw_readl(sysram_base_addr + EXYNOS5420_CPU_STATE);
 	}
 
 	/* Set value of power down register for sleep mode */
@@ -286,6 +319,27 @@ static void exynos_pm_prepare(void)
 	/* ensure at least INFORM0 has the resume address */
 
 	pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
+
+	if (soc_is_exynos5420()) {
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5_ARM_L2_OPTION);
+		tmp &= ~EXYNOS5_USE_RETENTION;

arch/arm/mach-exynos/pm.c static void exynos_pm_prepare(void) · line 335

Quoted 10 lines
arch/arm/mach-exynos/pm.c +10 -0
+		pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
+
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_SFR_AXI_CGDIS1);
+		tmp |= EXYNOS5420_UFS;
+		pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
+
+		tmp = __raw_readl(pmu_base_addr +
+				EXYNOS5420_ARM_COMMON_OPTION);
+		tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE;
+		pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION);

nit: A blank line here could improve readability.

arch/arm/mach-exynos/pm.c static void exynos_pm_prepare(void) · line 338

Quoted 3 lines
arch/arm/mach-exynos/pm.c +3 -0
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_FSYS2_OPTION);
+		tmp |= EXYNOS5420_EMULATION;
+		pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);

nit: A blank line here could improve readability.

arch/arm/mach-exynos/pm.c static void exynos_pm_central_suspend(void) · line 358

Quoted 12 lines
arch/arm/mach-exynos/pm.c +5 -0
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_PSGEN_OPTION);
+		tmp |= EXYNOS5420_EMULATION;
+		pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
+	}
 }
 
 static void exynos_pm_central_suspend(void)
@@ -301,13 +355,24 @@ static void exynos_pm_central_suspend(void)
 static int exynos_pm_suspend(void)
 {
 	unsigned long tmp;
+	unsigned int  this_cluster;

nit: Two spaces between "int" and "this_cluster". Also it might be a better idea to use explicitly sized types with same size as register width.

arch/arm/mach-exynos/pm.c static void exynos_pm_central_suspend(void) · line 364

Quoted 8 lines
arch/arm/mach-exynos/pm.c +1 -2
 	exynos_pm_central_suspend();
 
 	/* Setting SEQ_OPTION register */
 
-	tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
-	pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
+	if (soc_is_exynos5420()) {

I believe this is not Exynos5420-specific, but rather specific to any multi-cluster Exynos SoC. I think there might be a way to check the number of clusters.

arch/arm/mach-exynos/pm.c static void exynos_pm_central_suspend(void) · line 371

Quoted 7 lines
arch/arm/mach-exynos/pm.c +7 -0
+		this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+		if (!this_cluster)
+			pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0,
+					S5P_CENTRAL_SEQ_OPTION);
+		else
+			pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0,
+					S5P_CENTRAL_SEQ_OPTION);

By the way, is it even possible to boot this SoC using other CPU than first Cortex A15?

Quoted 34 lines
arch/arm/mach-exynos/pm.c +20 -0
+	} else {
+		tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
+		pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
+	}
 
 	if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9)
 		exynos_cpu_save_register();
@@ -340,6 +405,17 @@ static int exynos_pm_central_resume(void)
 
 static void exynos_pm_resume(void)
 {
+	unsigned int tmp;
+
+	if (soc_is_exynos5420()) {
+		/* Restore the sysram cpu state register */
+		__raw_writel(exynos5420_cpu_state,
+		sysram_base_addr + EXYNOS5420_CPU_STATE);
+
+		pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
+				S5P_CENTRAL_SEQ_OPTION);
+	}
+
 	if (exynos_pm_central_resume())
 		goto early_wakeup;
 
@@ -347,18 +423,42 @@ static void exynos_pm_resume(void)
 		exynos_cpu_restore_register();
 
 	/* For release retention */
+	if (soc_is_exynos5420()) {
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_DRAM_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_MAUDIO_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_JTAG_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_GPIO_OPTION);

arch/arm/mach-exynos/pm.c static void exynos_pm_resume(void) · line 440

Quoted 10 lines
arch/arm/mach-exynos/pm.c +10 -0
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_UART_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCA_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCB_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCC_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_HSI_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_EBIA_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_EBIB_OPTION);
+		pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_SPI_OPTION);
+		pmu_raw_writel((1 << 28),
+				EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION);

This could be replaced with an array of registers that is specified in the exynos_pm_data struct. Also while at it, the (1 << 28) could be replaced with proper macro.

Quoted 34 lines
arch/arm/mach-exynos/pm.c +18 -9
+	} else {
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
+		pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
+	}
 
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
-	pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
-
-	if (soc_is_exynos5250())
+	if (soc_is_exynos5250()) {
 		s3c_pm_do_restore(exynos5_sys_save,
 			ARRAY_SIZE(exynos5_sys_save));
+	} else if (soc_is_exynos5420()) {
+		unsigned int i;
+
+		for (i = 0; i < ARRAY_SIZE(exynos5420_pmu_reg_save); i++)
+			pmu_raw_writel(
+			(unsigned int)exynos5420_pmu_reg_save[i].val,
+			(unsigned int)exynos5420_pmu_reg_save[i].reg);
+	}
 
 	s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 

arch/arm/mach-exynos/pm.c static void exynos_pm_resume(void) · line 473

Quoted 7 lines
arch/arm/mach-exynos/pm.c +4 -0
@@ -367,6 +467,18 @@ static void exynos_pm_resume(void)
 
 early_wakeup:
 
+	if (soc_is_exynos5420()) {
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_SFR_AXI_CGDIS1);
+		tmp &= ~EXYNOS5420_UFS;
+		pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);

nit: Spacing here would be nice.

arch/arm/mach-exynos/pm.c static void exynos_pm_resume(void) · line 476

Quoted 3 lines
arch/arm/mach-exynos/pm.c +3 -0
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_FSYS2_OPTION);
+		tmp &= ~EXYNOS5420_EMULATION;
+		pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);

Ditto.

Quoted 9 lines
arch/arm/mach-exynos/pm.c +5 -0
+		tmp = __raw_readl(pmu_base_addr + EXYNOS5420_PSGEN_OPTION);
+		tmp &= ~EXYNOS5420_EMULATION;
+		pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
+	}
+
 	/* Clear SLEEP mode set in INFORM1 */
 	pmu_raw_writel(0x0, S5P_INFORM1);
 

arch/arm/mach-exynos/pm.c void __init exynos_pm_init(void) · line 600

Quoted 9 lines
arch/arm/mach-exynos/pm.c +3 -3
@@ -483,9 +595,15 @@ void __init exynos_pm_init(void)
 	gic_arch_extn.irq_set_wake = exynos_irq_set_wake;
 
 	/* All wakeup disable */
-	tmp = __raw_readl(pmu_base_addr + S5P_WAKEUP_MASK);
-	tmp |= ((0xFF << 8) | (0x1F << 1));
-	pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
+	if (soc_is_exynos5420()) {
+		tmp = __raw_readl(pmu_base_addr + S5P_WAKEUP_MASK);
+		tmp |= ((0x7F << 7) | (0x1F << 1));

This mask could be also moved to the struct.

Best regards,
Tomasz

#4 lore raw

PATCH v5 2/3 arm: exynos5: Add Suspend-to-RAM support for 5420

Hi Tomasz,

Quoted 113 lines · Tomasz Figa

Hi Vikas, Abhilash,

Please see my comments inline.

Quoted 29 lines · Vikas Sajjan

From: Abhilash Kesavan <[email protected]>

Adds Suspend-to-RAM support for EXYNOS5420

---
 arch/arm/mach-exynos/pm.c |  150 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 134 insertions(+), 16 deletions(-)
arch/arm/mach-exynos/pm.c +4 -0
index de61d48..bf8564a 100644
@@ -38,9 +38,13 @@
 #include "regs-pmu.h"
 #include "regs-sys.h"
 
+#define EXYNOS5420_CPU_STATE 0x28
+
 #define pmu_raw_writel(val, offset) \
              __raw_writel(val, pmu_base_addr + offset)
 
+static int exynos5420_cpu_state;
+
 /**
  * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping
  * @hwirq: Hardware IRQ signal of the GIC

arch/arm/mach-exynos/pm.c static struct sleep_save exynos_core_save[] = { · line 73

Quoted 6 lines
arch/arm/mach-exynos/pm.c +3 -0
@@ -64,6 +68,10 @@ static struct sleep_save exynos_core_save[] = {
      SAVE_ITEM(S5P_SROM_BC3),
 };
 
+static struct sleep_save exynos5420_pmu_reg_save[] = {
+     SAVE_ITEM((void __iomem *)S5P_PMU_SPARE3),
+};

Do you need a whole array for this single register?

arch/arm/mach-exynos/pm.c static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) · line 97

Quoted 10 lines
arch/arm/mach-exynos/pm.c +2 -1
+
 /*
  * GIC wake-up support
  */
@@ -86,7 +94,7 @@ static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
 {
      const struct exynos_wkup_irq *wkup_irq;
 
-     if (soc_is_exynos5250())
+     if (soc_is_exynos5250() || soc_is_exynos5420())

You should rework this to eliminate the need to use any SoC-specific checks. For example:

1) create a struct where any SoC/family specific data are stored, e.g.

        struct exynos_pm_data {
                const struct exynos_wkup_irq *wkup_irq;
                /* arrays, flags, values, function pointers, etc. */
        };

2) describe supported variants using instances of this struct, e.g.

        static const struct exynos_pm_data exynos5250_pm_data {
                .wkup_irq = exynos5250_wkup_irq,
                /* ... */
        };

        static const struct exynos_pm_data exynos5420_pm_data {
                .wkup_irq = exynos5250_wkup_irq,
                /* ... */
        };

3) put pointers to those structs in DT match table:

        static const struct of_device_id exynos_pm_matches[] = {
                { .compatible = "samsung,exynos5250-pmu",
                        .data = &exynos5250_pm_data },
                { .compatible = "samsung,exynos5420-pmu",
                        .data = &exynos5420_pm_data },
        };

4) find a matching node in DT and use the struct pointed by match data.

Also certain checks could probably be replaced with non-SoC-specific checks, e.g. by CPU part checks.

Quoted 8 lines
arch/arm/mach-exynos/pm.c +0 -1
              wkup_irq = exynos5250_wkup_irq;
      else
              wkup_irq = exynos4_wkup_irq;
@@ -250,7 +258,16 @@ static int exynos_cpu_suspend(unsigned long arg)
      outer_flush_all();
 #endif
 
-     if (soc_is_exynos5250())

arch/arm/mach-exynos/pm.c static int exynos_cpu_suspend(unsigned long arg) · line 270

Quoted 10 lines
arch/arm/mach-exynos/pm.c +10 -0
+     /*
+      * Clear sysram register for cpu state so that primary CPU does
+      * not enter low power start in U-Boot.
+      * This is specific to exynos5420 SoC only.
+      */
+     if (soc_is_exynos5420())
+             __raw_writel(0x0,
+                     sysram_base_addr + EXYNOS5420_CPU_STATE);
+
+     if (soc_is_exynos5250() || soc_is_exynos5420())

This probably can be replaced with a check for Cortex A15 or A7.

Quoted 2 lines
arch/arm/mach-exynos/pm.c +0 -0
              flush_cache_all();
 
Quoted 7 lines

arch/arm/mach-exynos/pm.c static void exynos_pm_prepare(void) · line 297

Quoted 7 lines
arch/arm/mach-exynos/pm.c +2 -0
      /* issue the standby signal into the pm unit. */
@@ -276,6 +293,22 @@ static void exynos_pm_prepare(void)
              tmp = __raw_readl(pmu_base_addr + EXYNOS5_JPEG_MEM_OPTION);
              tmp &= ~EXYNOS5_OPTION_USE_RETENTION;
              pmu_raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION);
+     } else if (soc_is_exynos5420()) {
+             unsigned int i;

I have a question here.

I can come up with a function like exynos5420_pm_prepare(), which does the same as the code under this if condition.

call it here like below,

static void exynos_pm_prepare(void)
{
/* common to all SoCs */

              ......
                  .....
                    ......
 /* specific to given SoC */
 exynos_pm_data->pm_prepare();
                   ........
                .......
           .......
}

but at line -286,6 +319,27 @@ static void exynos_pm_prepare(void)
also we have something specific to 5420.

how do we handle such cases. Because in future there may be new a SoC which does SoC specific things at 3 different

location in same function exynos_pm_prepare().

This will also apply to function like exynos_pm_suspend() exynos_pm_resume() etc.,

Quoted 206 lines
Quoted 25 lines
arch/arm/mach-exynos/pm.c +18 -0
+
+             for (i = 0; i < ARRAY_SIZE(exynos5420_pmu_reg_save); i++)
+                     exynos5420_pmu_reg_save[i].val =
+                             __raw_readl(pmu_base_addr +
+                             (unsigned int)exynos5420_pmu_reg_save[i].reg);
+             /*
+              * The cpu state needs to be saved and restored so that the
+              * secondary CPUs will enter low power start. Though the U-Boot
+              * is setting the cpu state with low power flag, the kernel
+              * needs to restore it back in case, the primary cpu fails to
+              * suspend for any reason.
+              */
+             exynos5420_cpu_state =
+             __raw_readl(sysram_base_addr + EXYNOS5420_CPU_STATE);
      }
 
      /* Set value of power down register for sleep mode */
@@ -286,6 +319,27 @@ static void exynos_pm_prepare(void)
      /* ensure at least INFORM0 has the resume address */
 
      pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
+
+     if (soc_is_exynos5420()) {
+             tmp = __raw_readl(pmu_base_addr + EXYNOS5_ARM_L2_OPTION);
+             tmp &= ~EXYNOS5_USE_RETENTION;

arch/arm/mach-exynos/pm.c static void exynos_pm_prepare(void) · line 335

Quoted 10 lines
arch/arm/mach-exynos/pm.c +10 -0
+             pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
+
+             tmp = __raw_readl(pmu_base_addr + EXYNOS5420_SFR_AXI_CGDIS1);
+             tmp |= EXYNOS5420_UFS;
+             pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
+
+             tmp = __raw_readl(pmu_base_addr +
+                             EXYNOS5420_ARM_COMMON_OPTION);
+             tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE;
+             pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION);

nit: A blank line here could improve readability.

arch/arm/mach-exynos/pm.c static void exynos_pm_prepare(void) · line 338

Quoted 3 lines
arch/arm/mach-exynos/pm.c +3 -0
+             tmp = __raw_readl(pmu_base_addr + EXYNOS5420_FSYS2_OPTION);
+             tmp |= EXYNOS5420_EMULATION;
+             pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);

nit: A blank line here could improve readability.

arch/arm/mach-exynos/pm.c static void exynos_pm_central_suspend(void) · line 358

Quoted 12 lines
arch/arm/mach-exynos/pm.c +5 -0
+             tmp = __raw_readl(pmu_base_addr + EXYNOS5420_PSGEN_OPTION);
+             tmp |= EXYNOS5420_EMULATION;
+             pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
+     }
 }
 
 static void exynos_pm_central_suspend(void)
@@ -301,13 +355,24 @@ static void exynos_pm_central_suspend(void)
 static int exynos_pm_suspend(void)
 {
      unsigned long tmp;
+     unsigned int  this_cluster;

nit: Two spaces between "int" and "this_cluster". Also it might be a better idea to use explicitly sized types with same size as register width.

arch/arm/mach-exynos/pm.c static void exynos_pm_central_suspend(void) · line 364

Quoted 8 lines
arch/arm/mach-exynos/pm.c +1 -2
      exynos_pm_central_suspend();
 
      /* Setting SEQ_OPTION register */
 
-     tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
-     pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
+     if (soc_is_exynos5420()) {

I believe this is not Exynos5420-specific, but rather specific to any multi-cluster Exynos SoC. I think there might be a way to check the number of clusters.

arch/arm/mach-exynos/pm.c static void exynos_pm_central_suspend(void) · line 371

Quoted 7 lines
arch/arm/mach-exynos/pm.c +7 -0
+             this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+             if (!this_cluster)
+                     pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0,
+                                     S5P_CENTRAL_SEQ_OPTION);
+             else
+                     pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0,
+                                     S5P_CENTRAL_SEQ_OPTION);

By the way, is it even possible to boot this SoC using other CPU than first Cortex A15?

Quoted 34 lines
arch/arm/mach-exynos/pm.c +20 -0
+     } else {
+             tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
+             pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
+     }
 
      if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9)
              exynos_cpu_save_register();
@@ -340,6 +405,17 @@ static int exynos_pm_central_resume(void)
 
 static void exynos_pm_resume(void)
 {
+     unsigned int tmp;
+
+     if (soc_is_exynos5420()) {
+             /* Restore the sysram cpu state register */
+             __raw_writel(exynos5420_cpu_state,
+             sysram_base_addr + EXYNOS5420_CPU_STATE);
+
+             pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
+                             S5P_CENTRAL_SEQ_OPTION);
+     }
+
      if (exynos_pm_central_resume())
              goto early_wakeup;
 
@@ -347,18 +423,42 @@ static void exynos_pm_resume(void)
              exynos_cpu_restore_register();
 
      /* For release retention */
+     if (soc_is_exynos5420()) {
+             pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_DRAM_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_MAUDIO_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_JTAG_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_GPIO_OPTION);

arch/arm/mach-exynos/pm.c static void exynos_pm_resume(void) · line 440

Quoted 10 lines
arch/arm/mach-exynos/pm.c +10 -0
+             pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_UART_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCA_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCB_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_MMCC_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_HSI_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_EBIA_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS_PAD_RET_EBIB_OPTION);
+             pmu_raw_writel((1 << 28), EXYNOS5420_PAD_RET_SPI_OPTION);
+             pmu_raw_writel((1 << 28),
+                             EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION);

This could be replaced with an array of registers that is specified in the exynos_pm_data struct. Also while at it, the (1 << 28) could be replaced with proper macro.

Quoted 34 lines
arch/arm/mach-exynos/pm.c +18 -9
+     } else {
+             pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
+             pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
+             pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
+             pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
+             pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
+             pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
+             pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
+     }
 
-     pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
-     pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
-     pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
-     pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
-     pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
-     pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
-     pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
-
-     if (soc_is_exynos5250())
+     if (soc_is_exynos5250()) {
              s3c_pm_do_restore(exynos5_sys_save,
                      ARRAY_SIZE(exynos5_sys_save));
+     } else if (soc_is_exynos5420()) {
+             unsigned int i;
+
+             for (i = 0; i < ARRAY_SIZE(exynos5420_pmu_reg_save); i++)
+                     pmu_raw_writel(
+                     (unsigned int)exynos5420_pmu_reg_save[i].val,
+                     (unsigned int)exynos5420_pmu_reg_save[i].reg);
+     }
 
      s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
 

arch/arm/mach-exynos/pm.c static void exynos_pm_resume(void) · line 473

Quoted 7 lines
arch/arm/mach-exynos/pm.c +4 -0
@@ -367,6 +467,18 @@ static void exynos_pm_resume(void)
 
 early_wakeup:
 
+     if (soc_is_exynos5420()) {
+             tmp = __raw_readl(pmu_base_addr + EXYNOS5420_SFR_AXI_CGDIS1);
+             tmp &= ~EXYNOS5420_UFS;
+             pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);

nit: Spacing here would be nice.

arch/arm/mach-exynos/pm.c static void exynos_pm_resume(void) · line 476

Quoted 3 lines
arch/arm/mach-exynos/pm.c +3 -0
+             tmp = __raw_readl(pmu_base_addr + EXYNOS5420_FSYS2_OPTION);
+             tmp &= ~EXYNOS5420_EMULATION;
+             pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);

Ditto.

Quoted 9 lines
arch/arm/mach-exynos/pm.c +5 -0
+             tmp = __raw_readl(pmu_base_addr + EXYNOS5420_PSGEN_OPTION);
+             tmp &= ~EXYNOS5420_EMULATION;
+             pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
+     }
+
      /* Clear SLEEP mode set in INFORM1 */
      pmu_raw_writel(0x0, S5P_INFORM1);
 

arch/arm/mach-exynos/pm.c void __init exynos_pm_init(void) · line 600

Quoted 9 lines
arch/arm/mach-exynos/pm.c +3 -3
@@ -483,9 +595,15 @@ void __init exynos_pm_init(void)
      gic_arch_extn.irq_set_wake = exynos_irq_set_wake;
 
      /* All wakeup disable */
-     tmp = __raw_readl(pmu_base_addr + S5P_WAKEUP_MASK);
-     tmp |= ((0xFF << 8) | (0x1F << 1));
-     pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
+     if (soc_is_exynos5420()) {
+             tmp = __raw_readl(pmu_base_addr + S5P_WAKEUP_MASK);
+             tmp |= ((0x7F << 7) | (0x1F << 1));

This mask could be also moved to the struct.

Best regards,
Tomasz

#5 lore raw

PATCH v5 3/3 clk: samsung: exynos5420: Setup clocks before system suspend

In reply to Vikas Sajjan

Prior to suspending the system, we need to ensure that certain clock source and gate registers are unmasked.

while at it, add these clks to save/restore list also.

---
 drivers/clk/samsung/clk-exynos5420.c |   29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
drivers/clk/samsung/clk-exynos5420.c +29 -0
index 9d7d7ee..7e87d7c 100644
@@ -28,6 +28,7 @@
 #define GATE_BUS_CPU		0x700
 #define GATE_SCLK_CPU		0x800
 #define CLKOUT_CMU_CPU		0xa00
+#define SRC_MASK_CPERI		0x4300
 #define GATE_IP_G2D		0x8800
 #define CPLL_LOCK		0x10020
 #define DPLL_LOCK		0x10030
@@ -70,6 +71,8 @@
 #define SRC_TOP11		0x10284
 #define SRC_TOP12		0x10288
 #define SRC_TOP13		0x1028c /* 5800 specific */
+#define SRC_MASK_TOP0		0x10300
+#define SRC_MASK_TOP1		0x10304
 #define SRC_MASK_TOP2		0x10308
 #define SRC_MASK_TOP7		0x1031c
 #define SRC_MASK_DISP10		0x1032c
@@ -77,6 +80,7 @@
 #define SRC_MASK_FSYS		0x10340
 #define SRC_MASK_PERIC0		0x10350
 #define SRC_MASK_PERIC1		0x10354
+#define SRC_MASK_ISP		0x10370
 #define DIV_TOP0		0x10500
 #define DIV_TOP1		0x10504
 #define DIV_TOP2		0x10508
@@ -98,6 +102,7 @@
 #define DIV2_RATIO0		0x10590
 #define DIV4_RATIO		0x105a0
 #define GATE_BUS_TOP		0x10700
+#define GATE_BUS_DISP1		0x10728
 #define GATE_BUS_GEN		0x1073c
 #define GATE_BUS_FSYS0		0x10740
 #define GATE_BUS_FSYS2		0x10748
@@ -190,6 +195,10 @@ static unsigned long exynos5x_clk_regs[] __initdata = {
 	SRC_MASK_FSYS,
 	SRC_MASK_PERIC0,
 	SRC_MASK_PERIC1,
+	SRC_MASK_TOP0,
+	SRC_MASK_TOP1,
+	SRC_MASK_MAU,
+	SRC_MASK_ISP,
 	SRC_ISP,
 	DIV_TOP0,
 	DIV_TOP1,
@@ -208,6 +217,7 @@ static unsigned long exynos5x_clk_regs[] __initdata = {
 	SCLK_DIV_ISP1,
 	DIV2_RATIO0,
 	DIV4_RATIO,
+	GATE_BUS_DISP1,
 	GATE_BUS_TOP,
 	GATE_BUS_GEN,
 	GATE_BUS_FSYS0,
@@ -249,6 +259,22 @@ static unsigned long exynos5800_clk_regs[] __initdata = {
 	GATE_IP_CAM,
 };
 
+static const struct samsung_clk_reg_dump exynos5420_set_clksrc[] = {
+	{ .offset = SRC_MASK_CPERI,		.value = 0xffffffff, },
+	{ .offset = SRC_MASK_TOP0,		.value = 0x11111111, },
+	{ .offset = SRC_MASK_TOP1,		.value = 0x11101111, },
+	{ .offset = SRC_MASK_TOP2,		.value = 0x11111110, },
+	{ .offset = SRC_MASK_TOP7,		.value = 0x00111100, },
+	{ .offset = SRC_MASK_DISP10,		.value = 0x11111110, },
+	{ .offset = SRC_MASK_MAU,		.value = 0x10000000, },
+	{ .offset = SRC_MASK_FSYS,		.value = 0x11111110, },
+	{ .offset = SRC_MASK_PERIC0,		.value = 0x11111110, },
+	{ .offset = SRC_MASK_PERIC1,		.value = 0x11111100, },
+	{ .offset = SRC_MASK_ISP,		.value = 0x11111000, },
+	{ .offset = GATE_BUS_DISP1,		.value = 0xffffffff, },
+	{ .offset = GATE_IP_PERIC,		.value = 0xffffffff, },
+};
+
 static int exynos5420_clk_suspend(void)
 {
 	samsung_clk_save(reg_base, exynos5x_save,
@@ -258,6 +284,9 @@ static int exynos5420_clk_suspend(void)
 		samsung_clk_save(reg_base, exynos5800_save,
 				ARRAY_SIZE(exynos5800_clk_regs));
 
+	samsung_clk_restore(reg_base, exynos5420_set_clksrc,
+				ARRAY_SIZE(exynos5420_set_clksrc));
+
 	return 0;
 }
 
Signature · 1 line
1.7.9.5
#6 lore raw

PATCH v5 3/3 clk: samsung: exynos5420: Setup clocks before system suspend

Hi Vikas, Abhilash,

Quoted 10 lines · Vikas Sajjan

Prior to suspending the system, we need to ensure that certain clock source and gate registers are unmasked.

while at it, add these clks to save/restore list also.

---
 drivers/clk/samsung/clk-exynos5420.c |   29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

Looks good. Will apply.

Best regards,
Tomasz

#7 lore raw

PATCH v5 3/3 clk: samsung: exynos5420: Setup clocks before system suspend

Hi Kukjin,

Quoted 8 lines · Tomasz Figa

Hi Vikas, Abhilash,

Quoted 5 lines · Vikas Sajjan

Prior to suspending the system, we need to ensure that certain clock source and gate registers are unmasked.

while at it, add these clks to save/restore list also.

Quoted 8 lines
Quoted 5 lines
---
 drivers/clk/samsung/clk-exynos5420.c |   29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

Looks good. Will apply.

Can you apply this patch.

Quoted 2 lines

Best regards,
Tomasz

#8 lore raw

PATCH v5 3/3 clk: samsung: exynos5420: Setup clocks before system suspend

Vikas,

Quoted 17 lines · Vikas Sajjan

Hi Kukjin,

Quoted 14 lines · Tomasz Figa

Hi Vikas, Abhilash,

Quoted 10 lines · Vikas Sajjan

Prior to suspending the system, we need to ensure that certain clock source and gate registers are unmasked.

while at it, add these clks to save/restore list also.

---
 drivers/clk/samsung/clk-exynos5420.c |   29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
Quoted 4 lines
Quoted 2 lines

Looks good. Will apply.

Can you apply this patch.

As I said, I will take this through the samsung-clk tree. The patch should appear there soon.

Best regards,
Tomasz

#9 lore raw

PATCH v5 3/3 clk: samsung: exynos5420: Setup clocks before system suspend

Quoted 20 lines · Tomasz Figa

Vikas,

Quoted 17 lines · Vikas Sajjan

Hi Kukjin,

Quoted 14 lines · Tomasz Figa

Hi Vikas, Abhilash,

Quoted 10 lines · Vikas Sajjan

Prior to suspending the system, we need to ensure that certain clock source and gate registers are unmasked.

while at it, add these clks to save/restore list also.

---
 drivers/clk/samsung/clk-exynos5420.c |   29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

Looks good. Will apply.

Can you apply this patch.

As I said, I will take this through the samsung-clk tree. The patch should appear there soon.

OK, Thanks.

Quoted 7 lines

Best regards,
Tomasz
--
To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html