/** * xilinx_drm_dp_link_train - Train the link * @dp: DisplayPort IP core structure * * Return: 0 if all trains are done successfully, or corresponding error code. */ static int xilinx_drm_dp_train(struct xilinx_drm_dp *dp) { u32 reg; u8 bw_code = dp->mode.bw_code; u8 lane_cnt = dp->mode.lane_cnt; u8 aux_lane_cnt; bool enhanced; int ret; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_LANE_CNT_SET, lane_cnt); enhanced = drm_dp_enhanced_frame_cap(dp->dpcd); if (enhanced) { xilinx_drm_writel(dp->iomem, XILINX_DP_TX_ENHANCED_FRAME_EN, 1); aux_lane_cnt = lane_cnt | DP_LANE_COUNT_ENHANCED_FRAME_EN; } ret = xilinx_drm_dp_aux_write_byte(dp, DP_LANE_COUNT_SET, aux_lane_cnt); if (ret) { DRM_ERROR("failed to set lane count\n"); return ret; } ret = xilinx_drm_dp_aux_write_byte(dp, DP_LINK_BW_SET, bw_code); if (ret) { DRM_ERROR("failed to set DP bandwidth\n"); return ret; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_LINK_BW_SET, bw_code); switch (bw_code) { case DP_LINK_BW_1_62: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_162; break; case DP_LINK_BW_2_7: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_270; break; case DP_LINK_BW_5_4: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_540; break; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING, reg); ret = xilinx_drm_dp_phy_ready(dp); if (ret < 0) return ret; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_SCRAMBLING_DISABLE, 1); memset(dp->train_set, 0, 4); ret = xilinx_drm_dp_link_train_cr(dp); if (ret) { DRM_ERROR("failed to train clock recovery\n"); reg = xilinx_drm_readl(dp->iomem, XILINX_DP_TX_PHY_STATUS); return ret; } ret = xilinx_drm_dp_link_train_ce(dp); if (ret) { DRM_ERROR("failed to train channel eq\n"); reg = xilinx_drm_readl(dp->iomem, XILINX_DP_TX_PHY_STATUS); return ret; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); ret = xilinx_drm_dp_aux_write_byte(dp, DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); if (ret) { DRM_ERROR("failed to disable training pattern\n"); return ret; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_SCRAMBLING_DISABLE, 0); return 0; }
/** * xilinx_drm_dp_link_train - Train the link * @dp: DisplayPort IP core structure * * Return: 0 if all trains are done successfully, or corresponding error code. */ static int xilinx_drm_dp_train(struct xilinx_drm_dp *dp) { u32 reg; u8 bw_code = dp->mode.bw_code; u8 lane_cnt = dp->mode.lane_cnt; u8 aux_lane_cnt = lane_cnt; bool enhanced; int ret; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_LANE_CNT_SET, lane_cnt); enhanced = drm_dp_enhanced_frame_cap(dp->dpcd); if (enhanced) { xilinx_drm_writel(dp->iomem, XILINX_DP_TX_ENHANCED_FRAME_EN, 1); aux_lane_cnt |= DP_LANE_COUNT_ENHANCED_FRAME_EN; } if (dp->dpcd[3] & 0x1) { xilinx_drm_writel(dp->iomem, XILINX_DP_TX_DOWNSPREAD_CTL, 1); drm_dp_dpcd_writeb(&dp->aux, DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); } else { xilinx_drm_writel(dp->iomem, XILINX_DP_TX_DOWNSPREAD_CTL, 0); drm_dp_dpcd_writeb(&dp->aux, DP_DOWNSPREAD_CTRL, 0); } ret = drm_dp_dpcd_writeb(&dp->aux, DP_LANE_COUNT_SET, aux_lane_cnt); if (ret < 0) { DRM_ERROR("failed to set lane count\n"); return ret; } ret = drm_dp_dpcd_writeb(&dp->aux, DP_MAIN_LINK_CHANNEL_CODING_SET, DP_SET_ANSI_8B10B); if (ret < 0) { DRM_ERROR("failed to set ANSI 8B/10B encoding\n"); return ret; } ret = drm_dp_dpcd_writeb(&dp->aux, DP_LINK_BW_SET, bw_code); if (ret < 0) { DRM_ERROR("failed to set DP bandwidth\n"); return ret; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_LINK_BW_SET, bw_code); switch (bw_code) { case DP_LINK_BW_1_62: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_162; break; case DP_LINK_BW_2_7: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_270; break; case DP_LINK_BW_5_4: default: reg = XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING_540; break; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_PHY_CLOCK_FEEDBACK_SETTING, reg); ret = xilinx_drm_dp_phy_ready(dp); if (ret < 0) return ret; xilinx_drm_writel(dp->iomem, XILINX_DP_TX_SCRAMBLING_DISABLE, 1); memset(dp->train_set, 0, 4); ret = xilinx_drm_dp_link_train_cr(dp); if (ret) { DRM_ERROR("failed to train clock recovery\n"); return ret; } ret = xilinx_drm_dp_link_train_ce(dp); if (ret) { DRM_ERROR("failed to train channel eq\n"); return ret; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); ret = drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); if (ret < 0) { DRM_ERROR("failed to disable training pattern\n"); return ret; } xilinx_drm_writel(dp->iomem, XILINX_DP_TX_SCRAMBLING_DISABLE, 0); return 0; }