From f0eefda5f4eefaf36417d6260add5fe068f391b7 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 21 Oct 2011 10:48:56 +0800 Subject: [PATCH] ENGR00160513 [MX6Q]Lower SOC power in dormant Add necessary implement to lower the SOC power when dormant, on ddr3, ARM+SOC is ~3.8mA, and on LPDDR2, it is ~2.3mA. Signed-off-by: Anson Huang --- arch/arm/mach-mx6/crm_regs.h | 2 +- arch/arm/mach-mx6/pm.c | 20 +++++++++++++++-- arch/arm/mach-mx6/system.c | 42 ++++++++++++++++++++++++++---------- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/arch/arm/mach-mx6/crm_regs.h b/arch/arm/mach-mx6/crm_regs.h index 03ef76648453..273e8d238caa 100644 --- a/arch/arm/mach-mx6/crm_regs.h +++ b/arch/arm/mach-mx6/crm_regs.h @@ -409,7 +409,7 @@ #define MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS (1 << 21) #define MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS (1 << 19) #define MXC_CCM_CLPCR_WB_CORE_AT_LPM (1 << 17) -#define MXC_CCM_CLPCR_WB_PER_AT_LPM (1 << 17) +#define MXC_CCM_CLPCR_WB_PER_AT_LPM (1 << 16) #define MXC_CCM_CLPCR_COSC_PWRDOWN (1 << 11) #define MXC_CCM_CLPCR_STBY_COUNT_MASK (0x3 << 9) #define MXC_CCM_CLPCR_STBY_COUNT_OFFSET (9) diff --git a/arch/arm/mach-mx6/pm.c b/arch/arm/mach-mx6/pm.c index 2d36c4bffbb9..a93963b566d1 100644 --- a/arch/arm/mach-mx6/pm.c +++ b/arch/arm/mach-mx6/pm.c @@ -46,6 +46,7 @@ #define GPC_ISR2_OFFSET 0x1c #define GPC_ISR3_OFFSET 0x20 #define GPC_ISR4_OFFSET 0x24 +#define GPC_PGC_GPU_PGCR_OFFSET 0x260 #define GPC_PGC_CPU_PDN_OFFSET 0x2a0 #define GPC_PGC_CPU_PUPSCR_OFFSET 0x2a4 #define GPC_PGC_CPU_PDNSCR_OFFSET 0x2a8 @@ -57,6 +58,9 @@ #define LOCAL_TWD_COUNT_OFFSET 0x4 #define LOCAL_TWD_CONTROL_OFFSET 0x8 #define LOCAL_TWD_INT_OFFSET 0xc +#define ANATOP_REG_2P5_OFFSET 0x130 +#define ANATOP_REG_CORE_OFFSET 0x140 + static struct clk *cpu_clk; static struct pm_platform_data *pm_data; @@ -75,18 +79,22 @@ static void __iomem *src_base; static void __iomem *local_twd_base; static void __iomem *gic_dist_base; static void __iomem *gic_cpu_base; +static void __iomem *anatop_base; static void *suspend_iram_base; static void (*suspend_in_iram)(suspend_state_t state, unsigned long iram_paddr, unsigned long suspend_iram_base) = NULL; static unsigned long iram_paddr, cpaddr; -static u32 ccm_clpcr, scu_ctrl; -static u32 gpc_imr[4], gpc_cpu_pup, gpc_cpu_pdn, gpc_cpu; +static u32 ccm_ccr, ccm_clpcr, scu_ctrl; +static u32 gpc_imr[4], gpc_cpu_pup, gpc_cpu_pdn, gpc_cpu, gpc_gpu_pgcr; +static u32 anatop[2]; + static void mx6_suspend_store(void) { /* save some settings before suspend */ + ccm_ccr = __raw_readl(MXC_CCM_CCR); ccm_clpcr = __raw_readl(MXC_CCM_CLPCR); scu_ctrl = __raw_readl(scu_base + SCU_CTRL_OFFSET); gpc_imr[0] = __raw_readl(gpc_base + GPC_IMR1_OFFSET); @@ -96,11 +104,15 @@ static void mx6_suspend_store(void) gpc_cpu_pup = __raw_readl(gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET); gpc_cpu_pdn = __raw_readl(gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); gpc_cpu = __raw_readl(gpc_base + GPC_PGC_CPU_PDN_OFFSET); + gpc_gpu_pgcr = __raw_readl(gpc_base + GPC_PGC_GPU_PGCR_OFFSET); + anatop[0] = __raw_readl(anatop_base + ANATOP_REG_2P5_OFFSET); + anatop[1] = __raw_readl(anatop_base + ANATOP_REG_CORE_OFFSET); } static void mx6_suspend_restore(void) { /* restore settings after suspend */ + __raw_writel(ccm_ccr, MXC_CCM_CCR); __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); __raw_writel(scu_ctrl, scu_base + SCU_CTRL_OFFSET); __raw_writel(gpc_imr[0], gpc_base + GPC_IMR1_OFFSET); @@ -110,6 +122,9 @@ static void mx6_suspend_restore(void) __raw_writel(gpc_cpu_pup, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET); __raw_writel(gpc_cpu_pdn, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); __raw_writel(gpc_cpu, gpc_base + GPC_PGC_CPU_PDN_OFFSET); + __raw_writel(gpc_gpu_pgcr, gpc_base + GPC_PGC_GPU_PGCR_OFFSET); + __raw_writel(anatop[0], anatop_base + ANATOP_REG_2P5_OFFSET); + __raw_writel(anatop[1], anatop_base + ANATOP_REG_CORE_OFFSET); } static int mx6_suspend_enter(suspend_state_t state) @@ -239,6 +254,7 @@ static int __init pm_init(void) gic_dist_base = IO_ADDRESS(IC_DISTRIBUTOR_BASE_ADDR); gic_cpu_base = IO_ADDRESS(IC_INTERFACES_BASE_ADDR); local_twd_base = IO_ADDRESS(LOCAL_TWD_ADDR); + anatop_base = IO_ADDRESS(ANATOP_BASE_ADDR); pr_info("Static Power Management for Freescale i.MX6\n"); diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c index 243152e81695..db1dea5b74d1 100644 --- a/arch/arm/mach-mx6/system.c +++ b/arch/arm/mach-mx6/system.c @@ -28,22 +28,26 @@ #include #include "crm_regs.h" -#define SCU_CTRL 0x00 -#define SCU_CONFIG 0x04 -#define SCU_CPU_STATUS 0x08 -#define SCU_INVALIDATE 0x0c -#define SCU_FPGA_REVISION 0x10 -#define GPC_PGC_CPU_PDN_OFFSET 0x2a0 +#define SCU_CTRL 0x00 +#define SCU_CONFIG 0x04 +#define SCU_CPU_STATUS 0x08 +#define SCU_INVALIDATE 0x0c +#define SCU_FPGA_REVISION 0x10 +#define GPC_CNTR_OFFSET 0x0 +#define GPC_PGC_GPU_PGCR_OFFSET 0x260 +#define GPC_PGC_CPU_PDN_OFFSET 0x2a0 #define GPC_PGC_CPU_PUPSCR_OFFSET 0x2a4 #define GPC_PGC_CPU_PDNSCR_OFFSET 0x2a8 +#define ANATOP_REG_2P5_OFFSET 0x130 +#define ANATOP_REG_CORE_OFFSET 0x140 #define MODULE_CLKGATE (1 << 30) #define MODULE_SFTRST (1 << 31) -static DEFINE_SPINLOCK(wfi_lock); +/* static DEFINE_SPINLOCK(wfi_lock); */ extern unsigned int gpc_wake_irq[4]; -static unsigned int cpu_idle_mask; +/* static unsigned int cpu_idle_mask; */ static void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR); @@ -64,8 +68,10 @@ void gpc_set_wakeup(unsigned int irq[4]) /* set cpu low power mode before WFI instruction */ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) { - u32 ccm_clpcr; + int stop_mode = 0; + void __iomem *anatop_base = IO_ADDRESS(ANATOP_BASE_ADDR); + u32 ccm_clpcr, anatop_val; ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); @@ -116,8 +122,22 @@ void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); /* dormant mode, need to power off the arm core */ - if (stop_mode == 2) - __raw_writel(0x1, gpc_base + GPC_PGC_CPU_PDN_OFFSET); + if (stop_mode == 2) { + __raw_writel(0x1, gpc_base + GPC_PGC_CPU_PDN_OFFSET); + __raw_writel(0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET); + __raw_writel(0x1, gpc_base + GPC_CNTR_OFFSET); + /* Enable weak 2P5 linear regulator */ + anatop_val = __raw_readl(anatop_base + ANATOP_REG_2P5_OFFSET); + anatop_val |= 1 << 18; + __raw_writel(anatop_val, anatop_base + ANATOP_REG_2P5_OFFSET); + /* Set ARM core power domain to 1V and PU domain set to off */ + anatop_val = __raw_readl(anatop_base + ANATOP_REG_CORE_OFFSET); + anatop_val &= 0xfffc0000; + anatop_val |= 0xc; + __raw_writel(anatop_val, anatop_base + ANATOP_REG_CORE_OFFSET); + __raw_writel(__raw_readl(MXC_CCM_CCR) | MXC_CCM_CCR_RBC_EN, MXC_CCM_CCR); + ccm_clpcr |= MXC_CCM_CLPCR_WB_PER_AT_LPM; + } } __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); } -- 2.39.5