aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2017-11-13 12:04:18 -0500
committerVille Syrjälä <ville.syrjala@linux.intel.com>2017-11-22 09:55:35 -0500
commit593f4b19a094c4426bd1e1e3cbab87a48bd13c71 (patch)
tree5c4fa000fd96dc52b4890fecb817be7191a2ad38 /drivers
parent03e4e0a9e02cf703da331ff6cfd57d0be9bf5692 (diff)
video/hdmi: Allow "empty" HDMI infoframes
HDMI 2.0 Appendix F suggest that we should keep sending the infoframe when switching from 3D to 2D mode, even if the infoframe isn't strictly necessary (ie. not needed to transmit the VIC or stereo information). This is a workaround against some sinks that fail to realize that they should switch from 3D to 2D mode when the source stop transmitting the infoframe. v2: Handle unpack() as well Pull the length calculation into a helper Cc: Shashank Sharma <shashank.sharma@intel.com> Cc: Andrzej Hajda <a.hajda@samsung.com> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Hans Verkuil <hans.verkuil@cisco.com> Cc: linux-media@vger.kernel.org Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> #v1 Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20171113170427.4150-2-ville.syrjala@linux.intel.com Reviewed-by: Shashank Sharma <shashank.sharma@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/hdmi.c51
1 files changed, 31 insertions, 20 deletions
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 1cf907ecded4..111a0ab6280a 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -321,6 +321,17 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
321} 321}
322EXPORT_SYMBOL(hdmi_vendor_infoframe_init); 322EXPORT_SYMBOL(hdmi_vendor_infoframe_init);
323 323
324static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
325{
326 /* for side by side (half) we also need to provide 3D_Ext_Data */
327 if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
328 return 6;
329 else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
330 return 5;
331 else
332 return 4;
333}
334
324/** 335/**
325 * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer 336 * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer
326 * @frame: HDMI infoframe 337 * @frame: HDMI infoframe
@@ -341,19 +352,11 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
341 u8 *ptr = buffer; 352 u8 *ptr = buffer;
342 size_t length; 353 size_t length;
343 354
344 /* empty info frame */
345 if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID)
346 return -EINVAL;
347
348 /* only one of those can be supplied */ 355 /* only one of those can be supplied */
349 if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) 356 if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
350 return -EINVAL; 357 return -EINVAL;
351 358
352 /* for side by side (half) we also need to provide 3D_Ext_Data */ 359 frame->length = hdmi_vendor_infoframe_length(frame);
353 if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
354 frame->length = 6;
355 else
356 frame->length = 5;
357 360
358 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; 361 length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
359 362
@@ -372,14 +375,16 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
372 ptr[5] = 0x0c; 375 ptr[5] = 0x0c;
373 ptr[6] = 0x00; 376 ptr[6] = 0x00;
374 377
375 if (frame->vic) { 378 if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
376 ptr[7] = 0x1 << 5; /* video format */
377 ptr[8] = frame->vic;
378 } else {
379 ptr[7] = 0x2 << 5; /* video format */ 379 ptr[7] = 0x2 << 5; /* video format */
380 ptr[8] = (frame->s3d_struct & 0xf) << 4; 380 ptr[8] = (frame->s3d_struct & 0xf) << 4;
381 if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) 381 if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
382 ptr[9] = (frame->s3d_ext_data & 0xf) << 4; 382 ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
383 } else if (frame->vic) {
384 ptr[7] = 0x1 << 5; /* video format */
385 ptr[8] = frame->vic;
386 } else {
387 ptr[7] = 0x0 << 5; /* video format */
383 } 388 }
384 389
385 hdmi_infoframe_set_checksum(buffer, length); 390 hdmi_infoframe_set_checksum(buffer, length);
@@ -1165,7 +1170,7 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
1165 1170
1166 if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR || 1171 if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
1167 ptr[1] != 1 || 1172 ptr[1] != 1 ||
1168 (ptr[2] != 5 && ptr[2] != 6)) 1173 (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
1169 return -EINVAL; 1174 return -EINVAL;
1170 1175
1171 length = ptr[2]; 1176 length = ptr[2];
@@ -1193,16 +1198,22 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
1193 1198
1194 hvf->length = length; 1199 hvf->length = length;
1195 1200
1196 if (hdmi_video_format == 0x1) { 1201 if (hdmi_video_format == 0x2) {
1197 hvf->vic = ptr[4]; 1202 if (length != 5 && length != 6)
1198 } else if (hdmi_video_format == 0x2) { 1203 return -EINVAL;
1199 hvf->s3d_struct = ptr[4] >> 4; 1204 hvf->s3d_struct = ptr[4] >> 4;
1200 if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) { 1205 if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
1201 if (length == 6) 1206 if (length != 6)
1202 hvf->s3d_ext_data = ptr[5] >> 4;
1203 else
1204 return -EINVAL; 1207 return -EINVAL;
1208 hvf->s3d_ext_data = ptr[5] >> 4;
1205 } 1209 }
1210 } else if (hdmi_video_format == 0x1) {
1211 if (length != 5)
1212 return -EINVAL;
1213 hvf->vic = ptr[4];
1214 } else {
1215 if (length != 4)
1216 return -EINVAL;
1206 } 1217 }
1207 1218
1208 return 0; 1219 return 0;