/** * 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; }
/** * 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; }