diff mbox series

[1/2] media: v4l2-dv-timings: add v4l2_num_edid_blocks() helper

Message ID aa6ec77d6c0e565a8c1105178540a5a7e8170b27.1737454902.git.hverkuil@xs4all.nl (mailing list archive)
State New
Headers show
Series media: add support for the EDID EEODB | expand

Commit Message

Hans Verkuil Jan. 21, 2025, 10:21 a.m. UTC
This new function determines how many blocks the EDID has.
Traditionally the number of extension blocks is read from
the EDID at offset 126, but this can be overridden by the
HDMI Forum EDID Extension Override Data Block. So check
that as well in this helper.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
---
 drivers/media/v4l2-core/v4l2-dv-timings.c | 29 +++++++++++++++++++++++
 include/media/v4l2-dv-timings.h           |  1 +
 2 files changed, 30 insertions(+)
diff mbox series

Patch

diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index d26edf157e64..f17766b2d800 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -1017,6 +1017,35 @@  v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
 }
 EXPORT_SYMBOL_GPL(v4l2_hdmi_rx_colorimetry);
 
+/**
+ * v4l2_num_edid_blocks() - return the number of EDID blocks
+ *
+ * @edid:	pointer to the EDID data
+ * @max_blocks:	maximum number of supported EDID blocks
+ *
+ * Return: the number of EDID blocks based on the contents of the EDID.
+ *	   This supports the HDMI Forum EDID Extension Override Data Block.
+ */
+unsigned int v4l2_num_edid_blocks(const u8 *edid, unsigned int max_blocks)
+{
+	unsigned int blocks = 0;
+
+	if (edid && max_blocks) {
+		blocks = edid[126] + 1;
+		// Check for HDMI Forum EDID Extension Override Data Block
+		if (blocks >= 2 &&
+		    max_blocks >= 3 &&
+		    edid[128] == 2 &&
+		    edid[133] == 0x78 &&
+		    (edid[132] & 0xe0) == 0xe0 &&
+		    (edid[132] & 0x1f) >= 2 &&
+		    edid[134] > 1)
+			blocks = edid[134] + 1;
+	}
+	return blocks > max_blocks ? max_blocks : blocks;
+}
+EXPORT_SYMBOL_GPL(v4l2_num_edid_blocks);
+
 /**
  * v4l2_get_edid_phys_addr() - find and return the physical address
  *
diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h
index ff07dc6b103c..714075c72f77 100644
--- a/include/media/v4l2-dv-timings.h
+++ b/include/media/v4l2-dv-timings.h
@@ -252,6 +252,7 @@  v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
 			 const struct hdmi_vendor_infoframe *hdmi,
 			 unsigned int height);
 
+unsigned int v4l2_num_edid_blocks(const u8 *edid, unsigned int max_blocks);
 u16 v4l2_get_edid_phys_addr(const u8 *edid, unsigned int size,
 			    unsigned int *offset);
 void v4l2_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr);