[PATCH] drm/i915/dp: Add FEC Enable Retry mechanism
Chaitanya Kumar Borah
chaitanya.kumar.borah at intel.com
Sun Sep 29 13:44:33 UTC 2024
>From PTL, FEC_DECODE_EN sequence can be sent to a DPRX independent
of TRANS_CONF enable. This allows us to re-issue an FEC_DECODE_EN
sequence without re-doing the whole mode set sequence. This separate
control over FEC_ECODE_EN/DIS sequence enables us to have a retry
mechanism in case the DPRX does not respond with an FEC_ENABLE
within the stipulated 5ms.
Signed-off-by: Chaitanya Kumar Borah <chaitanya.kumar.borah at intel.com>
---
drivers/gpu/drm/i915/display/intel_ddi.c | 80 +++++++++++++++++----
drivers/gpu/drm/i915/display/intel_ddi.h | 2 +-
drivers/gpu/drm/i915/display/intel_dp_mst.c | 4 +-
3 files changed, 68 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index fe1ded6707f9..fb6b622a7c32 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -79,6 +79,8 @@
#include "skl_scaler.h"
#include "skl_universal_plane.h"
+#define FEC_RETRY_COUNT 3
+
static const u8 index_to_dp_signal_levels[] = {
[0] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0,
[1] = DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1,
@@ -2256,30 +2258,74 @@ static int read_fec_detected_status(struct drm_dp_aux *aux)
return status;
}
-static void wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled)
+static void retry_fec_enable(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ struct drm_dp_aux *aux)
+{
+ struct drm_i915_private *i915 = to_i915(aux->drm_dev);
+ int ret = 0;
+
+ ret = intel_de_wait_for_clear(i915, dp_tp_status_reg(encoder, crtc_state),
+ DP_TP_STATUS_FEC_ENABLE_LIVE, 1);
+
+ if (ret)
+ drm_err(&i915->drm,
+ "Timeout waiting for FEC live state to get disabled during retry\n");
+
+ /* Clear FEC enable */
+ intel_de_rmw(i915, dp_tp_ctl_reg(encoder, crtc_state),
+ DP_TP_CTL_FEC_ENABLE, 0);
+
+ /* Set FEC enable */
+ intel_de_rmw(i915, dp_tp_ctl_reg(encoder, crtc_state),
+ 0, DP_TP_CTL_FEC_ENABLE);
+
+ ret = intel_de_wait_for_set(i915, dp_tp_status_reg(encoder, crtc_state),
+ DP_TP_STATUS_FEC_ENABLE_LIVE, 1);
+ if (!ret)
+ drm_dbg_kms(&i915->drm,
+ "Timeout waiting for FEC live state to get enabled");
+}
+
+static void wait_for_fec_detected(struct intel_encoder *encoder,
+ const struct intel_crtc_state *crtc_state,
+ struct drm_dp_aux *aux, bool enabled, bool retry)
{
struct drm_i915_private *i915 = to_i915(aux->drm_dev);
int mask = enabled ? DP_FEC_DECODE_EN_DETECTED : DP_FEC_DECODE_DIS_DETECTED;
int status;
int err;
+ int max_retries = retry ? 3 : 1;
- err = readx_poll_timeout(read_fec_detected_status, aux, status,
- status & mask || status < 0,
- 10000, 200000);
+ for (int retrycount = 0; retrycount < max_retries; retrycount++) {
+ err = readx_poll_timeout(read_fec_detected_status, aux, status,
+ status & mask || status < 0, 500, retry ? 5000 : 5000);
- if (!err && status >= 0)
- return;
+ if (!err && status >= 0)
+ return;
- if (err == -ETIMEDOUT)
- drm_dbg_kms(&i915->drm, "Timeout waiting for FEC %s to get detected\n",
- str_enabled_disabled(enabled));
- else
- drm_dbg_kms(&i915->drm, "FEC detected status read error: %d\n", status);
+ if (err == -ETIMEDOUT) {
+ drm_dbg_kms(&i915->drm,
+ "Timeout waiting for FEC %s to get detected, retrying (%d/%d)\n",
+ str_enabled_disabled(enabled), retrycount + 1, max_retries);
+
+ /* If retry is requested and FEC is being enabled, try re-enabling */
+ if (retry && enabled)
+ retry_fec_enable(encoder, crtc_state, aux);
+ } else {
+ drm_dbg_kms(&i915->drm, "FEC detected status read error: %d\n", status);
+ return;
+ }
+ }
+
+ /* If retries are exhausted or not enabled, print final failure message */
+ drm_err(&i915->drm, "FEC %s Failed after %d attempts\n",
+ str_enabled_disabled(enabled), max_retries);
}
void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
- bool enabled)
+ bool enabled, bool retry)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
@@ -2305,7 +2351,7 @@ void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder,
* FEC decoding disabling so skip waiting for that.
*/
if (enabled)
- wait_for_fec_detected(&intel_dp->aux, enabled);
+ wait_for_fec_detected(encoder, crtc_state, &intel_dp->aux, true, retry);
}
static void intel_ddi_enable_fec(struct intel_encoder *encoder,
@@ -2318,6 +2364,8 @@ static void intel_ddi_enable_fec(struct intel_encoder *encoder,
intel_de_rmw(dev_priv, dp_tp_ctl_reg(encoder, crtc_state),
0, DP_TP_CTL_FEC_ENABLE);
+
+ intel_ddi_wait_for_fec_status(encoder, crtc_state, true, true);
}
static void intel_ddi_disable_fec(struct intel_encoder *encoder,
@@ -3010,7 +3058,7 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder,
disable_ddi_buf(encoder, crtc_state);
}
- intel_ddi_wait_for_fec_status(encoder, crtc_state, false);
+ intel_ddi_wait_for_fec_status(encoder, crtc_state, false, false);
}
static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
@@ -3383,6 +3431,7 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state)
{
+ struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_display *display = to_intel_display(encoder);
struct intel_crtc *pipe_crtc;
int i;
@@ -3394,7 +3443,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
intel_enable_transcoder(crtc_state);
- intel_ddi_wait_for_fec_status(encoder, crtc_state, true);
+ if (DISPLAY_VER(i915) < 30)
+ intel_ddi_wait_for_fec_status(encoder, crtc_state, true, false);
for_each_pipe_crtc_modeset_enable(display, pipe_crtc, crtc_state, i) {
const struct intel_crtc_state *pipe_crtc_state =
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.h b/drivers/gpu/drm/i915/display/intel_ddi.h
index 6d85422bdefe..981e7702e11e 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.h
+++ b/drivers/gpu/drm/i915/display/intel_ddi.h
@@ -65,7 +65,7 @@ void intel_ddi_enable_transcoder_clock(struct intel_encoder *encoder,
void intel_ddi_disable_transcoder_clock(const struct intel_crtc_state *crtc_state);
void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
- bool enabled);
+ bool enabled, bool retry);
void intel_ddi_set_dp_msa(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state);
bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 732d7543ad06..226ac9a73a55 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -1289,8 +1289,8 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
wait_for_act_sent(encoder, pipe_config);
- if (first_mst_stream)
- intel_ddi_wait_for_fec_status(encoder, pipe_config, true);
+ if (first_mst_stream && DISPLAY_VER(dev_priv) < 30)
+ intel_ddi_wait_for_fec_status(encoder, pipe_config, true, false);
ret = drm_dp_add_payload_part2(&intel_dp->mst_mgr,
drm_atomic_get_mst_payload_state(mst_state,
--
2.25.1
More information about the Intel-gfx-trybot
mailing list