summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnson Huang <b20788@freescale.com>2014-06-13 14:35:24 +0800
committerNitin Garg <nitin.garg@freescale.com>2014-08-27 18:28:57 -0500
commit7beced60440f90e8949f826ce323e6adc02742d8 (patch)
tree2eee68f9015efc93c5a778ce81d5625372efb580
parent0ab7b6489d0dc253cd5c4b8b8a00d8e3f13fb34a (diff)
ENGR00318259-2 ARM: imx: support mega fast domain power off in DSM
Add mega fast domain power off feature in DSM, it can save about 0.72mW power; If there is any module in Mega/Fast domain enabled as wakeup source, then Mega/Fast domain's power will be kept on in DSM. Signed-off-by: Anson Huang <b20788@freescale.com>
-rw-r--r--Documentation/devicetree/bindings/arm/imx/gpc.txt6
-rw-r--r--arch/arm/mach-imx/gpc.c37
-rw-r--r--arch/arm/mach-imx/suspend-imx6.S247
3 files changed, 250 insertions, 40 deletions
diff --git a/Documentation/devicetree/bindings/arm/imx/gpc.txt b/Documentation/devicetree/bindings/arm/imx/gpc.txt
index 5a363a85822c..dd6a4be066ac 100644
--- a/Documentation/devicetree/bindings/arm/imx/gpc.txt
+++ b/Documentation/devicetree/bindings/arm/imx/gpc.txt
@@ -9,9 +9,15 @@ Optional properties:
These properties are for adjusting the GPC PGC CPU power up/down setting, if there is no such property in dts, then default
value in GPC PGC registers will be used.
+- fsl,mf-mix-wakeup-irq: for recording those wakeup sources' irq number in fast/mega mix domain, same as GPC_IMRx register layout.
+If the bitmap in this properties is 1, then fast/mega mix's power can NOT be gated if it is set as wakeup source in kernel.
Example:
+ gpc: gpc@020dc000 {
+ fsl,mf-mix-wakeup-irq = <0x4000000 0x3d00 0x0 0x0>;
+ };
+
&gpc {
fsl,cpu_pupscr_sw2iso = <0xf>;
fsl,cpu_pupscr_sw = <0xf>;
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index da6409285c64..07fac4b13bdd 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -27,6 +27,7 @@
#include "hardware.h"
#define GPC_IMR1 0x008
+#define GPC_PGC_MF_PDN 0x220
#define GPC_PGC_CPU_PDN 0x2a0
#define GPC_PGC_GPU_PDN 0x260
#define GPC_PGC_GPU_PUPSCR 0x264
@@ -56,6 +57,7 @@
#define IMR_NUM 4
static void __iomem *gpc_base;
+static u32 gpc_mf_irqs[IMR_NUM];
static u32 gpc_wake_irqs[IMR_NUM];
static u32 gpc_saved_imrs[IMR_NUM];
static struct clk *gpu3d_clk, *gpu3d_shader_clk, *gpu2d_clk, *gpu2d_axi_clk;
@@ -128,6 +130,19 @@ static void imx_gpc_dispmix_off(void)
}
}
+static void imx_gpc_mf_mix_off(void)
+{
+ int i;
+
+ for (i = 0; i < IMR_NUM; i++)
+ if ((gpc_wake_irqs[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_pre_suspend(bool arm_power_off)
{
void __iomem *reg_imr1 = gpc_base + GPC_IMR1;
@@ -135,6 +150,9 @@ void imx_gpc_pre_suspend(bool arm_power_off)
imx_gpc_dispmix_off();
+ if (cpu_is_imx6sx() && arm_power_off)
+ imx_gpc_mf_mix_off();
+
if (arm_power_off)
/* Tell GPC to power off ARM core when suspend */
writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_PDN);
@@ -153,6 +171,10 @@ void imx_gpc_post_resume(void)
/* Keep ARM core powered on for other low-power modes */
writel_relaxed(0x0, gpc_base + GPC_PGC_CPU_PDN);
+ /* Keep M/F mix powered on for other low-power modes */
+ if (cpu_is_imx6sx())
+ writel_relaxed(0x0, gpc_base + GPC_PGC_MF_PDN);
+
for (i = 0; i < IMR_NUM; i++)
writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
@@ -394,6 +416,21 @@ void __init imx_gpc_init(void)
of_property_read_u32(np, "fsl,cpu_pdnscr_iso2sw", &cpu_pdnscr_iso2sw);
of_property_read_u32(np, "fsl,cpu_pdnscr_iso", &cpu_pdnscr_iso);
+ /* Read supported wakeup source in M/F domain */
+ if (cpu_is_imx6sx()) {
+ of_property_read_u32_index(np, "fsl,mf-mix-wakeup-irq", 0,
+ &gpc_mf_irqs[0]);
+ of_property_read_u32_index(np, "fsl,mf-mix-wakeup-irq", 1,
+ &gpc_mf_irqs[1]);
+ of_property_read_u32_index(np, "fsl,mf-mix-wakeup-irq", 2,
+ &gpc_mf_irqs[2]);
+ of_property_read_u32_index(np, "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");
+ }
+
/* Update CPU PUPSCR timing if it is defined in dts */
val = readl_relaxed(gpc_base + GPC_PGC_CPU_PUPSCR);
if (cpu_pupscr_sw2iso)
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index da9bd589f5ea..7cd6a8cbd39c 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -36,6 +36,31 @@
.align 3
+ .macro reset_fifo
+
+ /* reset read FIFO, RST_RD_FIFO */
+ ldr r7, =MX6Q_MMDC_MPDGCTRL0
+ ldr r6, [r8, r7]
+ orr r6, r6, #(1 << 31)
+ str r6, [r8, r7]
+2:
+ ldr r6, [r8, r7]
+ and r6, r6, #(1 << 31)
+ cmp r6, #0
+ bne 2b
+
+ /* reset FIFO a second time */
+ ldr r6, [r8, r7]
+ orr r6, r6, #(1 << 31)
+ str r6, [r8, r7]
+3:
+ ldr r6, [r8, r7]
+ and r6, r6, #(1 << 31)
+ cmp r6, #0
+ bne 3b
+
+ .endm
+
.macro imx6sx_ddr_io_save
ldr r4, [r8, #0x2ec] /* DRAM_DQM0 */
@@ -70,6 +95,50 @@
.endm
+ .macro imx6sx_mmdc_save
+
+ ldr r4, [r8, #0x800]
+ ldr r5, [r8, #0x80c]
+ ldr r6, [r8, #0x810]
+ ldr r7, [r8, #0x83c]
+ stmfd r10!, {r4-r7}
+
+ ldr r4, [r8, #0x840]
+ ldr r5, [r8, #0x848]
+ ldr r6, [r8, #0x850]
+ ldr r7, [r8, #0x81c]
+ stmfd r10!, {r4-r7}
+
+ ldr r4, [r8, #0x820]
+ ldr r5, [r8, #0x824]
+ ldr r6, [r8, #0x828]
+ ldr r7, [r8, #0x8b8]
+ stmfd r10!, {r4-r7}
+
+ ldr r4, [r8, #0x004]
+ ldr r5, [r8, #0x008]
+ ldr r6, [r8, #0x00c]
+ ldr r7, [r8, #0x010]
+ stmfd r10!, {r4-r7}
+
+ ldr r4, [r8, #0x014]
+ ldr r5, [r8, #0x018]
+ ldr r6, [r8, #0x01c]
+ ldr r7, [r8, #0x02c]
+ stmfd r10!, {r4-r7}
+
+ ldr r4, [r8, #0x030]
+ ldr r5, [r8, #0x040]
+ ldr r6, [r8, #0x000]
+ ldr r7, [r8, #0x020]
+ stmfd r10!, {r4-r7}
+
+ ldr r4, [r8, #0x818]
+ ldr r5, [r8, #0x01c]
+ stmfd r10!, {r4-r5}
+
+ .endm
+
.macro imx6sx_ddr_io_restore
ldmea r10!, {r4-r7}
@@ -104,6 +173,103 @@
.endm
+ .macro imx6sx_mmdc_restore
+
+ ldr r7, =0x4000
+ add r8, r8, r7
+ ldr r4, [r8, #0x8] /* DRAM_RESET_BYPASS */
+ bic r4, r4, #(0x1 << 27)
+ str r4, [r8, #0x8]
+
+ ldr r4, [r8, #0x8] /* DRAM_CKE_BYPASS */
+ bic r4, r4, #(0x1 << 31)
+ str r4, [r8, #0x8]
+
+ .endm
+
+ .macro imx6sx_mmdc_restore_dsm
+
+ ldmea r10!, {r4-r7}
+ str r4, [r8, #0x800]
+ str r5, [r8, #0x80c]
+ str r6, [r8, #0x810]
+ str r7, [r8, #0x83c]
+
+ ldmea r10!, {r4-r7}
+ str r4, [r8, #0x840]
+ str r5, [r8, #0x848]
+ str r6, [r8, #0x850]
+ str r7, [r8, #0x81c]
+
+ ldmea r10!, {r4-r7}
+ str r4, [r8, #0x820]
+ str r5, [r8, #0x824]
+ str r6, [r8, #0x828]
+ str r7, [r8, #0x8b8]
+
+ ldmea r10!, {r4-r7}
+ str r4, [r8, #0x004]
+ str r5, [r8, #0x008]
+ str r6, [r8, #0x00c]
+ str r7, [r8, #0x010]
+
+ ldmea r10!, {r4-r7}
+ str r4, [r8, #0x014]
+ str r5, [r8, #0x018]
+ str r6, [r8, #0x01c]
+ str r7, [r8, #0x02c]
+
+ ldmea r10!, {r4-r7}
+ bic r4, #0xff00
+ bic r4, #0xff
+ orr r4, #0x0200
+ orr r4, #0x02
+ str r4, [r8, #0x030]
+ str r5, [r8, #0x040]
+ str r6, [r8, #0x000]
+ /* make sure MMDC is ready */
+ ldr r4, =0x8033
+ str r4, [r8, #0x01c]
+ str r7, [r8, #0x020]
+
+ ldmea r10!, {r4-r5}
+ str r4, [r8, #0x818]
+ str r5, [r8, #0x01c]
+
+ /* make the DDR explicitly enter self-refresh. */
+ ldr r7, [r8, #MX6Q_MMDC_MAPSR]
+ orr r7, r7, #(1 << 20)
+ str r7, [r8, #MX6Q_MMDC_MAPSR]
+4:
+ ldr r7, [r8, #0x404]
+ ands r7, r7, #(1 << 24)
+ beq 4b
+
+ ldr r7, =0x4000
+ add r11, r11, r7
+ ldr r4, [r11, #0x8] /* DRAM_RESET_BYPASS */
+ bic r4, r4, #(0x1 << 27)
+ str r4, [r11, #0x8]
+
+ ldr r4, [r11, #0x8] /* DRAM_CKE_BYPASS */
+ bic r4, r4, #(0x1 << 31)
+ str r4, [r11, #0x8]
+
+ /* make the DDR explicitly exit self-refresh. */
+ ldr r7, [r8, #MX6Q_MMDC_MAPSR]
+ bic r7, r7, #(1 << 20)
+ str r7, [r8, #MX6Q_MMDC_MAPSR]
+
+5:
+ ldr r7, [r8, #0x404]
+ ands r7, r7, #(1 << 24)
+ bne 5b
+
+ ldr r4, =0x0
+ str r4, [r8, #0x1c]
+
+ .endm
+
.macro imx6sx_ddr_io_set_lpm
mov r10, #0
@@ -134,6 +300,25 @@
.endm
+ .macro imx6sx_mmdc_set_lpm
+
+ ldr r7, =0x4000
+ add r11, r8, r7
+
+ ldr r4, [r11, #0x8] /* DRAM_RESET */
+ orr r4, r4, #(0x1 << 28)
+ str r4, [r11, #0x8]
+
+ ldr r4, [r11, #0x8] /* DRAM_RESET_BYPASS */
+ orr r4, r4, #(0x1 << 27)
+ str r4, [r11, #0x8]
+
+ ldr r4, [r11, #0x8] /* DRAM_CKE_BYPASS */
+ orr r4, r4, #(0x1 << 31)
+ str r4, [r11, #0x8]
+
+ .endm
+
.macro imx6sl_ddr_io_save
ldr r4, [r8, #0x30c] /* DRAM_DQM0 */
@@ -625,7 +810,10 @@ sl_io_save:
imx6sl_ddr_io_save
b ddr_io_save_dsm_done
sx_io_save:
+ ldr r8, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR)
imx6sx_ddr_io_save
+ ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR)
+ imx6sx_mmdc_save
ddr_io_save_dsm_done:
/* need to sync L2 cache before DSM. */
@@ -726,6 +914,7 @@ sl_io_dsm_set_lpm:
b ddr_io_set_lpm_dsm_done
sx_io_dsm_set_lpm:
imx6sx_ddr_io_set_lpm
+ imx6sx_mmdc_set_lpm
ddr_io_set_lpm_dsm_done:
/*
@@ -852,29 +1041,12 @@ sl_io_restore:
bne sx_io_restore
imx6sl_ddr_io_restore
ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR)
- /* reset read FIFO, RST_RD_FIFO */
- ldr r7, =MX6Q_MMDC_MPDGCTRL0
- ldr r6, [r8, r7]
- orr r6, r6, #(1 << 31)
- str r6, [r8, r7]
-fifo_reset1_wait:
- ldr r6, [r8, r7]
- and r6, r6, #(1 << 31)
- cmp r6, #0
- bne fifo_reset1_wait
-
- /* reset FIFO a second time */
- ldr r6, [r8, r7]
- orr r6, r6, #(1 << 31)
- str r6, [r8, r7]
-fifo_reset2_wait:
- ldr r6, [r8, r7]
- and r6, r6, #(1 << 31)
- cmp r6, #0
- bne fifo_reset2_wait
+ reset_fifo
b ddr_io_restore_done
sx_io_restore:
+ ldr r8, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR)
imx6sx_ddr_io_restore
+ imx6sx_mmdc_restore
ddr_io_restore_done:
ldr r8, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR)
@@ -983,29 +1155,24 @@ sl_io_dsm_restore:
bne sx_io_dsm_restore
imx6sl_ddr_io_restore
ldr r8, =MX6Q_MMDC_P0_BASE_ADDR
- /* reset read FIFO, RST_RD_FIFO */
- ldr r7, =MX6Q_MMDC_MPDGCTRL0
- ldr r6, [r8, r7]
- orr r6, r6, #(1 << 31)
- str r6, [r8, r7]
-dsm_fifo_reset1_wait:
- ldr r6, [r8, r7]
- and r6, r6, #(1 << 31)
- cmp r6, #0
- bne dsm_fifo_reset1_wait
-
- /* reset FIFO a second time */
- ldr r6, [r8, r7]
- orr r6, r6, #(1 << 31)
- str r6, [r8, r7]
-dsm_fifo_reset2_wait:
- ldr r6, [r8, r7]
- and r6, r6, #(1 << 31)
- cmp r6, #0
- bne dsm_fifo_reset2_wait
+ reset_fifo
b ddr_io_restore_dsm_done
sx_io_dsm_restore:
+ ldr r8, =MX6Q_IOMUXC_BASE_ADDR
imx6sx_ddr_io_restore
+ /* check whether M/F mix is powered off */
+ ldr r8, =MX6Q_GPC_BASE_ADDR
+ ldr r7, [r8, #0x220]
+ ands r7, #0x1
+ bne mega_fast_off
+ ldr r8, =MX6Q_IOMUXC_BASE_ADDR
+ imx6sx_mmdc_restore
+ b ddr_io_restore_dsm_done
+mega_fast_off:
+ ldr r8, =MX6Q_MMDC_P0_BASE_ADDR
+ ldr r11, =MX6Q_IOMUXC_BASE_ADDR
+ imx6sx_mmdc_restore_dsm
+ reset_fifo
ddr_io_restore_dsm_done:
ldr r8, =MX6Q_MMDC_P0_BASE_ADDR