summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBai Ping <b51503@freescale.com>2015-08-13 18:52:08 +0800
committerLeonard Crestez <leonard.crestez@nxp.com>2018-08-23 16:57:18 +0300
commit3a98deeef314ae2d9e8aaa88b7b0ae9f4162efa8 (patch)
treede5f920a6f8f39720434d1929b51a3f27c15a492
parent1e680a227de61bbdb1428c3d27a5ad3b924c4e49 (diff)
MLK-11365-02 ARM: imx: add M/F mix support on imx6ul
Add M/F mix support on i.MX6UL. Signed-off-by: Bai Ping <b51503@freescale.com>
-rw-r--r--arch/arm/mach-imx/gpc.c43
-rw-r--r--arch/arm/mach-imx/pm-imx6.c48
-rw-r--r--arch/arm/mach-imx/suspend-imx6.S203
3 files changed, 263 insertions, 31 deletions
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index b54db47f6f32..7e0aa32af3d8 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -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.
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index e0f59360bd9e..9d3d0bdee56f 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -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,
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index d2d216db06db..e34fdc39aef0 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -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
@@ -134,29 +137,8 @@
.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
@@ -176,15 +158,20 @@
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]
@@ -193,6 +180,126 @@
.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)