[PATCH] This patch enables the reading of the 3D capabilities of t=

Sateesh Kavuri sateesh.kavuri at intel.com
Wed Dec 7 01:19:20 PST 2011


he connected
 HDMI monitor. Currently only the 3D format support fields are read.
 Later this could be extended. This information is expected to be sent to
 the user space which then sets the format on the monitor.
 This patch also handles DIP register signaling to the HDMI connected 3D
 monitor the 3D format to be set

---
Signed-off-by: Sateesh Kavuri <sateesh.kavuri at intel.com>
---
---
 drivers/gpu/drm/drm_edid.c        |  109 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h  |   11 ++++
 drivers/gpu/drm/i915/intel_hdmi.c |  119 +++++++++++++++++++++++++++++++++=
++++
 include/drm/drm_crtc.h            |    2 +
 include/drm/drm_edid.h            |   20 ++++++
 5 files changed, 261 insertions(+), 0 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index fe39c35..5d4a425 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1321,6 +1321,8 @@ add_detailed_modes(struct drm_connector *connector, s=
truct edid *edid,
 #define VENDOR_BLOCK    0x03
 #define SPEAKER_BLOCK	0x04
 #define EDID_BASIC_AUDIO	(1 << 6)
+#define MONITOR_VIDEO_PRESENT	0x01
+#define PANEL_SUPPORTS_3D	0x01
=20
 /**
  * Search EDID for CEA extension block.
@@ -1610,6 +1612,113 @@ end:
 }
 EXPORT_SYMBOL(drm_detect_monitor_audio);
=20
+enum {
+	NO_SPL_CAPS =3D 0x0,
+	STRUCTURE_PRESENT =3D 0x1,
+	STRUCTURE_MASK_PRESENT =3D 0x2
+} are_3d_caps_present;
+
+/**
+ * drm_detect_monitor_3D - check monitor 3D capabilities
+ *
+ * Monitor should have CEA extension block.
+ * Check if the monitor has 3D capabilities. If it does, store the capabil=
itie
+ * to a data structure
+ *
+ * FIXME: Currently returning bool (to denote 3D present or not), later sh=
ould
+ * return the 3D capabilities (or can there be a separate function for tha=
t?)
+ */
+bool drm_detect_3D_monitor(struct edid *edid)
+{
+	u8 *edid_ext;
+	int i, hdmi_id;
+	int start_offset, end_offset;
+	bool is_hdmi =3D false;
+	bool is_3d =3D false;
+	struct panel_3d_caps *caps =3D kmalloc(sizeof(struct panel_3d_caps), GFP_=
KERNEL);
+
+	edid_ext =3D drm_find_cea_extension(edid);
+	if (!edid_ext)
+		goto end;
+
+	/* Data block offset in CEA extension block */
+	start_offset =3D 4;
+	end_offset =3D edid_ext[2];
+
+	/* 3D vars */
+	int multi_present =3D 0;
+
+	/*
+	 * Because HDMI identifier is in Vendor Specific Block,
+	 * search it from all data blocks of CEA extension.
+	 */
+	for (i =3D start_offset; i < end_offset;
+		/* Increased by data block len */
+		i +=3D ((edid_ext[i] & 0x1f) + 1)) {
+		/* Find vendor specific block */
+		/* 6'th bit is the VIDEO_PRESENT bit */
+		if ( ((edid_ext[i] >> 5) =3D=3D VENDOR_BLOCK) &&
+	             ((edid_ext[i+8] & 0x20) =3D=3D MONITOR_VIDEO_PRESENT) ) {
+			hdmi_id =3D edid_ext[i + 1] | (edid_ext[i + 2] << 8) |
+				  edid_ext[i + 3] << 16;
+			/* Find HDMI identifier */
+			if (hdmi_id =3D=3D HDMI_IDENTIFIER)
+				is_hdmi =3D true;
+
+			/* Check for the 3D_Present flag */
+			if ((edid_ext[i+13] >> 6) =3D=3D PANEL_SUPPORTS_3D) {
+				caps->panel_supports_3d =3D 1;
+				is_3d =3D true;
+			}
+
+			/* Check if 3D_Multi_present is set */
+			if ((edid_ext[i+13] & 0x60) =3D=3D 0x0) {
+				multi_present =3D true;
+			}
+
+			/* Collect 3D capabilities of the monitor */
+			int hdmi_3d_len =3D 0;
+			int hdmi_vic_len =3D 0;
+			hdmi_vic_len =3D (edid_ext[i+14] >> 0x05);
+			hdmi_3d_len =3D ((edid_ext[i+14] << 0x03) >>0x03);
+			int multi_val =3D edid_ext[i+13] & 0x6;
+			if (multi_val =3D=3D 0x0)
+				multi_present =3D NO_SPL_CAPS;
+			else if (multi_val =3D=3D 0x1)
+				multi_present =3D STRUCTURE_PRESENT;
+			else if (multi_val =3D=3D 0x2)
+				multi_val =3D STRUCTURE_MASK_PRESENT;
+
+			if ((multi_val =3D=3D STRUCTURE_PRESENT) ||=20
+				(multi_val =3D=3D STRUCTURE_MASK_PRESENT) ) {
+				if ((edid_ext[i+15+hdmi_vic_len] & 0x01) =3D=3D 0x01)
+					caps->format |=3D 0x0; /* FRAME_PACKING */
+				if ((edid_ext[i+15+hdmi_vic_len] & 0x02) =3D=3D 0x02)
+					caps->format |=3D 0x1; /*FIELD_ALTERNATIVE */
+				if ((edid_ext[i+15+hdmi_vic_len] & 0x04) =3D=3D 0x04)
+					caps->format |=3D 0x2; /* LINE_ALTERNATIVE */
+				if ((edid_ext[i+15+hdmi_vic_len] & 0x08) =3D=3D 0x08)
+					caps->format |=3D 0x3; /*SIDE_BY_SIDE_FULL */
+				if ((edid_ext[i+15+hdmi_vic_len] & 0x10) =3D=3D 0x10)
+					caps->format |=3D 0x4; /* L_DEPTH */
+				if ((edid_ext[i+15+hdmi_vic_len] & 0x20) =3D=3D 0x20)
+					caps->format |=3D 0x5; /* L_DEPTH_GFX_GFX_DEPTH */
+				if ((edid_ext[i+15+hdmi_vic_len] & 0x40) =3D=3D 0x40)
+					caps->format |=3D 0x6; /* TOP_BOTTOM */
+				if ((edid_ext[i+14+hdmi_vic_len] & 0x01) =3D=3D 0x01)
+					caps->format |=3D 0x7; /* S_BY_S_HALF */
+				if ((edid_ext[i+14+hdmi_vic_len] & 0x80) =3D=3D 0x80)
+					caps->format |=3D 0x8; /* S_BY_S_HALF_QUINCUNX */
+			}
+			break;=20
+		}
+	}
+
+end:
+	return is_3d;
+}
+EXPORT_SYMBOL(drm_detect_3D_monitor);
+
 /**
  * drm_add_display_info - pull display info out if present
  * @edid: EDID data
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_=
drv.h
index bd9a604..2edfdc4 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -183,6 +183,11 @@ struct intel_crtc {
=20
 #define DIP_HEADER_SIZE	5
=20
+/* Vendor info frame =3D 0x81 */
+#define DIP_TYPE_VSIF    0x81
+#define DIP_VERSION_VSIF    0x01
+#define DIP_LEN_VSIF     06
+
 #define DIP_TYPE_AVI    0x82
 #define DIP_VERSION_AVI 0x2
 #define DIP_LEN_AVI     13
@@ -232,6 +237,12 @@ struct dip_infoframe {
 			uint8_t pd[16];
 			uint8_t sdi;
 		} spd;
+		struct {
+                        uint8_t ieee[3];
+                        uint8_t hdmi_video_format; /* last 3 bits are used=
 */
+                        uint8_t s3d_struct;         /* last 4 bits are use=
d */
+                        uint8_t s3d_struct_ext;     /* last 4 bits are use=
d */
+                } hdmi_vendor_info;
 		uint8_t payload[27];
 	} __attribute__ ((packed)) body;
 } __attribute__((packed));
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel=
_hdmi.c
index d4f5a0b..db1d196 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -44,6 +44,7 @@ struct intel_hdmi {
 	uint32_t color_range;
 	bool has_hdmi_sink;
 	bool has_audio;
+	bool has_3D;
 	int force_audio;
 	void (*write_infoframe)(struct drm_encoder *encoder,
 				struct dip_infoframe *frame);
@@ -86,6 +87,9 @@ static u32 intel_infoframe_index(struct dip_infoframe *fr=
ame)
 	case DIP_TYPE_SPD:
 		flags |=3D VIDEO_DIP_SELECT_SPD;
 		break;
+	case DIP_TYPE_VSIF:
+		flags |=3D VIDEO_DIP_SELECT_VENDOR;
+		break;
 	default:
 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
 		break;
@@ -105,6 +109,9 @@ static u32 intel_infoframe_flags(struct dip_infoframe *=
frame)
 	case DIP_TYPE_SPD:
 		flags |=3D VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_VSYNC;
 		break;
+	case DIP_TYPE_VSIF:
+		flags |=3D VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_FREQ_VSYNC;
+		break;
 	default:
 		DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
 		break;
@@ -200,6 +207,117 @@ static void intel_hdmi_set_avi_infoframe(struct drm_e=
ncoder *encoder)
 	intel_set_infoframe(encoder, &avi_if);
 }
=20
+#define VSIF_RESET_INDEX 0xFFFFFFF8
+#define VSIF_RESET_BIT_22 0xFFBFFFFF
+#define VSIF_SET_BIT_19 0x80000
+#define VSIF_RESET_BIT_20 0xFFEFFFFF
+#define VSIF_RESET_BIT_17 0x10000
+#define VSIF_SET_BIT_16 0xFFFDFFFF
+#define VSIF_SET_MASTER_BIT 0x400000
+
+/*
+ * write_vendor_infoframe
+ * Writes the vendor info frame
+ */
+static void write_vendor_infoframe(struct drm_encoder *encoder,
+				     struct dip_infoframe *frame)
+{
+
+	uint32_t *data =3D (uint32_t *)frame;
+	struct drm_device *dev =3D encoder->dev;
+	struct drm_i915_private *dev_priv =3D dev->dev_private;
+	struct drm_crtc *crtc =3D encoder->crtc;
+	struct intel_crtc *intel_crtc =3D to_intel_crtc(crtc);
+	int reg =3D TVIDEO_DIP_CTL(intel_crtc->pipe);
+	unsigned i, len =3D DIP_HEADER_SIZE + frame->len;
+	u32 val =3D I915_READ(reg);
+
+	intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+	/* set bits 0..3 =3D 0, i.e., reset the index of the data register */
+	val &=3D VSIF_RESET_INDEX;
+
+	/* Set bit 22=3D0 */
+	val &=3D VSIF_RESET_BIT_22;
+	/* Set bit 19=3D1 */
+	val |=3D VSIF_SET_BIT_19;
+
+	/* Set bit 20=3D0 */
+	val &=3D VSIF_RESET_BIT_20;
+
+	/* Set bits 17,16 =3D 01 */
+	val |=3D VSIF_RESET_BIT_17;
+	val &=3D VSIF_SET_BIT_16;
+
+        I915_WRITE(reg, val );
+
+	for (i =3D 0; i < len; i +=3D 4) {
+		I915_WRITE(reg, *data);
+		data++;
+	}
+	val =3D I915_READ(reg);
+
+	/* Set bit 22=3D1 */
+	val |=3D VSIF_SET_MASTER_BIT;
+=20
+	I915_WRITE(reg, val );
+}
+
+#define HDMI_REG_ID_1 0x03
+#define HDMI_REG_ID_2 0x0C
+#define HDMI_REG_ID_3 0x00
+#define HDMI_3D_VIDEO_FORMAT 0x40
+
+/**
+ * intel_hdmi_set_vendor_infoframe
+ * Sets the vendor info frame for a particular 3D format
+ */
+static void intel_hdmi_set_vendor_infoframe(struct drm_encoder *encoder,
+					enum s3d_formats format,
+					enum s3d_formats_ext subformat)
+{
+	struct dip_infoframe hdmi_vendor_if;
+	hdmi_vendor_if.type =3D DIP_TYPE_VSIF;
+	hdmi_vendor_if.ver =3D DIP_VERSION_VSIF;
+	hdmi_vendor_if.len =3D DIP_LEN_VSIF;
+	hdmi_vendor_if.body.hdmi_vendor_info.ieee[0] =3D HDMI_REG_ID_1;
+	hdmi_vendor_if.body.hdmi_vendor_info.ieee[1] =3D HDMI_REG_ID_2;
+	hdmi_vendor_if.body.hdmi_vendor_info.ieee[2] =3D HDMI_REG_ID_3;
+	hdmi_vendor_if.body.hdmi_vendor_info.hdmi_video_format =3D HDMI_3D_VIDEO_=
FORMAT;
+	/* 0x80 for side-by-side half */
+	hdmi_vendor_if.body.hdmi_vendor_info.s3d_struct =3D format;
+	/* 0x10 for horizontal sub-sampling */
+	hdmi_vendor_if.body.hdmi_vendor_info.s3d_struct_ext =3D subformat;
+
+	struct intel_hdmi *intel_hdmi =3D enc_to_intel_hdmi(encoder);
+
+        if (!intel_hdmi->has_hdmi_sink)
+                return;
+
+        intel_dip_infoframe_csum(&hdmi_vendor_if);
+	write_vendor_infoframe(encoder, &hdmi_vendor_if);
+
+}
+
+/**
+ * Disable s3d by knocking out the vendor info frame
+ */
+static void disable_vendor_info_frame(struct drm_encoder *encoder)
+{
+	struct drm_device *dev =3D encoder->dev;
+	struct drm_i915_private *dev_priv =3D dev->dev_private;
+	struct drm_crtc *crtc =3D encoder->crtc;
+	struct intel_crtc *intel_crtc =3D to_intel_crtc(crtc);
+	int reg =3D TVIDEO_DIP_CTL(intel_crtc->pipe);
+	u32 val =3D I915_READ(reg);
+
+	intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+	val &=3D ~VIDEO_DIP_ENABLE_VENDOR;
+
+	I915_WRITE(reg, val);
+}
+
 static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
 {
 	struct dip_infoframe spd_if;
@@ -337,6 +455,7 @@ intel_hdmi_detect(struct drm_connector *connector, bool=
 force)
 			status =3D connector_status_connected;
 			intel_hdmi->has_hdmi_sink =3D drm_detect_hdmi_monitor(edid);
 			intel_hdmi->has_audio =3D drm_detect_monitor_audio(edid);
+			intel_hdmi->has_3D =3D drm_detect_3D_monitor(edid);
 		}
 		connector->display_info.raw_edid =3D NULL;
 		kfree(edid);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 8020798..5b4d09c 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -798,6 +798,8 @@ extern int drm_mode_gamma_set_ioctl(struct drm_device *=
dev,
 extern u8 *drm_find_cea_extension(struct edid *edid);
 extern bool drm_detect_hdmi_monitor(struct edid *edid);
 extern bool drm_detect_monitor_audio(struct edid *edid);
+extern bool drm_detect_3D_monitor(struct edid *edid);
+//extern struct panel_3d_caps* drm_detect_3D_monitor(struct edid *edid);
 extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
 				    void *data, struct drm_file *file_priv);
 extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index 74ce916..06445e6 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -230,6 +230,26 @@ struct edid {
=20
 #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8))
=20
+enum s3d_formats {
+	FRAME_PACKING		=3D 0x0,
+	FIELD_ALTERNATIVE	=3D 0x1,
+	LINE_ALTERNATIVE	=3D 0x2,
+	SIDE_BY_SIDE_FULL	=3D 0x3,
+	L_DEPTH			=3D 0x4,
+	L_DEPTH_GFX_GFX_DEPTH	=3D 0x5,
+	TOP_BOTTOM		=3D 0x6, /* 0x7 is reserved for future */
+	SIDE_BY_SIDE_HALF	=3D 0x8  /* 0x9 onwards is reserved for future */
+};
+
+enum s3d_formats_ext {
+	HORIZONTAL_SUB_SAMPLING	=3D 0x10
+};
+
+struct panel_3d_caps {
+	u16	panel_supports_3d;
+	u16	format;
+};
+
 struct drm_encoder;
 struct drm_connector;
 struct drm_display_mode;
--=20
1.7.4.1



More information about the dri-devel mailing list