summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Lespiau <damien.lespiau@intel.com>2012-09-06 19:45:03 +0100
committerDamien Lespiau <damien.lespiau@intel.com>2012-09-28 02:51:05 +0100
commit4948618cc274cc705ce7a6c685f93046d7333302 (patch)
tree04e030ad442bdf9384bf40e5dab27de702f54131
parent5aa680799406b5ee85b452dea29278010caad29e (diff)
drm/i915: Add HDMI vendor info frame supportstereo-3d
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>
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h14
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c49
-rw-r--r--drivers/gpu/drm/i915/intel_modes.c12
3 files changed, 74 insertions, 1 deletions
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index cd54cf88a28..c326d30e232 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 98f602427eb..2d51b7ee19c 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 29b72593fbb..50216afd33c 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);
+}