]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: v4l2-dv-timings: add v4l2_num_edid_blocks() helper
authorHans Verkuil <hverkuil@xs4all.nl>
Mon, 27 Jan 2025 11:03:12 +0000 (12:03 +0100)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Tue, 18 Feb 2025 07:11:37 +0000 (08:11 +0100)
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>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/v4l2-core/v4l2-dv-timings.c
include/media/v4l2-dv-timings.h

index d26edf157e640001569a5779ee24abffa8be09b7..6361e11d2be7cd1a509e1d43ba66ed381ea9d013 100644 (file)
@@ -1017,6 +1017,42 @@ 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;
+
+       if (!edid || !max_blocks)
+               return 0;
+
+       // The number of extension blocks is recorded at byte 126 of the
+       // first 128-byte block in the EDID.
+       //
+       // If there is an HDMI Forum EDID Extension Override Data Block
+       // present, then it is in bytes 4-6 of the first CTA-861 extension
+       // block of the EDID.
+       blocks = edid[126] + 1;
+       // Check for HDMI Forum EDID Extension Override Data Block
+       if (blocks >= 2 &&      // The EDID must be at least 2 blocks
+           max_blocks >= 3 &&  // The caller supports at least 3 blocks
+           edid[128] == 2 &&   // The first extension block is type CTA-861
+           edid[133] == 0x78 && // Identifier for the EEODB
+           (edid[132] & 0xe0) == 0xe0 && // Tag Code == 7
+           (edid[132] & 0x1f) >= 2 &&  // Length >= 2
+           edid[134] > 1)      // Number of extension blocks is sane
+               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
  *
index ff07dc6b103c6bfff4bb600e466d70b3d8fad578..714075c72f779196f9642f3540e015685266a135 100644 (file)
@@ -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);