diff options
author | Jean Pihet <jean.pihet@newoldbits.com> | 2012-06-01 11:11:07 -0400 |
---|---|---|
committer | Kevin Hilman <khilman@ti.com> | 2012-06-25 14:24:24 -0400 |
commit | 13d65c897e93dfeaed6fe28233559239f9676164 (patch) | |
tree | 0e68226def4d9b927ef44abbf6ac742a42680496 | |
parent | 063a5d011698950c86a01044394105605556e92c (diff) |
ARM: OMAP3: PM: cpuidle: optimize the PER latency in C1 state
One of the main contributors of the low power code latency is
the PER power domain. To optimize the high-performance and
low-latency C1 state, prevent any PER state which is lower
than the CORE state in C1.
Reported and suggested by Kevin Hilman.
Reported-by: Kevin Hilman <khilman@ti.com>
Signed-off-by: Jean Pihet <j-pihet@ti.com>
Signed-off-by: Kevin Hilman <khilman@ti.com>
-rw-r--r-- | arch/arm/mach-omap2/cpuidle34xx.c | 41 |
1 files changed, 22 insertions, 19 deletions
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index f619a928f01e..2e2f1c6f0f0b 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c | |||
@@ -222,23 +222,22 @@ static int next_valid_state(struct cpuidle_device *dev, | |||
222 | * the device to the specified or a safer state. | 222 | * the device to the specified or a safer state. |
223 | */ | 223 | */ |
224 | static int omap3_enter_idle_bm(struct cpuidle_device *dev, | 224 | static int omap3_enter_idle_bm(struct cpuidle_device *dev, |
225 | struct cpuidle_driver *drv, | 225 | struct cpuidle_driver *drv, |
226 | int index) | 226 | int index) |
227 | { | 227 | { |
228 | int new_state_idx; | 228 | int new_state_idx; |
229 | u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state; | 229 | u32 core_next_state, per_next_state = 0, per_saved_state = 0; |
230 | struct omap3_idle_statedata *cx; | 230 | struct omap3_idle_statedata *cx; |
231 | int ret; | 231 | int ret; |
232 | 232 | ||
233 | /* | 233 | /* |
234 | * Prevent idle completely if CAM is active. | 234 | * Use only C1 if CAM is active. |
235 | * CAM does not have wakeup capability in OMAP3. | 235 | * CAM does not have wakeup capability in OMAP3. |
236 | */ | 236 | */ |
237 | cam_state = pwrdm_read_pwrst(cam_pd); | 237 | if (pwrdm_read_pwrst(cam_pd) == PWRDM_POWER_ON) |
238 | if (cam_state == PWRDM_POWER_ON) { | ||
239 | new_state_idx = drv->safe_state_index; | 238 | new_state_idx = drv->safe_state_index; |
240 | goto select_state; | 239 | else |
241 | } | 240 | new_state_idx = next_valid_state(dev, drv, index); |
242 | 241 | ||
243 | /* | 242 | /* |
244 | * FIXME: we currently manage device-specific idle states | 243 | * FIXME: we currently manage device-specific idle states |
@@ -248,24 +247,28 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
248 | * its own code. | 247 | * its own code. |
249 | */ | 248 | */ |
250 | 249 | ||
251 | /* | 250 | /* Program PER state */ |
252 | * Prevent PER off if CORE is not in retention or off as this | 251 | cx = &omap3_idle_data[new_state_idx]; |
253 | * would disable PER wakeups completely. | ||
254 | */ | ||
255 | cx = &omap3_idle_data[index]; | ||
256 | core_next_state = cx->core_state; | 252 | core_next_state = cx->core_state; |
257 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); | 253 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); |
258 | if ((per_next_state == PWRDM_POWER_OFF) && | 254 | if (new_state_idx == 0) { |
259 | (core_next_state > PWRDM_POWER_RET)) | 255 | /* In C1 do not allow PER state lower than CORE state */ |
260 | per_next_state = PWRDM_POWER_RET; | 256 | if (per_next_state < core_next_state) |
257 | per_next_state = core_next_state; | ||
258 | } else { | ||
259 | /* | ||
260 | * Prevent PER OFF if CORE is not in RETention or OFF as this | ||
261 | * would disable PER wakeups completely. | ||
262 | */ | ||
263 | if ((per_next_state == PWRDM_POWER_OFF) && | ||
264 | (core_next_state > PWRDM_POWER_RET)) | ||
265 | per_next_state = PWRDM_POWER_RET; | ||
266 | } | ||
261 | 267 | ||
262 | /* Are we changing PER target state? */ | 268 | /* Are we changing PER target state? */ |
263 | if (per_next_state != per_saved_state) | 269 | if (per_next_state != per_saved_state) |
264 | pwrdm_set_next_pwrst(per_pd, per_next_state); | 270 | pwrdm_set_next_pwrst(per_pd, per_next_state); |
265 | 271 | ||
266 | new_state_idx = next_valid_state(dev, drv, index); | ||
267 | |||
268 | select_state: | ||
269 | ret = omap3_enter_idle(dev, drv, new_state_idx); | 272 | ret = omap3_enter_idle(dev, drv, new_state_idx); |
270 | 273 | ||
271 | /* Restore original PER state if it was modified */ | 274 | /* Restore original PER state if it was modified */ |
@@ -282,7 +285,7 @@ struct cpuidle_driver omap3_idle_driver = { | |||
282 | .owner = THIS_MODULE, | 285 | .owner = THIS_MODULE, |
283 | .states = { | 286 | .states = { |
284 | { | 287 | { |
285 | .enter = omap3_enter_idle, | 288 | .enter = omap3_enter_idle_bm, |
286 | .exit_latency = 2 + 2, | 289 | .exit_latency = 2 + 2, |
287 | .target_residency = 5, | 290 | .target_residency = 5, |
288 | .flags = CPUIDLE_FLAG_TIME_VALID, | 291 | .flags = CPUIDLE_FLAG_TIME_VALID, |