From: Anson Huang Date: Thu, 23 Jul 2015 11:05:16 +0000 (+0800) Subject: MLK-11281-6 ARM: imx: add lpsr support for imx7d X-Git-Tag: C0P2-H0.0--20200415~4104 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=1fa8f3a839f4f6927a9807143058edb7ba2aa43b;p=linux.git MLK-11281-6 ARM: imx: add lpsr support for imx7d Add LPSR mode support if dtb contains "fsl,enable-lpsr" property, when echo mem to make system enter DSM mode, whole SOC will be powered down except LPSR, SNVS domain and DDR chip's power, that means all modules in SOC domain will be powered down, including ccm, iomuxc, gpc.... So, all drivers need to restore their iomux settings and clk settings after resume; When system enters LPSR mode, can be waked up by long press ON/OFF button or using RTC alarm. In LPSR mode resume, ROM will read the entry point in LPSR register, make DRAM exit retention mode and jump to DRAM to resume kernel immediately, so before entering LPSR mode, we need to set the resume entry correctly in LPSR register and clear it after resume. Signed-off-by: Anson Huang --- diff --git a/arch/arm/mach-imx/mx7.h b/arch/arm/mach-imx/mx7.h index 97eff9cd7d8b..979a1c6bff7f 100644 --- a/arch/arm/mach-imx/mx7.h +++ b/arch/arm/mach-imx/mx7.h @@ -14,6 +14,8 @@ #define MX7D_IO_P2V(x) IMX_IO_P2V(x) #define MX7D_IO_ADDRESS(x) IOMEM(MX7D_IO_P2V(x)) +#define MX7D_LPSR_BASE_ADDR 0x30270000 +#define MX7D_LPSR_SIZE 0x10000 #define MX7D_CCM_BASE_ADDR 0x30380000 #define MX7D_CCM_SIZE 0x10000 #define MX7D_IOMUXC_BASE_ADDR 0x30330000 @@ -22,6 +24,8 @@ #define MX7D_IOMUXC_GPR_SIZE 0x10000 #define MX7D_ANATOP_BASE_ADDR 0x30360000 #define MX7D_ANATOP_SIZE 0x10000 +#define MX7D_SNVS_BASE_ADDR 0x30370000 +#define MX7D_SNVS_SIZE 0x10000 #define MX7D_GPC_BASE_ADDR 0x303a0000 #define MX7D_GPC_SIZE 0x10000 #define MX7D_SRC_BASE_ADDR 0x30390000 diff --git a/arch/arm/mach-imx/pm-imx7.c b/arch/arm/mach-imx/pm-imx7.c index 8ef6fed30c24..e7869c9970e5 100644 --- a/arch/arm/mach-imx/pm-imx7.c +++ b/arch/arm/mach-imx/pm-imx7.c @@ -68,6 +68,8 @@ static void __iomem *ccm_base; static void __iomem *console_base; static void __iomem *suspend_ocram_base; static void (*imx7_suspend_in_ocram_fn)(void __iomem *ocram_vbase); +struct imx7_cpu_pm_info *pm_info; +static bool lpsr_enabled; /* * suspend ocram space layout: * ======================== high address ====================== @@ -238,8 +240,9 @@ struct imx7_cpu_pm_info { struct imx7_pm_base iomuxc_gpr_base; struct imx7_pm_base ccm_base; struct imx7_pm_base gpc_base; - struct imx7_pm_base l2_base; + struct imx7_pm_base snvs_base; struct imx7_pm_base anatop_base; + struct imx7_pm_base lpsr_base; u32 ttbr1; /* Store TTBR1 */ u32 ddrc_num; /* Number of DDRC which need saved/restored. */ u32 ddrc_val[MX7_MAX_DDRC_NUM][2]; /* To save offset and value */ @@ -308,6 +311,11 @@ static int imx7_suspend_finish(unsigned long val) return 0; } +static void imx7_pm_set_lpsr_resume_addr(unsigned long addr) +{ + writel_relaxed(addr, pm_info->lpsr_base.vbase); +} + static int imx7_pm_enter(suspend_state_t state) { unsigned int console_saved_reg[10] = {0}; @@ -336,6 +344,8 @@ static int imx7_pm_enter(suspend_state_t state) if (imx_gpcv2_is_mf_mix_off()) { imx7_console_save(console_saved_reg); memcpy(ocram_saved_in_ddr, ocram_base, ocram_size); + if (lpsr_enabled) + imx7_pm_set_lpsr_resume_addr(pm_info->resume_addr); } /* Zzz ... */ @@ -345,6 +355,8 @@ static int imx7_pm_enter(suspend_state_t state) memcpy(ocram_base, ocram_saved_in_ddr, ocram_size); imx7_console_restore(console_saved_reg); } + /* clear LPSR resume address */ + imx7_pm_set_lpsr_resume_addr(0); imx_anatop_post_resume(); imx_gpcv2_post_resume(); break; @@ -468,7 +480,6 @@ void __init imx7_pm_map_io(void) static int __init imx7_suspend_init(const struct imx7_pm_socdata *socdata) { struct device_node *node; - struct imx7_cpu_pm_info *pm_info; int i, ret = 0; const u32 (*ddrc_offset_array)[2]; const u32 (*ddrc_phy_offset_array)[2]; @@ -509,31 +520,39 @@ static int __init imx7_suspend_init(const struct imx7_pm_socdata *socdata) */ pm_info->ccm_base.pbase = MX7D_CCM_BASE_ADDR; pm_info->ccm_base.vbase = (void __iomem *) - IMX_IO_P2V(MX7D_CCM_BASE_ADDR); + IMX_IO_P2V(MX7D_CCM_BASE_ADDR); pm_info->ddrc_base.pbase = MX7D_DDRC_BASE_ADDR; pm_info->ddrc_base.vbase = (void __iomem *) - IMX_IO_P2V(MX7D_DDRC_BASE_ADDR); + IMX_IO_P2V(MX7D_DDRC_BASE_ADDR); pm_info->ddrc_phy_base.pbase = MX7D_DDRC_PHY_BASE_ADDR; pm_info->ddrc_phy_base.vbase = (void __iomem *) - IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR); + IMX_IO_P2V(MX7D_DDRC_PHY_BASE_ADDR); pm_info->src_base.pbase = MX7D_SRC_BASE_ADDR; pm_info->src_base.vbase = (void __iomem *) - IMX_IO_P2V(MX7D_SRC_BASE_ADDR); + IMX_IO_P2V(MX7D_SRC_BASE_ADDR); pm_info->iomuxc_gpr_base.pbase = MX7D_IOMUXC_GPR_BASE_ADDR; pm_info->iomuxc_gpr_base.vbase = (void __iomem *) - IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR); + IMX_IO_P2V(MX7D_IOMUXC_GPR_BASE_ADDR); pm_info->gpc_base.pbase = MX7D_GPC_BASE_ADDR; pm_info->gpc_base.vbase = (void __iomem *) - IMX_IO_P2V(MX7D_GPC_BASE_ADDR); + IMX_IO_P2V(MX7D_GPC_BASE_ADDR); pm_info->anatop_base.pbase = MX7D_ANATOP_BASE_ADDR; pm_info->anatop_base.vbase = (void __iomem *) - IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR); + IMX_IO_P2V(MX7D_ANATOP_BASE_ADDR); + + pm_info->snvs_base.pbase = MX7D_SNVS_BASE_ADDR; + pm_info->snvs_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_SNVS_BASE_ADDR); + + pm_info->lpsr_base.pbase = MX7D_LPSR_BASE_ADDR; + pm_info->lpsr_base.vbase = (void __iomem *) + IMX_IO_P2V(MX7D_LPSR_BASE_ADDR); pm_info->ddrc_num = socdata->ddrc_num; ddrc_offset_array = socdata->ddrc_offset; @@ -606,6 +625,13 @@ void __init imx7d_pm_init(void) struct device_node *np; struct resource res; + np = of_find_compatible_node(NULL, NULL, "fsl,lpm-sram"); + if (of_get_property(np, "fsl,enable-lpsr", NULL)) + lpsr_enabled = true; + + if (lpsr_enabled) + pr_info("LPSR mode enabled, DSM will go into LPSR mode!\n"); + if (imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR3 || imx_ddrc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2) imx7_pm_common_init(&imx7d_pm_data_lpddr3); @@ -624,4 +650,7 @@ void __init imx7d_pm_init(void) "/soc/aips-bus@30800000/spba-bus@30800000/serial@30860000"); if (np) console_base = of_iomap(np, 0); + + /* clear LPSR resume address first */ + imx7_pm_set_lpsr_resume_addr(0); } diff --git a/arch/arm/mach-imx/suspend-imx7.S b/arch/arm/mach-imx/suspend-imx7.S index 3cc0dc5bebc8..d8da34c51de0 100644 --- a/arch/arm/mach-imx/suspend-imx7.S +++ b/arch/arm/mach-imx/suspend-imx7.S @@ -60,17 +60,19 @@ #define PM_INFO_MX7_CCM_V_OFFSET 0x40 #define PM_INFO_MX7_GPC_P_OFFSET 0x44 #define PM_INFO_MX7_GPC_V_OFFSET 0x48 -#define PM_INFO_MX7_L2_P_OFFSET 0x4c -#define PM_INFO_MX7_L2_V_OFFSET 0x50 +#define PM_INFO_MX7_SNVS_P_OFFSET 0x4c +#define PM_INFO_MX7_SNVS_V_OFFSET 0x50 #define PM_INFO_MX7_ANATOP_P_OFFSET 0x54 #define PM_INFO_MX7_ANATOP_V_OFFSET 0x58 -#define PM_INFO_MX7_TTBR1_V_OFFSET 0x5c -#define PM_INFO_DDRC_REG_NUM_OFFSET 0x60 -#define PM_INFO_DDRC_REG_OFFSET 0x64 -#define PM_INFO_DDRC_VALUE_OFFSET 0x68 -#define PM_INFO_DDRC_PHY_REG_NUM_OFFSET 0x164 -#define PM_INFO_DDRC_PHY_REG_OFFSET 0x168 -#define PM_INFO_DDRC_PHY_VALUE_OFFSET 0x16c +#define PM_INFO_MX7_LPSR_P_OFFSET 0x5c +#define PM_INFO_MX7_LPSR_V_OFFSET 0x60 +#define PM_INFO_MX7_TTBR1_V_OFFSET 0x64 +#define PM_INFO_DDRC_REG_NUM_OFFSET 0x68 +#define PM_INFO_DDRC_REG_OFFSET 0x6c +#define PM_INFO_DDRC_VALUE_OFFSET 0x70 +#define PM_INFO_DDRC_PHY_REG_NUM_OFFSET 0x16c +#define PM_INFO_DDRC_PHY_REG_OFFSET 0x170 +#define PM_INFO_DDRC_PHY_VALUE_OFFSET 0x174 #define MX7_SRC_GPR1 0x74 #define MX7_SRC_GPR2 0x78 @@ -490,7 +492,20 @@ ENTRY(imx7_suspend) beq ddr_only_self_refresh ddr_enter_retention - b ddr_retention_enter_out + /* enter LPSR mode if resume addr is valid */ + ldr r11, [r0, #PM_INFO_MX7_LPSR_V_OFFSET] + ldr r7, [r11] + cmp r7, #0x0 + beq ddr_retention_enter_out + + /* shut down vddsoc to enter lpsr mode */ + ldr r11, [r0, #PM_INFO_MX7_SNVS_V_OFFSET] + ldr r7, [r11, #0x38] + orr r7, r7, #0x60 + str r7, [r11, #0x38] +wait_shutdown: + b wait_shutdown + ddr_only_self_refresh: ddrc_enter_self_refresh ddr_retention_enter_out: