[Intel-gfx] [PATCH 2/7] drm/i915/sdvo: Implement proper HDMI audio support for SDVO
Imre Deak
imre.deak at intel.com
Thu Jun 6 14:43:43 UTC 2019
On Tue, Apr 09, 2019 at 11:00:10PM +0300, Ville Syrjälä wrote:
> On Tue, Apr 09, 2019 at 05:40:49PM +0300, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> >
> > Our SDVO audio support is pretty bogus. We can't push audio over the
> > SDVO bus, so trying to enable audio in the SDVO control register doesn't
> > do anything. In fact it looks like the SDVO encoder will always mix in
> > the audio coming over HDA, and there's no (at least documented) way to
> > disable that from our side. So HDMI audio does work currently but only by
> > luck really. What is missing though is the ELD.
>
> Hmm. Looks like I forgot to update this text after the gen3 bug was
> reported. The situation is that audio works on gen4 by luck. On gen3
> it got broken by the referenced commit since we no longer enable
> HDMI encoding on the SDVO device (that will stop audio transmission
> entirely).
>
> >
> > To pass the ELD to the audio driver we need to write it to magic buffer
> > in the SDVO encoder hardware which then gets pulled out via HDA in the
> > other end. Ie. pretty much the same thing we had for native HDMI before
> > we started to just pass the ELD between the drivers. This sort of
> > explains why we even have that silly hardware buffer with native HDMI.
> >
> > $ cat /proc/asound/card0/eld#1.0
> > -monitor_present 0
> > -eld_valid 0
> > +monitor_present 1
> > +eld_valid 1
> > +monitor_name LG TV
> > +connection_type HDMI
> > +...
> >
> > This also fixes our state readout since we can now query the SDVO
> > encoder about the state of the "ELD valid" and "presence detect"
> > bits. As mentioned those don't actually control whether audio
> > gets sent over the HDMI cable, but it's the best we can do.
> >
> > Cc: stable at vger.kernel.org
> > Cc: Daniel Vetter <daniel.vetter at ffwll.ch>
> > Cc: zardam at gmail.com
> > Tested-by: zardam at gmail.com
> > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=108976
> > Fixes: de44e256b92c ("drm/i915/sdvo: Shut up state checker with hdmi cards on gen3")
> > Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
Matches the sdvo specs and bspec (SDVO_AUDIO_ENABLE is a reserved/MBZ
bit on GEN3,3.5, and on GEN4 it's probably HDMI specific, since there is
no audio traffic over the SDVO bus):
Reviewed-by: Imre Deak <imre.deak at intel.com>
Btw, is it guaranteed that we have a valid ELD when
force_audio == HDMI_AUDIO_ON ?
> > ---
> > drivers/gpu/drm/i915/intel_sdvo.c | 58 +++++++++++++++++++++-----
> > drivers/gpu/drm/i915/intel_sdvo_regs.h | 3 ++
> > 2 files changed, 50 insertions(+), 11 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> > index 61db07244296..7f64352a3413 100644
> > --- a/drivers/gpu/drm/i915/intel_sdvo.c
> > +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> > @@ -916,6 +916,13 @@ static bool intel_sdvo_set_colorimetry(struct intel_sdvo *intel_sdvo,
> > return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
> > }
> >
> > +static bool intel_sdvo_set_audio_state(struct intel_sdvo *intel_sdvo,
> > + u8 audio_state)
> > +{
> > + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_AUDIO_STAT,
> > + &audio_state, 1);
> > +}
> > +
> > #if 0
> > static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
> > {
> > @@ -1487,11 +1494,6 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
> > else
> > sdvox |= SDVO_PIPE_SEL(crtc->pipe);
> >
> > - if (crtc_state->has_audio) {
> > - WARN_ON_ONCE(INTEL_GEN(dev_priv) < 4);
> > - sdvox |= SDVO_AUDIO_ENABLE;
> > - }
> > -
> > if (INTEL_GEN(dev_priv) >= 4) {
> > /* done in crtc_mode_set as the dpll_md reg must be written early */
> > } else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
> > @@ -1635,8 +1637,13 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
> > if (sdvox & HDMI_COLOR_RANGE_16_235)
> > pipe_config->limited_color_range = true;
> >
> > - if (sdvox & SDVO_AUDIO_ENABLE)
> > - pipe_config->has_audio = true;
> > + if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT,
> > + &val, 1)) {
> > + u8 mask = SDVO_AUDIO_ELD_VALID | SDVO_AUDIO_PRESENCE_DETECT;
> > +
> > + if ((val & mask) == mask)
> > + pipe_config->has_audio = true;
> > + }
> >
> > if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
> > &val, 1)) {
> > @@ -1647,6 +1654,32 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
> > intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config);
> > }
> >
> > +static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo)
> > +{
> > + intel_sdvo_set_audio_state(intel_sdvo, 0);
> > +}
> > +
> > +static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo,
> > + const struct intel_crtc_state *crtc_state,
> > + const struct drm_connector_state *conn_state)
> > +{
> > + const struct drm_display_mode *adjusted_mode =
> > + &crtc_state->base.adjusted_mode;
> > + struct drm_connector *connector = conn_state->connector;
> > + u8 *eld = connector->eld;
> > +
> > + eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
> > +
> > + intel_sdvo_set_audio_state(intel_sdvo, 0);
> > +
> > + intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD,
> > + SDVO_HBUF_TX_DISABLED,
> > + eld, drm_eld_size(eld));
> > +
> > + intel_sdvo_set_audio_state(intel_sdvo, SDVO_AUDIO_ELD_VALID |
> > + SDVO_AUDIO_PRESENCE_DETECT);
> > +}
> > +
> > static void intel_disable_sdvo(struct intel_encoder *encoder,
> > const struct intel_crtc_state *old_crtc_state,
> > const struct drm_connector_state *conn_state)
> > @@ -1656,6 +1689,9 @@ static void intel_disable_sdvo(struct intel_encoder *encoder,
> > struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
> > u32 temp;
> >
> > + if (old_crtc_state->has_audio)
> > + intel_sdvo_disable_audio(intel_sdvo);
> > +
> > intel_sdvo_set_active_outputs(intel_sdvo, 0);
> > if (0)
> > intel_sdvo_set_encoder_power_state(intel_sdvo,
> > @@ -1741,6 +1777,9 @@ static void intel_enable_sdvo(struct intel_encoder *encoder,
> > intel_sdvo_set_encoder_power_state(intel_sdvo,
> > DRM_MODE_DPMS_ON);
> > intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
> > +
> > + if (pipe_config->has_audio)
> > + intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state);
> > }
> >
> > static enum drm_mode_status
> > @@ -2603,7 +2642,6 @@ static bool
> > intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
> > {
> > struct drm_encoder *encoder = &intel_sdvo->base.base;
> > - struct drm_i915_private *dev_priv = to_i915(encoder->dev);
> > struct drm_connector *connector;
> > struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
> > struct intel_connector *intel_connector;
> > @@ -2640,9 +2678,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
> > encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
> > connector->connector_type = DRM_MODE_CONNECTOR_DVID;
> >
> > - /* gen3 doesn't do the hdmi bits in the SDVO register */
> > - if (INTEL_GEN(dev_priv) >= 4 &&
> > - intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
> > + if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
> > connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
> > intel_sdvo_connector->is_hdmi = true;
> > }
> > diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h
> > index db0ed499268a..e9ba3b047f93 100644
> > --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h
> > +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h
> > @@ -707,6 +707,9 @@ struct intel_sdvo_enhancements_arg {
> > #define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90
> > #define SDVO_CMD_SET_AUDIO_STAT 0x91
> > #define SDVO_CMD_GET_AUDIO_STAT 0x92
> > + #define SDVO_AUDIO_ELD_VALID (1 << 0)
> > + #define SDVO_AUDIO_PRESENCE_DETECT (1 << 1)
> > + #define SDVO_AUDIO_CP_READY (1 << 2)
> > #define SDVO_CMD_SET_HBUF_INDEX 0x93
> > #define SDVO_HBUF_INDEX_ELD 0
> > #define SDVO_HBUF_INDEX_AVI_IF 1
> > --
> > 2.21.0
>
> --
> Ville Syrjälä
> Intel
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the Intel-gfx
mailing list