diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index b6b1ecfca652ea0cd03fc8ed1dd53babb4a3636b..d6826607efdad437edc1685a0fe1248c65067569 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1302,6 +1302,7 @@ struct intel_dp { u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS]; u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]; u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]; + u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE]; u8 fec_capable; /* source rates */ int num_source_rates; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 5a0a50d36dfb251f2f12c6d837852603f69517a2..2a7527108fa076cfcfac70945ac07498be690926 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4790,6 +4790,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) { int ret; + intel_dp_lttpr_init(intel_dp); + if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd)) return false; diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 71a8c9a546a332fa10aa6111bb52cceabee6d136..a19f0fd50c6931087795b8288f73239aed5145cf 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -34,6 +34,55 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE]) link_status[3], link_status[4], link_status[5]); } +static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp) +{ + if (drm_dp_read_lttpr_common_caps(&intel_dp->aux, + intel_dp->lttpr_common_caps) < 0) { + memset(intel_dp->lttpr_common_caps, 0, + sizeof(intel_dp->lttpr_common_caps)); + return false; + } + + drm_dbg_kms(&dp_to_i915(intel_dp)->drm, + "LTTPR common capabilities: %*ph\n", + (int)sizeof(intel_dp->lttpr_common_caps), + intel_dp->lttpr_common_caps); + + return true; +} + +static bool +intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable) +{ + u8 val = enable ? DP_PHY_REPEATER_MODE_TRANSPARENT : + DP_PHY_REPEATER_MODE_NON_TRANSPARENT; + + return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1; +} + +/** + * intel_dp_lttpr_init - detect LTTPRs and init the LTTPR link training mode + * @intel_dp: Intel DP struct + * + * Read the LTTPR common capabilities and switch to transparent link training + * mode. + */ +int intel_dp_lttpr_init(struct intel_dp *intel_dp) +{ + if (intel_dp_is_edp(intel_dp)) + return 0; + + intel_dp_read_lttpr_common_caps(intel_dp); + + /* + * See DP Standard v2.0 3.6.6.1. about the explicit disabling of + * non-transparent mode. + */ + intel_dp_set_lttpr_transparent_mode(intel_dp, true); + + return 0; +} + static u8 dp_voltage_max(u8 preemph) { switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) { @@ -492,6 +541,12 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp, void intel_dp_start_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { + /* + * TODO: Reiniting LTTPRs here won't be needed once proper connector + * HW state readout is added. + */ + intel_dp_lttpr_init(intel_dp); + if (!intel_dp_link_train(intel_dp, crtc_state)) intel_dp_schedule_fallback_link_training(intel_dp, crtc_state); } diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h index bf9474e41aedf9a19e10ec7eed9ac151f9f2ab7c..b3fb1d125b9b2acb529abc3cbe041dd664fb09a0 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h @@ -11,6 +11,8 @@ struct intel_crtc_state; struct intel_dp; +int intel_dp_lttpr_init(struct intel_dp *intel_dp); + void intel_dp_get_adjust_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, const u8 link_status[DP_LINK_STATUS_SIZE]);