/**
 * 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;
}
示例#2
0
/*
 * This sets pwrdm state (other than mpu & core. Currently only ON &
 * RET are supported.
 */
int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
{
	u32 cur_state;
	int sleep_switch = 0;
	int ret = 0;

	if (pwrdm == NULL || IS_ERR(pwrdm))
		return -EINVAL;

	while (!(pwrdm->pwrsts & (1 << state))) {
		if (state == PWRDM_POWER_OFF)
			return ret;
		state--;
	}

	cur_state = pwrdm_read_next_pwrst(pwrdm);
	if (cur_state == state)
		return ret;

	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
		if ((pwrdm_read_pwrst(pwrdm) > state) &&
			(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
			sleep_switch = LOWPOWERSTATE_SWITCH;
		} else {
			clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
			pwrdm_wait_transition(pwrdm);
			sleep_switch = FORCEWAKEUP_SWITCH;
		}
	}

	ret = pwrdm_set_next_pwrst(pwrdm, state);
	if (ret) {
		printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
		       pwrdm->name);
		goto err;
	}

	switch (sleep_switch) {
	case FORCEWAKEUP_SWITCH:
		if (pwrdm->pwrdm_clkdms[0]->flags & CLKDM_CAN_ENABLE_AUTO)
			clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
		else
			clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
		break;
	case LOWPOWERSTATE_SWITCH:
		pwrdm_set_lowpwrstchange(pwrdm);
		break;
	default:
		return ret;
	}

	pwrdm_wait_transition(pwrdm);
	pwrdm_state_switch(pwrdm);
err:
	return ret;
}
示例#3
0
/*
 * This sets pwrdm state (other than mpu & core. Currently only ON &
 * RET are supported.
 */
int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
{
	u32 cur_state;
	int sleep_switch = -1;
	int ret = 0;
	int hwsup = 0;

	if (pwrdm == NULL || IS_ERR(pwrdm))
		return -EINVAL;

	while (!(pwrdm->pwrsts & (1 << state))) {
		if (state == PWRDM_POWER_OFF)
			return ret;
		state--;
	}

	cur_state = pwrdm_read_next_pwrst(pwrdm);
	if (cur_state == state)
		return ret;

	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
		if ((pwrdm_read_pwrst(pwrdm) > state) &&
			(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
			sleep_switch = LOWPOWERSTATE_SWITCH;
		} else {
			hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
			clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
			sleep_switch = FORCEWAKEUP_SWITCH;
		}
	}

	ret = pwrdm_set_next_pwrst(pwrdm, state);
	if (ret) {
		pr_err("%s: unable to set state of powerdomain: %s\n",
		       __func__, pwrdm->name);
		goto err;
	}

	switch (sleep_switch) {
	case FORCEWAKEUP_SWITCH:
		if (hwsup)
			clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
		else
			clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
		break;
	case LOWPOWERSTATE_SWITCH:
		pwrdm_set_lowpwrstchange(pwrdm);
		break;
	default:
		return ret;
	}

	pwrdm_state_switch(pwrdm);
err:
	return ret;
}
示例#4
0
/**
 * 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;
    u32 saved_mpu_state;

    current_cx_state = *cx;

    /* Used to keep track of the total time in idle */
    getnstimeofday(&ts_preidle);

    local_irq_disable();
    local_fiq_disable();

    if (!enable_off_mode) {
        if (mpu_state < PWRDM_POWER_RET)
            mpu_state = PWRDM_POWER_RET;
        if (core_state < PWRDM_POWER_RET)
            core_state = PWRDM_POWER_RET;
    }

    if (omap_irq_pending() || need_resched())
        goto return_sleep_time;

    saved_mpu_state = pwrdm_read_next_pwrst(mpu_pd);
    pwrdm_set_next_pwrst(mpu_pd, mpu_state);
    pwrdm_set_next_pwrst(core_pd, core_state);

    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);
    }

    pwrdm_set_next_pwrst(mpu_pd, saved_mpu_state);

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;
}
示例#5
0
文件: pm.c 项目: ivdok/linux
/*
 * This sets pwrdm state (other than mpu & core. Currently only ON &
 * RET are supported.
 */
int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 pwrst)
{
	u8 curr_pwrst, next_pwrst;
	int sleep_switch = -1, ret = 0, hwsup = 0;

	if (!pwrdm || IS_ERR(pwrdm))
		return -EINVAL;

	while (!(pwrdm->pwrsts & (1 << pwrst))) {
		if (pwrst == PWRDM_POWER_OFF)
			return ret;
		pwrst--;
	}

	next_pwrst = pwrdm_read_next_pwrst(pwrdm);
	if (next_pwrst == pwrst)
		return ret;

	curr_pwrst = pwrdm_read_pwrst(pwrdm);
	if (curr_pwrst < PWRDM_POWER_ON) {
		if ((curr_pwrst > pwrst) &&
			(pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE)) {
			sleep_switch = LOWPOWERSTATE_SWITCH;
		} else {
			hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
			clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
			sleep_switch = FORCEWAKEUP_SWITCH;
		}
	}

	ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
	if (ret)
		pr_err("%s: unable to set power state of powerdomain: %s\n",
		       __func__, pwrdm->name);

	switch (sleep_switch) {
	case FORCEWAKEUP_SWITCH:
		if (hwsup)
			clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
		else
			clkdm_sleep(pwrdm->pwrdm_clkdms[0]);
		break;
	case LOWPOWERSTATE_SWITCH:
		pwrdm_set_lowpwrstchange(pwrdm);
		pwrdm_wait_transition(pwrdm);
		pwrdm_state_switch(pwrdm);
		break;
	}

	return ret;
}
示例#6
0
/*
 * This sets pwrdm state (other than mpu & core. Currently only ON &
 * RET are supported. Function is assuming that clkdm doesn't have
 * hw_sup mode enabled.
 */
int omap_set_pwrdm_state(struct powerdomain *pwrdm, u32 state)
{
	u32 cur_state;
	int sleep_switch = 0;
	int ret = 0;

	if (pwrdm == NULL || IS_ERR(pwrdm))
		return -EINVAL;

	while (!(pwrdm->pwrsts & (1 << state))) {
		if (state == PWRDM_POWER_OFF)
			return ret;
		state--;
	}

	cur_state = pwrdm_read_next_pwrst(pwrdm);
	if (cur_state == state)
		return ret;

	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
		omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
		sleep_switch = 1;
		pwrdm_wait_transition(pwrdm);
	}

	ret = pwrdm_set_next_pwrst(pwrdm, state);
	if (ret) {
		printk(KERN_ERR "Unable to set state of powerdomain: %s\n",
		       pwrdm->name);
		goto err;
	}

	if (sleep_switch) {
		omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
		pwrdm_wait_transition(pwrdm);
		pwrdm_state_switch(pwrdm);
	}

err:
	return ret;
}
/*
 * FIXME: This function should be called before entering off-mode after
 * OMAP3 secure services have been accessed. Currently it is only called
 * once during boot sequence, but this works as we are not using secure
 * services.
 */
static void omap3_save_secure_ram_context(void)
{
	u32 ret;
	int mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);

	if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
		/*
		 * MPU next state must be set to POWER_ON temporarily,
		 * otherwise the WFI executed inside the ROM code
		 * will hang the system.
		 */
		pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
		ret = _omap_save_secure_sram((u32 *)
				__pa(omap3_secure_ram_storage));
		pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
		/* Following is for error tracking, it should not happen */
		if (ret) {
			printk(KERN_ERR "save_secure_sram() returns %08x\n",
				ret);
			while (1)
				;
		}
	}
}
示例#8
0
/*
 * OMAP4 MPUSS Low Power Entry Function
 *
 * The purpose of this function is to manage low power programming
 * of OMAP4 MPUSS subsystem
 * Paramenters:
 *	cpu : CPU ID
 *	power_state: Targetted Low power state.
 *
 * MPUSS Low power states
 * The basic rule is that the MPUSS power domain must be at the higher or
 * equal power state (state that consume more power) than the higher of the
 * two CPUs. For example, it is illegal for system power to be OFF, while
 * the power of one or both of the CPU is DORMANT. When an illegal state is
 * entered, then the hardware behavior is unpredictable.
 *
 * MPUSS state for the context save
 * save_state =
 *	0 - Nothing lost and no need to save: MPUSS INACTIVE
 *	1 - CPUx L1 and logic lost: MPUSS CSWR
 *	2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
 *	3 - CPUx L1 and logic lost + GIC + L2 lost: MPUSS OFF
 */
void omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
{
	unsigned int save_state, wakeup_cpu;

	if (cpu > NR_CPUS)
		return;

	/*
	 * Low power state not supported on ES1.0 silicon
	 */
	if (omap_rev() == OMAP4430_REV_ES1_0) {
		wmb();
		do_wfi();
		return;
	}

	switch (power_state) {
	case PWRDM_POWER_ON:
	case PWRDM_POWER_INACTIVE:
		save_state = 0;
		break;
	case PWRDM_POWER_OFF:
		save_state = 1;
		setup_wakeup_routine(cpu);
		save_local_timers(cpu);
		break;
	case PWRDM_POWER_RET:
		/*
		 * CPUx CSWR is invalid hardware state. Additionally
		 * CPUx OSWR  doesn't give any gain vs CPUxOFF and
		 * hence not supported
		 */
	default:
		/* Invalid state */
		pr_debug("Invalid CPU low power state\n");
		return;
	}

	/*
	 * MPUSS book keeping should be executed by master
	 * CPU only which is the last CPU to go down
	 */
	if (cpu)
		goto cpu_prepare;
	/*
	 * Check MPUSS next state and save GIC if needed
	 * GIC lost during MPU OFF and OSWR
	 */
	pwrdm_clear_all_prev_pwrst(mpuss_pd);
	if (omap4_device_off_read_next_state() &&
			 (omap_type() != OMAP2_DEVICE_TYPE_GP)) {
		/* FIXME: Check if this can be optimised */
		save_secure_all();
		save_ivahd_tesla_regs();
		save_l3instr_regs();
		save_state = 3;
		goto cpu_prepare;
	}

	switch (pwrdm_read_next_pwrst(mpuss_pd)) {
	case PWRDM_POWER_ON:
	case PWRDM_POWER_INACTIVE:
		/* No need to save MPUSS context */
		break;
	case PWRDM_POWER_RET:
		/* MPUSS OSWR, logic lost */
		if (pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF) {
			if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
				save_gic_wakeupgen_secure();
				save_l3instr_regs();
			} else {
				save_gic();
				omap4_wakeupgen_save();
			}
			save_state = 2;
		}
		break;
	case PWRDM_POWER_OFF:
		/* MPUSS OFF */
		if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
			save_secure_ram();
			save_gic_wakeupgen_secure();
			save_ivahd_tesla_regs();
			save_l3instr_regs();
		} else {
			save_gic();
			omap4_wakeupgen_save();
		}
		save_state = 3;
		break;
	default:
		/* Fall through */
		;
	}

	/*
	 * Program the CPU targeted state
	 */
cpu_prepare:
	clear_cpu_prev_pwrst(cpu);
	if (cpu)
		pwrdm_set_next_pwrst(cpu1_pwrdm, power_state);
	else
		pwrdm_set_next_pwrst(cpu0_pwrdm, power_state);
	scu_pwrst_prepare(cpu, power_state);

	/*
	 * Call low level routine to enter to
	 * targeted power state
	 */
	__omap4_cpu_suspend(cpu, save_state);
	wakeup_cpu = hard_smp_processor_id();

	/*
	 * Restore the CPUx and mpuss power state to ON otherwise
	 * CPUx power domain can transitions to programmed low power
	 * state while doing WFI outside the low powe code. On HS devices,
	 * CPUx can do WFI outside idle thread  which can result in
	 * power domain domain transition if the previous state was
	 * programmed to OFF/RET.
	 */
	if (wakeup_cpu) {
		pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON);
	} else {
		pwrdm_set_next_pwrst(cpu0_pwrdm, PWRDM_POWER_ON);
		pwrdm_set_next_pwrst(mpuss_pd, PWRDM_POWER_ON);
	}

	/*
	 * Check the CPUx previous power state
	 */
	if (read_cpu_prev_pwrst(wakeup_cpu) == PWRDM_POWER_OFF) {
		cpu_init();
		restore_mmu_table_entry();
		restore_local_timers(wakeup_cpu);
	}

	/*
	 * Check MPUSS previous power state and enable
	 * GIC if needed.
	 */
	switch (pwrdm_read_prev_pwrst(mpuss_pd)) {
	case PWRDM_POWER_ON:
		/* No need to restore */
		break;
	case PWRDM_POWER_RET:
		/* FIXME:
		 * if (pwrdm_read_prev_logic_pwrst(mpuss_pd) == PWRDM_POWER_OFF)
		 */
		if (omap_readl(0x4a306324) == PWRDM_POWER_OFF)
			break;
	case PWRDM_POWER_OFF:
		/*
		 * Enable GIC distributor
		 */
		if (!wakeup_cpu) {
			if ((omap_type() == OMAP2_DEVICE_TYPE_GP)
					&& omap4_device_off_read_prev_state()) {
				restore_gic();
				omap4_wakeupgen_restore();
			}
			enable_gic_distributor();
			if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
				restore_ivahd_tesla_regs();
				restore_l3instr_regs();
			}
		}
		/*
		 * Enable GIC cpu inrterface
		 */
		enable_gic_cpu_interface();
		break;
	default:
		;
	}

}
/**
 * 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 core_next_state, per_next_state = 0, per_saved_state = 0;
	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);

	/*
	 * Don't allow PER to go to OFF in idle state
	 * transitions.
	 * This is a tempory fix for display flashing issue
	 * which occurs when off mode is enabled
	 */

	per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
	if (per_next_state == PWRDM_POWER_OFF)
		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);


	if (omap_irq_pending() || need_resched())
		goto return_sleep_time;

	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);

	/* Restore original PER state if it was modified */
	if (per_next_state != per_saved_state)
		pwrdm_set_next_pwrst(per_pd, per_saved_state);

	local_irq_enable();
	local_fiq_enable();

	return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
}
示例#10
0
/**
 * omap4_enter_lowpower: OMAP4 MPUSS Low Power Entry Function
 * The purpose of this function is to manage low power programming
 * of OMAP4 MPUSS subsystem
 * @cpu : CPU ID
 * @power_state: Low power state.
 *
 * MPUSS states for the context save:
 * save_state =
 *	0 - Nothing lost and no need to save: MPUSS INACTIVE
 *	1 - CPUx L1 and logic lost: MPUSS CSWR
 *	2 - CPUx L1 and logic lost + GIC lost: MPUSS OSWR
 *	3 - CPUx L1 and logic lost + GIC + L2 lost: DEVICE OFF
 */
int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
{
	unsigned int save_state = 0;
	unsigned int wakeup_cpu;

	if (omap_rev() == OMAP4430_REV_ES1_0)
		return -ENXIO;

	switch (power_state) {
	case PWRDM_POWER_ON:
	case PWRDM_POWER_INACTIVE:
		save_state = 0;
		break;
	case PWRDM_POWER_OFF:
		save_state = 1;
		break;
	case PWRDM_POWER_RET:
	default:
		/*
		 * CPUx CSWR is invalid hardware state. Also CPUx OSWR
		 * doesn't make much scense, since logic is lost and $L1
		 * needs to be cleaned because of coherency. This makes
		 * CPUx OSWR equivalent to CPUX OFF and hence not supported
		 */
		WARN_ON(1);
		return -ENXIO;
	}

	pwrdm_pre_transition(NULL);

	/*
	 * Check MPUSS next state and save interrupt controller if needed.
	 * In MPUSS OSWR or device OFF, interrupt controller  contest is lost.
	 */
	mpuss_clear_prev_logic_pwrst();
	if ((pwrdm_read_next_pwrst(mpuss_pd) == PWRDM_POWER_RET) &&
		(pwrdm_read_logic_retst(mpuss_pd) == PWRDM_POWER_OFF))
		save_state = 2;

	cpu_clear_prev_logic_pwrst(cpu);
	set_cpu_next_pwrst(cpu, power_state);
	set_cpu_wakeup_addr(cpu, virt_to_phys(omap4_cpu_resume));
	scu_pwrst_prepare(cpu, power_state);
	l2x0_pwrst_prepare(cpu, save_state);

	/*
	 * Call low level function  with targeted low power state.
	 */
	cpu_suspend(save_state, omap4_finish_suspend);

	/*
	 * Restore the CPUx power state to ON otherwise CPUx
	 * power domain can transitions to programmed low power
	 * state while doing WFI outside the low powe code. On
	 * secure devices, CPUx does WFI which can result in
	 * domain transition
	 */
	wakeup_cpu = smp_processor_id();
	set_cpu_next_pwrst(wakeup_cpu, PWRDM_POWER_ON);

	pwrdm_post_transition(NULL);

	return 0;
}
示例#11
0
/**
 * power_domain_test - Test the power domain APIs
 *
 * Test the power domain APIs for all power domains
 *
 */
void power_domain_test()
{
	int bank, i;
	int val = -EINVAL;
	static struct powerdomain *p, *pwrdm;

	for (i = 0; powerdomains_omap[i] != NULL; i++)	{
		p = powerdomains_omap[i];
		pwrdm = pwrdm_lookup(p->name);
		if (pwrdm)
			printk(KERN_INFO "PWR DM No%d = %s\n", i, pwrdm->name);
		else
			printk(KERN_INFO "PWR DM %s not supported\n", p->name);
	}

	/* i starts from 1 as gfx_pwrdm not supported in ES3.1.1 */
	for (i = 1; powerdomains_omap[i] != NULL; i++)	{
		val = pwrdm_add_clkdm(p = powerdomains_omap[i], &dummy_clkdm);
		if (val == 0)
			printk(KERN_INFO "Clock Domain Registered for %s\n",
							 p->name);
		else if (val == -EINVAL)
			printk(KERN_ERR "Clock Domain Register FAILED!!! for"
				" %s\n", p->name);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++)	{
		val = pwrdm_del_clkdm(p = powerdomains_omap[i], &dummy_clkdm);
		if (val == 0)
			printk(KERN_INFO "Clock Domain Unregistered for %s\n",
							 p->name);
		else if (val == -EINVAL)
			printk(KERN_ERR "Clock Domain Unregister FAILED!!! for"
				" %s\n", p->name);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_get_mem_bank_count(p = powerdomains_omap[i]);
		printk(KERN_INFO "Bnk Cnt for %s = %d\n", p->name, val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_read_logic_pwrst(p = powerdomains_omap[i]);
		printk(KERN_INFO "PwrState of %s = %d\n", p->name, val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_set_logic_retst(p = powerdomains_omap[i],
						 PWRDM_POWER_OFF);
		if (val == 0)
			printk(KERN_INFO "Logic RET State OFF for %s Set\n",
							 p->name);
		else if (val == -EINVAL)
			printk(KERN_INFO "OFF State not supported for %s\n",
							 p->name);
		else
			printk(KERN_ERR "Set Logic RET State OFF FAILED!!!"
				" with value %d\n", val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_set_logic_retst(p = powerdomains_omap[i],
						 PWRDM_POWER_RET);
		if (val == 0)
			printk(KERN_INFO "Logic RET State RET for %s Set\n",
							 p->name);
		else if (val == -EINVAL)
			printk(KERN_INFO "RET State not supported for %s\n",
							 p->name);
		else
			printk(KERN_ERR "Logic RET State RET FAILED!!!"
				" with value %d\n", val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_read_pwrst(p = powerdomains_omap[i]);
		printk(KERN_INFO "PwrState of %s = %d\n", p->name, val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_set_next_pwrst(p = powerdomains_omap[i],
						 PWRDM_POWER_OFF);
		if (val == 0)
			printk(KERN_INFO "Next PWRST for %s Set to OFF\n",
							 p->name);
		else if (val == -EINVAL)
			printk(KERN_INFO "OFF not supported for %s\n",
							 p->name);
		else
			printk(KERN_ERR "Next PWRST Set to OFF FAILED!!!"
				" with value %d\n", val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_set_next_pwrst(p = powerdomains_omap[i],
						 PWRDM_POWER_RET);
		if (val == 0)
			printk(KERN_INFO "Next PWRST for %s Set to RET\n",
							 p->name);
		else if (val == -EINVAL)
			printk(KERN_INFO "RET not supported for %s\n",
							 p->name);
		else
			printk(KERN_ERR "Next PWRST Set to RET FAILED!!!"
				" with value %d\n", val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_set_next_pwrst(p = powerdomains_omap[i],
						 PWRDM_POWER_ON);
		if (val == 0)
			printk(KERN_INFO "Next PWRST for %s Set to ON\n",
							 p->name);
		else if (val == -EINVAL)
			printk(KERN_INFO "ON not supported for %s\n",
							 p->name);
		else
			printk(KERN_ERR "Next PWRST Set to ON FAILED!!!"
				" with value %d\n", val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_read_next_pwrst(p = powerdomains_omap[i]);
		printk(KERN_INFO "Next Power State of %s = %d\n",
							 p->name, val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		val = pwrdm_read_pwrst(p = powerdomains_omap[i]);
		printk(KERN_INFO "Current Power State of %s = %d\n",
							 p->name, val);
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) {
			val = pwrdm_set_mem_onst(p = powerdomains_omap[i],
						 bank, PWRDM_POWER_OFF);
			if (val == 0)
				printk(KERN_INFO "Memory ON State OFF for %s"
							" Set\n", p->name);
			else if (val == -EINVAL)
				printk(KERN_INFO "OFF State not supported"
						" for %s\n", p->name);
			else if (val == -EEXIST)
				printk(KERN_ERR "Memory Bank %d not present"
						" for %s\n", bank, p->name);
			else
				printk(KERN_ERR "Memory ON State OFF FAILED!!!"
					" with value %d\n", val);
		}
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) {
			val = pwrdm_set_mem_onst(p = powerdomains_omap[i],
						 bank, PWRDM_POWER_RET);
			if (val == 0)
				printk(KERN_INFO "Memory ON State RET for %s"
							" Set\n", p->name);
			else if (val == -EINVAL)
				printk(KERN_INFO "RET State not supported"
						" for %s\n", p->name);
			else if (val == -EEXIST)
				printk(KERN_ERR "Memory Bank %d not present"
						" for %s\n", bank, p->name);
			else
				printk(KERN_ERR "Memory ON State RET FAILED!!!"
					" with value %d\n", val);
		}
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) {
			val = pwrdm_set_mem_retst(p = powerdomains_omap[i],
						bank, PWRDM_POWER_OFF);
			if (val == 0)
				printk(KERN_INFO "Memory RET State OFF for"
							" %s Set\n", p->name);
			else if (val == -EINVAL)
				printk(KERN_INFO "OFF State not supported for"
							" %s\n", p->name);
			else if (val == -EEXIST)
				printk(KERN_ERR "Memory Bank %d not present"
						" for %s\n", bank, p->name);
			else
				printk(KERN_ERR "Memory ON State OFF FAILED!!!"
					" with value %d\n", val);
		}
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) {
			val = pwrdm_set_mem_retst(p = powerdomains_omap[i],
						bank, PWRDM_POWER_RET);
			if (val == 0)
				printk(KERN_INFO "Memory RET State RET for"
							" %s Set\n", p->name);
			else if (val == -EINVAL)
				printk(KERN_INFO "RET State not supported for"
							" %s\n", p->name);
			else if (val == -EEXIST)
				printk(KERN_ERR "Memory Bank %d not present"
						" for %s\n", bank, p->name);
			else
				printk(KERN_ERR "MEM PWRST Set FAILED!!!"
						" with value %d\n", val);
		}
	}

	for (i = 1; powerdomains_omap[i] != NULL; i++) {
		for (bank = 0; bank < PWRDM_MAX_MEM_BANKS; bank++) {
			val = pwrdm_read_mem_pwrst(p = powerdomains_omap[i],
									bank);
			if (val == -EEXIST)
				printk(KERN_ERR "Memory Bank %d not present"
						" for %s\n", bank, p->name);
			else if (val == -EINVAL)
				printk(KERN_ERR "MEM PWRST Read FAILED!!!"
						" with value %d\n", val);
			else
				printk(KERN_INFO "MEM PWRST for bank %d of"
					" %s = %d\n", bank, p->name, val);
		}
	}
}
static int pwrdm_get_idle_state(struct powerdomain *pwrdm)
{
	if (pwrdm_can_idle(pwrdm))
		return pwrdm_read_next_pwrst(pwrdm);
	return PWRDM_POWER_ON;
}
/**
 * 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;
}