diff mbox

[3/3] drm/i915: Add HDMI vendor info frame support

Message ID 1348771268-3436-4-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>

When scanning out a 3D framebuffer, send the corresponding infoframe to
the HDMI sink.

See http://www.hdmi.org/manufacturer/specification.aspx for details.

Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h   | 14 +++++++++++
 drivers/gpu/drm/i915/intel_hdmi.c  | 49 +++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_modes.c | 12 ++++++++++
 3 files changed, 74 insertions(+), 1 deletion(-)

Comments

Rodrigo Vivi Sept. 29, 2012, 12:50 a.m. UTC | #1
On Thu, Sep 27, 2012 at 3:41 PM, Damien Lespiau
<damien.lespiau@gmail.com> wrote:
> From: Damien Lespiau <damien.lespiau@intel.com>
>
> When scanning out a 3D framebuffer, send the corresponding infoframe to
> the HDMI sink.
>
> See http://www.hdmi.org/manufacturer/specification.aspx for details.
>
> Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_drv.h   | 14 +++++++++++
>  drivers/gpu/drm/i915/intel_hdmi.c  | 49 +++++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_modes.c | 12 ++++++++++
>  3 files changed, 74 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index cd54cf8..c326d30e 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -263,6 +263,13 @@ struct cxsr_latency {
>  #define DIP_SPD_BD     0xa
>  #define DIP_SPD_SCD    0xb
>
> +#define DIP_TYPE_VENDOR                0x81
> +#define DIP_VERSION_VENDOR     0x1
> +#define DIP_HDMI_3D_PRESENT    (0x2<<5)
> +#define DIP_HDMI_3D_STRUCT_FP  (0x0<<4)
> +#define DIP_HDMI_3D_STRUCT_TB  (0x6<<4)
> +#define DIP_HDMI_3D_STRUCT_SBSH        (0x8<<4)
> +
>  struct dip_infoframe {
>         uint8_t type;           /* HB0 */
>         uint8_t ver;            /* HB1 */
> @@ -292,6 +299,12 @@ struct dip_infoframe {
>                         uint8_t pd[16];
>                         uint8_t sdi;
>                 } __attribute__ ((packed)) spd;
> +               struct {
> +                       uint8_t vendor_id[3];
> +                       uint8_t video_format;
> +                       uint8_t s3d_struct;
> +                       uint8_t s3d_ext_data;
> +               } __attribute__ ((packed)) hdmi;
>                 uint8_t payload[27];
>         } __attribute__ ((packed)) body;
>  } __attribute__((packed));
> @@ -348,6 +361,7 @@ int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
>
>  extern void intel_attach_force_audio_property(struct drm_connector *connector);
>  extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
> +extern void intel_attach_expose_3d_modes_property(struct drm_connector *connector);
>
>  extern void intel_crt_init(struct drm_device *dev);
>  extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 98f6024..2d51b7e 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -83,6 +83,8 @@ static u32 g4x_infoframe_index(struct dip_infoframe *frame)
>                 return VIDEO_DIP_SELECT_AVI;
>         case DIP_TYPE_SPD:
>                 return VIDEO_DIP_SELECT_SPD;
> +       case DIP_TYPE_VENDOR:
> +               return VIDEO_DIP_SELECT_VENDOR;
>         default:
>                 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
>                 return 0;
> @@ -96,6 +98,8 @@ static u32 g4x_infoframe_enable(struct dip_infoframe *frame)
>                 return VIDEO_DIP_ENABLE_AVI;
>         case DIP_TYPE_SPD:
>                 return VIDEO_DIP_ENABLE_SPD;
> +       case DIP_TYPE_VENDOR:
> +               return VIDEO_DIP_ENABLE_VENDOR;
>         default:
>                 DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
>                 return 0;
> @@ -338,6 +342,42 @@ static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
>         intel_set_infoframe(encoder, &spd_if);
>  }
>
> +static void intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
> +                                         struct drm_display_mode *adjusted_mode)
> +{
> +       struct dip_infoframe hdmi_if;
> +
> +       /* We really only need to send a HDMI vendor info frame when having
> +        * a 3D format to describe */
> +       if (!(adjusted_mode->flags & DRM_MODE_FLAG_3D_MASK))
> +               return;
> +
> +       memset(&hdmi_if, 0, sizeof(hdmi_if));
> +       hdmi_if.type = DIP_TYPE_VENDOR;
> +       hdmi_if.ver = DIP_VERSION_VENDOR;
> +       /* HDMI IEEE registration id, least significant bit first */
> +       hdmi_if.body.hdmi.vendor_id[0] = 0x03;
> +       hdmi_if.body.hdmi.vendor_id[1] = 0x0c;
> +       hdmi_if.body.hdmi.vendor_id[2] = 0x00;
> +       hdmi_if.body.hdmi.video_format = DIP_HDMI_3D_PRESENT;
> +       if (adjusted_mode->flags & DRM_MODE_FLAG_3D_FRAME_PACKING)
> +               hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_FP;
> +       else if (adjusted_mode->flags & DRM_MODE_FLAG_3D_TOP_BOTTOM)
> +               hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_TB;
> +       else if (adjusted_mode->flags & DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF)
> +               hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_SBSH;
> +       /* len is the payload len, not including checksum. Side by side (half)
> +        * has an extra byte for 3D_Ext_Data */
> +       if (adjusted_mode->flags & DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF) {
> +               hdmi_if.len = 6;
> +               /* SBSH is subsampled by a factor of 2 */
> +               hdmi_if.body.hdmi.s3d_ext_data = 2 << 4;
> +       } else
> +               hdmi_if.len = 5;
> +
> +       intel_set_infoframe(encoder, &hdmi_if);
> +}
> +
>  static void g4x_set_infoframes(struct drm_encoder *encoder,
>                                struct drm_display_mode *adjusted_mode)
>  {
> @@ -398,6 +438,7 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
>
>         intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
>         intel_hdmi_set_spd_infoframe(encoder);
> +       intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
>  }
>
>  static void ibx_set_infoframes(struct drm_encoder *encoder,
> @@ -457,6 +498,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
>
>         intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
>         intel_hdmi_set_spd_infoframe(encoder);
> +       intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
>  }
>
>  static void cpt_set_infoframes(struct drm_encoder *encoder,
> @@ -492,6 +534,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder,
>
>         intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
>         intel_hdmi_set_spd_infoframe(encoder);
> +       intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
>  }
>
>  static void vlv_set_infoframes(struct drm_encoder *encoder,
> @@ -526,6 +569,7 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
>
>         intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
>         intel_hdmi_set_spd_infoframe(encoder);
> +       intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);

set hdmi infoframes on hsw is missing. I can send my patch here, but
maybe it is better to keep everything together

>  }
>
>  static void hsw_set_infoframes(struct drm_encoder *encoder,
> @@ -792,7 +836,8 @@ intel_hdmi_set_property(struct drm_connector *connector,
>                         uint64_t val)
>  {
>         struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
> -       struct drm_i915_private *dev_priv = connector->dev->dev_private;
> +       struct drm_device *dev = connector->dev;
> +       struct drm_i915_private *dev_priv = dev->dev_private;
>         int ret;
>
>         ret = drm_connector_property_set_value(connector, property, val);
> @@ -828,6 +873,7 @@ intel_hdmi_set_property(struct drm_connector *connector,
>                 goto done;
>         }
>
> +
>         return -EINVAL;
>
>  done:
> @@ -887,6 +933,7 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
>  {
>         intel_attach_force_audio_property(connector);
>         intel_attach_broadcast_rgb_property(connector);
> +       intel_attach_expose_3d_modes_property(connector);
>  }
>
>  void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
> diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
> index 29b7259..50216af 100644
> --- a/drivers/gpu/drm/i915/intel_modes.c
> +++ b/drivers/gpu/drm/i915/intel_modes.c
> @@ -124,3 +124,15 @@ intel_attach_broadcast_rgb_property(struct drm_connector *connector)
>
>         drm_connector_attach_property(connector, prop, 0);
>  }
> +
> +void
> +intel_attach_expose_3d_modes_property(struct drm_connector *connector)
> +{
> +       struct drm_device *dev = connector->dev;
> +       struct drm_property *prop;
> +
> +       drm_mode_create_s3d_properties(dev);
> +       prop = dev->mode_config.s3d_expose_modes_property;
> +       drm_connector_attach_property(connector, prop,
> +                                     DRM_MODE_EXPOSE_3D_MODES_OFF);
> +}
> --
> 1.7.11.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reviewed-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
Tested-by: Rodrigo Vivi <rodrigo.vivi@gmail.com>
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cd54cf8..c326d30e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -263,6 +263,13 @@  struct cxsr_latency {
 #define DIP_SPD_BD	0xa
 #define DIP_SPD_SCD	0xb
 
+#define DIP_TYPE_VENDOR		0x81
+#define DIP_VERSION_VENDOR	0x1
+#define DIP_HDMI_3D_PRESENT	(0x2<<5)
+#define DIP_HDMI_3D_STRUCT_FP	(0x0<<4)
+#define DIP_HDMI_3D_STRUCT_TB	(0x6<<4)
+#define DIP_HDMI_3D_STRUCT_SBSH	(0x8<<4)
+
 struct dip_infoframe {
 	uint8_t type;		/* HB0 */
 	uint8_t ver;		/* HB1 */
@@ -292,6 +299,12 @@  struct dip_infoframe {
 			uint8_t pd[16];
 			uint8_t sdi;
 		} __attribute__ ((packed)) spd;
+		struct {
+			uint8_t vendor_id[3];
+			uint8_t video_format;
+			uint8_t s3d_struct;
+			uint8_t s3d_ext_data;
+		} __attribute__ ((packed)) hdmi;
 		uint8_t payload[27];
 	} __attribute__ ((packed)) body;
 } __attribute__((packed));
@@ -348,6 +361,7 @@  int intel_ddc_get_modes(struct drm_connector *c, struct i2c_adapter *adapter);
 
 extern void intel_attach_force_audio_property(struct drm_connector *connector);
 extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector);
+extern void intel_attach_expose_3d_modes_property(struct drm_connector *connector);
 
 extern void intel_crt_init(struct drm_device *dev);
 extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 98f6024..2d51b7e 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -83,6 +83,8 @@  static u32 g4x_infoframe_index(struct dip_infoframe *frame)
 		return VIDEO_DIP_SELECT_AVI;
 	case DIP_TYPE_SPD:
 		return VIDEO_DIP_SELECT_SPD;
+	case DIP_TYPE_VENDOR:
+		return VIDEO_DIP_SELECT_VENDOR;
 	default:
 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
 		return 0;
@@ -96,6 +98,8 @@  static u32 g4x_infoframe_enable(struct dip_infoframe *frame)
 		return VIDEO_DIP_ENABLE_AVI;
 	case DIP_TYPE_SPD:
 		return VIDEO_DIP_ENABLE_SPD;
+	case DIP_TYPE_VENDOR:
+		return VIDEO_DIP_ENABLE_VENDOR;
 	default:
 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
 		return 0;
@@ -338,6 +342,42 @@  static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
 	intel_set_infoframe(encoder, &spd_if);
 }
 
+static void intel_hdmi_set_hdmi_infoframe(struct drm_encoder *encoder,
+					  struct drm_display_mode *adjusted_mode)
+{
+	struct dip_infoframe hdmi_if;
+
+	/* We really only need to send a HDMI vendor info frame when having
+	 * a 3D format to describe */
+	if (!(adjusted_mode->flags & DRM_MODE_FLAG_3D_MASK))
+		return;
+
+	memset(&hdmi_if, 0, sizeof(hdmi_if));
+	hdmi_if.type = DIP_TYPE_VENDOR;
+	hdmi_if.ver = DIP_VERSION_VENDOR;
+	/* HDMI IEEE registration id, least significant bit first */
+	hdmi_if.body.hdmi.vendor_id[0] = 0x03;
+	hdmi_if.body.hdmi.vendor_id[1] = 0x0c;
+	hdmi_if.body.hdmi.vendor_id[2] = 0x00;
+	hdmi_if.body.hdmi.video_format = DIP_HDMI_3D_PRESENT;
+	if (adjusted_mode->flags & DRM_MODE_FLAG_3D_FRAME_PACKING)
+		hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_FP;
+	else if (adjusted_mode->flags & DRM_MODE_FLAG_3D_TOP_BOTTOM)
+		hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_TB;
+	else if (adjusted_mode->flags & DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF)
+		hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_SBSH;
+	/* len is the payload len, not including checksum. Side by side (half)
+	 * has an extra byte for 3D_Ext_Data */
+	if (adjusted_mode->flags & DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF) {
+		hdmi_if.len = 6;
+		/* SBSH is subsampled by a factor of 2 */
+		hdmi_if.body.hdmi.s3d_ext_data = 2 << 4;
+	} else
+		hdmi_if.len = 5;
+
+	intel_set_infoframe(encoder, &hdmi_if);
+}
+
 static void g4x_set_infoframes(struct drm_encoder *encoder,
 			       struct drm_display_mode *adjusted_mode)
 {
@@ -398,6 +438,7 @@  static void g4x_set_infoframes(struct drm_encoder *encoder,
 
 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
 	intel_hdmi_set_spd_infoframe(encoder);
+	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
 }
 
 static void ibx_set_infoframes(struct drm_encoder *encoder,
@@ -457,6 +498,7 @@  static void ibx_set_infoframes(struct drm_encoder *encoder,
 
 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
 	intel_hdmi_set_spd_infoframe(encoder);
+	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
 }
 
 static void cpt_set_infoframes(struct drm_encoder *encoder,
@@ -492,6 +534,7 @@  static void cpt_set_infoframes(struct drm_encoder *encoder,
 
 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
 	intel_hdmi_set_spd_infoframe(encoder);
+	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
 }
 
 static void vlv_set_infoframes(struct drm_encoder *encoder,
@@ -526,6 +569,7 @@  static void vlv_set_infoframes(struct drm_encoder *encoder,
 
 	intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
 	intel_hdmi_set_spd_infoframe(encoder);
+	intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
 }
 
 static void hsw_set_infoframes(struct drm_encoder *encoder,
@@ -792,7 +836,8 @@  intel_hdmi_set_property(struct drm_connector *connector,
 			uint64_t val)
 {
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
-	struct drm_i915_private *dev_priv = connector->dev->dev_private;
+	struct drm_device *dev = connector->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
 	ret = drm_connector_property_set_value(connector, property, val);
@@ -828,6 +873,7 @@  intel_hdmi_set_property(struct drm_connector *connector,
 		goto done;
 	}
 
+
 	return -EINVAL;
 
 done:
@@ -887,6 +933,7 @@  intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *c
 {
 	intel_attach_force_audio_property(connector);
 	intel_attach_broadcast_rgb_property(connector);
+	intel_attach_expose_3d_modes_property(connector);
 }
 
 void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index 29b7259..50216af 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -124,3 +124,15 @@  intel_attach_broadcast_rgb_property(struct drm_connector *connector)
 
 	drm_connector_attach_property(connector, prop, 0);
 }
+
+void
+intel_attach_expose_3d_modes_property(struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct drm_property *prop;
+
+	drm_mode_create_s3d_properties(dev);
+	prop = dev->mode_config.s3d_expose_modes_property;
+	drm_connector_attach_property(connector, prop,
+				      DRM_MODE_EXPOSE_3D_MODES_OFF);
+}