diff options
author | Anson Huang <b20788@freescale.com> | 2014-06-13 14:35:24 +0800 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-08-27 18:28:57 -0500 |
commit | 7beced60440f90e8949f826ce323e6adc02742d8 (patch) | |
tree | 2eee68f9015efc93c5a778ce81d5625372efb580 | |
parent | 0ab7b6489d0dc253cd5c4b8b8a00d8e3f13fb34a (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.txt | 6 | ||||
-rw-r--r-- | arch/arm/mach-imx/gpc.c | 37 | ||||
-rw-r--r-- | arch/arm/mach-imx/suspend-imx6.S | 247 |
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 |