/** * xilinx_drm_dp_link_train_cr - Train clock recovery * @dp: DisplayPort IP core structure * * Return: 0 if clock recovery train is done successfully, or corresponding * error code. */ static int xilinx_drm_dp_link_train_cr(struct xilinx_drm_dp *dp) { u8 link_status[DP_LINK_STATUS_SIZE]; u8 lane_cnt = dp->mode.lane_cnt; u8 vs = 0, tries = 0; u16 max_tries, i; bool cr_done; int ret; ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE); if (ret < 0) return ret; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_1); /* 256 loops should be maximum iterations for 4 lanes and 4 values. * So, This loop should exit before 512 iterations */ for (max_tries = 0; max_tries < 512; max_tries++) { ret = xilinx_drm_dp_update_vs_emph(dp); if (ret) return ret; drm_dp_link_train_clock_recovery_delay(dp->dpcd); ret = drm_dp_dpcd_read_link_status(&dp->aux, link_status); if (ret < 0) return ret; cr_done = drm_dp_clock_recovery_ok(link_status, lane_cnt); if (cr_done) break; for (i = 0; i < lane_cnt; i++) if (!(dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED)) break; if (i == lane_cnt) break; if ((dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == vs) tries++; else tries = 0; if (tries == DP_MAX_TRAINING_TRIES) break; vs = dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; xilinx_drm_dp_adjust_train(dp, link_status); } if (!cr_done) return -EIO; return 0; }
static int edp_start_link_train_1(struct edp_ctrl *ctrl) { u8 link_status[DP_LINK_STATUS_SIZE]; u8 old_v_level; int tries; int ret; int rlen; DBG(""); edp_host_train_set(ctrl, DP_TRAINING_PATTERN_1); ret = edp_voltage_pre_emphasise_set(ctrl); if (ret) return ret; ret = edp_train_pattern_set_write(ctrl, DP_TRAINING_PATTERN_1 | DP_RECOVERED_CLOCK_OUT_EN); if (ret) return ret; tries = 0; old_v_level = ctrl->v_level; while (1) { drm_dp_link_train_clock_recovery_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_clock_recovery_ok(link_status, ctrl->lane_cnt)) { ret = 0; break; } if (ctrl->v_level == DPCD_LINK_VOLTAGE_MAX) { ret = -1; break; } if (old_v_level == ctrl->v_level) { tries++; if (tries >= 5) { ret = -1; break; } } else { tries = 0; old_v_level = ctrl->v_level; } edp_sink_train_set_adjust(ctrl, link_status); ret = edp_voltage_pre_emphasise_set(ctrl); if (ret) return ret; } return ret; }
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; }
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 = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, pat | DP_LINK_SCRAMBLING_DISABLE); if (ret < 0) 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 = drm_dp_dpcd_read_link_status(&dp->aux, link_status); if (ret < 0) 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) return -EIO; return 0; }
static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info) { bool clock_recovery; u8 voltage; int i; radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1); memset(dp_info->train_set, 0, 4); radeon_dp_update_vs_emph(dp_info); udelay(400); /* clock recovery loop */ clock_recovery = false; dp_info->tries = 0; voltage = 0xff; while (1) { drm_dp_link_train_clock_recovery_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_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) { clock_recovery = true; break; } for (i = 0; i < dp_info->dp_lane_count; i++) { if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; } if (i == dp_info->dp_lane_count) { DRM_ERROR("clock recovery reached max voltage\n"); break; } if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { ++dp_info->tries; if (dp_info->tries == 5) { DRM_ERROR("clock recovery tried 5 times\n"); break; } } else dp_info->tries = 0; voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; /* 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); } if (!clock_recovery) { DRM_ERROR("clock recovery failed\n"); return -1; } else { DRM_DEBUG_KMS("clock recovery 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; } }