[PATCH 7/9] drm/edid: Expose mandatory stereo modes for HDMI sinks

Damien Lespiau damien.lespiau at intel.com
Fri Sep 6 11:57:23 PDT 2013


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.lespiau at intel.com>
---
 drivers/gpu/drm/drm_edid.c | 75 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index a207cc3..9d9881b 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -2550,13 +2550,60 @@ do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
 	return modes;
 }
 
+struct s3d_mandatory_mode {
+	int width, height, freq;
+	unsigned int interlace_flag, formats;
+};
+
+static const struct s3d_mandatory_mode s3d_mandatory_modes[] = {
+	{ 1920, 1080, 24, 0,
+	  DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING },
+	{ 1920, 1080, 50, DRM_MODE_FLAG_INTERLACE,
+	  DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
+	{ 1920, 1080, 60, DRM_MODE_FLAG_INTERLACE,
+	  DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF },
+	{ 1280, 720,  50, 0,
+	  DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING },
+	{ 1280, 720,  60, 0,
+	  DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING }
+};
+
+static bool match_s3d_mandatory_mode(const struct drm_display_mode *mode,
+				     const struct s3d_mandatory_mode *s3d_mode)
+{
+	unsigned int interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
+
+	return mode->hdisplay == s3d_mode->width &&
+	       mode->vdisplay == s3d_mode->height &&
+	       interlaced == s3d_mode->interlace_flag &&
+	       drm_mode_vrefresh(mode) == s3d_mode->freq;
+}
+
+static void hdmi_patch_stereo_mode(struct drm_display_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(s3d_mandatory_modes); i++)
+		if (match_s3d_mandatory_mode(mode, &s3d_mandatory_modes[i]))
+			mode->flags |= s3d_mandatory_modes[i].formats;
+}
+
+static void hdmi_patch_stereo_modes(struct drm_connector *connector)
+{
+	struct drm_display_mode *mode;
+
+	list_for_each_entry(mode, &connector->probed_modes, head)
+		hdmi_patch_stereo_mode(mode);
+}
+
 /*
  * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block
  * @connector: connector corresponding to the HDMI sink
  * @db: start of the CEA vendor specific block
  * @len: length of the CEA block payload, ie. one can access up to db[len]
  *
- * Parses the HDMI VSDB looking for modes to add to @connector.
+ * Parses the HDMI VSDB looking for modes to add to @connector. This function
+ * also adds the stereo 3d flags to already added modes.
  */
 static int
 do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
@@ -2582,10 +2629,15 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
 
 	/* the declared length is not long enough for the 2 first bytes
 	 * of additional video format capabilities */
-	offset += 2;
-	if (len < (8 + offset))
+	if (len < (8 + offset + 2))
 		goto out;
 
+	/* 3D_Present */
+	offset++;
+	if (db[8 + offset] & (1 << 7))
+		hdmi_patch_stereo_modes(connector);
+
+	offset++;
 	vic_len = db[8 + offset] >> 5;
 
 	for (i = 0; i < vic_len && len >= (9 + offset + i); i++) {
@@ -2665,8 +2717,8 @@ static int
 add_cea_modes(struct drm_connector *connector, struct edid *edid)
 {
 	const u8 *cea = drm_find_cea_extension(edid);
-	const u8 *db;
-	u8 dbl;
+	const u8 *db, *hdmi = NULL;
+	u8 dbl, hdmi_len;
 	int modes = 0;
 
 	if (cea && cea_revision(cea) >= 3) {
@@ -2681,11 +2733,20 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
 
 			if (cea_db_tag(db) == VIDEO_BLOCK)
 				modes += do_cea_modes(connector, db + 1, dbl);
-			else if (cea_db_is_hdmi_vsdb(db))
-				modes += do_hdmi_vsdb_modes(connector, db, dbl);
+			else if (cea_db_is_hdmi_vsdb(db)) {
+				hdmi = db;
+				hdmi_len = dbl;
+			}
 		}
 	}
 
+	/*
+	 * We parse the HDMI VSDB after having added the cea modes as we will
+	 * be patching their flags when the sink supports stereo 3D.
+	 */
+	if (hdmi)
+		modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len);
+
 	return modes;
 }
 
-- 
1.8.3.1



More information about the dri-devel mailing list