diff mbox

[2/3] drm: Parse the HDMI cea vendor block for 3D present

Message ID 1348771268-3436-3-git-send-email-damien.lespiau@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Damien Lespiau Sept. 27, 2012, 6:41 p.m. UTC
From: Damien Lespiau <damien.lespiau@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.lespiau@intel.com>
---
 drivers/gpu/drm/drm_edid.c | 87 ++++++++++++++++++++++++++++++++++++++++++++--
 include/drm/drm_mode.h     | 35 +++++++++++--------
 2 files changed, 105 insertions(+), 17 deletions(-)

Comments

Rodrigo Vivi Sept. 29, 2012, 12:46 a.m. UTC | #1
Reviewed-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
Tested-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>

On Thu, Sep 27, 2012 at 3:41 PM, Damien Lespiau
<damien.lespiau@gmail.com> wrote:
> From: Damien Lespiau <damien.lespiau@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.lespiau@intel.com>
> ---
>  drivers/gpu/drm/drm_edid.c | 87 ++++++++++++++++++++++++++++++++++++++++++++--
>  include/drm/drm_mode.h     | 35 +++++++++++--------
>  2 files changed, 105 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index b7ee230..7eecfa0 100644
> --- a/drivers/gpu/drm/drm_edid.c
> +++ b/drivers/gpu/drm/drm_edid.c
> @@ -1522,21 +1522,102 @@ 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;
> -       int modes = 0;
> +       u8 * db, *hdmi = NULL, dbl;
> +       int modes = 0, vendor_id;
>
> +       /* 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:
> +                               vendor_id = db[1] | db[2] << 8 | db[3] << 16;
> +                               if (vendor_id == HDMI_IDENTIFIER)
> +                                       hdmi = db;
> +                       }
>                 }
>         }
>
> +       if (connector->expose_3d_modes && 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 45b19c6..d5d22de 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
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index b7ee230..7eecfa0 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1522,21 +1522,102 @@  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;
-	int modes = 0;
+	u8 * db, *hdmi = NULL, dbl;
+	int modes = 0, vendor_id;
 
+	/* 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:
+				vendor_id = db[1] | db[2] << 8 | db[3] << 16;
+				if (vendor_id == HDMI_IDENTIFIER)
+					hdmi = db;
+			}
 		}
 	}
 
+	if (connector->expose_3d_modes && 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 45b19c6..d5d22de 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. */