aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorPaulo Zanoni <paulo.r.zanoni@intel.com>2012-09-25 12:23:34 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-09-26 03:24:09 -0400
commitadf00b26d18e1b3570451296e03bcb20e4798cdd (patch)
tree92e61f23b7c3634c92945f0d5b58ee3601d220bc /drivers/gpu/drm
parent398b7a1b882a655ee84bd985f6c2ba89082404ae (diff)
drm/i915: make sure we write all the DIP data bytes
... even if the actual infoframe is smaller than the maximum possible size. If we don't write all the 32 DIP data bytes the InfoFrame ECC may not be correctly calculated in some cases (e.g., when changing the port), and this will lead to black screens on HDMI monitors. The ECC value is generated by the hardware. I don't see how this should break anything since we're writing 0 and that should be the correct value, so this patch should be safe. Notice that on IVB and older we actually have 64 bytes available for VIDEO_DIP_DATA, but only bytes 0-31 actually store infoframe data: the others are either read-only ECC values or marked as "reserved". On HSW we only have 32 bytes, and the ECC value is stored on its own separate read-only register. See BSpec. This patch fixes bug #46761, which is marked as a regression introduced by commit 4e89ee174bb2da341bf90a84321c7008a3c9210d: drm/i915: set the DIP port on ibx_write_infoframe Before commit 4e89 we were just failing to send AVI infoframes when we needed to change the port, which can lead to black screens in some cases. After commit 4e89 we started sending infoframes, but with a possibly wrong ECC value. After this patch I hope we start sending correct infoframes. Version 2: - Improve commit message - Try to make the code more clear Cc: stable@vger.kernel.org Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=46761 Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h4
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c15
2 files changed, 19 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index a828e90602b9..7637824c6a7d 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1794,6 +1794,10 @@
1794 1794
1795/* Video Data Island Packet control */ 1795/* Video Data Island Packet control */
1796#define VIDEO_DIP_DATA 0x61178 1796#define VIDEO_DIP_DATA 0x61178
1797/* Read the description of VIDEO_DIP_DATA (before Haswel) or VIDEO_DIP_ECC
1798 * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte
1799 * of the infoframe structure specified by CEA-861. */
1800#define VIDEO_DIP_DATA_SIZE 32
1797#define VIDEO_DIP_CTL 0x61170 1801#define VIDEO_DIP_CTL 0x61170
1798/* Pre HSW: */ 1802/* Pre HSW: */
1799#define VIDEO_DIP_ENABLE (1 << 31) 1803#define VIDEO_DIP_ENABLE (1 << 31)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index f9fb47cd1779..08f2b63d740a 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -151,6 +151,9 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
151 I915_WRITE(VIDEO_DIP_DATA, *data); 151 I915_WRITE(VIDEO_DIP_DATA, *data);
152 data++; 152 data++;
153 } 153 }
154 /* Write every possible data byte to force correct ECC calculation. */
155 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
156 I915_WRITE(VIDEO_DIP_DATA, 0);
154 mmiowb(); 157 mmiowb();
155 158
156 val |= g4x_infoframe_enable(frame); 159 val |= g4x_infoframe_enable(frame);
@@ -186,6 +189,9 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
186 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 189 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
187 data++; 190 data++;
188 } 191 }
192 /* Write every possible data byte to force correct ECC calculation. */
193 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
194 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
189 mmiowb(); 195 mmiowb();
190 196
191 val |= g4x_infoframe_enable(frame); 197 val |= g4x_infoframe_enable(frame);
@@ -224,6 +230,9 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
224 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 230 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
225 data++; 231 data++;
226 } 232 }
233 /* Write every possible data byte to force correct ECC calculation. */
234 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
235 I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
227 mmiowb(); 236 mmiowb();
228 237
229 val |= g4x_infoframe_enable(frame); 238 val |= g4x_infoframe_enable(frame);
@@ -259,6 +268,9 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
259 I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data); 268 I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
260 data++; 269 data++;
261 } 270 }
271 /* Write every possible data byte to force correct ECC calculation. */
272 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
273 I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), 0);
262 mmiowb(); 274 mmiowb();
263 275
264 val |= g4x_infoframe_enable(frame); 276 val |= g4x_infoframe_enable(frame);
@@ -292,6 +304,9 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
292 I915_WRITE(data_reg + i, *data); 304 I915_WRITE(data_reg + i, *data);
293 data++; 305 data++;
294 } 306 }
307 /* Write every possible data byte to force correct ECC calculation. */
308 for (; i < VIDEO_DIP_DATA_SIZE; i += 4)
309 I915_WRITE(data_reg + i, 0);
295 mmiowb(); 310 mmiowb();
296 311
297 val |= hsw_infoframe_enable(frame); 312 val |= hsw_infoframe_enable(frame);