Both DP MST and UHBR SST require the audio component to use a real cpu_transcoder (>= 0) value to identify the audio stream on a port. For DP MST this was already handled; for UHBR SST it was not, causing pin_eld_notify() to signal cpu_transcoder = -1 (the legacy SST sentinel) and find_audio_state() to skip the per-transcoder entry for the UHBR stream.
After suspend/resume or replug, the ELD lookup fails and audio goes silent. Fix by detecting UHBR SST alongside DP MST when deciding whether a real cpu_transcoder value must be used for audio state addressing, in both the pin_eld_notify() signalling and the find_audio_state() lookup paths. --v2: - Commit message and comment update. (Suraj) - Change function name has_mst_transcoder. (Suraj) - Avoid Live crtc access in find_audio_state. (Suraj) Signed-off-by: Kai Vehmanen <[email protected]> Signed-off-by: Mitul Golani <[email protected]> --- drivers/gpu/drm/i915/display/intel_audio.c | 61 ++++++++++++++----- .../gpu/drm/i915/display/intel_display_core.h | 1 + 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_audio.c b/drivers/gpu/drm/i915/display/intel_audio.c index 9729f1837d2c..7a2bc73744a3 100644 --- a/drivers/gpu/drm/i915/display/intel_audio.c +++ b/drivers/gpu/drm/i915/display/intel_audio.c @@ -38,6 +38,7 @@ #include "intel_de.h" #include "intel_display_types.h" #include "intel_display_wa.h" +#include "intel_dp.h" #include "intel_lpe_audio.h" /** @@ -696,6 +697,21 @@ static void ibx_audio_codec_enable(struct intel_encoder *encoder, mutex_unlock(&display->audio.mutex); } +/* + * 128b/132b transport is used for both DP MST and UHBR SST. As far as audio + * is concerned the hardware behaves identically in both cases: the port can + * carry multiple streams and the cpu_transcoder is a meaningful (>= 0, + * possibly > 0) identifier of the audio stream on that port. Legacy 8b/10b + * SST instead carries a single stream per port, for which the audio drivers + * expect the cpu_transcoder to be signalled as -1. + */ +static +bool intel_audio_needs_cpu_transcoder_id(const struct intel_crtc_state *crtc_state) +{ + return intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST) || + intel_dp_is_uhbr(crtc_state); +} + bool intel_audio_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) @@ -762,6 +778,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, audio_state = &display->audio.state[cpu_transcoder]; audio_state->encoder = encoder; + audio_state->needs_cpu_transcoder_id = + intel_audio_needs_cpu_transcoder_id(crtc_state); BUILD_BUG_ON(sizeof(audio_state->eld) != sizeof(crtc_state->eld)); memcpy(audio_state->eld, crtc_state->eld, sizeof(audio_state->eld)); @@ -769,8 +787,12 @@ void intel_audio_codec_enable(struct intel_encoder *encoder, if (acomp && acomp->base.audio_ops && acomp->base.audio_ops->pin_eld_notify) { - /* audio drivers expect cpu_transcoder = -1 to indicate Non-MST cases */ - if (!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST)) + /* + * Audio drivers expect cpu_transcoder = -1 to indicate + * Non-MST/HBR cases. MST and UHBR SST are addressed by + * a real cpu_transcoder. + */ + if (!intel_audio_needs_cpu_transcoder_id(crtc_state)) cpu_transcoder = -1; acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr, (int)port, (int)cpu_transcoder); @@ -819,14 +841,19 @@ void intel_audio_codec_disable(struct intel_encoder *encoder, audio_state = &display->audio.state[cpu_transcoder]; audio_state->encoder = NULL; + audio_state->needs_cpu_transcoder_id = false; memset(audio_state->eld, 0, sizeof(audio_state->eld)); mutex_unlock(&display->audio.mutex); if (acomp && acomp->base.audio_ops && acomp->base.audio_ops->pin_eld_notify) { - /* audio drivers expect cpu_transcoder = -1 to indicate Non-MST cases */ - if (!intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST)) + /* + * Audio drivers expect cpu_transcoder = -1 to indicate + * Non-MST/HBR cases. MST and UHBR SST are addressed by + * a real cpu_transcoder. + */ + if (!intel_audio_needs_cpu_transcoder_id(old_crtc_state)) cpu_transcoder = -1; acomp->base.audio_ops->pin_eld_notify(acomp->base.audio_ops->audio_ptr, (int)port, (int)cpu_transcoder); @@ -1118,18 +1145,24 @@ static int intel_audio_component_get_cdclk_freq(struct device *kdev) } /* - * get the intel audio state according to the parameter port and cpu_transcoder - * MST & (cpu_transcoder >= 0): return the audio.state[cpu_transcoder].encoder], + * Get the intel audio state according to the parameter port and cpu_transcoder + * + * A "MST transcoder" below means 128b/132b transport, i.e. either DP MST or + * UHBR SST, both of which use a meaningful (>= 0) cpu_transcoder to identify + * the audio stream on a port (see intel_audio_needs_cpu_transcoder_id()): + * + * MST transcoder & (cpu_transcoder >= 0): return the audio.state[cpu_transcoder], * when port is matched - * MST & (cpu_transcoder < 0): this is invalid - * Non-MST & (cpu_transcoder >= 0): only cpu_transcoder = 0 (the first device entry) - * will get the right intel_encoder with port matched - * Non-MST & (cpu_transcoder < 0): get the right intel_encoder with port matched + * MST transcoder & (cpu_transcoder < 0): this is invalid + * Non-MST transcoder & (cpu_transcoder >= 0): only cpu_transcoder = 0 (the first + * device entry) will get the right intel_encoder with port matched + * Non-MST transcoder & (cpu_transcoder < 0): get the right intel_encoder with + * port matched */ static struct intel_audio_state *find_audio_state(struct intel_display *display, int port, int cpu_transcoder) { - /* MST */ + /* MST, or UHBR SST. */ if (cpu_transcoder >= 0) { struct intel_audio_state *audio_state; struct intel_encoder *encoder; @@ -1142,11 +1175,11 @@ static struct intel_audio_state *find_audio_state(struct intel_display *display, encoder = audio_state->encoder; if (encoder && encoder->port == port && - encoder->type == INTEL_OUTPUT_DP_MST) + audio_state->needs_cpu_transcoder_id) return audio_state; } - /* Non-MST */ + /* Legacy SST. */ if (cpu_transcoder > 0) return NULL; @@ -1158,7 +1191,7 @@ static struct intel_audio_state *find_audio_state(struct intel_display *display, encoder = audio_state->encoder; if (encoder && encoder->port == port && - encoder->type != INTEL_OUTPUT_DP_MST) + !audio_state->needs_cpu_transcoder_id) return audio_state; } diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 17f7d3abdb9c..a6129d0b523f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -97,6 +97,7 @@ struct intel_wm_funcs { struct intel_audio_state { struct intel_encoder *encoder; u8 eld[MAX_ELD_BYTES]; + bool needs_cpu_transcoder_id; /* MST, or SST on UHBR link */ }; struct intel_audio { -- 2.48.1
