void mainboard_train_link(struct intel_dp *intel_dp) { u8 read_val; u8 link_status[DP_LINK_STATUS_SIZE]; gtt_write(DP_TP_CTL(intel_dp->port),DP_TP_CTL_ENABLE | DP_TP_CTL_ENHANCED_FRAME_ENABLE); gtt_write(DP_A, DP_PORT_EN | DP_LINK_TRAIN_PAT_1 | DP_LINK_TRAIN_PAT_1_CPT | DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0 | DP_PORT_WIDTH_1 | DP_PLL_FREQ_270MHZ | DP_SYNC_VS_HIGH |0x80000011); intel_dp_get_training_pattern(intel_dp, &read_val); intel_dp_set_training_pattern(intel_dp, DP_TRAINING_PATTERN_1 | DP_LINK_QUAL_PATTERN_DISABLE | DP_SYMBOL_ERROR_COUNT_BOTH); intel_dp_get_lane_count(intel_dp, &read_val); intel_dp_set_training_lane0(intel_dp, DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0); intel_dp_get_link_status(intel_dp, link_status); gtt_write(DP_TP_CTL(intel_dp->port),DP_TP_CTL_ENABLE | DP_TP_CTL_ENHANCED_FRAME_ENABLE | DP_TP_CTL_LINK_TRAIN_PAT2); intel_dp_get_training_pattern(intel_dp, &read_val); intel_dp_set_training_pattern(intel_dp, DP_TRAINING_PATTERN_2 | DP_LINK_QUAL_PATTERN_DISABLE | DP_SYMBOL_ERROR_COUNT_BOTH); intel_dp_get_link_status(intel_dp, link_status); intel_dp_get_lane_align_status(intel_dp, &read_val); intel_dp_get_training_pattern(intel_dp, &read_val); intel_dp_set_training_pattern(intel_dp, DP_TRAINING_PATTERN_DISABLE | DP_LINK_QUAL_PATTERN_DISABLE | DP_SYMBOL_ERROR_COUNT_BOTH); }
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"); }
/* 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; } } }