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> Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
This commit is contained in:
@ -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
|
||||
@ -21,6 +21,7 @@
|
||||
#include "hardware.h"
|
||||
|
||||
#define GPC_IMR1 0x008
|
||||
#define GPC_PGC_MF_PDN 0x220
|
||||
#define GPC_PGC_CPU_PDN 0x2a0
|
||||
#define GPC_PGC_CPU_PUPSCR 0x2a4
|
||||
#define GPC_PGC_CPU_PDNSCR 0x2a8
|
||||
@ -33,6 +34,27 @@
|
||||
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)
|
||||
{
|
||||
@ -56,6 +78,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);
|
||||
@ -250,6 +276,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.
|
||||
|
||||
@ -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)
|
||||
@ -581,6 +606,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);
|
||||
|
||||
@ -644,16 +670,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,
|
||||
|
||||
@ -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)
|
||||
|
||||
Reference in New Issue
Block a user