Ejemplo n.º 1
0
/**
 * 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);
}
Ejemplo n.º 3
0
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);
}
Ejemplo n.º 4
0
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;
}