diff options
Diffstat (limited to 'arch/arm/mach-omap2/cpuidle34xx.c')
-rw-r--r-- | arch/arm/mach-omap2/cpuidle34xx.c | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c index 3d3d035db9af..8ea012ef0b5a 100644 --- a/arch/arm/mach-omap2/cpuidle34xx.c +++ b/arch/arm/mach-omap2/cpuidle34xx.c | |||
@@ -60,7 +60,8 @@ struct omap3_processor_cx { | |||
60 | 60 | ||
61 | struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; | 61 | struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES]; |
62 | struct omap3_processor_cx current_cx_state; | 62 | struct omap3_processor_cx current_cx_state; |
63 | struct powerdomain *mpu_pd, *core_pd; | 63 | struct powerdomain *mpu_pd, *core_pd, *per_pd; |
64 | struct powerdomain *cam_pd; | ||
64 | 65 | ||
65 | /* | 66 | /* |
66 | * The latencies/thresholds for various C states have | 67 | * The latencies/thresholds for various C states have |
@@ -233,14 +234,62 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev, | |||
233 | struct cpuidle_state *state) | 234 | struct cpuidle_state *state) |
234 | { | 235 | { |
235 | struct cpuidle_state *new_state = next_valid_state(dev, state); | 236 | struct cpuidle_state *new_state = next_valid_state(dev, state); |
237 | u32 core_next_state, per_next_state = 0, per_saved_state = 0; | ||
238 | u32 cam_state; | ||
239 | struct omap3_processor_cx *cx; | ||
240 | int ret; | ||
236 | 241 | ||
237 | if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { | 242 | if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { |
238 | BUG_ON(!dev->safe_state); | 243 | BUG_ON(!dev->safe_state); |
239 | new_state = dev->safe_state; | 244 | new_state = dev->safe_state; |
245 | goto select_state; | ||
246 | } | ||
247 | |||
248 | cx = cpuidle_get_statedata(state); | ||
249 | core_next_state = cx->core_state; | ||
250 | |||
251 | /* | ||
252 | * FIXME: we currently manage device-specific idle states | ||
253 | * for PER and CORE in combination with CPU-specific | ||
254 | * idle states. This is wrong, and device-specific | ||
255 | * idle managment needs to be separated out into | ||
256 | * its own code. | ||
257 | */ | ||
258 | |||
259 | /* | ||
260 | * Prevent idle completely if CAM is active. | ||
261 | * CAM does not have wakeup capability in OMAP3. | ||
262 | */ | ||
263 | cam_state = pwrdm_read_pwrst(cam_pd); | ||
264 | if (cam_state == PWRDM_POWER_ON) { | ||
265 | new_state = dev->safe_state; | ||
266 | goto select_state; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * Prevent PER off if CORE is not in retention or off as this | ||
271 | * would disable PER wakeups completely. | ||
272 | */ | ||
273 | per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); | ||
274 | if ((per_next_state == PWRDM_POWER_OFF) && | ||
275 | (core_next_state > PWRDM_POWER_RET)) { | ||
276 | per_next_state = PWRDM_POWER_RET; | ||
277 | pwrdm_set_next_pwrst(per_pd, per_next_state); | ||
240 | } | 278 | } |
241 | 279 | ||
280 | /* Are we changing PER target state? */ | ||
281 | if (per_next_state != per_saved_state) | ||
282 | pwrdm_set_next_pwrst(per_pd, per_next_state); | ||
283 | |||
284 | select_state: | ||
242 | dev->last_state = new_state; | 285 | dev->last_state = new_state; |
243 | return omap3_enter_idle(dev, new_state); | 286 | ret = omap3_enter_idle(dev, new_state); |
287 | |||
288 | /* Restore original PER state if it was modified */ | ||
289 | if (per_next_state != per_saved_state) | ||
290 | pwrdm_set_next_pwrst(per_pd, per_saved_state); | ||
291 | |||
292 | return ret; | ||
244 | } | 293 | } |
245 | 294 | ||
246 | DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); | 295 | DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev); |
@@ -328,7 +377,8 @@ void omap_init_power_states(void) | |||
328 | cpuidle_params_table[OMAP3_STATE_C2].threshold; | 377 | cpuidle_params_table[OMAP3_STATE_C2].threshold; |
329 | omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; | 378 | omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON; |
330 | omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; | 379 | omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON; |
331 | omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID; | 380 | omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID | |
381 | CPUIDLE_FLAG_CHECK_BM; | ||
332 | 382 | ||
333 | /* C3 . MPU CSWR + Core inactive */ | 383 | /* C3 . MPU CSWR + Core inactive */ |
334 | omap3_power_states[OMAP3_STATE_C3].valid = | 384 | omap3_power_states[OMAP3_STATE_C3].valid = |
@@ -426,6 +476,8 @@ int __init omap3_idle_init(void) | |||
426 | 476 | ||
427 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); | 477 | mpu_pd = pwrdm_lookup("mpu_pwrdm"); |
428 | core_pd = pwrdm_lookup("core_pwrdm"); | 478 | core_pd = pwrdm_lookup("core_pwrdm"); |
479 | per_pd = pwrdm_lookup("per_pwrdm"); | ||
480 | cam_pd = pwrdm_lookup("cam_pwrdm"); | ||
429 | 481 | ||
430 | omap_init_power_states(); | 482 | omap_init_power_states(); |
431 | cpuidle_register_driver(&omap3_idle_driver); | 483 | cpuidle_register_driver(&omap3_idle_driver); |