[U-Boot] [PATCH 2/3] edid: Add HDMI flag to timing info

Jernej Skrabec jernej.skrabec at siol.net
Sat Apr 29 12:43:36 UTC 2017


Some DVI monitors don't show anything in HDMI mode since audio stream
confuses them. To solve this situation, this commit adds HDMI flag in
timing data and sets it accordingly during edid parsing.

First existence of extension block is checked. If it exists and it is
CEA861 extension, then data blocks are checked for presence of HDMI
vendor specific data block. If it is present, HDMI flag is set.

Signed-off-by: Jernej Skrabec <jernej.skrabec at siol.net>
---

 common/edid.c    | 42 ++++++++++++++++++++++++++++++++++++++++++
 include/edid.h   | 14 ++++++++++++++
 include/fdtdec.h |  1 +
 3 files changed, 57 insertions(+)

diff --git a/common/edid.c b/common/edid.c
index ab7069fdcd..19410aa4fc 100644
--- a/common/edid.c
+++ b/common/edid.c
@@ -136,6 +136,39 @@ static void decode_timing(u8 *buf, struct display_timing *timing)
 	      va + vbl, vborder);
 }
 
+/**
+ * Check if HDMI vendor specific data block is present in CEA block
+ * @param info	CEA extension block
+ * @return true if block is found
+ */
+static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info)
+{
+	u8 end, i = 0;
+
+	/* check for end of data block */
+	end = info->dtd_offset;
+	if (end == 0)
+		end = 127;
+	if (end < 4 || end > 127)
+		return false;
+	end -= 4;
+
+	while (i < end) {
+		/* Look for vendor specific data block of appropriate size */
+		if ((EDID_CEA861_DB_TYPE(*info, i) == EDID_CEA861_DB_VENDOR) &&
+		    (EDID_CEA861_DB_LEN(*info, i) >= 5)) {
+			u8 *db = &info->data[i + 1];
+			u32 oui = db[0] | (db[1] << 8) | (db[2] << 16);
+
+			if (oui == HDMI_IEEE_OUI)
+				return true;
+		}
+		i += EDID_CEA861_DB_LEN(*info, i) + 1;
+	}
+
+	return false;
+}
+
 int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
 		    int *panel_bits_per_colourp)
 {
@@ -181,6 +214,15 @@ int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
 			((edid->video_input_definition & 0x70) >> 3) + 4;
 	}
 
+	timing->hdmi_monitor = false;
+	if (edid->extension_flag && (buf_size >= EDID_EXT_SIZE)) {
+		struct edid_cea861_info *info =
+			(struct edid_cea861_info *)(buf + sizeof(*edid));
+
+		if (info->extension_tag == EDID_CEA861_EXTENSION_TAG)
+			timing->hdmi_monitor = cea_is_hdmi_vsdb_present(info);
+	}
+
 	return 0;
 }
 
diff --git a/include/edid.h b/include/edid.h
index 8b022fa98a..a9f2f3d3ab 100644
--- a/include/edid.h
+++ b/include/edid.h
@@ -19,6 +19,9 @@
 #define EDID_SIZE	128
 #define EDID_EXT_SIZE	256
 
+/* OUI of HDMI vendor specific data block */
+#define HDMI_IEEE_OUI 0x000c03
+
 #define GET_BIT(_x, _pos) \
 	(((_x) >> (_pos)) & 1)
 #define GET_BITS(_x, _pos_msb, _pos_lsb) \
@@ -234,6 +237,13 @@ struct edid1_info {
 	unsigned char checksum;
 } __attribute__ ((__packed__));
 
+enum edid_cea861_db_types {
+	EDID_CEA861_DB_AUDIO = 0x01,
+	EDID_CEA861_DB_VIDEO = 0x02,
+	EDID_CEA861_DB_VENDOR = 0x03,
+	EDID_CEA861_DB_SPEAKER = 0x04,
+};
+
 struct edid_cea861_info {
 	unsigned char extension_tag;
 #define EDID_CEA861_EXTENSION_TAG	0x02
@@ -251,6 +261,10 @@ struct edid_cea861_info {
 #define EDID_CEA861_DTD_COUNT(_x) \
 	GET_BITS(((_x).dtd_count), 3, 0)
 	unsigned char data[124];
+#define EDID_CEA861_DB_TYPE(_x, offset) \
+	GET_BITS((_x).data[offset], 7, 5)
+#define EDID_CEA861_DB_LEN(_x, offset) \
+	GET_BITS((_x).data[offset], 4, 0)
 } __attribute__ ((__packed__));
 
 /**
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 2134701c54..340766da1b 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -967,6 +967,7 @@ struct display_timing {
 	struct timing_entry vsync_len;		/* ver. sync len */
 
 	enum display_flags flags;		/* display flags */
+	bool hdmi_monitor;			/* is hdmi monitor? */
 };
 
 /**
-- 
2.12.2



More information about the U-Boot mailing list