/** * omap3_enter_idle_bm - Checks for any bus activity * @dev: cpuidle device * @state: The target state to be programmed * * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This * function checks for any pending activity and then programs the * device to the specified or a safer state. */ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = next_valid_state(dev, state); u32 core_next_state, per_next_state = 0, per_saved_state = 0; u32 cam_state; struct omap3_processor_cx *cx; int ret; if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { BUG_ON(!dev->safe_state); new_state = dev->safe_state; goto select_state; } cx = cpuidle_get_statedata(state); core_next_state = cx->core_state; /* * FIXME: we currently manage device-specific idle states * for PER and CORE in combination with CPU-specific * idle states. This is wrong, and device-specific * idle managment needs to be separated out into * its own code. */ /* * Prevent idle completely if CAM is active. * CAM does not have wakeup capability in OMAP3. */ cam_state = pwrdm_read_pwrst(cam_pd); if (cam_state == PWRDM_POWER_ON) { new_state = dev->safe_state; goto select_state; } /* * Prevent PER off if CORE is not in retention or off as this * would disable PER wakeups completely. */ per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd); if ((per_next_state == PWRDM_POWER_OFF) && (core_next_state > PWRDM_POWER_RET)) per_next_state = PWRDM_POWER_RET; /* Are we changing PER target state? */ if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_next_state); select_state: dev->last_state = new_state; ret = omap3_enter_idle(dev, new_state); /* Restore original PER state if it was modified */ if (per_next_state != per_saved_state) pwrdm_set_next_pwrst(per_pd, per_saved_state); return ret; }
static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = next_valid_state(dev, state); if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { BUG_ON(!dev->safe_state); new_state = dev->safe_state; } dev->last_state = new_state; return omap3_enter_idle(dev, new_state); }
static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) { if (dev->safe_state) { /* fix cpuidle accounting for state change */ dev->last_state = dev->safe_state; return dev->safe_state->enter(dev, dev->safe_state); } else { omap_sram_idle(); return 0; } } return omap3_enter_idle(dev, state); }
/** * omap3_enter_idle - Programs OMAP3 to enter the specified state * @dev: cpuidle device * @state: The target state to be programmed * * Called from the CPUidle framework to program the device to the * specified target state selected by the governor. */ static int omap3_enter_idle(struct cpuidle_device *dev, struct cpuidle_state *state) { struct omap3_processor_cx *cx = cpuidle_get_statedata(state); struct timespec ts_preidle, ts_postidle, ts_idle; u32 mpu_state = cx->mpu_state, core_state = cx->core_state; current_cx_state = *cx; /* Used to keep track of the total time in idle */ getnstimeofday(&ts_preidle); local_irq_disable(); local_fiq_disable(); pwrdm_set_next_pwrst(mpu_pd, mpu_state); pwrdm_set_next_pwrst(core_pd, core_state); //&*&*&*BC1_110630: add cpu idle control flag if (omap_irq_pending() || need_resched() || omap3_idle_bm_check()) goto return_sleep_time; //&*&*&*BC2_110630: add cpu idle control flag if (cx->type == OMAP3_STATE_C1) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle); } /* Execute ARM wfi */ omap_sram_idle(); if (cx->type == OMAP3_STATE_C1) { pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle); pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle); } return_sleep_time: getnstimeofday(&ts_postidle); ts_idle = timespec_sub(ts_postidle, ts_preidle); local_irq_enable(); local_fiq_enable(); return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC; }
static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { if (omap3_idle_bm_check()) { /* Someone's busy, pick a safe idle state. */ if (dev->safe_state) { return dev->safe_state->enter(dev, dev->safe_state); } else { struct omap3_processor_cx *cx; cx = cpuidle_get_statedata(state); omap_sram_idle(cx->mpu_state); return 0; } } return omap3_enter_idle(dev, state); }
/** * omap3_enter_idle_bm - Checks for any bus activity * @dev: cpuidle device * @state: The target state to be programmed * * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This * function checks for any pending activity and then programs the * device to the specified or a safer state. */ static int omap3_enter_idle_bm(struct cpuidle_device *dev, struct cpuidle_state *state) { struct cpuidle_state *new_state = state; u32 per_state = PWRDM_POWER_RET; u32 saved_per_state = PWRDM_POWER_RET; u32 cam_state, usb_state, iva2_state; u32 sgx_state, dss_state, new_core_state; struct omap3_processor_cx *cx; int ret; if (state->flags & CPUIDLE_FLAG_CHECK_BM) { if (omap3_idle_bm_check()) { BUG_ON(!dev->safe_state); new_state = dev->safe_state; goto select_state; } cx = cpuidle_get_statedata(state); new_core_state = cx->core_state; /* Check if CORE is active, if yes, fallback to inactive */ if (!pwrdm_can_idle(core_pd)) new_core_state = PWRDM_POWER_INACTIVE; /* * Prevent idle completely if CAM is active. * CAM does not have wakeup capability in OMAP3. */ cam_state = pwrdm_get_idle_state(cam_pd); if (cam_state == PWRDM_POWER_ON) { new_state = dev->safe_state; goto select_state; } /* * Check if PER can idle or not. If we are not likely * to idle, deny PER off. This prevents unnecessary * context save/restore. */ saved_per_state = pwrdm_read_next_pwrst(per_pd); per_state = saved_per_state; if (pwrdm_can_idle(per_pd)) { /* * Prevent PER off if CORE is active as this * would disable PER wakeups completely */ if (per_state == PWRDM_POWER_OFF && new_core_state > PWRDM_POWER_RET) per_state = PWRDM_POWER_RET; } else if (saved_per_state == PWRDM_POWER_OFF) per_state = PWRDM_POWER_RET; /* * If we are attempting CORE off, check if any other * powerdomains are at retention or higher. CORE off causes * chipwide reset which would reset these domains also. */ if (new_core_state == PWRDM_POWER_OFF) { dss_state = pwrdm_get_idle_state(dss_pd); iva2_state = pwrdm_get_idle_state(iva2_pd); sgx_state = pwrdm_get_idle_state(sgx_pd); usb_state = pwrdm_get_idle_state(usb_pd); if (cam_state > PWRDM_POWER_OFF || dss_state > PWRDM_POWER_OFF || iva2_state > PWRDM_POWER_OFF || per_state > PWRDM_POWER_OFF || sgx_state > PWRDM_POWER_OFF || usb_state > PWRDM_POWER_OFF) new_core_state = PWRDM_POWER_RET; } /* Fallback to new target core state */ while (cx->core_state < new_core_state) { state--; cx = cpuidle_get_statedata(state); } new_state = state; /* Are we changing PER target state? */ if (per_state != saved_per_state) pwrdm_set_next_pwrst(per_pd, per_state); } select_state: dev->last_state = new_state; ret = omap3_enter_idle(dev, new_state); /* Restore potentially tampered PER state */ if (per_state != saved_per_state) pwrdm_set_next_pwrst(per_pd, saved_per_state); return ret; }