Commit 6e916b35 authored by Imre Deak's avatar Imre Deak

drm/i915/dp: Wait for FEC detected status in the sink

As required by the DP standard wait for the sink to detect the FEC
decode enabling symbol sent by the source.

There is a difference between SST and MST when the source enables
the FEC encoding: on SST this happens only after enabling the
transcoder, whereas on MST it happens already after enabling the
transcoder function (before enabling the transcoder). Wait for the
detected status at the earliest spot accordingly.

v2:
- Wait for the FEC detected status on SST after the transcoder is
  enabled.
Reviewed-by: default avatarStanislav Lisovskiy <stanislav.lisovskiy@intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20231030155843.2251023-20-imre.deak@intel.com
parent 0cfdf662
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* *
*/ */
#include <linux/iopoll.h>
#include <linux/string_helpers.h> #include <linux/string_helpers.h>
#include <drm/display/drm_scdc_helper.h> #include <drm/display/drm_scdc_helper.h>
...@@ -2220,6 +2221,74 @@ static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp, ...@@ -2220,6 +2221,74 @@ static void intel_dp_sink_set_fec_ready(struct intel_dp *intel_dp,
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0) if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_CONFIGURATION, DP_FEC_READY) <= 0)
drm_dbg_kms(&i915->drm, drm_dbg_kms(&i915->drm,
"Failed to set FEC_READY in the sink\n"); "Failed to set FEC_READY in the sink\n");
if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_FEC_STATUS,
DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED) <= 0)
drm_dbg_kms(&i915->drm, "Failed to clear FEC detected flags\n");
}
static int read_fec_detected_status(struct drm_dp_aux *aux)
{
int ret;
u8 status;
ret = drm_dp_dpcd_readb(aux, DP_FEC_STATUS, &status);
if (ret < 0)
return ret;
return status;
}
static void wait_for_fec_detected(struct drm_dp_aux *aux, bool enabled)
{
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;
err = readx_poll_timeout(read_fec_detected_status, aux, status,
status & mask || status < 0,
10000, 200000);
if (!err && status >= 0)
return;
if (err == -ETIMEDOUT)
drm_err(&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);
}
void intel_ddi_wait_for_fec_status(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state,
bool enabled)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
int ret;
if (!crtc_state->fec_enable)
return;
if (enabled)
ret = intel_de_wait_for_set(i915, dp_tp_status_reg(encoder, crtc_state),
DP_TP_STATUS_FEC_ENABLE_LIVE, 1);
else
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 %s\n",
str_enabled_disabled(enabled));
/*
* At least the Synoptics MST hub doesn't set the detected flag for
* FEC decoding disabling so skip waiting for that.
*/
if (enabled)
wait_for_fec_detected(&intel_dp->aux, enabled);
} }
static void intel_ddi_enable_fec(struct intel_encoder *encoder, static void intel_ddi_enable_fec(struct intel_encoder *encoder,
...@@ -2887,6 +2956,8 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder, ...@@ -2887,6 +2956,8 @@ static void intel_disable_ddi_buf(struct intel_encoder *encoder,
} else { } else {
disable_ddi_buf(encoder, crtc_state); disable_ddi_buf(encoder, crtc_state);
} }
intel_ddi_wait_for_fec_status(encoder, crtc_state, false);
} }
static void intel_ddi_post_disable_dp(struct intel_atomic_state *state, static void intel_ddi_post_disable_dp(struct intel_atomic_state *state,
...@@ -3262,6 +3333,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state, ...@@ -3262,6 +3333,8 @@ static void intel_enable_ddi(struct intel_atomic_state *state,
intel_enable_transcoder(crtc_state); intel_enable_transcoder(crtc_state);
intel_ddi_wait_for_fec_status(encoder, crtc_state, true);
intel_crtc_vblank_on(crtc_state); intel_crtc_vblank_on(crtc_state);
if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI)) if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI))
......
...@@ -62,6 +62,9 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state ...@@ -62,6 +62,9 @@ void intel_ddi_disable_transcoder_func(const struct intel_crtc_state *crtc_state
void intel_ddi_enable_transcoder_clock(struct intel_encoder *encoder, void intel_ddi_enable_transcoder_clock(struct intel_encoder *encoder,
const struct intel_crtc_state *crtc_state); const struct intel_crtc_state *crtc_state);
void intel_ddi_disable_transcoder_clock(const struct intel_crtc_state *crtc_state); 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);
void intel_ddi_set_dp_msa(const struct intel_crtc_state *crtc_state, void intel_ddi_set_dp_msa(const struct intel_crtc_state *crtc_state,
const struct drm_connector_state *conn_state); const struct drm_connector_state *conn_state);
bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
......
...@@ -878,6 +878,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, ...@@ -878,6 +878,7 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
struct drm_dp_mst_topology_state *mst_state = struct drm_dp_mst_topology_state *mst_state =
drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr); drm_atomic_get_new_mst_topology_state(&state->base, &intel_dp->mst_mgr);
enum transcoder trans = pipe_config->cpu_transcoder; enum transcoder trans = pipe_config->cpu_transcoder;
bool first_mst_stream = intel_dp->active_mst_links == 1;
drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder); drm_WARN_ON(&dev_priv->drm, pipe_config->has_pch_encoder);
...@@ -904,6 +905,9 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state, ...@@ -904,6 +905,9 @@ static void intel_mst_enable_dp(struct intel_atomic_state *state,
wait_for_act_sent(encoder, pipe_config); wait_for_act_sent(encoder, pipe_config);
if (first_mst_stream)
intel_ddi_wait_for_fec_status(encoder, pipe_config, true);
drm_dp_add_payload_part2(&intel_dp->mst_mgr, &state->base, drm_dp_add_payload_part2(&intel_dp->mst_mgr, &state->base,
drm_atomic_get_mst_payload_state(mst_state, connector->port)); drm_atomic_get_mst_payload_state(mst_state, connector->port));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment