On Thu, Oct 07, 2021 at 04:39:08PM +0300, Jani Nikula wrote: > The 128b/132b channel coding link training uses more straightforward TX > FFE preset values. Reuse voltage tries and max vswing for retry logic. > > The delays for 128b/132b are still all wrong, but this is regardless a > step forward. > > v2: Fix UHBR rate checks, use intel_dp_is_uhbr() helper > > v3: > - Rebase > - Modify intel_dp_adjust_request_changed() and > intel_dp_link_max_vswing_reached() to take 128b/132b into > account. (Ville) > > v4: > - Train request printing for TX FFE (Ville) > - Log 8b/10b vs. 128b/132b (Ville) > - Add helper for per-lane max vswing / tx ffe (Ville) > - Name functions with tx_ffe/vswing instead of 128b132b/8b10b > > Cc: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > Reviewed-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> # v3 v4 looks even better Reviewed-by: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> > --- > drivers/gpu/drm/i915/display/intel_ddi.c | 18 ++- > .../drm/i915/display/intel_dp_link_training.c | 152 ++++++++++++++---- > 2 files changed, 134 insertions(+), 36 deletions(-) > > diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c > index 3f7bbeb3e3cd..59428ce4f8c1 100644 > --- a/drivers/gpu/drm/i915/display/intel_ddi.c > +++ b/drivers/gpu/drm/i915/display/intel_ddi.c > @@ -1338,13 +1338,20 @@ static int translate_signal_level(struct intel_dp *intel_dp, > return 0; > } > > -static int intel_ddi_dp_level(struct intel_dp *intel_dp, int lane) > +static int intel_ddi_dp_level(struct intel_dp *intel_dp, > + const struct intel_crtc_state *crtc_state, > + int lane) > { > u8 train_set = intel_dp->train_set[lane]; > - u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | > - DP_TRAIN_PRE_EMPHASIS_MASK); > > - return translate_signal_level(intel_dp, signal_levels); > + if (intel_dp_is_uhbr(crtc_state)) { > + return train_set & DP_TX_FFE_PRESET_VALUE_MASK; > + } else { > + u8 signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | > + DP_TRAIN_PRE_EMPHASIS_MASK); > + > + return translate_signal_level(intel_dp, signal_levels); > + } > } > > int intel_ddi_level(struct intel_encoder *encoder, > @@ -1362,7 +1369,8 @@ int intel_ddi_level(struct intel_encoder *encoder, > if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) > level = intel_ddi_hdmi_level(encoder, trans); > else > - level = intel_ddi_dp_level(enc_to_intel_dp(encoder), lane); > + level = intel_ddi_dp_level(enc_to_intel_dp(encoder), crtc_state, > + lane); > > if (drm_WARN_ON_ONCE(&i915->drm, level >= n_entries)) > level = n_entries - 1; > 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 d239d72bfcf2..6eb7803ee0b3 100644 > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c > @@ -304,11 +304,33 @@ static bool has_per_lane_signal_levels(struct intel_dp *intel_dp, > return !intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy); > } > > -static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, > - const struct intel_crtc_state *crtc_state, > - enum drm_dp_phy dp_phy, > - const u8 link_status[DP_LINK_STATUS_SIZE], > - int lane) > + > +/* 128b/132b */ > +static u8 intel_dp_get_lane_adjust_tx_ffe_preset(struct intel_dp *intel_dp, > + const struct intel_crtc_state *crtc_state, > + enum drm_dp_phy dp_phy, > + const u8 link_status[DP_LINK_STATUS_SIZE], > + int lane) > +{ > + u8 tx_ffe = 0; > + > + if (has_per_lane_signal_levels(intel_dp, dp_phy)) { > + lane = min(lane, crtc_state->lane_count - 1); > + tx_ffe = drm_dp_get_adjust_tx_ffe_preset(link_status, lane); > + } else { > + for (lane = 0; lane < crtc_state->lane_count; lane++) > + tx_ffe = max(tx_ffe, drm_dp_get_adjust_tx_ffe_preset(link_status, lane)); > + } > + > + return tx_ffe; > +} > + > +/* 8b/10b */ > +static u8 intel_dp_get_lane_adjust_vswing_preemph(struct intel_dp *intel_dp, > + const struct intel_crtc_state *crtc_state, > + enum drm_dp_phy dp_phy, > + const u8 link_status[DP_LINK_STATUS_SIZE], > + int lane) > { > u8 v = 0; > u8 p = 0; > @@ -340,6 +362,20 @@ static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, > return v | p; > } > > +static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, > + const struct intel_crtc_state *crtc_state, > + enum drm_dp_phy dp_phy, > + const u8 link_status[DP_LINK_STATUS_SIZE], > + int lane) > +{ > + if (intel_dp_is_uhbr(crtc_state)) > + return intel_dp_get_lane_adjust_tx_ffe_preset(intel_dp, crtc_state, > + dp_phy, link_status, lane); > + else > + return intel_dp_get_lane_adjust_vswing_preemph(intel_dp, crtc_state, > + dp_phy, link_status, lane); > +} > + > #define TRAIN_REQ_FMT "%d/%d/%d/%d" > #define _TRAIN_REQ_VSWING_ARGS(link_status, lane) \ > (drm_dp_get_adjust_request_voltage((link_status), (lane)) >> DP_TRAIN_VOLTAGE_SWING_SHIFT) > @@ -355,6 +391,13 @@ static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp, > _TRAIN_REQ_PREEMPH_ARGS(link_status, 1), \ > _TRAIN_REQ_PREEMPH_ARGS(link_status, 2), \ > _TRAIN_REQ_PREEMPH_ARGS(link_status, 3) > +#define _TRAIN_REQ_TX_FFE_ARGS(link_status, lane) \ > + drm_dp_get_adjust_tx_ffe_preset((link_status), (lane)) > +#define TRAIN_REQ_TX_FFE_ARGS(link_status) \ > + _TRAIN_REQ_TX_FFE_ARGS(link_status, 0), \ > + _TRAIN_REQ_TX_FFE_ARGS(link_status, 1), \ > + _TRAIN_REQ_TX_FFE_ARGS(link_status, 2), \ > + _TRAIN_REQ_TX_FFE_ARGS(link_status, 3) > > void > intel_dp_get_adjust_train(struct intel_dp *intel_dp, > @@ -367,14 +410,23 @@ intel_dp_get_adjust_train(struct intel_dp *intel_dp, > char phy_name[10]; > int lane; > > - drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] lanes: %d, " > - "vswing request: " TRAIN_REQ_FMT ", " > - "pre-emphasis request: " TRAIN_REQ_FMT "\n", > - encoder->base.base.id, encoder->base.name, > - intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), > - crtc_state->lane_count, > - TRAIN_REQ_VSWING_ARGS(link_status), > - TRAIN_REQ_PREEMPH_ARGS(link_status)); > + if (intel_dp_is_uhbr(crtc_state)) { > + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 128b/132b, lanes: %d, " > + "TX FFE request: " TRAIN_REQ_FMT "\n", > + encoder->base.base.id, encoder->base.name, > + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), > + crtc_state->lane_count, > + TRAIN_REQ_TX_FFE_ARGS(link_status)); > + } else { > + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 8b/10b, lanes: %d, " > + "vswing request: " TRAIN_REQ_FMT ", " > + "pre-emphasis request: " TRAIN_REQ_FMT "\n", > + encoder->base.base.id, encoder->base.name, > + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), > + crtc_state->lane_count, > + TRAIN_REQ_VSWING_ARGS(link_status), > + TRAIN_REQ_PREEMPH_ARGS(link_status)); > + } > > for (lane = 0; lane < 4; lane++) > intel_dp->train_set[lane] = > @@ -464,6 +516,13 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, > _TRAIN_SET_PREEMPH_ARGS((train_set)[1]), \ > _TRAIN_SET_PREEMPH_ARGS((train_set)[2]), \ > _TRAIN_SET_PREEMPH_ARGS((train_set)[3]) > +#define _TRAIN_SET_TX_FFE_ARGS(train_set) \ > + ((train_set) & DP_TX_FFE_PRESET_VALUE_MASK), "" > +#define TRAIN_SET_TX_FFE_ARGS(train_set) \ > + _TRAIN_SET_TX_FFE_ARGS((train_set)[0]), \ > + _TRAIN_SET_TX_FFE_ARGS((train_set)[1]), \ > + _TRAIN_SET_TX_FFE_ARGS((train_set)[2]), \ > + _TRAIN_SET_TX_FFE_ARGS((train_set)[3]) > > void intel_dp_set_signal_levels(struct intel_dp *intel_dp, > const struct intel_crtc_state *crtc_state, > @@ -473,14 +532,23 @@ void intel_dp_set_signal_levels(struct intel_dp *intel_dp, > struct drm_i915_private *i915 = to_i915(encoder->base.dev); > char phy_name[10]; > > - drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] lanes: %d, " > - "vswing levels: " TRAIN_SET_FMT ", " > - "pre-emphasis levels: " TRAIN_SET_FMT "\n", > - encoder->base.base.id, encoder->base.name, > - intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), > - crtc_state->lane_count, > - TRAIN_SET_VSWING_ARGS(intel_dp->train_set), > - TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set)); > + if (intel_dp_is_uhbr(crtc_state)) { > + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 128b/132b, lanes: %d, " > + "TX FFE presets: " TRAIN_SET_FMT "\n", > + encoder->base.base.id, encoder->base.name, > + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), > + crtc_state->lane_count, > + TRAIN_SET_TX_FFE_ARGS(intel_dp->train_set)); > + } else { > + drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 8b/10b, lanes: %d, " > + "vswing levels: " TRAIN_SET_FMT ", " > + "pre-emphasis levels: " TRAIN_SET_FMT "\n", > + encoder->base.base.id, encoder->base.name, > + intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)), > + crtc_state->lane_count, > + TRAIN_SET_VSWING_ARGS(intel_dp->train_set), > + TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set)); > + } > > if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy)) > encoder->set_signal_levels(encoder, crtc_state); > @@ -515,7 +583,16 @@ intel_dp_update_link_train(struct intel_dp *intel_dp, > return ret == crtc_state->lane_count; > } > > +/* 128b/132b */ > +static bool intel_dp_lane_max_tx_ffe_reached(u8 train_set_lane) > +{ > + return (train_set_lane & DP_TX_FFE_PRESET_VALUE_MASK) == > + DP_TX_FFE_PRESET_VALUE_MASK; > +} > + > /* > + * 8b/10b > + * > * FIXME: The DP spec is very confusing here, also the Link CTS spec seems to > * have self contradicting tests around this area. > * > @@ -545,8 +622,15 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp, > int lane; > > for (lane = 0; lane < crtc_state->lane_count; lane++) { > - if (!intel_dp_lane_max_vswing_reached(intel_dp->train_set[lane])) > - return false; > + u8 train_set_lane = intel_dp->train_set[lane]; > + > + if (intel_dp_is_uhbr(crtc_state)) { > + if (!intel_dp_lane_max_tx_ffe_reached(train_set_lane)) > + return false; > + } else { > + if (!intel_dp_lane_max_vswing_reached(train_set_lane)) > + return false; > + } > } > > return true; > @@ -609,17 +693,24 @@ static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_d > drm_dp_lttpr_link_train_clock_recovery_delay(); > } > > -static bool intel_dp_adjust_request_changed(int lane_count, > +static bool intel_dp_adjust_request_changed(const struct intel_crtc_state *crtc_state, > const u8 old_link_status[DP_LINK_STATUS_SIZE], > const u8 new_link_status[DP_LINK_STATUS_SIZE]) > { > int lane; > > - for (lane = 0; lane < lane_count; lane++) { > - u8 old = drm_dp_get_adjust_request_voltage(old_link_status, lane) | > - drm_dp_get_adjust_request_pre_emphasis(old_link_status, lane); > - u8 new = drm_dp_get_adjust_request_voltage(new_link_status, lane) | > - drm_dp_get_adjust_request_pre_emphasis(new_link_status, lane); > + for (lane = 0; lane < crtc_state->lane_count; lane++) { > + u8 old, new; > + > + if (intel_dp_is_uhbr(crtc_state)) { > + old = drm_dp_get_adjust_tx_ffe_preset(old_link_status, lane); > + new = drm_dp_get_adjust_tx_ffe_preset(new_link_status, lane); > + } else { > + old = drm_dp_get_adjust_request_voltage(old_link_status, lane) | > + drm_dp_get_adjust_request_pre_emphasis(old_link_status, lane); > + new = drm_dp_get_adjust_request_voltage(new_link_status, lane) | > + drm_dp_get_adjust_request_pre_emphasis(new_link_status, lane); > + } > > if (old != new) > return true; > @@ -729,8 +820,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp, > return false; > } > > - if (!intel_dp_adjust_request_changed(crtc_state->lane_count, > - old_link_status, link_status)) > + if (!intel_dp_adjust_request_changed(crtc_state, old_link_status, link_status)) > ++voltage_tries; > else > voltage_tries = 1; > -- > 2.30.2 -- Ville Syrjälä Intel