MLK-11365-02 ARM: imx: add M/F mix support on imx6ul
authorBai Ping <b51503@freescale.com>
Thu, 13 Aug 2015 10:52:08 +0000 (18:52 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 19:47:30 +0000 (14:47 -0500)
Add M/F mix support on i.MX6UL.

Signed-off-by: Bai Ping <b51503@freescale.com>
arch/arm/mach-imx/gpc.c
arch/arm/mach-imx/pm-imx6.c
arch/arm/mach-imx/suspend-imx6.S

index b54db47..7e0aa32 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011-2013 Freescale Semiconductor, Inc.
+ * Copyright 2011-2015 Freescale Semiconductor, Inc.
  * Copyright 2011 Linaro Ltd.
  *
  * The code contained herein is licensed under the GNU General Public
@@ -27,6 +27,7 @@
 
 #define GPC_CNTR               0x000
 #define GPC_IMR1               0x008
+#define GPC_PGC_MF_PDN         0x220
 #define GPC_PGC_GPU_PDN                0x260
 #define GPC_PGC_GPU_PUPSCR     0x264
 #define GPC_PGC_GPU_PDNSCR     0x268
@@ -54,6 +55,27 @@ struct pu_domain {
 static void __iomem *gpc_base;
 static u32 gpc_wake_irqs[IMR_NUM];
 static u32 gpc_saved_imrs[IMR_NUM];
+static u32 gpc_mf_irqs[IMR_NUM];
+static u32 gpc_mf_request_on[IMR_NUM];
+
+unsigned int imx_gpc_is_mf_mix_off(void)
+{
+       return readl_relaxed(gpc_base + GPC_PGC_MF_PDN);
+}
+
+static void imx_gpc_mf_mix_off(void)
+{
+       int i;
+
+       for (i = 0; i < IMR_NUM; i++)
+               if (((gpc_wake_irqs[i] | gpc_mf_request_on[i]) &
+                                               gpc_mf_irqs[i]) != 0)
+                       return;
+
+       pr_info("Turn off M/F mix!\n");
+       /* turn off mega/fast mix */
+       writel_relaxed(0x1, gpc_base + GPC_PGC_MF_PDN);
+}
 
 void imx_gpc_set_arm_power_up_timing(u32 sw2iso, u32 sw)
 {
@@ -77,6 +99,10 @@ void imx_gpc_pre_suspend(bool arm_power_off)
        void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
        int i;
 
+       /* power down the mega-fast power domain */
+       if (cpu_is_imx6ul() && arm_power_off)
+               imx_gpc_mf_mix_off();
+
        /* Tell GPC to power off ARM core when suspend */
        if (arm_power_off)
                imx_gpc_set_arm_power_in_lpm(arm_power_off);
@@ -271,6 +297,21 @@ static int __init imx_gpc_init(struct device_node *node,
        for (i = 0; i < IMR_NUM; i++)
                writel_relaxed(~0, gpc_base + GPC_IMR1 + i * 4);
 
+       /* Read supported wakeup source in M/F domain */
+       if (cpu_is_imx6ul()) {
+               of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 0,
+                       &gpc_mf_irqs[0]);
+               of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 1,
+                       &gpc_mf_irqs[1]);
+               of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 2,
+                       &gpc_mf_irqs[2]);
+               of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 3,
+                       &gpc_mf_irqs[3]);
+               if (!(gpc_mf_irqs[0] | gpc_mf_irqs[1] |
+                       gpc_mf_irqs[2] | gpc_mf_irqs[3]))
+                       pr_info("No wakeup source in Mega/Fast domain found!\n");
+       }
+
        /*
         * Clear the OF_POPULATED flag set in of_irq_init so that
         * later the GPC power domain driver will not be skipped.
index e0f5936..9d3d0bd 100644 (file)
@@ -65,6 +65,7 @@
 
 #define MX6Q_SUSPEND_OCRAM_SIZE                0x1000
 #define MX6_MAX_MMDC_IO_NUM            33
+#define MX6_MAX_MMDC_NUM               34
 
 extern unsigned long iram_tlb_base_addr;
 extern unsigned long iram_tlb_phys_addr;
@@ -101,6 +102,8 @@ struct imx6_pm_socdata {
        const char *pl310_compat;
        const u32 mmdc_io_num;
        const u32 *mmdc_io_offset;
+       const u32 mmdc_num;
+       const u32 *mmdc_offset;
 };
 
 static const u32 imx6q_mmdc_io_offset[] __initconst = {
@@ -150,6 +153,16 @@ static const u32 imx6ul_mmdc_io_offset[] __initconst = {
        0x494, 0x4b0,               /* MODE_CTL, MODE, */
 };
 
+static const u32 imx6ul_mmdc_offset[] __initconst = {
+       0x01c, 0x800, 0x80c, 0x83c,
+       0x848, 0x850, 0x81c, 0x820,
+       0x82c, 0x830, 0x8c0, 0x8b8,
+       0x004, 0x008, 0x00c, 0x010,
+       0x014, 0x018, 0x01c, 0x02c,
+       0x030, 0x040, 0x000, 0x01c,
+       0x020, 0x818, 0x01c,
+};
+
 static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
        .mmdc_compat = "fsl,imx6q-mmdc",
        .src_compat = "fsl,imx6q-src",
@@ -158,6 +171,8 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
        .pl310_compat = "arm,pl310-cache",
        .mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset),
        .mmdc_io_offset = imx6q_mmdc_io_offset,
+       .mmdc_num = 0,
+       .mmdc_offset = NULL,
 };
 
 static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
@@ -168,6 +183,8 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
        .pl310_compat = "arm,pl310-cache",
        .mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset),
        .mmdc_io_offset = imx6dl_mmdc_io_offset,
+       .mmdc_num = 0,
+       .mmdc_offset = NULL,
 };
 
 static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
@@ -178,6 +195,8 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
        .pl310_compat = "arm,pl310-cache",
        .mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset),
        .mmdc_io_offset = imx6sl_mmdc_io_offset,
+       .mmdc_num = 0,
+       .mmdc_offset = NULL,
 };
 
 static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
@@ -188,6 +207,8 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
        .pl310_compat = "arm,pl310-cache",
        .mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset),
        .mmdc_io_offset = imx6sx_mmdc_io_offset,
+       .mmdc_num = 0,
+       .mmdc_offset = NULL,
 };
 
 static const struct imx6_pm_socdata imx6ul_pm_data __initconst = {
@@ -198,6 +219,8 @@ static const struct imx6_pm_socdata imx6ul_pm_data __initconst = {
        .pl310_compat = NULL,
        .mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_offset),
        .mmdc_io_offset = imx6ul_mmdc_io_offset,
+       .mmdc_num = ARRAY_SIZE(imx6ul_mmdc_offset),
+       .mmdc_offset = imx6ul_mmdc_offset,
 };
 
 static struct map_desc iram_tlb_io_desc __initdata = {
@@ -253,6 +276,8 @@ struct imx6_cpu_pm_info {
        u32 ttbr1; /* Store TTBR1 */
        u32 mmdc_io_num; /* Number of MMDC IOs which need saved/restored. */
        u32 mmdc_io_val[MX6_MAX_MMDC_IO_NUM][2]; /* To save offset and value */
+       u32 mmdc_num; /* Number of MMDC registers which need saved/restored. */
+       u32 mmdc_val[MX6_MAX_MMDC_NUM][2];
 } __aligned(8);
 
 unsigned long save_ttbr1(void)
@@ -579,6 +604,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
        unsigned long iram_paddr;
        int i, ret = 0;
        const u32 *mmdc_offset_array;
+       const u32 *mmdc_io_offset_array;
 
        suspend_set_ops(&imx6q_pm_ops);
 
@@ -642,16 +668,34 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
 
        pm_info->ddr_type = imx_mmdc_get_ddr_type();
        pm_info->mmdc_io_num = socdata->mmdc_io_num;
-       mmdc_offset_array = socdata->mmdc_io_offset;
+       mmdc_io_offset_array = socdata->mmdc_io_offset;
+       pm_info->mmdc_num = socdata->mmdc_num;
+       mmdc_offset_array = socdata->mmdc_offset;
 
        for (i = 0; i < pm_info->mmdc_io_num; i++) {
                pm_info->mmdc_io_val[i][0] =
-                       mmdc_offset_array[i];
+                       mmdc_io_offset_array[i];
                pm_info->mmdc_io_val[i][1] =
                        readl_relaxed(pm_info->iomuxc_base.vbase +
+                       mmdc_io_offset_array[i]);
+       }
+
+       /* initialize MMDC settings */
+       for (i = 0; i < pm_info->mmdc_num; i++) {
+               pm_info->mmdc_val[i][0] =
+                       mmdc_offset_array[i];
+               pm_info->mmdc_val[i][1] =
+                       readl_relaxed(pm_info->mmdc_base.vbase +
                        mmdc_offset_array[i]);
        }
 
+       /* need to overwrite the value for some mmdc registers */
+       if (cpu_is_imx6ul()) {
+               pm_info->mmdc_val[20][1] = (pm_info->mmdc_val[20][1]
+                       & 0xffff0000) | 0x0202;
+               pm_info->mmdc_val[23][1] = 0x8033;
+       }
+
        imx6_suspend_in_ocram_fn = fncpy(
                suspend_ocram_base + sizeof(*pm_info),
                &imx6_suspend,
index d2d216d..e34fdc3 100644 (file)
@@ -64,6 +64,9 @@
 #define        PM_INFO_MX6Q_TTBR1_V_OFFSET             0x48
 #define PM_INFO_MMDC_IO_NUM_OFFSET             0x4c
 #define PM_INFO_MMDC_IO_VAL_OFFSET             0x50
+/* below offsets depends on MX6_MAX_MMDC_IO_NUM(33) definition */
+#define PM_INFO_MMDC_NUM_OFFSET                        0x158
+#define PM_INFO_MMDC_VAL_OFFSET                        0x15c
 
 #define MX6Q_SRC_GPR1  0x20
 #define MX6Q_SRC_GPR2  0x24
 
        .endm
 
-       .macro  resume_mmdc
-
-       /* restore MMDC IO */
-       cmp     r5, #0x0
-       ldreq   r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
-       ldrne   r11, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
-
-       ldr     r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
-       ldr     r7, =PM_INFO_MMDC_IO_VAL_OFFSET
-       add     r7, r7, r0
-1:
-       ldr     r8, [r7], #0x4
-       ldr     r9, [r7], #0x4
-       str     r9, [r11, r8]
-       subs    r6, r6, #0x1
-       bne     1b
-
-       cmp     r5, #0x0
-       ldreq   r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
-       ldrne   r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
-
-       cmp     r3, #IMX_DDR_TYPE_LPDDR2
-       bne     4f
+       /* r11 must be MMDC base address */
+       .macro reset_read_fifo
 
        /* reset read FIFO, RST_RD_FIFO */
        ldr     r7, =MX6Q_MMDC_MPDGCTRL0
        ldr     r6, [r11, r7]
        ands    r6, r6, #(1 << 31)
        bne     3b
-4:
+
+       .endm
+
+       /* r11 must be MMDC base address */
+       .macro mmdc_out_and_auto_self_refresh
+
        /* let DDR out of self-refresh */
        ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
        bic     r7, r7, #(1 << 21)
        str     r7, [r11, #MX6Q_MMDC_MAPSR]
-5:
+4:
        ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
        ands    r7, r7, #(1 << 25)
-       bne     5b
+       bne     4b
 
        /* enable DDR auto power saving */
        ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
 
        .endm
 
+       /* r10 must be iomuxc base address */
+       .macro resume_iomuxc_gpr
+
+       add     r10, r10, #0x4000
+       /* IOMUXC GPR DRAM_RESET_BYPASS */
+       ldr     r4, [r10, #0x8]
+       bic     r4, r4, #(0x1 << 27)
+       str     r4, [r10, #0x8]
+       /* IOMUXC GPR DRAM_CKE_BYPASS */
+       ldr     r4, [r10, #0x8]
+       bic     r4, r4, #(0x1 << 31)
+       str     r4, [r10, #0x8]
+
+       .endm
+
+       .macro  resume_io
+
+       /* restore MMDC IO */
+       cmp     r5, #0x0
+       ldreq   r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
+       ldrne   r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
+
+       ldr     r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
+       ldr     r7, =PM_INFO_MMDC_IO_VAL_OFFSET
+       add     r7, r7, r0
+5:
+       ldr     r8, [r7], #0x4
+       ldr     r9, [r7], #0x4
+       str     r9, [r10, r8]
+       subs    r6, r6, #0x1
+       bne     5b
+
+       cmp     r5, #0x0
+       /* Here only MMDC0 is set */
+       ldreq   r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
+       ldrne   r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
+
+       cmp     r3, #IMX_DDR_TYPE_LPDDR2
+       bne     6f
+
+       reset_read_fifo
+6:
+       mmdc_out_and_auto_self_refresh
+
+       .endm
+
+       .macro  resume_mmdc_io
+
+       cmp     r5, #0x0
+       ldreq   r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
+       ldrne   r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
+       ldreq   r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
+       ldrne   r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
+
+       /* resume mmdc iomuxc settings */
+       ldr     r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
+       ldr     r7, =PM_INFO_MMDC_IO_VAL_OFFSET
+       add     r7, r7, r0
+7:
+       ldr     r8, [r7], #0x4
+       ldr     r9, [r7], #0x4
+       str     r9, [r10, r8]
+       subs    r6, r6, #0x1
+       bne     7b
+
+       /* check whether we need to restore MMDC */
+       cmp     r5, #0x0
+       beq     8f
+
+       /* check whether last suspend is with M/F mix off */
+       ldr     r9, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET]
+       ldr     r6, [r9, #0x220]
+       cmp     r6, #0x0
+       bne     9f
+8:
+       resume_iomuxc_gpr
+
+       b       13f
+9:
+       /* restore MMDC settings */
+       ldr     r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]
+       ldr     r7, =PM_INFO_MMDC_VAL_OFFSET
+       add     r7, r7, r0
+10:
+       ldr     r8, [r7], #0x4
+       ldr     r9, [r7], #0x4
+       str     r9, [r11, r8]
+       subs    r6, r6, #0x1
+       bne     10b
+
+       /* let DDR enter self-refresh */
+       ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
+       orr     r7, r7, #(1 << 20)
+       str     r7, [r11, #MX6Q_MMDC_MAPSR]
+11:
+       ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
+       ands    r7, r7, #(1 << 24)
+       beq     11b
+
+       resume_iomuxc_gpr
+
+       reset_read_fifo
+
+       /* let DDR out of self-refresh */
+       ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
+       bic     r7, r7, #(1 << 20)
+       str     r7, [r11, #MX6Q_MMDC_MAPSR]
+12:
+       ldr     r7, [r11, #MX6Q_MMDC_MAPSR]
+       ands    r7, r7, #(1 << 24)
+       bne     12b
+
+       /* kick off MMDC */
+       ldr     r4, =0x0
+       str     r4, [r11, #0x1c]
+13:
+       mmdc_out_and_auto_self_refresh
+
+       .endm
+
        .macro store_ttbr1
 
        /* Store TTBR1 to pm_info->ttbr1 */
@@ -394,6 +501,28 @@ set_mmdc_io_lpm:
        str     r6, [r11, r9]
 set_mmdc_io_lpm_done:
 
+       /* check whether it supports Mega/Fast off */
+       ldr     r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]
+       cmp     r6, #0x0
+       beq     set_mmdc_lpm_done
+
+       /* IOMUXC GPR DRAM_RESET */
+       add     r11, r11, #0x4000
+       ldr     r6, [r11, #0x8]
+       orr     r6, r6, #(0x1 << 28)
+       str     r6, [r11, #0x8]
+
+       /* IOMUXC GPR DRAM_RESET_BYPASS */
+       ldr     r6, [r11, #0x8]
+       orr     r6, r6, #(0x1 << 27)
+       str     r6, [r11, #0x8]
+
+       /* IOMUXC GPR DRAM_CKE_BYPASS */
+       ldr     r6, [r11, #0x8]
+       orr     r6, r6, #(0x1 << 31)
+       str     r6, [r11, #0x8]
+set_mmdc_lpm_done:
+
        /*
         * mask all GPC interrupts before
         * enabling the RBC counters to
@@ -465,7 +594,16 @@ rbc_loop:
         * resume, we need to restore MMDC IO first
         */
        mov     r5, #0x0
-       resume_mmdc
+       /* check whether it supports Mega/Fast off */
+       ldr     r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]
+       cmp     r6, #0x0
+       beq     only_resume_io
+       resume_mmdc_io
+       b       resume_mmdc_done
+only_resume_io:
+       resume_io
+resume_mmdc_done:
+
        restore_ttbr1
 
        /* return to suspend finish */
@@ -491,7 +629,16 @@ resume:
 
        ldr     r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
        mov     r5, #0x1
-       resume_mmdc
+       /* check whether it supports Mega/Fast off */
+       ldr     r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]
+       cmp     r6, #0x0
+       beq     dsm_only_resume_io
+       resume_mmdc_io
+       b       dsm_resume_mmdc_done
+dsm_only_resume_io:
+       ldr     r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
+       resume_io
+dsm_resume_mmdc_done:
 
        ret     lr
 ENDPROC(imx6_suspend)