diff options
author | Zhou Jingyu <b02241@freescale.com> | 2009-09-24 16:30:13 +0800 |
---|---|---|
committer | Zhou Jingyu <b02241@freescale.com> | 2009-09-25 11:07:12 +0800 |
commit | b65c630ab48da66103b3458fae6c1f2de3c5be63 (patch) | |
tree | db964d4c3da1f84217a4a4d7b889c21bb97e3762 | |
parent | 4a9f71207f841630756caf3c19f2fa1509d1abf7 (diff) |
ENGR00115040 imx233: reduce stanby power below 2mA@3.7v
reduce stanby power to 2mA@3.7v
Signed-off-by: Zhou Jingyu <Jingyu.Zhou@freescale.com>
-rw-r--r-- | arch/arm/mach-stmp3xxx/clock.c | 17 | ||||
-rw-r--r-- | arch/arm/mach-stmp3xxx/core.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-stmp3xxx/pm.c | 157 |
3 files changed, 172 insertions, 4 deletions
diff --git a/arch/arm/mach-stmp3xxx/clock.c b/arch/arm/mach-stmp3xxx/clock.c index dd21105abbb7..feed28bcc40d 100644 --- a/arch/arm/mach-stmp3xxx/clock.c +++ b/arch/arm/mach-stmp3xxx/clock.c @@ -1319,6 +1319,22 @@ struct clk *clk_get_parent(struct clk *clk) } EXPORT_SYMBOL(clk_get_parent); +static void clkctrl_enable_powersavings(void) +{ + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_APBHDMA_AS_ENABLE); + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_APBXDMA_AS_ENABLE); + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_TRAFFIC_AS_ENABLE); + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_TRAFFIC_JAM_AS_ENABLE); + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_CPU_DATA_AS_ENABLE); + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_CPU_INSTR_AS_ENABLE); + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_DCP_AS_ENABLE); + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_PXP_AS_ENABLE); + + HW_CLKCTRL_HBUS_SET(BF_CLKCTRL_HBUS_SLOW_DIV( + BV_CLKCTRL_HBUS_SLOW_DIV__BY32)); + HW_CLKCTRL_HBUS_SET(BM_CLKCTRL_HBUS_AUTO_SLOW_MODE); +} + static int __init clk_init(void) { struct clk **clkp; @@ -1351,6 +1367,7 @@ static int __init clk_init(void) pr_debug("%s: clock %s, rate %d\n", __func__, (*clkp)->name, (*clkp)->rate); } + clkctrl_enable_powersavings(); return 0; } diff --git a/arch/arm/mach-stmp3xxx/core.c b/arch/arm/mach-stmp3xxx/core.c index 3c92cd10e54c..cfe68dec9c9a 100644 --- a/arch/arm/mach-stmp3xxx/core.c +++ b/arch/arm/mach-stmp3xxx/core.c @@ -140,8 +140,6 @@ static void stmp3xxx_machine_restart(char mode) void __init stmp3xxx_init(void) { - /* Turn off auto-slow and other tricks */ - HW_CLKCTRL_HBUS_CLR(0x07f00000U); /* Re-route machine restart to our own handler */ arm_pm_restart = stmp3xxx_machine_restart; diff --git a/arch/arm/mach-stmp3xxx/pm.c b/arch/arm/mach-stmp3xxx/pm.c index 522668530307..804431a251ab 100644 --- a/arch/arm/mach-stmp3xxx/pm.c +++ b/arch/arm/mach-stmp3xxx/pm.c @@ -36,6 +36,15 @@ #include <mach/regs-clkctrl.h> #include <mach/regs-pinctrl.h> #include <mach/regs-power.h> +#include <mach/regs-gpmi.h> +#include <mach/regs-pwm.h> +#include <mach/regs-usbctrl.h> +#include <mach/regs-apbh.h> +#include <mach/regs-apbx.h> +#include <mach/regs-rtc.h> +#include <mach/regs-dram.h> +#include <mach/regs-emi.h> +#include <mach/regs-digctl.h> #include "clock.h" #include "sleep.h" @@ -44,6 +53,129 @@ static void *saved_sram; static int saved_sleep_state; +#define WAIT_DC_OK_CYCLES 24000 +#define WAIT_CYCLE(n) for (i = 0; i < n; i++); +#define LOWER_VDDIO 10 +#define LOWER_VDDA 9 +#define LOWER_VDDD 0xa +#define MAX_POWEROFF_CODE_SIZE (6 * 1024) + +static void stmp378x_standby(void) +{ + int i; + u32 reg_vddd, reg_vdda, reg_vddio; + + /* DDR EnterSelfrefreshMode */ + HW_DRAM_CTL08_SET(BM_DRAM_CTL08_SREFRESH); + + /* Gating EMI CLock */ + HW_CLKCTRL_EMI_SET(BM_CLKCTRL_EMI_CLKGATE); + + /* Disable PLL */ + HW_CLKCTRL_PLLCTRL0_CLR(BM_CLKCTRL_PLLCTRL0_POWER); + + /* Reduce the VDDIO (3.050 volt) */ + reg_vddio = HW_POWER_VDDIOCTRL_RD(); + HW_POWER_VDDIOCTRL_WR(HW_POWER_VDDIOCTRL_RD() | + BM_POWER_VDDIOCTRL_BO_OFFSET); + HW_POWER_VDDIOCTRL_WR( + (HW_POWER_VDDIOCTRL_RD() & + ~BM_POWER_VDDIOCTRL_TRG)|LOWER_VDDIO); + WAIT_CYCLE(WAIT_DC_OK_CYCLES) + + while (!(HW_POWER_STS_RD() & BM_POWER_STS_DC_OK)) + ; + + /* Reduce VDDA 1.725volt */ + reg_vdda = HW_POWER_VDDACTRL_RD(); + HW_POWER_VDDACTRL_WR(HW_POWER_VDDACTRL_RD() | + BM_POWER_VDDACTRL_BO_OFFSET); + HW_POWER_VDDACTRL_WR((HW_POWER_VDDACTRL_RD() & + ~BM_POWER_VDDACTRL_TRG) | LOWER_VDDA); + WAIT_CYCLE(WAIT_DC_OK_CYCLES) + + /* wait for DC_OK */ + while (!(HW_POWER_STS_RD() & BM_POWER_STS_DC_OK)) + ; + + /* Reduce VDDD 1.000 volt */ + reg_vddd = HW_POWER_VDDDCTRL_RD(); + HW_POWER_VDDDCTRL_WR(HW_POWER_VDDDCTRL_RD() | + BM_POWER_VDDDCTRL_BO_OFFSET); + HW_POWER_VDDDCTRL_WR((HW_POWER_VDDDCTRL_RD() & + ~BM_POWER_VDDDCTRL_TRG) | LOWER_VDDD); + + WAIT_CYCLE(WAIT_DC_OK_CYCLES) + + while (!(HW_POWER_STS_RD() & BM_POWER_STS_DC_OK)) + ; + + /* optimize the DCDC loop gain */ + HW_POWER_LOOPCTRL_WR((HW_POWER_LOOPCTRL_RD() & + ~BM_POWER_LOOPCTRL_EN_RCSCALE)); + HW_POWER_LOOPCTRL_WR((HW_POWER_LOOPCTRL_RD() & + ~BM_POWER_LOOPCTRL_DC_R) | + (2<<BP_POWER_LOOPCTRL_DC_R)); + + /* half the fets */ + HW_POWER_MINPWR_SET(BM_POWER_MINPWR_HALF_FETS); + + HW_POWER_LOOPCTRL_CLR(BM_POWER_LOOPCTRL_CM_HYST_THRESH); + HW_POWER_LOOPCTRL_CLR(BM_POWER_LOOPCTRL_EN_CM_HYST); + HW_POWER_LOOPCTRL_CLR(BM_POWER_LOOPCTRL_EN_DF_HYST); + /* enable PFM */ + HW_POWER_LOOPCTRL_SET(BM_POWER_LOOPCTRL_HYST_SIGN); + HW_POWER_MINPWR_SET(BM_POWER_MINPWR_EN_DC_PFM); + + HW_CLKCTRL_CPU_SET(BM_CLKCTRL_CPU_INTERRUPT_WAIT); + /* Power off ... */ + asm("mcr p15, 0, r2, c7, c0, 4"); + HW_CLKCTRL_CPU_CLR(BM_CLKCTRL_CPU_INTERRUPT_WAIT); + + /* restore the DCDC parameter */ + + HW_POWER_MINPWR_CLR(BM_POWER_MINPWR_EN_DC_PFM); + HW_POWER_LOOPCTRL_CLR(BM_POWER_LOOPCTRL_HYST_SIGN); + HW_POWER_LOOPCTRL_SET(BM_POWER_LOOPCTRL_EN_DF_HYST); + HW_POWER_LOOPCTRL_SET(BM_POWER_LOOPCTRL_EN_CM_HYST); + HW_POWER_LOOPCTRL_SET(BM_POWER_LOOPCTRL_CM_HYST_THRESH); + + HW_POWER_LOOPCTRL_WR((HW_POWER_LOOPCTRL_RD() & + ~BM_POWER_LOOPCTRL_DC_R) | + (2<<BP_POWER_LOOPCTRL_DC_R)); + HW_POWER_LOOPCTRL_WR((HW_POWER_LOOPCTRL_RD() & + ~BM_POWER_LOOPCTRL_EN_RCSCALE) | + (3 << BP_POWER_LOOPCTRL_EN_RCSCALE)); + + + /* Restore VDDD */ + HW_POWER_VDDDCTRL_WR(reg_vddd); + + WAIT_CYCLE(WAIT_DC_OK_CYCLES) + while (!(HW_POWER_STS_RD() & BM_POWER_STS_DC_OK)) + ; + + HW_POWER_VDDACTRL_WR(reg_vdda); + WAIT_CYCLE(WAIT_DC_OK_CYCLES) + while (!(HW_POWER_STS_RD() & BM_POWER_STS_DC_OK)) + ; + + HW_POWER_VDDIOCTRL_WR(reg_vddio); + WAIT_CYCLE(WAIT_DC_OK_CYCLES) + while (!(HW_POWER_STS_RD() & BM_POWER_STS_DC_OK)) + ; + + + /* Enable PLL */ + HW_CLKCTRL_PLLCTRL0_SET(BM_CLKCTRL_PLLCTRL0_POWER); + /* Ungating EMI CLock */ + HW_CLKCTRL_EMI_CLR(BM_CLKCTRL_EMI_CLKGATE); + + /* LeaveSelfrefreshMode */ + HW_DRAM_CTL08_CLR(BM_DRAM_CTL08_SREFRESH); + WAIT_CYCLE(WAIT_DC_OK_CYCLES) +} + static inline void do_standby(void) { void (*stmp37xx_cpu_standby_ptr) (void); @@ -55,6 +187,7 @@ static inline void do_standby(void) int cpu_rate = 0; int hbus_rate = 0; int i, pending_irq; + u32 reg_clkctrl_clkseq, reg_clkctrl_xtal; /* * 1) switch clock domains from PLL to 24MHz @@ -72,8 +205,8 @@ static inline void do_standby(void) flush_cache_all(); /* copy suspend function into SRAM */ - memcpy((void *)STMP3XXX_OCRAM_VA_BASE, stmp37xx_cpu_standby, - stmp_standby_alloc_sz); + memcpy((void *)STMP3XXX_OCRAM_VA_BASE, (void*)stmp378x_standby, + MAX_POWEROFF_CODE_SIZE); /* now switch the CPU to ref_xtal */ cpu_clk = clk_get(NULL, "cpu"); @@ -110,10 +243,30 @@ static inline void do_standby(void) /* Barrier */ (void) HW_ICOLL_STAT_RD(); } + + reg_clkctrl_clkseq = HW_CLKCTRL_CLKSEQ_RD(); + + HW_CLKCTRL_CLKSEQ_SET(BM_CLKCTRL_CLKSEQ_BYPASS_ETM | + BM_CLKCTRL_CLKSEQ_BYPASS_SSP | + BM_CLKCTRL_CLKSEQ_BYPASS_GPMI | + BM_CLKCTRL_CLKSEQ_BYPASS_IR | + BM_CLKCTRL_CLKSEQ_BYPASS_PIX| + BM_CLKCTRL_CLKSEQ_BYPASS_SAIF); + + reg_clkctrl_xtal = HW_CLKCTRL_XTAL_RD(); + + HW_CLKCTRL_XTAL_SET(BM_CLKCTRL_XTAL_FILT_CLK24M_GATE | + BM_CLKCTRL_XTAL_PWM_CLK24M_GATE | + BM_CLKCTRL_XTAL_DRI_CLK24M_GATE); + /* do suspend */ stmp37xx_cpu_standby_ptr = (void *)STMP3XXX_OCRAM_VA_BASE; + stmp37xx_cpu_standby_ptr(); + HW_CLKCTRL_CLKSEQ_WR(reg_clkctrl_clkseq); + HW_CLKCTRL_XTAL_WR(reg_clkctrl_xtal); + pr_info("wakeup irq source = %d\n", HW_ICOLL_STAT_RD()); saved_sleep_state = 0; /* waking from standby */ HW_POWER_CTRL_CLR(BM_POWER_CTRL_PSWITCH_IRQ); |