static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(dp_info->encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; u8 tmp; /* power up the sink */ if (dp_info->dpcd[0] >= 0x11) { radeon_write_dpcd_reg(dp_info->radeon_connector, DP_SET_POWER, DP_SET_POWER_D0); usleep_range(1000, 2000); } /* possibly enable downspread on the sink */ if (dp_info->dpcd[3] & 0x1) radeon_write_dpcd_reg(dp_info->radeon_connector, DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); else radeon_write_dpcd_reg(dp_info->radeon_connector, DP_DOWNSPREAD_CTRL, 0); if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) && (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { radeon_write_dpcd_reg(dp_info->radeon_connector, DP_EDP_CONFIGURATION_SET, 1); } /* set the lane count on the sink */ tmp = dp_info->dp_lane_count; if (drm_dp_enhanced_frame_cap(dp_info->dpcd)) tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN; radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp); /* set the link rate on the sink */ tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock); radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp); /* start training on the source */ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) atombios_dig_encoder_setup(dp_info->encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0); else radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_START, dp_info->dp_clock, dp_info->enc_id, 0); /* disable the training pattern on the sink */ radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE); 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; 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; }
/* Enable corresponding port and start training pattern 1 */ static void intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) { int i; uint8_t voltage; int voltage_tries, loop_tries; uint8_t link_config[2]; uint8_t link_bw, rate_select; if (intel_dp->prepare_link_retrain) intel_dp->prepare_link_retrain(intel_dp); intel_dp_compute_rate(intel_dp, intel_dp->link_rate, &link_bw, &rate_select); /* Write the link configuration data */ link_config[0] = link_bw; link_config[1] = intel_dp->lane_count; if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2); if (intel_dp->num_sink_rates) drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET, &rate_select, 1); link_config[0] = 0; link_config[1] = DP_SET_ANSI_8B10B; drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2); intel_dp->DP |= DP_PORT_EN; /* clock recovery */ if (!intel_dp_reset_link_train(intel_dp, DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE)) { DRM_ERROR("failed to enable link training\n"); return; } voltage = 0xff; voltage_tries = 0; loop_tries = 0; for (;;) { uint8_t link_status[DP_LINK_STATUS_SIZE]; drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd); if (!intel_dp_get_link_status(intel_dp, link_status)) { DRM_ERROR("failed to get link status\n"); break; } if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { DRM_DEBUG_KMS("clock recovery OK\n"); break; } /* Check to see if we've tried the max voltage */ for (i = 0; i < intel_dp->lane_count; i++) if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; if (i == intel_dp->lane_count) { ++loop_tries; if (loop_tries == 5) { DRM_ERROR("too many full retries, give up\n"); intel_dp_dump_link_status(link_status); break; } intel_dp_reset_link_train(intel_dp, DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE); voltage_tries = 0; continue; } /* Check to see if we've tried the same voltage 5 times */ if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { ++voltage_tries; if (voltage_tries == 5) { DRM_ERROR("too many voltage retries, give up\n"); break; } } else voltage_tries = 0; voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; /* 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; } } }