]>
Commit | Line | Data |
---|---|---|
88c4f4d9 GKH |
1 | From d74408f528261f900dddb9778f61b5c5a7a6249c Mon Sep 17 00:00:00 2001 |
2 | From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> | |
3 | Date: Tue, 9 Apr 2019 17:40:49 +0300 | |
4 | Subject: drm/i915/sdvo: Implement proper HDMI audio support for SDVO | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Ville Syrjälä <ville.syrjala@linux.intel.com> | |
10 | ||
11 | commit d74408f528261f900dddb9778f61b5c5a7a6249c upstream. | |
12 | ||
13 | Our SDVO audio support is pretty bogus. We can't push audio over the | |
14 | SDVO bus, so trying to enable audio in the SDVO control register doesn't | |
15 | do anything. In fact it looks like the SDVO encoder will always mix in | |
16 | the audio coming over HDA, and there's no (at least documented) way to | |
17 | disable that from our side. So HDMI audio does work currently on gen4 | |
18 | but only by luck really. On gen3 it got broken by the referenced commit. | |
19 | And what has always been missing on every platform is the ELD. | |
20 | ||
21 | To pass the ELD to the audio driver we need to write it to magic buffer | |
22 | in the SDVO encoder hardware which then gets pulled out via HDA in the | |
23 | other end. Ie. pretty much the same thing we had for native HDMI before | |
24 | we started to just pass the ELD between the drivers. This sort of | |
25 | explains why we even have that silly hardware buffer with native HDMI. | |
26 | ||
27 | $ cat /proc/asound/card0/eld#1.0 | |
28 | -monitor_present 0 | |
29 | -eld_valid 0 | |
30 | +monitor_present 1 | |
31 | +eld_valid 1 | |
32 | +monitor_name LG TV | |
33 | +connection_type HDMI | |
34 | +... | |
35 | ||
36 | This also fixes our state readout since we can now query the SDVO | |
37 | encoder about the state of the "ELD valid" and "presence detect" | |
38 | bits. As mentioned those don't actually control whether audio | |
39 | gets sent over the HDMI cable, but it's the best we can do. And with | |
40 | the state checker appeased we can re-enable HDMI audio for gen3. | |
41 | ||
42 | Cc: stable@vger.kernel.org | |
43 | Cc: Daniel Vetter <daniel.vetter@ffwll.ch> | |
44 | Cc: zardam@gmail.com | |
45 | Tested-by: zardam@gmail.com | |
46 | Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=108976 | |
47 | Fixes: de44e256b92c ("drm/i915/sdvo: Shut up state checker with hdmi cards on gen3") | |
48 | Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> | |
49 | Link: https://patchwork.freedesktop.org/patch/msgid/20190409144054.24561-3-ville.syrjala@linux.intel.com | |
50 | Reviewed-by: Imre Deak <imre.deak@intel.com> | |
51 | (cherry picked from commit dc49a56bd43bb04982e64b44436831da801d0237) | |
52 | Signed-off-by: Jani Nikula <jani.nikula@intel.com> | |
53 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
54 | ||
55 | --- | |
56 | drivers/gpu/drm/i915/intel_sdvo.c | 58 ++++++++++++++++++++++++++------- | |
57 | drivers/gpu/drm/i915/intel_sdvo_regs.h | 3 + | |
58 | 2 files changed, 50 insertions(+), 11 deletions(-) | |
59 | ||
60 | --- a/drivers/gpu/drm/i915/intel_sdvo.c | |
61 | +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |
62 | @@ -925,6 +925,13 @@ static bool intel_sdvo_set_colorimetry(s | |
63 | return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_COLORIMETRY, &mode, 1); | |
64 | } | |
65 | ||
66 | +static bool intel_sdvo_set_audio_state(struct intel_sdvo *intel_sdvo, | |
67 | + u8 audio_state) | |
68 | +{ | |
69 | + return intel_sdvo_set_value(intel_sdvo, SDVO_CMD_SET_AUDIO_STAT, | |
70 | + &audio_state, 1); | |
71 | +} | |
72 | + | |
73 | #if 0 | |
74 | static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) | |
75 | { | |
76 | @@ -1371,11 +1378,6 @@ static void intel_sdvo_pre_enable(struct | |
77 | else | |
78 | sdvox |= SDVO_PIPE_SEL(crtc->pipe); | |
79 | ||
80 | - if (crtc_state->has_audio) { | |
81 | - WARN_ON_ONCE(INTEL_GEN(dev_priv) < 4); | |
82 | - sdvox |= SDVO_AUDIO_ENABLE; | |
83 | - } | |
84 | - | |
85 | if (INTEL_GEN(dev_priv) >= 4) { | |
86 | /* done in crtc_mode_set as the dpll_md reg must be written early */ | |
87 | } else if (IS_I945G(dev_priv) || IS_I945GM(dev_priv) || | |
88 | @@ -1515,8 +1517,13 @@ static void intel_sdvo_get_config(struct | |
89 | if (sdvox & HDMI_COLOR_RANGE_16_235) | |
90 | pipe_config->limited_color_range = true; | |
91 | ||
92 | - if (sdvox & SDVO_AUDIO_ENABLE) | |
93 | - pipe_config->has_audio = true; | |
94 | + if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_AUDIO_STAT, | |
95 | + &val, 1)) { | |
96 | + u8 mask = SDVO_AUDIO_ELD_VALID | SDVO_AUDIO_PRESENCE_DETECT; | |
97 | + | |
98 | + if ((val & mask) == mask) | |
99 | + pipe_config->has_audio = true; | |
100 | + } | |
101 | ||
102 | if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_ENCODE, | |
103 | &val, 1)) { | |
104 | @@ -1529,6 +1536,32 @@ static void intel_sdvo_get_config(struct | |
105 | pipe_config->pixel_multiplier, encoder_pixel_multiplier); | |
106 | } | |
107 | ||
108 | +static void intel_sdvo_disable_audio(struct intel_sdvo *intel_sdvo) | |
109 | +{ | |
110 | + intel_sdvo_set_audio_state(intel_sdvo, 0); | |
111 | +} | |
112 | + | |
113 | +static void intel_sdvo_enable_audio(struct intel_sdvo *intel_sdvo, | |
114 | + const struct intel_crtc_state *crtc_state, | |
115 | + const struct drm_connector_state *conn_state) | |
116 | +{ | |
117 | + const struct drm_display_mode *adjusted_mode = | |
118 | + &crtc_state->base.adjusted_mode; | |
119 | + struct drm_connector *connector = conn_state->connector; | |
120 | + u8 *eld = connector->eld; | |
121 | + | |
122 | + eld[6] = drm_av_sync_delay(connector, adjusted_mode) / 2; | |
123 | + | |
124 | + intel_sdvo_set_audio_state(intel_sdvo, 0); | |
125 | + | |
126 | + intel_sdvo_write_infoframe(intel_sdvo, SDVO_HBUF_INDEX_ELD, | |
127 | + SDVO_HBUF_TX_DISABLED, | |
128 | + eld, drm_eld_size(eld)); | |
129 | + | |
130 | + intel_sdvo_set_audio_state(intel_sdvo, SDVO_AUDIO_ELD_VALID | | |
131 | + SDVO_AUDIO_PRESENCE_DETECT); | |
132 | +} | |
133 | + | |
134 | static void intel_disable_sdvo(struct intel_encoder *encoder, | |
135 | const struct intel_crtc_state *old_crtc_state, | |
136 | const struct drm_connector_state *conn_state) | |
137 | @@ -1538,6 +1571,9 @@ static void intel_disable_sdvo(struct in | |
138 | struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->base.crtc); | |
139 | u32 temp; | |
140 | ||
141 | + if (old_crtc_state->has_audio) | |
142 | + intel_sdvo_disable_audio(intel_sdvo); | |
143 | + | |
144 | intel_sdvo_set_active_outputs(intel_sdvo, 0); | |
145 | if (0) | |
146 | intel_sdvo_set_encoder_power_state(intel_sdvo, | |
147 | @@ -1623,6 +1659,9 @@ static void intel_enable_sdvo(struct int | |
148 | intel_sdvo_set_encoder_power_state(intel_sdvo, | |
149 | DRM_MODE_DPMS_ON); | |
150 | intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output); | |
151 | + | |
152 | + if (pipe_config->has_audio) | |
153 | + intel_sdvo_enable_audio(intel_sdvo, pipe_config, conn_state); | |
154 | } | |
155 | ||
156 | static enum drm_mode_status | |
157 | @@ -2514,7 +2553,6 @@ static bool | |
158 | intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) | |
159 | { | |
160 | struct drm_encoder *encoder = &intel_sdvo->base.base; | |
161 | - struct drm_i915_private *dev_priv = to_i915(encoder->dev); | |
162 | struct drm_connector *connector; | |
163 | struct intel_encoder *intel_encoder = to_intel_encoder(encoder); | |
164 | struct intel_connector *intel_connector; | |
165 | @@ -2551,9 +2589,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *i | |
166 | encoder->encoder_type = DRM_MODE_ENCODER_TMDS; | |
167 | connector->connector_type = DRM_MODE_CONNECTOR_DVID; | |
168 | ||
169 | - /* gen3 doesn't do the hdmi bits in the SDVO register */ | |
170 | - if (INTEL_GEN(dev_priv) >= 4 && | |
171 | - intel_sdvo_is_hdmi_connector(intel_sdvo, device)) { | |
172 | + if (intel_sdvo_is_hdmi_connector(intel_sdvo, device)) { | |
173 | connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; | |
174 | intel_sdvo->is_hdmi = true; | |
175 | } | |
176 | --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h | |
177 | +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h | |
178 | @@ -707,6 +707,9 @@ struct intel_sdvo_enhancements_arg { | |
179 | #define SDVO_CMD_GET_AUDIO_ENCRYPT_PREFER 0x90 | |
180 | #define SDVO_CMD_SET_AUDIO_STAT 0x91 | |
181 | #define SDVO_CMD_GET_AUDIO_STAT 0x92 | |
182 | + #define SDVO_AUDIO_ELD_VALID (1 << 0) | |
183 | + #define SDVO_AUDIO_PRESENCE_DETECT (1 << 1) | |
184 | + #define SDVO_AUDIO_CP_READY (1 << 2) | |
185 | #define SDVO_CMD_SET_HBUF_INDEX 0x93 | |
186 | #define SDVO_HBUF_INDEX_ELD 0 | |
187 | #define SDVO_HBUF_INDEX_AVI_IF 1 |