static int edp_clear_training_pattern(struct edp_ctrl *ctrl) { int ret; ret = edp_train_pattern_set_write(ctrl, 0); drm_dp_link_train_channel_eq_delay(ctrl->dpcd); return ret; }
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; } }
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; }
/** * 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"); }