aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2019-04-09 10:40:49 -0400
committerJani Nikula <jani.nikula@intel.com>2019-06-12 03:42:16 -0400
commitd74408f528261f900dddb9778f61b5c5a7a6249c (patch)
tree652fb493efa72d134651afe1ee0dd7179051bb66
parent77ce94dbe586c1a6a26cf021c08109c9ce71b3e0 (diff)
drm/i915/sdvo: Implement proper HDMI audio support for SDVO
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 on gen4 but only by luck really. On gen3 it got broken by the referenced commit. And what has always been missing on every platform is the ELD. 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. And with the state checker appeased we can re-enable HDMI audio for gen3. Cc: stable@vger.kernel.org Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: zardam@gmail.com Tested-by: zardam@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@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190409144054.24561-3-ville.syrjala@linux.intel.com Reviewed-by: Imre Deak <imre.deak@intel.com> (cherry picked from commit dc49a56bd43bb04982e64b44436831da801d0237) Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c58
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo_regs.h3
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 0e3d91d9ef13..9ecfba0a54a1 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,
916 return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); 916 return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1);
917} 917}
918 918
919static bool intel_sdvo_set_audio_state(struct intel_sdvo *intel_sdvo,
920 u8 audio_state)
921{
922 return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_AUDIO_STAT,
923 &audio_state, 1);
924}
925
919#if 0 926#if 0
920static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) 927static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
921{ 928{
@@ -1487,11 +1494,6 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder,
1487 else 1494 else
1488 sdvox |= SDVO_PIPE_SEL(crtc->pipe); 1495 sdvox |= SDVO_PIPE_SEL(crtc->pipe);
1489 1496
1490 if (crtc_state->has_audio) {
1491 WARN_ON_ONCE(INTEL_GEN(dev_priv) < 4);
1492 sdvox |= SDVO_AUDIO_ENABLE;
1493 }
1494
1495 if (INTEL_GEN(dev_priv) >= 4) { 1497 if (INTEL_GEN(dev_priv) >= 4) {
1496 /* done in crtc_mode_set as the dpll_md reg must be written early */ 1498 /* done in crtc_mode_set as the dpll_md reg must be written early */
1497 } else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) || 1499 } else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) ||
@@ -1635,8 +1637,13 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
1635 if (sdvox & HDMI_COLOR_RANGE_16_235) 1637 if (sdvox & HDMI_COLOR_RANGE_16_235)
1636 pipe_config->limited_color_range = true; 1638 pipe_config->limited_color_range = true;
1637 1639
1638 if (sdvox & SDVO_AUDIO_ENABLE) 1640 if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT,
1639 pipe_config->has_audio = true; 1641 &val, 1)) {
1642 u8 mask = SDVO_AUDIO_ELD_VALID | SDVO_AUDIO_PRESENCE_DETECT;
1643
1644 if ((val & mask) == mask)
1645 pipe_config->has_audio = true;
1646 }
1640 1647
1641 if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, 1648 if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE,
1642 &val, 1)) { 1649 &val, 1)) {
@@ -1647,6 +1654,32 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
1647 intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config); 1654 intel_sdvo_get_avi_infoframe(intel_sdvo, pipe_config);
1648} 1655}
1649 1656
1657static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo)
1658{
1659 intel_sdvo_set_audio_state(intel_sdvo, 0);
1660}
1661
1662static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo,
1663 const struct intel_crtc_state *crtc_state,
1664 const struct drm_connector_state *conn_state)
1665{
1666 const struct drm_display_mode *adjusted_mode =
1667 &crtc_state->base.adjusted_mode;
1668 struct drm_connector *connector = conn_state->connector;
1669 u8 *eld = connector->eld;
1670
1671 eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2;
1672
1673 intel_sdvo_set_audio_state(intel_sdvo, 0);
1674
1675 intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD,
1676 SDVO_HBUF_TX_DISABLED,
1677 eld, drm_eld_size(eld));
1678
1679 intel_sdvo_set_audio_state(intel_sdvo, SDVO_AUDIO_ELD_VALID |
1680 SDVO_AUDIO_PRESENCE_DETECT);
1681}
1682
1650static void intel_disable_sdvo(struct intel_encoder *encoder, 1683static void intel_disable_sdvo(struct intel_encoder *encoder,
1651 const struct intel_crtc_state *old_crtc_state, 1684 const struct intel_crtc_state *old_crtc_state,
1652 const struct drm_connector_state *conn_state) 1685 const struct drm_connector_state *conn_state)
@@ -1656,6 +1689,9 @@ static void intel_disable_sdvo(struct intel_encoder *encoder,
1656 struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); 1689 struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc);
1657 u32 temp; 1690 u32 temp;
1658 1691
1692 if (old_crtc_state->has_audio)
1693 intel_sdvo_disable_audio(intel_sdvo);
1694
1659 intel_sdvo_set_active_outputs(intel_sdvo, 0); 1695 intel_sdvo_set_active_outputs(intel_sdvo, 0);
1660 if (0) 1696 if (0)
1661 intel_sdvo_set_encoder_power_state(intel_sdvo, 1697 intel_sdvo_set_encoder_power_state(intel_sdvo,
@@ -1741,6 +1777,9 @@ static void intel_enable_sdvo(struct intel_encoder *encoder,
1741 intel_sdvo_set_encoder_power_state(intel_sdvo, 1777 intel_sdvo_set_encoder_power_state(intel_sdvo,
1742 DRM_MODE_DPMS_ON); 1778 DRM_MODE_DPMS_ON);
1743 intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); 1779 intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
1780
1781 if (pipe_config->has_audio)
1782 intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state);
1744} 1783}
1745 1784
1746static enum drm_mode_status 1785static enum drm_mode_status
@@ -2603,7 +2642,6 @@ static bool
2603intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) 2642intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
2604{ 2643{
2605 struct drm_encoder *encoder = &intel_sdvo->base.base; 2644 struct drm_encoder *encoder = &intel_sdvo->base.base;
2606 struct drm_i915_private *dev_priv = to_i915(encoder->dev);
2607 struct drm_connector *connector; 2645 struct drm_connector *connector;
2608 struct intel_encoder *intel_encoder = to_intel_encoder(encoder); 2646 struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
2609 struct intel_connector *intel_connector; 2647 struct intel_connector *intel_connector;
@@ -2640,9 +2678,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
2640 encoder->encoder_type = DRM_MODE_ENCODER_TMDS; 2678 encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
2641 connector->connector_type = DRM_MODE_CONNECTOR_DVID; 2679 connector->connector_type = DRM_MODE_CONNECTOR_DVID;
2642 2680
2643 /* gen3 doesn't do the hdmi bits in the SDVO register */ 2681 if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
2644 if (INTEL_GEN(dev_priv) >= 4 &&
2645 intel_sdvo_is_hdmi_connector(intel_sdvo, device)) {
2646 connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; 2682 connector->connector_type = DRM_MODE_CONNECTOR_HDMIA;
2647 intel_sdvo_connector->is_hdmi = true; 2683 intel_sdvo_connector->is_hdmi = true;
2648 } 2684 }
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 {
707#define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90 707#define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90
708#define SDVO_CMD_SET_AUDIO_STAT 0x91 708#define SDVO_CMD_SET_AUDIO_STAT 0x91
709#define SDVO_CMD_GET_AUDIO_STAT 0x92 709#define SDVO_CMD_GET_AUDIO_STAT 0x92
710 #define SDVO_AUDIO_ELD_VALID (1 << 0)
711 #define SDVO_AUDIO_PRESENCE_DETECT (1 << 1)
712 #define SDVO_AUDIO_CP_READY (1 << 2)
710#define SDVO_CMD_SET_HBUF_INDEX 0x93 713#define SDVO_CMD_SET_HBUF_INDEX 0x93
711 #define SDVO_HBUF_INDEX_ELD 0 714 #define SDVO_HBUF_INDEX_ELD 0
712 #define SDVO_HBUF_INDEX_AVI_IF 1 715 #define SDVO_HBUF_INDEX_AVI_IF 1