Skip to contentSkip to conversation

per/neon and core handling in idle

PATCH In review Rajendra Nayak 2 participants 4 messages Jul 1, 2008 – Jul 2, 2008

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 2/11 per/neon and core handling in idle

This patches adds handling of PER/NEON and CORE domain in idle.

---
 arch/arm/mach-omap2/cpuidle34xx.c |   98 +++++++++++++++++++++++++++++++-------
 arch/arm/mach-omap2/cpuidle34xx.h |    6 +-
 arch/arm/mach-omap2/pm34xx.c      |   58 ++++++++++++++--------
 3 files changed, 121 insertions(+), 41 deletions(-)
arch/arm/mach-omap2/cpuidle34xx.c +80 -18
Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.c
===================================================================
@@ -26,6 +26,8 @@
 #include <asm/arch/pm.h>
 #include <asm/arch/prcm.h>
 #include <asm/arch/powerdomain.h>
+#include <asm/arch/clockdomain.h>
+#include <asm/arch/gpio.h>
 #include "cpuidle34xx.h"
 
 #ifdef CONFIG_CPU_IDLE
@@ -35,6 +37,8 @@ struct omap3_processor_cx current_cx_sta
 
 static int omap3_idle_bm_check(void)
 {
+	if (!omap3_can_sleep())
+		return 1;
 	return 0;
 }
 
@@ -46,34 +50,86 @@ static int omap3_enter_idle(struct cpuid
 {
 	struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
-	struct powerdomain *mpu_pd;
+	struct powerdomain *mpu_pd, *core_pd, *per_pd, *neon_pd;
+	int per_pwrst, neon_pwrst;
 
 	current_cx_state = *cx;
 
-	/* Used to keep track of the total time in idle */
-	getnstimeofday(&ts_preidle);
-
-
 	if (cx->type == OMAP3_STATE_C0) {
 		/* Do nothing for C0, not even a wfi */
 		return 0;
 	}
 
+	/* Used to keep track of the total time in idle */
+	getnstimeofday(&ts_preidle);
+
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
+	core_pd = pwrdm_lookup("core_pwrdm");
+	per_pd = pwrdm_lookup("per_pwrdm");
+	neon_pd = pwrdm_lookup("neon_pwrdm");
+
+	/* Reset previous power state registers */
+	pwrdm_clear_all_prev_pwrst(mpu_pd);
+	pwrdm_clear_all_prev_pwrst(neon_pd);
+	pwrdm_clear_all_prev_pwrst(core_pd);
+	pwrdm_clear_all_prev_pwrst(per_pd);
+
+	if (omap_irq_pending())
+		return 0;
+
+	per_pwrst = pwrdm_read_pwrst(per_pd);
+	neon_pwrst = pwrdm_read_pwrst(neon_pd);
+
 	/* Program MPU to target state */
-	if (cx->mpu_state < PWRDM_POWER_ON)
+	if (cx->mpu_state < PWRDM_POWER_ON) {
+		if (neon_pwrst == PWRDM_POWER_ON)
+			pwrdm_set_next_pwrst(neon_pd, PWRDM_POWER_RET);
 		pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
+	}
+
+	/* Program CORE and PER to target state */
+	if (cx->core_state < PWRDM_POWER_ON) {
+		if (per_pwrst == PWRDM_POWER_ON) {
+			omap2_gpio_prepare_for_retention();
+			if (clocks_off_while_idle) {
+				per_gpio_clk_disable();
+				omap_serial_enable_clocks(0);
+			}
+		}
+		pwrdm_set_next_pwrst(core_pd, cx->core_state);
+	}
 
 	/* Execute ARM wfi */
 	omap_sram_idle();
 
-	/* Program MPU to ON */
-	if (cx->mpu_state < PWRDM_POWER_ON)
+	/* Program MPU/NEON to ON */
+	if (cx->mpu_state < PWRDM_POWER_ON) {
+		if (neon_pwrst == PWRDM_POWER_ON)
+			pwrdm_set_next_pwrst(neon_pd, PWRDM_POWER_ON);
 		pwrdm_set_next_pwrst(mpu_pd, PWRDM_POWER_ON);
+	}
+
+	if (cx->core_state < PWRDM_POWER_ON) {
+		if (per_pwrst == PWRDM_POWER_ON) {
+			if (clocks_off_while_idle) {
+				omap_serial_enable_clocks(1);
+				per_gpio_clk_enable();
+			}
+			omap2_gpio_resume_after_retention();
+		}
+		pwrdm_set_next_pwrst(core_pd, PWRDM_POWER_ON);
+	}
+
+	pr_debug("MPU prev st:%x,NEON prev st:%x\n",
+			       pwrdm_read_prev_pwrst(mpu_pd),
+			       pwrdm_read_prev_pwrst(neon_pd));
+	pr_debug("PER prev st:%x,CORE prev st:%x\n",
+			       pwrdm_read_prev_pwrst(per_pd),
+			       pwrdm_read_prev_pwrst(core_pd));
 
 	getnstimeofday(&ts_postidle);
 	ts_idle = timespec_sub(ts_postidle, ts_preidle);
-	return timespec_to_ns(&ts_idle);
+	return (u32)timespec_to_ns(&ts_idle)/1000;
 }
 
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
@@ -130,7 +186,7 @@ void omap_init_power_states(void)
 	omap3_power_states[0].threshold = 0;
 	omap3_power_states[0].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[0].core_state = PWRDM_POWER_ON;
-	omap3_power_states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[0].flags = CPUIDLE_FLAG_SHALLOW;
 
 	/* C1 . MPU WFI + Core active */
 	omap3_power_states[1].valid = 1;
@@ -140,7 +196,8 @@ void omap_init_power_states(void)
 	omap3_power_states[1].threshold = 30;
 	omap3_power_states[1].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[1].core_state = PWRDM_POWER_ON;
-	omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID |
+						CPUIDLE_FLAG_SHALLOW;
 
 	/* C2 . MPU CSWR + Core active */
 	omap3_power_states[2].valid = 1;
@@ -150,7 +207,8 @@ void omap_init_power_states(void)
 	omap3_power_states[2].threshold = 300;
 	omap3_power_states[2].mpu_state = PWRDM_POWER_RET;
 	omap3_power_states[2].core_state = PWRDM_POWER_ON;
-	omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID |
+						CPUIDLE_FLAG_BALANCED;
 
 	/* C3 . MPU OFF + Core active */
 	omap3_power_states[3].valid = 0;
@@ -159,18 +217,20 @@ void omap_init_power_states(void)
 	omap3_power_states[3].wakeup_latency = 1800;
 	omap3_power_states[3].threshold = 4000;
 	omap3_power_states[3].mpu_state = PWRDM_POWER_OFF;
-	omap3_power_states[3].core_state = PWRDM_POWER_RET;
-	omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[3].core_state = PWRDM_POWER_ON;
+	omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C4 . MPU CSWR + Core CSWR*/
-	omap3_power_states[4].valid = 0;
+	omap3_power_states[4].valid = 1;
 	omap3_power_states[4].type = OMAP3_STATE_C4;
 	omap3_power_states[4].sleep_latency = 2500;
 	omap3_power_states[4].wakeup_latency = 7500;
 	omap3_power_states[4].threshold = 12000;
 	omap3_power_states[4].mpu_state = PWRDM_POWER_RET;
 	omap3_power_states[4].core_state = PWRDM_POWER_RET;
-	omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C5 . MPU OFF + Core CSWR */
 	omap3_power_states[5].valid = 0;
@@ -180,7 +240,8 @@ void omap_init_power_states(void)
 	omap3_power_states[5].threshold = 15000;
 	omap3_power_states[5].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[5].core_state = PWRDM_POWER_RET;
-	omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C6 . MPU OFF + Core OFF */
 	omap3_power_states[6].valid = 0;
@@ -190,7 +251,8 @@ void omap_init_power_states(void)
 	omap3_power_states[6].threshold = 300000;
 	omap3_power_states[6].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[6].core_state = PWRDM_POWER_OFF;
-	omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_CHECK_BM;
 }
 
 struct cpuidle_driver omap3_idle_driver = {
arch/arm/mach-omap2/cpuidle34xx.h +4 -2
Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.h
===================================================================
@@ -33,11 +33,13 @@
 /* Currently, we support only upto C2 */
 #define MAX_SUPPORTED_STATES 3
 
+extern unsigned short clocks_off_while_idle;
 extern void omap_sram_idle(void);
-extern int omap3_irq_pending(void);
+extern int omap_irq_pending(void);
 extern void per_gpio_clk_enable(void);
 extern void per_gpio_clk_disable(void);
-
+extern void omap_serial_enable_clocks(int enable);
+extern int omap3_can_sleep();
 struct omap3_processor_cx {
 	u8 valid;
 	u8 type;
arch/arm/mach-omap2/pm34xx.c +37 -21

99 lines not on this page · raw message

#1 lore raw
Quoted 78 lines · ext Rajendra Nayak

This patches adds handling of PER/NEON and CORE domain in idle.

---
 arch/arm/mach-omap2/cpuidle34xx.c |   98 +++++++++++++++++++++++++++++++-------
 arch/arm/mach-omap2/cpuidle34xx.h |    6 +-
 arch/arm/mach-omap2/pm34xx.c      |   58 ++++++++++++++--------
 3 files changed, 121 insertions(+), 41 deletions(-)

Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.c
===================================================================

arch/arm/mach-omap2/cpuidle34xx.c +29 -6
@@ -26,6 +26,8 @@
 #include <asm/arch/pm.h>
 #include <asm/arch/prcm.h>
 #include <asm/arch/powerdomain.h>
+#include <asm/arch/clockdomain.h>
+#include <asm/arch/gpio.h>
 #include "cpuidle34xx.h"
 
 #ifdef CONFIG_CPU_IDLE
@@ -35,6 +37,8 @@ struct omap3_processor_cx current_cx_sta
 
 static int omap3_idle_bm_check(void)
 {
+	if (!omap3_can_sleep())
+		return 1;
 	return 0;
 }
 
@@ -46,34 +50,86 @@ static int omap3_enter_idle(struct cpuid
 {
 	struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
-	struct powerdomain *mpu_pd;
+	struct powerdomain *mpu_pd, *core_pd, *per_pd, *neon_pd;
+	int per_pwrst, neon_pwrst;
 
 	current_cx_state = *cx;
 
-	/* Used to keep track of the total time in idle */
-	getnstimeofday(&ts_preidle);
-
-
 	if (cx->type == OMAP3_STATE_C0) {
 		/* Do nothing for C0, not even a wfi */
 		return 0;
 	}
 
+	/* Used to keep track of the total time in idle */
+	getnstimeofday(&ts_preidle);
+
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
+	core_pd = pwrdm_lookup("core_pwrdm");
+	per_pd = pwrdm_lookup("per_pwrdm");
+	neon_pd = pwrdm_lookup("neon_pwrdm");
+
+	/* Reset previous power state registers */
+	pwrdm_clear_all_prev_pwrst(mpu_pd);
+	pwrdm_clear_all_prev_pwrst(neon_pd);
+	pwrdm_clear_all_prev_pwrst(core_pd);
+	pwrdm_clear_all_prev_pwrst(per_pd);
+
+	if (omap_irq_pending())
+		return 0;
+
+	per_pwrst = pwrdm_read_pwrst(per_pd);
+	neon_pwrst = pwrdm_read_pwrst(neon_pd);
+
 	/* Program MPU to target state */
-	if (cx->mpu_state < PWRDM_POWER_ON)
+	if (cx->mpu_state < PWRDM_POWER_ON) {
+		if (neon_pwrst == PWRDM_POWER_ON)
+			pwrdm_set_next_pwrst(neon_pd, PWRDM_POWER_RET);
 		pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
+	}

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 98

Quoted 10 lines
arch/arm/mach-omap2/cpuidle34xx.c +10 -0
+
+	/* Program CORE and PER to target state */
+	if (cx->core_state < PWRDM_POWER_ON) {
+		if (per_pwrst == PWRDM_POWER_ON) {
+			omap2_gpio_prepare_for_retention();
+			if (clocks_off_while_idle) {
+				per_gpio_clk_disable();
+				omap_serial_enable_clocks(0);
+			}
+		}

Why this is here? Why per is not put to sleep state if core is not? Shouldn't you just disable gpio clocks in omap_sram_idle and if all clocks in per domain are cut off then per domain enters its sleep state. No matter what is the state of core domain.

Why per_pwrst is checked here? You know it is always on currently. It won't never be anything else until those things in this if block is done.

As the day comes when per_pwrst here is something else than PWRDM_POWER_ON then serial clocks in core domain are not disabled because disabling them are in that block.

Quoted 4 lines
arch/arm/mach-omap2/cpuidle34xx.c +2 -0
+		pwrdm_set_next_pwrst(core_pd, cx->core_state);
+	}
 
 	/* Execute ARM wfi */

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 110

Quoted 10 lines
arch/arm/mach-omap2/cpuidle34xx.c +5 -2
 	omap_sram_idle();
 
-	/* Program MPU to ON */
-	if (cx->mpu_state < PWRDM_POWER_ON)
+	/* Program MPU/NEON to ON */
+	if (cx->mpu_state < PWRDM_POWER_ON) {
+		if (neon_pwrst == PWRDM_POWER_ON)
+			pwrdm_set_next_pwrst(neon_pd, PWRDM_POWER_ON);
 		pwrdm_set_next_pwrst(mpu_pd, PWRDM_POWER_ON);
+	}

No need to do these as they are written anyway in the next round. MPU and NEON are not going to change their state in between.

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 118

Quoted 8 lines
arch/arm/mach-omap2/cpuidle34xx.c +8 -0
+
+	if (cx->core_state < PWRDM_POWER_ON) {
+		if (per_pwrst == PWRDM_POWER_ON) {
+			if (clocks_off_while_idle) {
+				omap_serial_enable_clocks(1);
+				per_gpio_clk_enable();
+			}
+			omap2_gpio_resume_after_retention();

Similiar comments as before omap_sram_idle() for this block.

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 120

Quoted 2 lines
arch/arm/mach-omap2/cpuidle34xx.c +2 -0
+		}
+		pwrdm_set_next_pwrst(core_pd, PWRDM_POWER_ON);

This can be also left to value before omap_sram_idle(), because it is anyway written again in next round.

Quoted 145 lines
arch/arm/mach-omap2/cpuidle34xx.c +24 -10
+	}
+
+	pr_debug("MPU prev st:%x,NEON prev st:%x\n",
+			       pwrdm_read_prev_pwrst(mpu_pd),
+			       pwrdm_read_prev_pwrst(neon_pd));
+	pr_debug("PER prev st:%x,CORE prev st:%x\n",
+			       pwrdm_read_prev_pwrst(per_pd),
+			       pwrdm_read_prev_pwrst(core_pd));
 
 	getnstimeofday(&ts_postidle);
 	ts_idle = timespec_sub(ts_postidle, ts_preidle);
-	return timespec_to_ns(&ts_idle);
+	return (u32)timespec_to_ns(&ts_idle)/1000;
 }
 
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
@@ -130,7 +186,7 @@ void omap_init_power_states(void)
 	omap3_power_states[0].threshold = 0;
 	omap3_power_states[0].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[0].core_state = PWRDM_POWER_ON;
-	omap3_power_states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[0].flags = CPUIDLE_FLAG_SHALLOW;
 
 	/* C1 . MPU WFI + Core active */
 	omap3_power_states[1].valid = 1;
@@ -140,7 +196,8 @@ void omap_init_power_states(void)
 	omap3_power_states[1].threshold = 30;
 	omap3_power_states[1].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[1].core_state = PWRDM_POWER_ON;
-	omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID |
+						CPUIDLE_FLAG_SHALLOW;
 
 	/* C2 . MPU CSWR + Core active */
 	omap3_power_states[2].valid = 1;
@@ -150,7 +207,8 @@ void omap_init_power_states(void)
 	omap3_power_states[2].threshold = 300;
 	omap3_power_states[2].mpu_state = PWRDM_POWER_RET;
 	omap3_power_states[2].core_state = PWRDM_POWER_ON;
-	omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID |
+						CPUIDLE_FLAG_BALANCED;
 
 	/* C3 . MPU OFF + Core active */
 	omap3_power_states[3].valid = 0;
@@ -159,18 +217,20 @@ void omap_init_power_states(void)
 	omap3_power_states[3].wakeup_latency = 1800;
 	omap3_power_states[3].threshold = 4000;
 	omap3_power_states[3].mpu_state = PWRDM_POWER_OFF;
-	omap3_power_states[3].core_state = PWRDM_POWER_RET;
-	omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[3].core_state = PWRDM_POWER_ON;
+	omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C4 . MPU CSWR + Core CSWR*/
-	omap3_power_states[4].valid = 0;
+	omap3_power_states[4].valid = 1;
 	omap3_power_states[4].type = OMAP3_STATE_C4;
 	omap3_power_states[4].sleep_latency = 2500;
 	omap3_power_states[4].wakeup_latency = 7500;
 	omap3_power_states[4].threshold = 12000;
 	omap3_power_states[4].mpu_state = PWRDM_POWER_RET;
 	omap3_power_states[4].core_state = PWRDM_POWER_RET;
-	omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C5 . MPU OFF + Core CSWR */
 	omap3_power_states[5].valid = 0;
@@ -180,7 +240,8 @@ void omap_init_power_states(void)
 	omap3_power_states[5].threshold = 15000;
 	omap3_power_states[5].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[5].core_state = PWRDM_POWER_RET;
-	omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C6 . MPU OFF + Core OFF */
 	omap3_power_states[6].valid = 0;
@@ -190,7 +251,8 @@ void omap_init_power_states(void)
 	omap3_power_states[6].threshold = 300000;
 	omap3_power_states[6].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[6].core_state = PWRDM_POWER_OFF;
-	omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_CHECK_BM;
 }
 
 struct cpuidle_driver omap3_idle_driver = {

Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.h
===================================================================

arch/arm/mach-omap2/cpuidle34xx.h +4 -2
@@ -33,11 +33,13 @@
 /* Currently, we support only upto C2 */
 #define MAX_SUPPORTED_STATES 3
 
+extern unsigned short clocks_off_while_idle;
 extern void omap_sram_idle(void);
-extern int omap3_irq_pending(void);
+extern int omap_irq_pending(void);
 extern void per_gpio_clk_enable(void);
 extern void per_gpio_clk_disable(void);
-
+extern void omap_serial_enable_clocks(int enable);
+extern int omap3_can_sleep();
 struct omap3_processor_cx {
 	u8 valid;
 	u8 type;

Index: linux-omap-2.6/arch/arm/mach-omap2/pm34xx.c
===================================================================

arch/arm/mach-omap2/pm34xx.c +2 -11
@@ -61,7 +61,7 @@ static struct clk *gpio_fcks[NUM_OF_PERG
 
 /* XXX This is for gpio fclk hack. Will be removed as gpio driver
  * handles fcks correctly */
-static void per_gpio_clk_enable(void)
+void per_gpio_clk_enable(void)
 {
 	int i;
 	for (i = 1; i < NUM_OF_PERGPIOS + 1; i++)
@@ -70,7 +70,7 @@ static void per_gpio_clk_enable(void)
 
 /* XXX This is for gpio fclk hack. Will be removed as gpio driver
  * handles fcks correctly */
-static void per_gpio_clk_disable(void)
+void per_gpio_clk_disable(void)
 {
 	int i;
 	for (i = 1; i < NUM_OF_PERGPIOS + 1; i++)
@@ -202,25 +202,7 @@ void omap_sram_idle(void)
 		return;
 	}
 
-	omap2_gpio_prepare_for_retention();
-
-	if (clocks_off_while_idle) {
-		omap_serial_enable_clocks(0);
-		/* XXX This is for gpio fclk hack. Will be removed as
-		 * gpio driver * handles fcks correctly */
-		per_gpio_clk_disable();
-	}
-

arch/arm/mach-omap2/pm34xx.c void omap_sram_idle(void) · line 223

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +0 -9
 	_omap_sram_idle(NULL, save_state, clocks_off_while_idle);
-
-	if (clocks_off_while_idle) {
-		omap_serial_enable_clocks(1);
-		/* XXX This is for gpio fclk hack. Will be removed as
-		 * gpio driver * handles fcks correctly */
-		per_gpio_clk_enable();
-	}
-
-	omap2_gpio_resume_after_retention();

Couldn't these be left here. I assume you want to do gpio and serial clock disabling only if per domain state is about to change. If this is what you want then you should check that all other clocks in per domain are disabled. If this is true then disable gpio and uart clocks here. Still this code could be left here if done that way.

Quoted 14 lines
arch/arm/mach-omap2/pm34xx.c +1 -1
 }
 
 static int omap3_fclks_active(void)
@@ -258,7 +240,7 @@ static int omap3_fclks_active(void)
 	return 0;
 }
 
-static int omap3_can_sleep(void)
+int omap3_can_sleep(void)
 {
 	if (!enable_dyn_sleep)
 		return 0;
@@ -329,8 +311,25 @@ static void omap3_pm_idle(void)
 	if (omap_irq_pending())

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 321

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +8 -0
 		goto out;
 
+	omap2_gpio_prepare_for_retention();
+
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(0);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_disable();
+	}

Same comment as above.

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 332

Quoted 11 lines
arch/arm/mach-omap2/pm34xx.c +9 -0
+
 	omap_sram_idle();
 
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(1);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_enable();
+	}
+
+	omap2_gpio_resume_after_retention();

and same goes here.

Quoted 6 lines
arch/arm/mach-omap2/pm34xx.c +0 -0
 out:
 	local_fiq_enable();
 	local_irq_enable();
@@ -363,8 +362,25 @@ static int omap3_pm_suspend(void)
 			goto restore;
 	}

arch/arm/mach-omap2/pm34xx.c static int omap3_pm_suspend(void) · line 373

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +9 -0
 
+	omap2_gpio_prepare_for_retention();
+
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(0);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_disable();
+	}
+

And here.

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 332

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +8 -0
 	omap_sram_idle();
 
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(1);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_enable();
+	}
+
+	omap2_gpio_resume_after_retention();

And here.

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +0 -1
 restore:
 	/* Restore next_pwrsts */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 
--

To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 6 lines
Jouni Högander

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#2 lore raw
Quoted 107 lines

-----Original Message-----
From: "Högander" Jouni [mailto:[email protected]]
Sent: Wednesday, July 02, 2008 5:19 PM
To: ext Rajendra Nayak
Cc: [email protected]
Subject: Re: [PATCH 02/11] per/neon and core handling in idle

Quoted 6 lines · ext Rajendra Nayak

This patches adds handling of PER/NEON and CORE domain in idle.

---
 arch/arm/mach-omap2/cpuidle34xx.c |   98 

+++++++++++++++++++++++++++++++-------

Quoted 7 lines
 arch/arm/mach-omap2/cpuidle34xx.h |    6 +-
 arch/arm/mach-omap2/pm34xx.c      |   58 ++++++++++++++--------
 3 files changed, 121 insertions(+), 41 deletions(-)

Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/cpuidle34xx.c

2008-07-01 18:48:09.962433167 +0530
Quoted 1 line

+++ linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.c

2008-07-01 18:48:12.884339399 +0530
Quoted 64 lines
arch/arm/mach-omap2/cpuidle34xx.c +29 -6
@@ -26,6 +26,8 @@
 #include <asm/arch/pm.h>
 #include <asm/arch/prcm.h>
 #include <asm/arch/powerdomain.h>
+#include <asm/arch/clockdomain.h>
+#include <asm/arch/gpio.h>
 #include "cpuidle34xx.h"
 
 #ifdef CONFIG_CPU_IDLE
@@ -35,6 +37,8 @@ struct omap3_processor_cx current_cx_sta
 
 static int omap3_idle_bm_check(void)
 {
+	if (!omap3_can_sleep())
+		return 1;
 	return 0;
 }
 
@@ -46,34 +50,86 @@ static int omap3_enter_idle(struct cpuid
 {
 	struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
-	struct powerdomain *mpu_pd;
+	struct powerdomain *mpu_pd, *core_pd, *per_pd, *neon_pd;
+	int per_pwrst, neon_pwrst;
 
 	current_cx_state = *cx;
 
-	/* Used to keep track of the total time in idle */
-	getnstimeofday(&ts_preidle);
-
-
 	if (cx->type == OMAP3_STATE_C0) {
 		/* Do nothing for C0, not even a wfi */
 		return 0;
 	}
 
+	/* Used to keep track of the total time in idle */
+	getnstimeofday(&ts_preidle);
+
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
+	core_pd = pwrdm_lookup("core_pwrdm");
+	per_pd = pwrdm_lookup("per_pwrdm");
+	neon_pd = pwrdm_lookup("neon_pwrdm");
+
+	/* Reset previous power state registers */
+	pwrdm_clear_all_prev_pwrst(mpu_pd);
+	pwrdm_clear_all_prev_pwrst(neon_pd);
+	pwrdm_clear_all_prev_pwrst(core_pd);
+	pwrdm_clear_all_prev_pwrst(per_pd);
+
+	if (omap_irq_pending())
+		return 0;
+
+	per_pwrst = pwrdm_read_pwrst(per_pd);
+	neon_pwrst = pwrdm_read_pwrst(neon_pd);
+
 	/* Program MPU to target state */
-	if (cx->mpu_state < PWRDM_POWER_ON)
+	if (cx->mpu_state < PWRDM_POWER_ON) {
+		if (neon_pwrst == PWRDM_POWER_ON)
+			pwrdm_set_next_pwrst(neon_pd, PWRDM_POWER_RET);
 		pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
+	}

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 98

Quoted 10 lines
arch/arm/mach-omap2/cpuidle34xx.c +10 -0
+
+	/* Program CORE and PER to target state */
+	if (cx->core_state < PWRDM_POWER_ON) {
+		if (per_pwrst == PWRDM_POWER_ON) {
+			omap2_gpio_prepare_for_retention();
+			if (clocks_off_while_idle) {
+				per_gpio_clk_disable();
+				omap_serial_enable_clocks(0);
+			}
+		}

Why this is here? Why per is not put to sleep state if core is not? Shouldn't you just disable gpio clocks in omap_sram_idle and if all clocks in per domain are cut off then per domain enters its sleep state. No matter what is the state of core domain.

Quoted 7 lines

Why per_pwrst is checked here? You know it is always on currently. It won't never be anything else until those things in this if block is done.

As the day comes when per_pwrst here is something else than PWRDM_POWER_ON then serial clocks in core domain are not disabled because disabling them are in that block.

PER domain has a hardwired sleep dep with CORE-L3, hence the above. Also IO wakeup works only while CORE is in RET/OFF. While CORE is active you need GPIO to wake you up. Hence cutting GPIO clocks only while you attempt a CORE RET/OFF makes more sense, so that while GPIO is down the IO pad can wake you up.

Quoted 7 lines
Quoted 7 lines
arch/arm/mach-omap2/cpuidle34xx.c +2 -0
+		pwrdm_set_next_pwrst(core_pd, cx->core_state);
+	}
 
 	/* Execute ARM wfi */
 	omap_sram_idle();
 
Quoted 11 lines

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 110

Quoted 8 lines
arch/arm/mach-omap2/cpuidle34xx.c +5 -2
-	/* Program MPU to ON */
-	if (cx->mpu_state < PWRDM_POWER_ON)
+	/* Program MPU/NEON to ON */
+	if (cx->mpu_state < PWRDM_POWER_ON) {
+		if (neon_pwrst == PWRDM_POWER_ON)
+			pwrdm_set_next_pwrst(neon_pd, PWRDM_POWER_ON);
 		pwrdm_set_next_pwrst(mpu_pd, PWRDM_POWER_ON);
+	}

No need to do these as they are written anyway in the next round. MPU and NEON are not going to change their state in between.

Yes, I can remove these.

Quoted 175 lines

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 118

Quoted 9 lines
arch/arm/mach-omap2/cpuidle34xx.c +8 -0
+
+	if (cx->core_state < PWRDM_POWER_ON) {
+		if (per_pwrst == PWRDM_POWER_ON) {
+			if (clocks_off_while_idle) {
+				omap_serial_enable_clocks(1);
+				per_gpio_clk_enable();
+			}
+			omap2_gpio_resume_after_retention();

Similiar comments as before omap_sram_idle() for this block.

Review static int omap3_enter_idle(struct cpuid · line 120

Quoted 2 lines
(quoted diff) +2 -0
+		}
+		pwrdm_set_next_pwrst(core_pd, PWRDM_POWER_ON);

This can be also left to value before omap_sram_idle(), because it is anyway written again in next round.

Quoted 90 lines
arch/arm/mach-omap2/cpuidle34xx.c +24 -10
+	}
+
+	pr_debug("MPU prev st:%x,NEON prev st:%x\n",
+			       pwrdm_read_prev_pwrst(mpu_pd),
+			       pwrdm_read_prev_pwrst(neon_pd));
+	pr_debug("PER prev st:%x,CORE prev st:%x\n",
+			       pwrdm_read_prev_pwrst(per_pd),
+			       pwrdm_read_prev_pwrst(core_pd));
 
 	getnstimeofday(&ts_postidle);
 	ts_idle = timespec_sub(ts_postidle, ts_preidle);
-	return timespec_to_ns(&ts_idle);
+	return (u32)timespec_to_ns(&ts_idle)/1000;
 }
 
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
@@ -130,7 +186,7 @@ void omap_init_power_states(void)
 	omap3_power_states[0].threshold = 0;
 	omap3_power_states[0].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[0].core_state = PWRDM_POWER_ON;
-	omap3_power_states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[0].flags = CPUIDLE_FLAG_SHALLOW;
 
 	/* C1 . MPU WFI + Core active */
 	omap3_power_states[1].valid = 1;
@@ -140,7 +196,8 @@ void omap_init_power_states(void)
 	omap3_power_states[1].threshold = 30;
 	omap3_power_states[1].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[1].core_state = PWRDM_POWER_ON;
-	omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID |
+						CPUIDLE_FLAG_SHALLOW;
 
 	/* C2 . MPU CSWR + Core active */
 	omap3_power_states[2].valid = 1;
@@ -150,7 +207,8 @@ void omap_init_power_states(void)
 	omap3_power_states[2].threshold = 300;
 	omap3_power_states[2].mpu_state = PWRDM_POWER_RET;
 	omap3_power_states[2].core_state = PWRDM_POWER_ON;
-	omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID |
+						CPUIDLE_FLAG_BALANCED;
 
 	/* C3 . MPU OFF + Core active */
 	omap3_power_states[3].valid = 0;
@@ -159,18 +217,20 @@ void omap_init_power_states(void)
 	omap3_power_states[3].wakeup_latency = 1800;
 	omap3_power_states[3].threshold = 4000;
 	omap3_power_states[3].mpu_state = PWRDM_POWER_OFF;
-	omap3_power_states[3].core_state = PWRDM_POWER_RET;
-	omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[3].core_state = PWRDM_POWER_ON;
+	omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C4 . MPU CSWR + Core CSWR*/
-	omap3_power_states[4].valid = 0;
+	omap3_power_states[4].valid = 1;
 	omap3_power_states[4].type = OMAP3_STATE_C4;
 	omap3_power_states[4].sleep_latency = 2500;
 	omap3_power_states[4].wakeup_latency = 7500;
 	omap3_power_states[4].threshold = 12000;
 	omap3_power_states[4].mpu_state = PWRDM_POWER_RET;
 	omap3_power_states[4].core_state = PWRDM_POWER_RET;
-	omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C5 . MPU OFF + Core CSWR */
 	omap3_power_states[5].valid = 0;
@@ -180,7 +240,8 @@ void omap_init_power_states(void)
 	omap3_power_states[5].threshold = 15000;
 	omap3_power_states[5].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[5].core_state = PWRDM_POWER_RET;
-	omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C6 . MPU OFF + Core OFF */
 	omap3_power_states[6].valid = 0;
@@ -190,7 +251,8 @@ void omap_init_power_states(void)
 	omap3_power_states[6].threshold = 300000;
 	omap3_power_states[6].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[6].core_state = PWRDM_POWER_OFF;
-	omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_CHECK_BM;
 }
 
 struct cpuidle_driver omap3_idle_driver = {
Quoted 3 lines

Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.h
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/cpuidle34xx.h

2008-07-01 18:48:09.962433167 +0530
Quoted 1 line

+++ linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.h

2008-07-01 18:48:12.885339367 +0530
Quoted 16 lines
arch/arm/mach-omap2/cpuidle34xx.h +4 -2
@@ -33,11 +33,13 @@
 /* Currently, we support only upto C2 */
 #define MAX_SUPPORTED_STATES 3
 
+extern unsigned short clocks_off_while_idle;
 extern void omap_sram_idle(void);
-extern int omap3_irq_pending(void);
+extern int omap_irq_pending(void);
 extern void per_gpio_clk_enable(void);
 extern void per_gpio_clk_disable(void);
-
+extern void omap_serial_enable_clocks(int enable);
+extern int omap3_can_sleep();
 struct omap3_processor_cx {
 	u8 valid;
 	u8 type;
Quoted 3 lines

Index: linux-omap-2.6/arch/arm/mach-omap2/pm34xx.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/pm34xx.c

2008-07-01 18:48:09.962433167 +0530
Quoted 1 line

+++ linux-omap-2.6/arch/arm/mach-omap2/pm34xx.c

2008-07-01 18:48:12.885339367 +0530
Quoted 39 lines
arch/arm/mach-omap2/pm34xx.c +2 -18
@@ -61,7 +61,7 @@ static struct clk *gpio_fcks[NUM_OF_PERG
 
 /* XXX This is for gpio fclk hack. Will be removed as gpio driver
  * handles fcks correctly */
-static void per_gpio_clk_enable(void)
+void per_gpio_clk_enable(void)
 {
 	int i;
 	for (i = 1; i < NUM_OF_PERGPIOS + 1; i++)
@@ -70,7 +70,7 @@ static void per_gpio_clk_enable(void)
 
 /* XXX This is for gpio fclk hack. Will be removed as gpio driver
  * handles fcks correctly */
-static void per_gpio_clk_disable(void)
+void per_gpio_clk_disable(void)
 {
 	int i;
 	for (i = 1; i < NUM_OF_PERGPIOS + 1; i++)
@@ -202,25 +202,7 @@ void omap_sram_idle(void)
 		return;
 	}
 
-	omap2_gpio_prepare_for_retention();
-
-	if (clocks_off_while_idle) {
-		omap_serial_enable_clocks(0);
-		/* XXX This is for gpio fclk hack. Will be removed as
-		 * gpio driver * handles fcks correctly */
-		per_gpio_clk_disable();
-	}
-
 	_omap_sram_idle(NULL, save_state, clocks_off_while_idle);
-
-	if (clocks_off_while_idle) {
-		omap_serial_enable_clocks(1);
-		/* XXX This is for gpio fclk hack. Will be removed as
-		 * gpio driver * handles fcks correctly */
-		per_gpio_clk_enable();
-	}
Quoted 8 lines

Review void omap_sram_idle(void) · line 223

Quoted 2 lines
(quoted diff) +0 -2
-
-	omap2_gpio_resume_after_retention();

Couldn't these be left here. I assume you want to do gpio and serial clock disabling only if per domain state is about to change. If this is what you want then you should check that all other clocks in per domain are disabled. If this is true then disable gpio and uart clocks here. Still this code could be left here if done that way.

All other fclks in PER are anyway checked for in omap3_fclks_active.

Quoted 78 lines
Quoted 15 lines
arch/arm/mach-omap2/pm34xx.c +1 -1
 }
 
 static int omap3_fclks_active(void)
@@ -258,7 +240,7 @@ static int omap3_fclks_active(void)
 	return 0;
 }
 
-static int omap3_can_sleep(void)
+int omap3_can_sleep(void)
 {
 	if (!enable_dyn_sleep)
 		return 0;
@@ -329,8 +311,25 @@ static void omap3_pm_idle(void)
 	if (omap_irq_pending())

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 321

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +8 -0
 		goto out;
 
+	omap2_gpio_prepare_for_retention();
+
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(0);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_disable();
+	}

Same comment as above.

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 332

Quoted 11 lines
arch/arm/mach-omap2/pm34xx.c +9 -0
+
 	omap_sram_idle();
 
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(1);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_enable();
+	}
+
+	omap2_gpio_resume_after_retention();

and same goes here.

Quoted 6 lines
arch/arm/mach-omap2/pm34xx.c +0 -0
 out:
 	local_fiq_enable();
 	local_irq_enable();
@@ -363,8 +362,25 @@ static int omap3_pm_suspend(void)
 			goto restore;
 	}

arch/arm/mach-omap2/pm34xx.c static int omap3_pm_suspend(void) · line 373

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +9 -0
 
+	omap2_gpio_prepare_for_retention();
+
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(0);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_disable();
+	}
+

And here.

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 332

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +8 -0
 	omap_sram_idle();
 
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(1);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_enable();
+	}
+
+	omap2_gpio_resume_after_retention();

And here.

Quoted 4 lines
arch/arm/mach-omap2/pm34xx.c +0 -0
 restore:
 	/* Restore next_pwrsts */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
Quoted 12 lines
Quoted 2 lines

--
To unsubscribe from this list: send the line "unsubscribe

linux-omap" in

Quoted 4 lines

the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 1 line
Jouni Högander

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#3 lore raw
Quoted 115 lines · ext Rajendra Nayak
Quoted 107 lines

-----Original Message-----
From: "Högander" Jouni [mailto:[email protected]]
Sent: Wednesday, July 02, 2008 5:19 PM
To: ext Rajendra Nayak
Cc: [email protected]
Subject: Re: [PATCH 02/11] per/neon and core handling in idle

Quoted 6 lines · ext Rajendra Nayak

This patches adds handling of PER/NEON and CORE domain in idle.

---
 arch/arm/mach-omap2/cpuidle34xx.c |   98 

+++++++++++++++++++++++++++++++-------

Quoted 7 lines
 arch/arm/mach-omap2/cpuidle34xx.h |    6 +-
 arch/arm/mach-omap2/pm34xx.c      |   58 ++++++++++++++--------
 3 files changed, 121 insertions(+), 41 deletions(-)

Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/cpuidle34xx.c

2008-07-01 18:48:09.962433167 +0530
Quoted 1 line

+++ linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.c

2008-07-01 18:48:12.884339399 +0530
Quoted 64 lines
arch/arm/mach-omap2/cpuidle34xx.c +29 -6
@@ -26,6 +26,8 @@
 #include <asm/arch/pm.h>
 #include <asm/arch/prcm.h>
 #include <asm/arch/powerdomain.h>
+#include <asm/arch/clockdomain.h>
+#include <asm/arch/gpio.h>
 #include "cpuidle34xx.h"
 
 #ifdef CONFIG_CPU_IDLE
@@ -35,6 +37,8 @@ struct omap3_processor_cx current_cx_sta
 
 static int omap3_idle_bm_check(void)
 {
+	if (!omap3_can_sleep())
+		return 1;
 	return 0;
 }
 
@@ -46,34 +50,86 @@ static int omap3_enter_idle(struct cpuid
 {
 	struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
-	struct powerdomain *mpu_pd;
+	struct powerdomain *mpu_pd, *core_pd, *per_pd, *neon_pd;
+	int per_pwrst, neon_pwrst;
 
 	current_cx_state = *cx;
 
-	/* Used to keep track of the total time in idle */
-	getnstimeofday(&ts_preidle);
-
-
 	if (cx->type == OMAP3_STATE_C0) {
 		/* Do nothing for C0, not even a wfi */
 		return 0;
 	}
 
+	/* Used to keep track of the total time in idle */
+	getnstimeofday(&ts_preidle);
+
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
+	core_pd = pwrdm_lookup("core_pwrdm");
+	per_pd = pwrdm_lookup("per_pwrdm");
+	neon_pd = pwrdm_lookup("neon_pwrdm");
+
+	/* Reset previous power state registers */
+	pwrdm_clear_all_prev_pwrst(mpu_pd);
+	pwrdm_clear_all_prev_pwrst(neon_pd);
+	pwrdm_clear_all_prev_pwrst(core_pd);
+	pwrdm_clear_all_prev_pwrst(per_pd);
+
+	if (omap_irq_pending())
+		return 0;
+
+	per_pwrst = pwrdm_read_pwrst(per_pd);
+	neon_pwrst = pwrdm_read_pwrst(neon_pd);
+
 	/* Program MPU to target state */
-	if (cx->mpu_state < PWRDM_POWER_ON)
+	if (cx->mpu_state < PWRDM_POWER_ON) {
+		if (neon_pwrst == PWRDM_POWER_ON)
+			pwrdm_set_next_pwrst(neon_pd, PWRDM_POWER_RET);
 		pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
+	}

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 98

Quoted 10 lines
arch/arm/mach-omap2/cpuidle34xx.c +10 -0
+
+	/* Program CORE and PER to target state */
+	if (cx->core_state < PWRDM_POWER_ON) {
+		if (per_pwrst == PWRDM_POWER_ON) {
+			omap2_gpio_prepare_for_retention();
+			if (clocks_off_while_idle) {
+				per_gpio_clk_disable();
+				omap_serial_enable_clocks(0);
+			}
+		}

Why this is here? Why per is not put to sleep state if core is not? Shouldn't you just disable gpio clocks in omap_sram_idle and if all clocks in per domain are cut off then per domain enters its sleep state. No matter what is the state of core domain.

Quoted 7 lines

Why per_pwrst is checked here? You know it is always on currently. It won't never be anything else until those things in this if block is done.

As the day comes when per_pwrst here is something else than PWRDM_POWER_ON then serial clocks in core domain are not disabled because disabling them are in that block.

Quoted 5 lines

PER domain has a hardwired sleep dep with CORE-L3, hence the above. Also IO wakeup works only while CORE is in RET/OFF. While CORE is active you need GPIO to wake you up. Hence cutting GPIO clocks only while you attempt a CORE RET/OFF makes more sense, so that while GPIO is down the IO pad can wake you up.

This is something I didn't know. Now it seems to be reasonable also to me to do these clock disables here:) Now it seems that we might still need to have some mean to add these deps statically. Wkdep between core and per might be needed at some point. Currently dep between per and mpu is enough, but if gpio clock disable is added to gpio code, then wkdep needs to be added. If statement is still even more unnecessary here, because it will never be anything else than per_pwrst == PWRDM_POWER_ON.

Quoted 206 lines
Quoted 8 lines
Quoted 8 lines
arch/arm/mach-omap2/cpuidle34xx.c +2 -0
+		pwrdm_set_next_pwrst(core_pd, cx->core_state);
+	}
 
 	/* Execute ARM wfi */
 	omap_sram_idle();
 
Quoted 11 lines

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 110

Quoted 8 lines
arch/arm/mach-omap2/cpuidle34xx.c +5 -2
-	/* Program MPU to ON */
-	if (cx->mpu_state < PWRDM_POWER_ON)
+	/* Program MPU/NEON to ON */
+	if (cx->mpu_state < PWRDM_POWER_ON) {
+		if (neon_pwrst == PWRDM_POWER_ON)
+			pwrdm_set_next_pwrst(neon_pd, PWRDM_POWER_ON);
 		pwrdm_set_next_pwrst(mpu_pd, PWRDM_POWER_ON);
+	}

No need to do these as they are written anyway in the next round. MPU and NEON are not going to change their state in between.

Yes, I can remove these.

Quoted 175 lines

arch/arm/mach-omap2/cpuidle34xx.c static int omap3_enter_idle(struct cpuid · line 118

Quoted 9 lines
arch/arm/mach-omap2/cpuidle34xx.c +8 -0
+
+	if (cx->core_state < PWRDM_POWER_ON) {
+		if (per_pwrst == PWRDM_POWER_ON) {
+			if (clocks_off_while_idle) {
+				omap_serial_enable_clocks(1);
+				per_gpio_clk_enable();
+			}
+			omap2_gpio_resume_after_retention();

Similiar comments as before omap_sram_idle() for this block.

Review static int omap3_enter_idle(struct cpuid · line 120

Quoted 2 lines
(quoted diff) +2 -0
+		}
+		pwrdm_set_next_pwrst(core_pd, PWRDM_POWER_ON);

This can be also left to value before omap_sram_idle(), because it is anyway written again in next round.

Quoted 90 lines
arch/arm/mach-omap2/cpuidle34xx.c +24 -10
+	}
+
+	pr_debug("MPU prev st:%x,NEON prev st:%x\n",
+			       pwrdm_read_prev_pwrst(mpu_pd),
+			       pwrdm_read_prev_pwrst(neon_pd));
+	pr_debug("PER prev st:%x,CORE prev st:%x\n",
+			       pwrdm_read_prev_pwrst(per_pd),
+			       pwrdm_read_prev_pwrst(core_pd));
 
 	getnstimeofday(&ts_postidle);
 	ts_idle = timespec_sub(ts_postidle, ts_preidle);
-	return timespec_to_ns(&ts_idle);
+	return (u32)timespec_to_ns(&ts_idle)/1000;
 }
 
 static int omap3_enter_idle_bm(struct cpuidle_device *dev,
@@ -130,7 +186,7 @@ void omap_init_power_states(void)
 	omap3_power_states[0].threshold = 0;
 	omap3_power_states[0].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[0].core_state = PWRDM_POWER_ON;
-	omap3_power_states[0].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[0].flags = CPUIDLE_FLAG_SHALLOW;
 
 	/* C1 . MPU WFI + Core active */
 	omap3_power_states[1].valid = 1;
@@ -140,7 +196,8 @@ void omap_init_power_states(void)
 	omap3_power_states[1].threshold = 30;
 	omap3_power_states[1].mpu_state = PWRDM_POWER_ON;
 	omap3_power_states[1].core_state = PWRDM_POWER_ON;
-	omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[1].flags = CPUIDLE_FLAG_TIME_VALID |
+						CPUIDLE_FLAG_SHALLOW;
 
 	/* C2 . MPU CSWR + Core active */
 	omap3_power_states[2].valid = 1;
@@ -150,7 +207,8 @@ void omap_init_power_states(void)
 	omap3_power_states[2].threshold = 300;
 	omap3_power_states[2].mpu_state = PWRDM_POWER_RET;
 	omap3_power_states[2].core_state = PWRDM_POWER_ON;
-	omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[2].flags = CPUIDLE_FLAG_TIME_VALID |
+						CPUIDLE_FLAG_BALANCED;
 
 	/* C3 . MPU OFF + Core active */
 	omap3_power_states[3].valid = 0;
@@ -159,18 +217,20 @@ void omap_init_power_states(void)
 	omap3_power_states[3].wakeup_latency = 1800;
 	omap3_power_states[3].threshold = 4000;
 	omap3_power_states[3].mpu_state = PWRDM_POWER_OFF;
-	omap3_power_states[3].core_state = PWRDM_POWER_RET;
-	omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[3].core_state = PWRDM_POWER_ON;
+	omap3_power_states[3].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C4 . MPU CSWR + Core CSWR*/
-	omap3_power_states[4].valid = 0;
+	omap3_power_states[4].valid = 1;
 	omap3_power_states[4].type = OMAP3_STATE_C4;
 	omap3_power_states[4].sleep_latency = 2500;
 	omap3_power_states[4].wakeup_latency = 7500;
 	omap3_power_states[4].threshold = 12000;
 	omap3_power_states[4].mpu_state = PWRDM_POWER_RET;
 	omap3_power_states[4].core_state = PWRDM_POWER_RET;
-	omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[4].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C5 . MPU OFF + Core CSWR */
 	omap3_power_states[5].valid = 0;
@@ -180,7 +240,8 @@ void omap_init_power_states(void)
 	omap3_power_states[5].threshold = 15000;
 	omap3_power_states[5].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[5].core_state = PWRDM_POWER_RET;
-	omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[5].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_BALANCED | CPUIDLE_FLAG_CHECK_BM;
 
 	/* C6 . MPU OFF + Core OFF */
 	omap3_power_states[6].valid = 0;
@@ -190,7 +251,8 @@ void omap_init_power_states(void)
 	omap3_power_states[6].threshold = 300000;
 	omap3_power_states[6].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[6].core_state = PWRDM_POWER_OFF;
-	omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[6].flags = CPUIDLE_FLAG_TIME_VALID |
+			CPUIDLE_FLAG_DEEP | CPUIDLE_FLAG_CHECK_BM;
 }
 
 struct cpuidle_driver omap3_idle_driver = {
Quoted 3 lines

Index: linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.h
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/cpuidle34xx.h

2008-07-01 18:48:09.962433167 +0530
Quoted 1 line

+++ linux-omap-2.6/arch/arm/mach-omap2/cpuidle34xx.h

2008-07-01 18:48:12.885339367 +0530
Quoted 16 lines
arch/arm/mach-omap2/cpuidle34xx.h +4 -2
@@ -33,11 +33,13 @@
 /* Currently, we support only upto C2 */
 #define MAX_SUPPORTED_STATES 3
 
+extern unsigned short clocks_off_while_idle;
 extern void omap_sram_idle(void);
-extern int omap3_irq_pending(void);
+extern int omap_irq_pending(void);
 extern void per_gpio_clk_enable(void);
 extern void per_gpio_clk_disable(void);
-
+extern void omap_serial_enable_clocks(int enable);
+extern int omap3_can_sleep();
 struct omap3_processor_cx {
 	u8 valid;
 	u8 type;
Quoted 3 lines

Index: linux-omap-2.6/arch/arm/mach-omap2/pm34xx.c
===================================================================
--- linux-omap-2.6.orig/arch/arm/mach-omap2/pm34xx.c

2008-07-01 18:48:09.962433167 +0530
Quoted 1 line

+++ linux-omap-2.6/arch/arm/mach-omap2/pm34xx.c

2008-07-01 18:48:12.885339367 +0530
Quoted 39 lines
arch/arm/mach-omap2/pm34xx.c +2 -18
@@ -61,7 +61,7 @@ static struct clk *gpio_fcks[NUM_OF_PERG
 
 /* XXX This is for gpio fclk hack. Will be removed as gpio driver
  * handles fcks correctly */
-static void per_gpio_clk_enable(void)
+void per_gpio_clk_enable(void)
 {
 	int i;
 	for (i = 1; i < NUM_OF_PERGPIOS + 1; i++)
@@ -70,7 +70,7 @@ static void per_gpio_clk_enable(void)
 
 /* XXX This is for gpio fclk hack. Will be removed as gpio driver
  * handles fcks correctly */
-static void per_gpio_clk_disable(void)
+void per_gpio_clk_disable(void)
 {
 	int i;
 	for (i = 1; i < NUM_OF_PERGPIOS + 1; i++)
@@ -202,25 +202,7 @@ void omap_sram_idle(void)
 		return;
 	}
 
-	omap2_gpio_prepare_for_retention();
-
-	if (clocks_off_while_idle) {
-		omap_serial_enable_clocks(0);
-		/* XXX This is for gpio fclk hack. Will be removed as
-		 * gpio driver * handles fcks correctly */
-		per_gpio_clk_disable();
-	}
-
 	_omap_sram_idle(NULL, save_state, clocks_off_while_idle);
-
-	if (clocks_off_while_idle) {
-		omap_serial_enable_clocks(1);
-		/* XXX This is for gpio fclk hack. Will be removed as
-		 * gpio driver * handles fcks correctly */
-		per_gpio_clk_enable();
-	}
Quoted 8 lines

Review void omap_sram_idle(void) · line 223

Quoted 2 lines
(quoted diff) +0 -2
-
-	omap2_gpio_resume_after_retention();

Couldn't these be left here. I assume you want to do gpio and serial clock disabling only if per domain state is about to change. If this is what you want then you should check that all other clocks in per domain are disabled. If this is true then disable gpio and uart clocks here. Still this code could be left here if done that way.

Quoted 1 line

All other fclks in PER are anyway checked for in omap3_fclks_active.

Yes, you are right. As there is that hw sleep dep per domain wont enter ret without core. For all cases where core sleeps fclk check is done.

Quoted 94 lines
Quoted 91 lines
Quoted 16 lines
arch/arm/mach-omap2/pm34xx.c +1 -1
 }
 
 static int omap3_fclks_active(void)
@@ -258,7 +240,7 @@ static int omap3_fclks_active(void)
 	return 0;
 }
 
-static int omap3_can_sleep(void)
+int omap3_can_sleep(void)
 {
 	if (!enable_dyn_sleep)
 		return 0;
@@ -329,8 +311,25 @@ static void omap3_pm_idle(void)
 	if (omap_irq_pending())

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 321

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +8 -0
 		goto out;
 
+	omap2_gpio_prepare_for_retention();
+
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(0);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_disable();
+	}

Same comment as above.

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 332

Quoted 11 lines
arch/arm/mach-omap2/pm34xx.c +9 -0
+
 	omap_sram_idle();
 
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(1);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_enable();
+	}
+
+	omap2_gpio_resume_after_retention();

and same goes here.

Quoted 6 lines
arch/arm/mach-omap2/pm34xx.c +0 -0
 out:
 	local_fiq_enable();
 	local_irq_enable();
@@ -363,8 +362,25 @@ static int omap3_pm_suspend(void)
 			goto restore;
 	}

arch/arm/mach-omap2/pm34xx.c static int omap3_pm_suspend(void) · line 373

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +9 -0
 
+	omap2_gpio_prepare_for_retention();
+
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(0);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_disable();
+	}
+

And here.

arch/arm/mach-omap2/pm34xx.c static void omap3_pm_idle(void) · line 332

Quoted 10 lines
arch/arm/mach-omap2/pm34xx.c +8 -0
 	omap_sram_idle();
 
+	if (clocks_off_while_idle) {
+		omap_serial_enable_clocks(1);
+		/* XXX This is for gpio fclk hack. Will be removed as
+		 * gpio driver * handles fcks correctly */
+		per_gpio_clk_enable();
+	}
+
+	omap2_gpio_resume_after_retention();

And here.

Quoted 6 lines
arch/arm/mach-omap2/pm34xx.c +0 -1
 restore:
 	/* Restore next_pwrsts */
 	list_for_each_entry(pwrst, &pwrst_list, node) {
 
--

To unsubscribe from this list: send the line "unsubscribe

linux-omap" in

Quoted 4 lines

the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 1 line
Jouni Högander
Signature · 6 lines
Jouni Högander

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html