diff options
-rw-r--r-- | arch/arm/mach-omap2/pm44xx.c | 61 |
1 files changed, 50 insertions, 11 deletions
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c index 837025bb6d2..9e50e1db8e5 100644 --- a/arch/arm/mach-omap2/pm44xx.c +++ b/arch/arm/mach-omap2/pm44xx.c @@ -105,10 +105,50 @@ static struct clockdomain *emif_clkdm, *mpuss_clkdm; */ #define OMAP4_PM_ERRATUM_MPU_EMIF_NO_DYNDEP_IDLE_iXXX BIT(4) +/* + * There is a HW bug in CMD PHY which gives ISO signals as same for both + * PADn and PADp on differential IO pad, because of which IO leaks higher + * as pull controls are differential internally and pull value does not + * match A value. + * Though there is no functionality impact due to this bug, it is seen + * that by disabling the pulls there is a savings ~500uA in OSWR, but draws + * ~300uA more during OFF mode. + * To save power during both idle/suspend following approach taken: + * 1) Enable WA during boot-up. + * 2) Disable WA while attempting suspend and enable during resume. + * + * CDDS no: OMAP4460-1.0BUG00291 (OMAP official errata ID yet to be available). + */ +#define OMAP4_PM_ERRATUM_LPDDR_CLK_IO_iXXX BIT(5) +#define LPDDR_WD_PULL_DOWN 0x02 + u8 pm44xx_errata; #define is_pm44xx_erratum(erratum) (pm44xx_errata & OMAP4_PM_ERRATUM_##erratum) #define MAX_IOPAD_LATCH_TIME 1000 + +void syscontrol_lpddr_clk_io_errata(bool enable) +{ + u32 v = 0; + + if (!is_pm44xx_erratum(LPDDR_CLK_IO_iXXX)) + return; + + v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2); + if (enable) + v &= ~OMAP4_LPDDR2IO1_GR10_WD_MASK; + else + v |= LPDDR_WD_PULL_DOWN << OMAP4_LPDDR2IO1_GR10_WD_SHIFT; + omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2); + + v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2); + if (enable) + v &= ~OMAP4_LPDDR2IO2_GR10_WD_MASK; + else + v |= LPDDR_WD_PULL_DOWN << OMAP4_LPDDR2IO1_GR10_WD_SHIFT; + omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2); +} + void omap4_trigger_ioctrl(void) { int i = 0; @@ -258,8 +298,14 @@ void omap4_enter_sleep(unsigned int cpu, unsigned int power_state, bool suspend) OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_IO_PMCTRL_OFFSET); } + if (suspend) + syscontrol_lpddr_clk_io_errata(false); + omap4_enter_lowpower(cpu, power_state); + if (suspend) + syscontrol_lpddr_clk_io_errata(true); + if (omap4_device_prev_state_off()) { /* Reconfigure the trim settings as well */ omap4_ldo_trim_configure(); @@ -946,16 +992,7 @@ static void __init syscontrol_setup_regs(void) v |= OMAP4_LPDDR21_VREF_AUTO_EN_CA_MASK | OMAP4_LPDDR21_VREF_AUTO_EN_DQ_MASK; omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_3); - /* - * Workaround for CK differential IO PADn, PADp values due to bug in - * EMIF CMD phy. - */ - v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2); - v &= ~OMAP4_LPDDR2IO1_GR10_WD_MASK; - omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO1_2); - v = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2); - v &= ~OMAP4_LPDDR2IO2_GR10_WD_MASK; - omap4_ctrl_pad_writel(v, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_LPDDR2IO2_2); + syscontrol_lpddr_clk_io_errata(true); } static void __init prcm_setup_regs(void) @@ -1265,7 +1302,9 @@ static void __init omap4_pm_setup_errata(void) */ if (cpu_is_omap44xx()) pm44xx_errata |= OMAP4_PM_ERRATUM_IVA_AUTO_RET_iXXX | - OMAP4_PM_ERRATUM_HSI_SWAKEUP_iXXX; + OMAP4_PM_ERRATUM_HSI_SWAKEUP_iXXX | + OMAP4_PM_ERRATUM_LPDDR_CLK_IO_iXXX; + /* Dynamic Dependency errata for all silicon !=443x */ if (cpu_is_omap443x()) pm44xx_errata |= OMAP4_PM_ERRATUM_MPU_EMIF_NO_DYNDEP_i688; |