MLK-11281-6 ARM: imx: add lpsr support for imx7d
authorAnson Huang <b20788@freescale.com>
Thu, 23 Jul 2015 11:05:16 +0000 (19:05 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:49:03 +0000 (14:49 -0500)
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 <b20788@freescale.com>
arch/arm/mach-imx/mx7.h
arch/arm/mach-imx/pm-imx7.c
arch/arm/mach-imx/suspend-imx7.S

index 97eff9c..979a1c6 100644 (file)
@@ -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
index 8ef6fed..e7869c9 100644 (file)
@@ -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);
 }
index 3cc0dc5..d8da34c 100644 (file)
 #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: