示例#1
0
bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
{
	u8 link_status[DP_LINK_STATUS_SIZE];
	struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;

	if (!radeon_dp_get_link_status(radeon_connector, link_status))
		return false;
	if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))
		return false;
	return true;
}
示例#2
0
bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
{
	u8 link_status[DP_LINK_STATUS_SIZE];
	struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;

	if (drm_dp_dpcd_read_link_status(&radeon_connector->ddc_bus->aux, link_status)
	    <= 0)
		return false;
	if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))
		return false;
	return true;
}
示例#3
0
static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)
{
	bool channel_eq;

	if (dp_info->tp3_supported)
		radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);
	else
		radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);

	/* channel equalization loop */
	dp_info->tries = 0;
	channel_eq = false;
	while (1) {
		drm_dp_link_train_channel_eq_delay(dp_info->dpcd);

		if (drm_dp_dpcd_read_link_status(dp_info->aux,
						 dp_info->link_status) <= 0) {
			DRM_ERROR("displayport link status failed\n");
			break;
		}

		if (drm_dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
			channel_eq = true;
			break;
		}

		/* Try 5 times */
		if (dp_info->tries > 5) {
			DRM_ERROR("channel eq failed: 5 tries\n");
			break;
		}

		/* Compute new train_set as requested by sink */
		dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);

		radeon_dp_update_vs_emph(dp_info);
		dp_info->tries++;
	}

	if (!channel_eq) {
		DRM_ERROR("channel eq failed\n");
		return -1;
	} else {
		DRM_DEBUG_KMS("channel eq at voltage %d pre-emphasis %d\n",
			  dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
			  (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
			  >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
		return 0;
	}
}
示例#4
0
static int edp_start_link_train_2(struct edp_ctrl *ctrl)
{
	u8 link_status[DP_LINK_STATUS_SIZE];
	int tries = 0;
	int ret;
	int rlen;

	DBG("");

	edp_host_train_set(ctrl, DP_TRAINING_PATTERN_2);
	ret = edp_voltage_pre_emphasise_set(ctrl);
	if (ret)
		return ret;

	ret = edp_train_pattern_set_write(ctrl,
			DP_TRAINING_PATTERN_2 | DP_RECOVERED_CLOCK_OUT_EN);
	if (ret)
		return ret;

	while (1) {
		drm_dp_link_train_channel_eq_delay(ctrl->dpcd);

		rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status);
		if (rlen < DP_LINK_STATUS_SIZE) {
			pr_err("%s: read link status failed\n", __func__);
			return -ENOLINK;
		}
		if (drm_dp_channel_eq_ok(link_status, ctrl->lane_cnt)) {
			ret = 0;
			break;
		}

		tries++;
		if (tries > 10) {
			ret = -1;
			break;
		}

		edp_sink_train_set_adjust(ctrl, link_status);
		ret = edp_voltage_pre_emphasise_set(ctrl);
		if (ret)
			return ret;
	}

	return ret;
}
示例#5
0
/**
 * xilinx_drm_dp_link_train_ce - Train channel equalization
 * @dp: DisplayPort IP core structure
 *
 * Return: 0 if channel equalization train is done successfully, or
 * corresponding error code.
 */
static int xilinx_drm_dp_link_train_ce(struct xilinx_drm_dp *dp)
{
	u8 link_status[DP_LINK_STATUS_SIZE];
	u8 lane_cnt = dp->mode.lane_cnt;
	u32 pat, tries;
	int ret;
	bool ce_done;

	if (dp->config.dp_version == DP_V1_2 &&
	    dp->dpcd[DP_DPCD_REV] >= DP_V1_2 &&
	    dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED)
		pat = DP_TRAINING_PATTERN_3;
	else
		pat = DP_TRAINING_PATTERN_2;

	ret = xilinx_drm_dp_aux_write_byte(dp, DP_TRAINING_PATTERN_SET,
					   pat | DP_LINK_SCRAMBLING_DISABLE);
	if (ret)
		return ret;

	xilinx_drm_writel(dp->iomem, XILINX_DP_TX_TRAINING_PATTERN_SET, pat);

	for (tries = 0; tries < DP_MAX_TRAINING_TRIES; tries++) {
		ret = xilinx_drm_dp_update_vs_emph(dp);
		if (ret)
			return ret;

		drm_dp_link_train_channel_eq_delay(dp->dpcd);

		ret = xilinx_drm_dp_aux_read(dp, DP_LANE0_1_STATUS, link_status,
					     DP_LINK_STATUS_SIZE);
		if (ret)
			return ret;

		ce_done = drm_dp_channel_eq_ok(link_status, lane_cnt);
		if (ce_done)
			break;

		xilinx_drm_dp_adjust_train(dp, link_status);
	}

	if (!ce_done)
		ret = -EIO;

	return ret;
}
static void
intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
{
	bool channel_eq = false;
	int tries, cr_tries;
	u32 training_pattern;

	training_pattern = intel_dp_training_pattern(intel_dp);

	/* channel equalization */
	if (!intel_dp_set_link_train(intel_dp,
				     training_pattern |
				     DP_LINK_SCRAMBLING_DISABLE)) {
		DRM_ERROR("failed to start channel equalization\n");
		return;
	}

	tries = 0;
	cr_tries = 0;
	channel_eq = false;
	for (;;) {
		uint8_t link_status[DP_LINK_STATUS_SIZE];

		if (cr_tries > 5) {
			DRM_ERROR("failed to train DP, aborting\n");
			intel_dp_dump_link_status(link_status);
			break;
		}

		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
		if (!intel_dp_get_link_status(intel_dp, link_status)) {
			DRM_ERROR("failed to get link status\n");
			break;
		}

		/* Make sure clock is still ok */
		if (!drm_dp_clock_recovery_ok(link_status,
					      intel_dp->lane_count)) {
			intel_dp_link_training_clock_recovery(intel_dp);
			intel_dp_set_link_train(intel_dp,
						training_pattern |
						DP_LINK_SCRAMBLING_DISABLE);
			cr_tries++;
			continue;
		}

		if (drm_dp_channel_eq_ok(link_status,
					 intel_dp->lane_count)) {
			channel_eq = true;
			break;
		}

		/* Try 5 times, then try clock recovery if that fails */
		if (tries > 5) {
			intel_dp_link_training_clock_recovery(intel_dp);
			intel_dp_set_link_train(intel_dp,
						training_pattern |
						DP_LINK_SCRAMBLING_DISABLE);
			tries = 0;
			cr_tries++;
			continue;
		}

		/* Update training set as requested by target */
		intel_get_adjust_train(intel_dp, link_status);
		if (!intel_dp_update_link_train(intel_dp)) {
			DRM_ERROR("failed to update link training\n");
			break;
		}
		++tries;
	}

	intel_dp_set_idle_link_train(intel_dp);

	if (channel_eq)
		DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
}