diff mbox

[02/17] OMAP3: PM: Dynamic check for CORE target state

Message ID 1255690150-16853-3-git-send-email-tero.kristo@nokia.com (mailing list archive)
State Superseded
Delegated to: Kevin Hilman
Headers show

Commit Message

Tero Kristo Oct. 16, 2009, 10:48 a.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h
index a2fcfcc..715ab14 100644
--- a/arch/arm/mach-omap2/cm.h
+++ b/arch/arm/mach-omap2/cm.h
@@ -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
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 5e2ef63..e8704a6 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -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) {