From: Damien Lespiau <damien.lesp...@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.lesp...@intel.com>
---
 drivers/gpu/drm/i915/intel_drv.h  | 14 ++++++++
 drivers/gpu/drm/i915/intel_hdmi.c | 71 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 84 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cd54cf8..76d488e 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<<4)
+#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));
@@ -305,6 +318,7 @@ struct intel_hdmi {
        bool has_hdmi_sink;
        bool has_audio;
        enum hdmi_force_audio force_audio;
+       unsigned int s3d_mode;
        void (*write_infoframe)(struct drm_encoder *encoder,
                                struct dip_infoframe *frame);
        void (*set_infoframes)(struct drm_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c 
b/drivers/gpu/drm/i915/intel_hdmi.c
index 98f6024..ab0553d 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,51 @@ 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 intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+       struct dip_infoframe hdmi_if;
+
+       /* We really only need to send a HDMI vendor info frame when having
+        * a 3D format to describe */
+       if (!intel_hdmi->s3d_mode)
+               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] = 0xc0;
+       hdmi_if.body.hdmi.vendor_id[2] = 0x00;
+       hdmi_if.body.hdmi.video_format = DIP_HDMI_3D_PRESENT;
+       if (intel_hdmi->s3d_mode & DRM_MODE_FLAG_3D_FRAME_PACKING)
+               hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_FP;
+       else if (intel_hdmi->s3d_mode & DRM_MODE_FLAG_3D_TOP_BOTTOM)
+               hdmi_if.body.hdmi.s3d_struct = DIP_HDMI_3D_STRUCT_TB;
+       else if (intel_hdmi->s3d_mode & 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 (intel_hdmi->s3d_mode & 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;
+
+       DRM_DEBUG_DRIVER("3D payload (len %d) %02x %02x %02x %02x %02x %02x\n",
+                       hdmi_if.len,
+                       hdmi_if.body.payload[0],
+                       hdmi_if.body.payload[1],
+                       hdmi_if.body.payload[2],
+                       hdmi_if.body.payload[3],
+                       hdmi_if.body.payload[4],
+                       hdmi_if.body.payload[5]);
+
+       intel_set_infoframe(encoder, &hdmi_if);
+}
+
 static void g4x_set_infoframes(struct drm_encoder *encoder,
                               struct drm_display_mode *adjusted_mode)
 {
@@ -398,6 +447,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);
 }
 
 static void ibx_set_infoframes(struct drm_encoder *encoder,
@@ -457,6 +507,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);
 }
 
 static void cpt_set_infoframes(struct drm_encoder *encoder,
@@ -492,6 +543,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);
 }
 
 static void vlv_set_infoframes(struct drm_encoder *encoder,
@@ -526,6 +578,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);
 }
 
 static void hsw_set_infoframes(struct drm_encoder *encoder,
@@ -792,7 +845,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 +882,15 @@ intel_hdmi_set_property(struct drm_connector *connector,
                goto done;
        }
 
+
+       if (property == dev->mode_config.s3d_select_mode_property) {
+               if (val == intel_hdmi->s3d_mode)
+                       return 0;
+
+               intel_hdmi->s3d_mode = val;
+               goto done;
+       }
+
        return -EINVAL;
 
 done:
@@ -885,8 +948,14 @@ static const struct drm_encoder_funcs intel_hdmi_enc_funcs 
= {
 static void
 intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector 
*connector)
 {
+       struct drm_device *dev = connector->dev;
+
        intel_attach_force_audio_property(connector);
        intel_attach_broadcast_rgb_property(connector);
+       drm_mode_create_3d_property(dev);
+       drm_object_attach_property(&connector->base,
+                                  dev->mode_config.s3d_select_mode_property,
+                                  0);
 }
 
 void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
-- 
1.7.11.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to