diff options
author | Paul Walmsley <paul@pwsan.com> | 2013-01-26 02:58:13 -0500 |
---|---|---|
committer | Paul Walmsley <paul@pwsan.com> | 2013-01-29 16:59:56 -0500 |
commit | 1cd96478cf1505a32861ffed8d8f1189d1b1b8ab (patch) | |
tree | d65ebdd4a5be3d688147b6acf3a2777fc31c9f13 /arch/arm/mach-omap2 | |
parent | fd6b42a5614077b04ce8f34fbbcf16864723f5df (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.c | 35 |
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 | ||
44 | static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd; | 45 | static 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 | ||
135 | return_sleep_time: | 145 | return_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; |