aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2013-01-26 02:58:13 -0500
committerPaul Walmsley <paul@pwsan.com>2013-01-29 16:59:56 -0500
commit1cd96478cf1505a32861ffed8d8f1189d1b1b8ab (patch)
treed65ebdd4a5be3d688147b6acf3a2777fc31c9f13 /arch/arm/mach-omap2
parentfd6b42a5614077b04ce8f34fbbcf16864723f5df (diff)
ARM: OMAP3xxx: CPUIdle: optimize __omap3_enter_idle()
Avoid programming the MPU and CORE powerdomain next-power-state registers if those powerdomains will never enter low-power states (e.g., the state that people refer to as "C1"). To avoid making assumptions about CPUIdle states based on their order in the list, use a flag to mark CPUIdle states that don't enter powerdomain low-power states. Avoid a previous-power-state register read on the MPU powerdomain unless we know that the MPU was supposed to go OFF during the last state transition. Previous-power-state register reads can be very expensive, so it's worth avoiding these when possible. Since the CORE_L3 clockdomain can't go inactive unless the MPU is active, there's little point blocking autoidle on the CORE_L3 clockdomain in "C1" state, since we've programmed the MPU clockdomain to stay active. Remove the unnecessary code. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c35
1 files changed, 22 insertions, 13 deletions
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index cba69455647a..80392fca86c6 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -39,11 +39,23 @@ struct omap3_idle_statedata {
39 u8 mpu_state; 39 u8 mpu_state;
40 u8 core_state; 40 u8 core_state;
41 u8 per_min_state; 41 u8 per_min_state;
42 u8 flags;
42}; 43};
43 44
44static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; 45static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
45 46
46/* 47/*
48 * Possible flag bits for struct omap3_idle_statedata.flags:
49 *
50 * OMAP_CPUIDLE_CX_NO_CLKDM_IDLE: don't allow the MPU clockdomain to go
51 * inactive. This in turn prevents the MPU DPLL from entering autoidle
52 * mode, so wakeup latency is greatly reduced, at the cost of additional
53 * energy consumption. This also prevents the CORE clockdomain from
54 * entering idle.
55 */
56#define OMAP_CPUIDLE_CX_NO_CLKDM_IDLE BIT(0)
57
58/*
47 * Prevent PER OFF if CORE is not in RETention or OFF as this would 59 * Prevent PER OFF if CORE is not in RETention or OFF as this would
48 * disable PER wakeups completely. 60 * disable PER wakeups completely.
49 */ 61 */
@@ -53,6 +65,7 @@ static struct omap3_idle_statedata omap3_idle_data[] = {
53 .core_state = PWRDM_POWER_ON, 65 .core_state = PWRDM_POWER_ON,
54 /* In C1 do not allow PER state lower than CORE state */ 66 /* In C1 do not allow PER state lower than CORE state */
55 .per_min_state = PWRDM_POWER_ON, 67 .per_min_state = PWRDM_POWER_ON,
68 .flags = OMAP_CPUIDLE_CX_NO_CLKDM_IDLE,
56 }, 69 },
57 { 70 {
58 .mpu_state = PWRDM_POWER_ON, 71 .mpu_state = PWRDM_POWER_ON,
@@ -93,27 +106,25 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
93 int index) 106 int index)
94{ 107{
95 struct omap3_idle_statedata *cx = &omap3_idle_data[index]; 108 struct omap3_idle_statedata *cx = &omap3_idle_data[index];
96 u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
97 109
98 local_fiq_disable(); 110 local_fiq_disable();
99 111
100 pwrdm_set_next_pwrst(mpu_pd, mpu_state);
101 pwrdm_set_next_pwrst(core_pd, core_state);
102
103 if (omap_irq_pending() || need_resched()) 112 if (omap_irq_pending() || need_resched())
104 goto return_sleep_time; 113 goto return_sleep_time;
105 114
106 /* Deny idle for C1 */ 115 /* Deny idle for C1 */
107 if (index == 0) { 116 if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE) {
108 clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]); 117 clkdm_deny_idle(mpu_pd->pwrdm_clkdms[0]);
109 clkdm_deny_idle(core_pd->pwrdm_clkdms[0]); 118 } else {
119 pwrdm_set_next_pwrst(mpu_pd, cx->mpu_state);
120 pwrdm_set_next_pwrst(core_pd, cx->core_state);
110 } 121 }
111 122
112 /* 123 /*
113 * Call idle CPU PM enter notifier chain so that 124 * Call idle CPU PM enter notifier chain so that
114 * VFP context is saved. 125 * VFP context is saved.
115 */ 126 */
116 if (mpu_state == PWRDM_POWER_OFF) 127 if (cx->mpu_state == PWRDM_POWER_OFF)
117 cpu_pm_enter(); 128 cpu_pm_enter();
118 129
119 /* Execute ARM wfi */ 130 /* Execute ARM wfi */
@@ -123,17 +134,15 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
123 * Call idle CPU PM enter notifier chain to restore 134 * Call idle CPU PM enter notifier chain to restore
124 * VFP context. 135 * VFP context.
125 */ 136 */
126 if (pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF) 137 if (cx->mpu_state == PWRDM_POWER_OFF &&
138 pwrdm_read_prev_pwrst(mpu_pd) == PWRDM_POWER_OFF)
127 cpu_pm_exit(); 139 cpu_pm_exit();
128 140
129 /* Re-allow idle for C1 */ 141 /* Re-allow idle for C1 */
130 if (index == 0) { 142 if (cx->flags & OMAP_CPUIDLE_CX_NO_CLKDM_IDLE)
131 clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]); 143 clkdm_allow_idle(mpu_pd->pwrdm_clkdms[0]);
132 clkdm_allow_idle(core_pd->pwrdm_clkdms[0]);
133 }
134 144
135return_sleep_time: 145return_sleep_time:
136
137 local_fiq_enable(); 146 local_fiq_enable();
138 147
139 return index; 148 return index;
@@ -198,7 +207,7 @@ static int next_valid_state(struct cpuidle_device *dev,
198 * Start search from the next (lower) state. 207 * Start search from the next (lower) state.
199 */ 208 */
200 for (idx = index - 1; idx >= 0; idx--) { 209 for (idx = index - 1; idx >= 0; idx--) {
201 cx = &omap3_idle_data[idx]; 210 cx = &omap3_idle_data[idx];
202 if ((cx->mpu_state >= mpu_deepest_state) && 211 if ((cx->mpu_state >= mpu_deepest_state) &&
203 (cx->core_state >= core_deepest_state)) { 212 (cx->core_state >= core_deepest_state)) {
204 next_index = idx; 213 next_index = idx;