From: Damien Lespiau <damien.lesp...@intel.com>

For now, let's just look at the 3D_present flag of the CEA HDMI vendor
block to detect if the sink supports a small list of then mandatory 3D
formats.

See the HDMI 1.4a 3D extraction for detail:
  http://www.hdmi.org/manufacturer/specification.aspx

Signed-off-by: Damien Lespiau <damien.lesp...@intel.com>
---
 drivers/gpu/drm/drm_edid.c | 84 ++++++++++++++++++++++++++++++++++++++++++++--
 include/drm/drm_mode.h     | 35 +++++++++++--------
 2 files changed, 103 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index b7ee230..9ffd5c8 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1522,21 +1522,101 @@ do_cea_modes (struct drm_connector *connector, u8 *db, 
u8 len)
        return modes;
 }
 
+static bool cea_hdmi_3d_present(u8 *hdmi)
+{
+       u8 len, skip = 0;
+
+       len = hdmi[0] & 0x1f;
+
+       if (len < 8)
+               return false;
+
+       /* no HDMI_Video_present */
+       if (!(hdmi[8] & (1<<5)))
+               return false;
+
+       /* Latency_fields_present */
+       if (hdmi[8] & (1 << 7))
+               skip += 2;
+
+       /* I_Latency_fields_present */
+       if (hdmi[8] & (1 << 6))
+               skip += 2;
+
+       /* the declared length is not long enough */
+       if (len < (9 + skip))
+               return false;
+
+       return (hdmi[9 + skip] & (1 << 7)) != 0;
+}
+
+static const struct {
+       int width, height, freq;
+       unsigned int select, value;
+       unsigned int formats;
+} s3d_mandatory_modes[] = {
+       { 1920, 1080, 24, DRM_MODE_FLAG_INTERLACE, 0,
+         DRM_MODE_FLAG_3D_TOP_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING },
+       { 1920, 1080, 50, DRM_MODE_FLAG_INTERLACE, DRM_MODE_FLAG_INTERLACE,
+         DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
+       { 1920, 1080, 60, DRM_MODE_FLAG_INTERLACE, DRM_MODE_FLAG_INTERLACE,
+         DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
+       { 1280, 720,  50, DRM_MODE_FLAG_INTERLACE, 0,
+         DRM_MODE_FLAG_3D_TOP_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING },
+       { 1280, 720,  60, DRM_MODE_FLAG_INTERLACE, 0,
+         DRM_MODE_FLAG_3D_TOP_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING }
+};
+
+static void cea_hdmi_patch_mandatory_3d_mode(struct drm_display_mode *mode)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(s3d_mandatory_modes); i++) {
+               if (mode->hdisplay == s3d_mandatory_modes[i].width &&
+                   mode->vdisplay == s3d_mandatory_modes[i].height &&
+                   (mode->flags & s3d_mandatory_modes[i].select) ==
+                               s3d_mandatory_modes[i].value &&
+                   drm_mode_vrefresh(mode) == s3d_mandatory_modes[i].freq) {
+                       mode->flags |= s3d_mandatory_modes[i].formats;
+               }
+       }
+}
+
+static void cea_hdmi_patch_mandatory_3d_modes(struct drm_connector *connector)
+{
+       struct drm_display_mode *mode;
+
+       list_for_each_entry(mode, &connector->probed_modes, head)
+               cea_hdmi_patch_mandatory_3d_mode(mode);
+}
+
 static int
 add_cea_modes(struct drm_connector *connector, struct edid *edid)
 {
        u8 * cea = drm_find_cea_extension(edid);
-       u8 * db, dbl;
+       u8 * db, *hdmi = NULL, dbl;
        int modes = 0;
 
+       /* let's find the cea modes before looking at the hdmi vendor block
+        * as the 3d_present flag needs to know about the supported modes
+        * to infer the 3D modes */
        if (cea && cea[1] >= 3) {
                for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
                        dbl = db[0] & 0x1f;
-                       if (((db[0] & 0xe0) >> 5) == VIDEO_BLOCK)
+                       switch ((db[0] & 0xe0) >> 5) {
+                       case VIDEO_BLOCK:
                                modes += do_cea_modes (connector, db+1, dbl);
+                               break;
+                       case VENDOR_BLOCK:
+                               hdmi = db;
+                               break;
+                       }
                }
        }
 
+       if (hdmi && cea_hdmi_3d_present(hdmi))
+               cea_hdmi_patch_mandatory_3d_modes(connector);
+
        return modes;
 }
 
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 3d6301b..04b4996 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -44,20 +44,27 @@
 
 /* Video mode flags */
 /* bit compatible with the xorg definitions. */
-#define DRM_MODE_FLAG_PHSYNC   (1<<0)
-#define DRM_MODE_FLAG_NHSYNC   (1<<1)
-#define DRM_MODE_FLAG_PVSYNC   (1<<2)
-#define DRM_MODE_FLAG_NVSYNC   (1<<3)
-#define DRM_MODE_FLAG_INTERLACE        (1<<4)
-#define DRM_MODE_FLAG_DBLSCAN  (1<<5)
-#define DRM_MODE_FLAG_CSYNC    (1<<6)
-#define DRM_MODE_FLAG_PCSYNC   (1<<7)
-#define DRM_MODE_FLAG_NCSYNC   (1<<8)
-#define DRM_MODE_FLAG_HSKEW    (1<<9) /* hskew provided */
-#define DRM_MODE_FLAG_BCAST    (1<<10)
-#define DRM_MODE_FLAG_PIXMUX   (1<<11)
-#define DRM_MODE_FLAG_DBLCLK   (1<<12)
-#define DRM_MODE_FLAG_CLKDIV2  (1<<13)
+#define DRM_MODE_FLAG_PHSYNC                   (1<<0)
+#define DRM_MODE_FLAG_NHSYNC                   (1<<1)
+#define DRM_MODE_FLAG_PVSYNC                   (1<<2)
+#define DRM_MODE_FLAG_NVSYNC                   (1<<3)
+#define DRM_MODE_FLAG_INTERLACE                        (1<<4)
+#define DRM_MODE_FLAG_DBLSCAN                  (1<<5)
+#define DRM_MODE_FLAG_CSYNC                    (1<<6)
+#define DRM_MODE_FLAG_PCSYNC                   (1<<7)
+#define DRM_MODE_FLAG_NCSYNC                   (1<<8)
+#define DRM_MODE_FLAG_HSKEW                    (1<<9) /* hskew provided */
+#define DRM_MODE_FLAG_BCAST                    (1<<10)
+#define DRM_MODE_FLAG_PIXMUX                   (1<<11)
+#define DRM_MODE_FLAG_DBLCLK                   (1<<12)
+#define DRM_MODE_FLAG_CLKDIV2                  (1<<13)
+#define DRM_MODE_FLAG_3D_TOP_BOTTOM            (1<<14)
+#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF     (1<<15)
+#define DRM_MODE_FLAG_3D_FRAME_PACKING         (1<<16)
+
+#define DRM_MODE_FLAG_3D_MASK  (DRM_MODE_FLAG_3D_TOP_BOTTOM |          \
+                                DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF |   \
+                                DRM_MODE_FLAG_3D_FRAME_PACKING)
 
 /* DPMS flags */
 /* bit compatible with the xorg definitions. */
-- 
1.7.11.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to