Commit 2885d283 authored by Imre Deak's avatar Imre Deak
Browse files

drm/i915/dp: Retrain SST links via a modeset commit



Instead of direct calls of the link training functions, use a modeset
commit to retrain a DP link in SST mode, similarly to how this is done
in DP-MST mode. Originally the current way was chosen presumedly,
because there wasn't a well-established way in place for the driver to
do an internal (vs. userspace/kernel client) commit. Since then such
internal commits became a common place (initial-, HDMI/TC link reset
commit), so there is no reason to handle the DP-SST link-retraining case
differently.

At the end of the current sequence the HW reported a FIFO underrun -
without other issues visible to users - because during retraining the
link's encoder/port was disabled/re-enabled without also
disabling/re-enabling the corresponding pipe/transcoder (as required by
the spec); the corresponding underrun error message was suppressed as a
known issue. Based on Ankit's test on DG2 the underrun error was still
reported as it got detected with some (vblank) delay wrt. other
platforms. Switching to a modeset commit resolves these underrun related
issues.

Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarSuraj Kandpal <suraj.kandpal@intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240712135724.660399-1-imre.deak@intel.com
parent d43caea1
Loading
Loading
Loading
Loading
+9 −58
Original line number Diff line number Diff line
@@ -5242,8 +5242,6 @@ static int intel_dp_retrain_link(struct intel_encoder *encoder,
{
	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
	struct intel_crtc *crtc;
	bool mst_output = false;
	u8 pipe_mask;
	int ret;

@@ -5272,65 +5270,18 @@ static int intel_dp_retrain_link(struct intel_encoder *encoder,
		    encoder->base.base.id, encoder->base.name,
		    str_yes_no(intel_dp->link.force_retrain));

	for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, crtc, pipe_mask) {
		const struct intel_crtc_state *crtc_state =
			to_intel_crtc_state(crtc->base.state);

		if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) {
			mst_output = true;
			break;
		}

		/* Suppress underruns caused by re-training */
		intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
		if (crtc_state->has_pch_encoder)
			intel_set_pch_fifo_underrun_reporting(dev_priv,
							      intel_crtc_pch_transcoder(crtc), false);
	}

	/* TODO: use a modeset for SST as well. */
	if (mst_output) {
	ret = intel_modeset_commit_pipes(dev_priv, pipe_mask, ctx);
	if (ret == -EDEADLK)
		return ret;

		if (ret && ret != -EDEADLK)
	intel_dp->link.force_retrain = false;

	if (ret)
		drm_dbg_kms(&dev_priv->drm,
			    "[ENCODER:%d:%s] link retraining failed: %pe\n",
			    encoder->base.base.id, encoder->base.name,
			    ERR_PTR(ret));

		goto out;
	}

	for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, crtc, pipe_mask) {
		const struct intel_crtc_state *crtc_state =
			to_intel_crtc_state(crtc->base.state);

		intel_dp->link_trained = false;

		intel_dp_check_frl_training(intel_dp);
		intel_dp_pcon_dsc_configure(intel_dp, crtc_state);
		intel_dp_start_link_train(NULL, intel_dp, crtc_state);
		intel_dp_stop_link_train(intel_dp, crtc_state);
		break;
	}

	for_each_intel_crtc_in_pipe_mask(&dev_priv->drm, crtc, pipe_mask) {
		const struct intel_crtc_state *crtc_state =
			to_intel_crtc_state(crtc->base.state);

		/* Keep underrun reporting disabled until things are stable */
		intel_crtc_wait_for_next_vblank(crtc);

		intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, true);
		if (crtc_state->has_pch_encoder)
			intel_set_pch_fifo_underrun_reporting(dev_priv,
							      intel_crtc_pch_transcoder(crtc), true);
	}

out:
	if (ret != -EDEADLK)
		intel_dp->link.force_retrain = false;

	return ret;
}