[igt-dev] [PATCH i-g-t v3 3/9] lib/igt_edid: add support for Vendor Specific Data blocks

Simon Ser simon.ser at intel.com
Tue May 14 12:06:40 UTC 2019


For some reason HDMI audio won't work unless you cast a magic IEEE Registration
Identifier alongside with its appropriate Components of Source Physical
Address. The easiest way to do this is to capture a wild HDMI EDID, study it,
and blindly copy bytes because you don't understand anything about their
possible meaning (if any).

This commit also changes the SAD API exposed by igt_edid, to allow for both a
SAD block and a VSD block to be included in the same CEA block.

Signed-off-by: Simon Ser <simon.ser at intel.com>
Reviewed-by: Arkadiusz Hiler <arkadiusz.hiler at intel.com>
---
 lib/igt_edid.c | 72 +++++++++++++++++++++++++++++++++++++++-----------
 lib/igt_edid.h | 23 ++++++++++++++--
 2 files changed, 78 insertions(+), 17 deletions(-)

diff --git a/lib/igt_edid.c b/lib/igt_edid.c
index d01defb0925e..fbdb0c06b8d7 100644
--- a/lib/igt_edid.c
+++ b/lib/igt_edid.c
@@ -292,30 +292,72 @@ void cea_sad_init_pcm(struct cea_sad *sad, int channels,
 }
 
 /**
- * edid_ext_set_cea_sad: set an extension block to be CEA SAD
+ * cea_vsd_get_hdmi_default:
+ *
+ * Returns the default Vendor Specific Data block for HDMI.
  */
-void edid_ext_set_cea_sad(struct edid_ext *ext, const struct cea_sad *sads,
-			  size_t sads_len)
+const struct cea_vsd *cea_vsd_get_hdmi_default(size_t *size)
 {
-	struct edid_cea *cea = &ext->data.cea;
-	struct edid_cea_data_block *data_block;
-	size_t sads_size, data_block_size;
+	static char raw[sizeof(struct cea_vsd) + 4] = {0};
+	struct cea_vsd *vsd;
+
+	*size = sizeof(raw);
+
+	/* Magic incantation. Works better if you orient your screen in the
+	 * direction of the VESA headquarters. */
+	vsd = (struct cea_vsd *) raw;
+	vsd->ieee_oui[0] = 0x03;
+	vsd->ieee_oui[1] = 0x0C;
+	vsd->ieee_oui[2] = 0x00;
+	vsd->data[0] = 0x10;
+	vsd->data[1] = 0x00;
+	vsd->data[2] = 0x38;
+	vsd->data[3] = 0x2D;
+
+	return vsd;
+}
+
+static void edid_cea_data_block_init(struct edid_cea_data_block *block,
+				     enum edid_cea_data_type type, size_t size)
+{
+	assert(size <= 0xFF);
+	block->type_len = type << 5 | size;
+}
 
-	memset(ext, 0, sizeof(struct edid_ext));
+size_t edid_cea_data_block_set_sad(struct edid_cea_data_block *block,
+				   const struct cea_sad *sads, size_t sads_len)
+{
+	size_t sads_size;
 
 	sads_size = sizeof(struct cea_sad) * sads_len;
-	data_block_size = sizeof(struct edid_cea_data_block) + sads_size;
+	edid_cea_data_block_init(block, EDID_CEA_DATA_AUDIO, sads_size);
+
+	memcpy(block->data.sads, sads, sads_size);
+
+	return sizeof(struct edid_cea_data_block) + sads_size;
+}
+
+size_t edid_cea_data_block_set_vsd(struct edid_cea_data_block *block,
+				   const struct cea_vsd *vsd, size_t vsd_size)
+{
+	edid_cea_data_block_init(block, EDID_CEA_DATA_VENDOR_SPECIFIC,
+				 vsd_size);
+
+	memcpy(block->data.vsds, vsd, vsd_size);
+
+	return sizeof(struct edid_cea_data_block) + vsd_size;
+}
+
+void edid_ext_set_cea(struct edid_ext *ext, size_t data_blocks_size,
+		      uint8_t flags)
+{
+	struct edid_cea *cea = &ext->data.cea;
 
 	ext->tag = EDID_EXT_CEA;
 
 	cea->revision = 3;
-	cea->dtd_start = 4 + data_block_size;
-	cea->misc = 1 << 6; /* basic audio, no DTD */
-
-	assert(sads_size <= 0xFF);
-	data_block = (struct edid_cea_data_block *) cea->data;
-	data_block->type_len = EDID_CEA_DATA_AUDIO << 5 | sads_size;
-	memcpy(data_block->data.sads, sads, sads_size);
+	cea->dtd_start = 4 + data_blocks_size;
+	cea->misc = flags; /* just flags, no DTD */
 }
 
 void edid_ext_update_cea_checksum(struct edid_ext *ext)
diff --git a/lib/igt_edid.h b/lib/igt_edid.h
index 3668d733f06a..7edd7e38f41e 100644
--- a/lib/igt_edid.h
+++ b/lib/igt_edid.h
@@ -189,6 +189,12 @@ struct cea_sad {
 	uint8_t bitrate;
 } __attribute__((packed));
 
+/* Vendor Specific Data */
+struct cea_vsd {
+	uint8_t ieee_oui[3];
+	char data[];
+};
+
 enum edid_cea_data_type {
 	EDID_CEA_DATA_AUDIO = 1,
 	EDID_CEA_DATA_VIDEO = 2,
@@ -200,9 +206,17 @@ struct edid_cea_data_block {
 	uint8_t type_len; /* type is from enum edid_cea_data_type */
 	union {
 		struct cea_sad sads[0];
+		struct cea_vsd vsds[0];
 	} data;
 } __attribute__((packed));
 
+enum edid_cea_flag {
+	EDID_CEA_YCBCR422 = 1 << 4,
+	EDID_CEA_YCBCR444 = 1 << 5,
+	EDID_CEA_BASIC_AUDIO = 1 << 6,
+	EDID_CEA_UNDERSCAN = 1 << 7,
+};
+
 struct edid_cea {
 	uint8_t revision;
 	uint8_t dtd_start;
@@ -275,8 +289,13 @@ void detailed_timing_set_string(struct detailed_timing *dt,
 
 void cea_sad_init_pcm(struct cea_sad *sad, int channels,
 		      uint8_t sampling_rates, uint8_t sample_sizes);
-void edid_ext_set_cea_sad(struct edid_ext *ext, const struct cea_sad *sads,
-			  size_t sads_len);
 void edid_ext_update_cea_checksum(struct edid_ext *ext);
+const struct cea_vsd *cea_vsd_get_hdmi_default(size_t *size);
+size_t edid_cea_data_block_set_sad(struct edid_cea_data_block *block,
+				   const struct cea_sad *sads, size_t sads_len);
+size_t edid_cea_data_block_set_vsd(struct edid_cea_data_block *block,
+				   const struct cea_vsd *vsd, size_t vsd_size);
+void edid_ext_set_cea(struct edid_ext *ext, size_t data_blocks_size,
+		      uint8_t flags);
 
 #endif
-- 
2.21.0



More information about the igt-dev mailing list