@@ -76,6 +76,7 @@
#define OMAP3430ES2_CM_CLKEN2 0x0004
#define OMAP3430ES2_CM_FCLKEN3 0x0008
#define OMAP3430_CM_IDLEST_PLL CM_IDLEST2
+#define OMAP3430_CM_IDLEST3 0x0028
#define OMAP3430_CM_AUTOIDLE_PLL CM_AUTOIDLE2
#define OMAP3430ES2_CM_AUTOIDLE2_PLL CM_AUTOIDLE2
#define OMAP3430_CM_CLKSEL1 CM_CLKSEL
@@ -64,6 +64,28 @@ u32 sleep_while_idle;
u32 wakeup_timer_seconds;
u32 voltage_off_while_idle;
+/* IDLEST bitmasks for core status checks */
+#define CORE_IDLEST1_ALL (\
+ OMAP3430ES2_ST_MMC3_MASK|OMAP3430_ST_ICR_MASK|\
+ OMAP3430_ST_AES2_MASK|OMAP3430_ST_SHA12_MASK|\
+ OMAP3430_ST_DES2_MASK|OMAP3430_ST_MMC2_MASK|\
+ OMAP3430_ST_MMC1_MASK|OMAP3430_ST_MSPRO_MASK|\
+ OMAP3430_ST_HDQ_MASK|OMAP3430_ST_MCSPI4_MASK|\
+ OMAP3430_ST_MCSPI3_MASK|OMAP3430_ST_MCSPI2_MASK|\
+ OMAP3430_ST_MCSPI1_MASK|OMAP3430_ST_I2C3_MASK|\
+ OMAP3430_ST_I2C2_MASK|OMAP3430_ST_I2C1_MASK|\
+ OMAP3430_ST_GPT11_MASK|OMAP3430_ST_GPT10_MASK|\
+ OMAP3430_ST_MCBSP5_MASK|OMAP3430_ST_MCBSP1_MASK|\
+ OMAP3430ES2_ST_HSOTGUSB_STDBY_MASK|\
+ OMAP3430ES2_ST_SSI_IDLE_MASK|OMAP3430_ST_SDMA_MASK|\
+ OMAP3430_ST_SSI_STDBY_MASK|OMAP3430_ST_D2D_MASK)
+#define CORE_IDLEST2_ALL (\
+ OMAP3430_ST_PKA_MASK|OMAP3430_ST_AES1_MASK|\
+ OMAP3430_ST_RNG_MASK|OMAP3430_ST_SHA11_MASK|\
+ OMAP3430_ST_DES1_MASK)
+#define CORE_IDLEST3_ALL (\
+ OMAP3430ES2_ST_USBTLL_MASK|OMAP3430ES2_ST_CPEFUSE_MASK)
+
struct power_state {
struct powerdomain *pwrdm;
u32 next_state;
@@ -408,6 +430,7 @@ void omap_sram_idle(void)
int core_prev_state, per_prev_state;
u32 sdrc_pwr = 0;
int per_state_modified = 0;
+ int core_saved_state = PWRDM_POWER_ON;
if (!_omap_sram_idle)
return;
@@ -439,9 +462,28 @@ void omap_sram_idle(void)
if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state);
+ /*
+ * Check whether core will enter idle or not. This is needed
+ * because I/O pad wakeup will fail if core stays on and PER
+ * enters off. This will also prevent unnecessary core context
+ * save / restore.
+ */
+ core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
+ if (core_next_state < PWRDM_POWER_ON) {
+ core_saved_state = core_next_state;
+ if ((cm_read_mod_reg(CORE_MOD, CM_IDLEST1) & CORE_IDLEST1_ALL)
+ != CORE_IDLEST1_ALL ||
+ (cm_read_mod_reg(CORE_MOD, CM_IDLEST2) & CORE_IDLEST2_ALL)
+ != CORE_IDLEST2_ALL ||
+ (cm_read_mod_reg(CORE_MOD, OMAP3430_CM_IDLEST3) &
+ CORE_IDLEST3_ALL) != CORE_IDLEST3_ALL) {
+ core_next_state = PWRDM_POWER_ON;
+ pwrdm_set_next_pwrst(core_pwrdm, PWRDM_POWER_ON);
+ }
+ }
+
/* PER */
per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
- core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
if (per_next_state < PWRDM_POWER_ON) {
omap_uart_prepare_idle(2);
omap2_gpio_prepare_for_idle(per_next_state);
@@ -539,6 +581,8 @@ void omap_sram_idle(void)
enable_smartreflex(SR1);
enable_smartreflex(SR2);
}
+ if (core_saved_state != core_next_state)
+ pwrdm_set_next_pwrst(core_pwrdm, core_saved_state);
/* PER */
if (per_next_state < PWRDM_POWER_ON) {