Example #1
0
/* VP force update method of voltage scaling */
int omap_vp_forceupdate_scale(struct voltagedomain *voltdm,
			      struct omap_volt_data *target_v)
{
	struct omap_vp_instance *vp = voltdm->vp;
	u32 vpconfig;
	u8 target_vsel, current_vsel;
	int ret, timeout = 0;
	unsigned long target_volt = omap_get_operation_voltage(target_v);

	/*
	 * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
	 * This is an additional allowance to ensure we are in proper state
	 * to enter into forceupdate state transition.
	 */
	omap_test_timeout((voltdm->read(vp->vstatus) & vp->common->vstatus_vpidle),
			VP_IDLE_TIMEOUT, timeout);

	if (timeout >= VP_IDLE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s:vdd_%s idletimdout forceupdate(v=%ld)\n",
			__func__, voltdm->name, target_volt);

	ret = omap_vc_pre_scale(voltdm, target_volt, target_v,
				&target_vsel, &current_vsel);
	if (ret)
		return ret;

	/*
	 * Clear all pending TransactionDone interrupt/status. Typical latency
	 * is <3us
	 */
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
		vp->common->ops->clear_txdone(vp->id);
		if (!vp->common->ops->check_txdone(vp->id))
			break;
		udelay(1);
	}
	if (timeout >= VP_TRANXDONE_TIMEOUT) {
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded."
			"Voltage change aborted target volt=%ld,"
			"target vsel=0x%02x, current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);
		return -ETIMEDOUT;
	}

	/* Configure for VP-Force Update */
	vpconfig = voltdm->read(vp->vpconfig);
	vpconfig &= ~(vp->common->vpconfig_initvdd |
			vp->common->vpconfig_forceupdate |
			vp->common->vpconfig_initvoltage_mask);
	vpconfig |= ((target_vsel <<
		      __ffs(vp->common->vpconfig_initvoltage_mask)));
	voltdm->write(vpconfig, vp->vpconfig);

	/* Trigger initVDD value copy to voltage processor */
	vpconfig |= vp->common->vpconfig_initvdd;
	voltdm->write(vpconfig, vp->vpconfig);

	/* Force update of voltage */
	vpconfig |= vp->common->vpconfig_forceupdate;
	voltdm->write(vpconfig, vp->vpconfig);

	/*
	 * Wait for TransactionDone. Typical latency is <200us.
	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
	 */
	timeout = 0;
	omap_test_timeout(vp->common->ops->check_txdone(vp->id),
			  VP_TRANXDONE_TIMEOUT, timeout);
	if (timeout >= VP_TRANXDONE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded. "
			"TRANXDONE never got set after the voltage update. "
			"target volt=%ld, target vsel=0x%02x, "
			"current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);

	omap_vc_post_scale(voltdm, target_volt, target_v,
			   target_vsel, current_vsel);

	/*
	 * Disable TransactionDone interrupt , clear all status, clear
	 * control registers
	 */
	timeout = 0;
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
		vp->common->ops->clear_txdone(vp->id);
		if (!vp->common->ops->check_txdone(vp->id))
			break;
		udelay(1);
	}

	if (timeout >= VP_TRANXDONE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded while"
			"trying to clear the TRANXDONE status. target volt=%ld,"
			"target vsel=0x%02x, current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);

	vpconfig = voltdm->read(vp->vpconfig);
	/* Clear initVDD copy trigger bit */
	vpconfig &= ~vp->common->vpconfig_initvdd;
	voltdm->write(vpconfig, vp->vpconfig);
	/* Clear force bit */
	vpconfig &= ~vp->common->vpconfig_forceupdate;
	voltdm->write(vpconfig, vp->vpconfig);

	return 0;
}
Example #2
0
/* VP force update method of voltage scaling */
int omap_vp_forceupdate_scale(struct voltagedomain *voltdm,
			      struct omap_volt_data *target_v)
{
	struct omap_vp_instance *vp;
	u32 vpconfig;
	u8 target_vsel, current_vsel;
	int ret, timeout = 0;
	unsigned long target_volt;

	if (IS_ERR_OR_NULL(voltdm)) {
		pr_err("%s: VDD specified does not exist!\n", __func__);
		return -EINVAL;
	}

	if (IS_ERR_OR_NULL(voltdm->write)) {
		pr_err("%s: No write API for writing vdd_%s regs\n",
		       __func__, voltdm->name);
		return -EINVAL;
	}

	if (IS_ERR_OR_NULL(target_v)) {
		pr_err("%s: No target_v info to scale vdd_%s\n",
		       __func__, voltdm->name);
		return -EINVAL;
	}

	vp = voltdm->vp;
	if (IS_ERR_OR_NULL(vp)) {
		pr_err("%s: No VP info for vdd_%s\n", __func__, voltdm->name);
		return -EINVAL;
	}

	target_volt = omap_get_operation_voltage(target_v);

	ret = _vp_wait_for_idle(voltdm, vp);
	if (ret) {
		_vp_controlled_err(vp, voltdm,
				   "%s: vdd_%s idle timedout (v=%ld)\n",
				   __func__, voltdm->name, target_volt);
		return ret;
	}

	ret = omap_vc_pre_scale(voltdm, target_volt, target_v,
				&target_vsel, &current_vsel);
	if (ret)
		return ret;

	/*
	 * Clear all pending TransactionDone interrupt/status. Typical latency
	 * is <3us
	 */
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
		vp->common->ops->clear_txdone(vp->id);
		if (!vp->common->ops->check_txdone(vp->id))
			break;
		udelay(1);
	}
	if (timeout >= VP_TRANXDONE_TIMEOUT) {
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded."
			"Voltage change aborted target volt=%ld,"
			"target vsel=0x%02x, current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);
		return -ETIMEDOUT;
	}

	vpconfig = _vp_set_init_voltage(voltdm, target_volt);

	/* Force update of voltage */
	voltdm->write(vpconfig | vp->common->vpconfig_forceupdate,
		      voltdm->vp->vpconfig);

	/*
	 * Wait for TransactionDone. Typical latency is <200us.
	 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
	 */
	timeout = 0;
	omap_test_timeout(vp->common->ops->check_txdone(vp->id),
			  VP_TRANXDONE_TIMEOUT, timeout);
	if (timeout >= VP_TRANXDONE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded. "
			"TRANXDONE never got set after the voltage update. "
			"target volt=%ld, target vsel=0x%02x, "
			"current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);

	omap_vc_post_scale(voltdm, target_volt, target_v,
			   target_vsel, current_vsel);

	/*
	 * Disable TransactionDone interrupt , clear all status, clear
	 * control registers
	 */
	timeout = 0;
	while (timeout++ < VP_TRANXDONE_TIMEOUT) {
		vp->common->ops->clear_txdone(vp->id);
		if (!vp->common->ops->check_txdone(vp->id))
			break;
		udelay(1);
	}

	if (timeout >= VP_TRANXDONE_TIMEOUT)
		_vp_controlled_err(vp, voltdm,
			"%s: vdd_%s TRANXDONE timeout exceeded while"
			"trying to clear the TRANXDONE status. target volt=%ld,"
			"target vsel=0x%02x, current_vsel=0x%02x\n",
			__func__, voltdm->name, target_volt,
			target_vsel, current_vsel);

	/* Clear force bit */
	voltdm->write(vpconfig, vp->vpconfig);

	return 0;
}