Support to parse multiple CEA extension blocks and HF-EEODB to extend drm edid driver's capability.
v4: add one more patch to support HF-SCDB v5: HF-SCDB and HF-VSDBS carry the same SCDS data. Reuse drm_parse_hdmi_forum_vsdb() to parse this packet. v6: save proper extension block index if CTA data information was found in DispalyID block.
Lee Shawn C (5): drm/edid: seek for available CEA block from specific EDID block index drm/edid: parse multiple CEA extension block drm/edid: read HF-EEODB ext block drm/edid: parse HF-EEODB CEA extension block drm/edid: check for HF-SCDB block
drivers/gpu/drm/drm_connector.c | 8 +- drivers/gpu/drm/drm_displayid.c | 5 +- drivers/gpu/drm/drm_edid.c | 173 ++++++++++++++++++++++++-------- include/drm/drm_edid.h | 4 +- 4 files changed, 143 insertions(+), 47 deletions(-)
drm_find_cea_extension() always look for a top level CEA block. Pass ext_index from caller then this function to search next available CEA ext block from a specific EDID block pointer.
v2: save proper extension block index if CTA data information was found in DispalyID block.
Cc: Jani Nikula jani.nikula@linux.intel.com Cc: Ville Syrjala ville.syrjala@linux.intel.com Cc: Ankit Nautiyal ankit.k.nautiyal@intel.com Cc: intel-gfx intel-gfx@lists.freedesktop.org Signed-off-by: Lee Shawn C shawn.c.lee@intel.com --- drivers/gpu/drm/drm_edid.c | 43 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 561f53831e29..e267d31d5c87 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3353,16 +3353,14 @@ const u8 *drm_find_edid_extension(const struct edid *edid, return edid_ext; }
-static const u8 *drm_find_cea_extension(const struct edid *edid) +static const u8 *drm_find_cea_extension(const struct edid *edid, int *ext_index) { const struct displayid_block *block; struct displayid_iter iter; const u8 *cea; - int ext_index = 0;
- /* Look for a top level CEA extension block */ - /* FIXME: make callers iterate through multiple CEA ext blocks? */ - cea = drm_find_edid_extension(edid, CEA_EXT, &ext_index); + /* Look for a CEA extension block from ext_index */ + cea = drm_find_edid_extension(edid, CEA_EXT, ext_index); if (cea) return cea;
@@ -3370,6 +3368,7 @@ static const u8 *drm_find_cea_extension(const struct edid *edid) displayid_iter_edid_begin(edid, &iter); displayid_iter_for_each(block, &iter) { if (block->tag == DATA_BLOCK_CTA) { + *ext_index = iter.ext_index; cea = (const u8 *)block; break; } @@ -3643,10 +3642,10 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) struct drm_device *dev = connector->dev; struct drm_display_mode *mode, *tmp; LIST_HEAD(list); - int modes = 0; + int modes = 0, ext_index = 0;
/* Don't add CEA modes if the CEA extension block is missing */ - if (!drm_find_cea_extension(edid)) + if (!drm_find_cea_extension(edid, &ext_index)) return 0;
/* @@ -4321,11 +4320,11 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, static int add_cea_modes(struct drm_connector *connector, struct edid *edid) { - const u8 *cea = drm_find_cea_extension(edid); - const u8 *db, *hdmi = NULL, *video = NULL; + const u8 *cea, *db, *hdmi = NULL, *video = NULL; u8 dbl, hdmi_len, video_len = 0; - int modes = 0; + int modes = 0, ext_index = 0;
+ cea = drm_find_cea_extension(edid, &ext_index); if (cea && cea_revision(cea) >= 3) { int i, start, end;
@@ -4562,7 +4561,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) uint8_t *eld = connector->eld; const u8 *cea; const u8 *db; - int total_sad_count = 0; + int total_sad_count = 0, ext_index = 0; int mnl; int dbl;
@@ -4571,7 +4570,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) if (!edid) return;
- cea = drm_find_cea_extension(edid); + cea = drm_find_cea_extension(edid, &ext_index); if (!cea) { DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); return; @@ -4655,11 +4654,11 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) */ int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads) { - int count = 0; + int count = 0, ext_index = 0; int i, start, end, dbl; const u8 *cea;
- cea = drm_find_cea_extension(edid); + cea = drm_find_cea_extension(edid, &ext_index); if (!cea) { DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); return 0; @@ -4717,11 +4716,11 @@ EXPORT_SYMBOL(drm_edid_to_sad); */ int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb) { - int count = 0; + int count = 0, ext_index = 0; int i, start, end, dbl; const u8 *cea;
- cea = drm_find_cea_extension(edid); + cea = drm_find_cea_extension(edid, &ext_index); if (!cea) { DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); return 0; @@ -4814,9 +4813,9 @@ bool drm_detect_hdmi_monitor(struct edid *edid) { const u8 *edid_ext; int i; - int start_offset, end_offset; + int start_offset, end_offset, ext_index = 0;
- edid_ext = drm_find_cea_extension(edid); + edid_ext = drm_find_cea_extension(edid, &ext_index); if (!edid_ext) return false;
@@ -4853,9 +4852,9 @@ bool drm_detect_monitor_audio(struct edid *edid) const u8 *edid_ext; int i, j; bool has_audio = false; - int start_offset, end_offset; + int start_offset, end_offset, ext_index = 0;
- edid_ext = drm_find_cea_extension(edid); + edid_ext = drm_find_cea_extension(edid, &ext_index); if (!edid_ext) goto end;
@@ -5177,9 +5176,9 @@ static void drm_parse_cea_ext(struct drm_connector *connector, { struct drm_display_info *info = &connector->display_info; const u8 *edid_ext; - int i, start, end; + int i, start, end, ext_index = 0;
- edid_ext = drm_find_cea_extension(edid); + edid_ext = drm_find_cea_extension(edid, &ext_index); if (!edid_ext) return;
On Fri, Mar 11, 2022 at 09:22:14AM +0800, Lee Shawn C wrote:
This could still end up in an infinite loop in patch 2 in the case that there is no CEA_EXT block in the edid, but there is a CEA block in the DisplayId block.
Repeating my review comment from elsewhere, consider the case: - If there are no cea extension blocks in the EDID, drm_find_edid_extension returns NULL - drm_find_cea_extension will then return the first DisplayId block with tag DATA_BLOCK_CTA
If the version of the cea data from DisplayId block is less than 3, the loop will restart and call drm_find_cea_extension the same way, returning the same DisplayID block every time.
Setting *ext_index inside the display_iter_for_each block doesn't change this, since we're not checking it.
But I don't think we want to use the same *ext_index both to pass into drm_find_edid_extension and for tracking the next DisplayId block to check. This might end up in similar infinite loops or skipping DisplayId blocks.
Maybe you'll need to pass in two indexes to drm_find_cea_extension, one which is passed to drm_find_edid_extension, and the other to keep track of the next DisplayId block to check.
On Saturday, March 12, 2022 7:41 AM, Drew Davenport ddavenport@chromium.org wrote:
As you mentioned, this situation would cause infinite loop. We may need two different parameters to store CEA and DisplayID block index.
Best regards, Shawn
Try to find and parse more CEA ext blocks if edid->extensions is greater than one.
v2: split prvious patch to two. And do CEA block parsing in this one. v3: simplify this patch based on previous change. v4: refine patch v3.
Cc: Jani Nikula jani.nikula@linux.intel.com Cc: Ville Syrjala ville.syrjala@linux.intel.com Cc: Ankit Nautiyal ankit.k.nautiyal@intel.com Cc: intel-gfx intel-gfx@lists.freedesktop.org Signed-off-by: Lee Shawn C shawn.c.lee@intel.com --- drivers/gpu/drm/drm_edid.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index e267d31d5c87..7717bf86c07d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -4320,16 +4320,22 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, static int add_cea_modes(struct drm_connector *connector, struct edid *edid) { - const u8 *cea, *db, *hdmi = NULL, *video = NULL; - u8 dbl, hdmi_len, video_len = 0; int modes = 0, ext_index = 0;
- cea = drm_find_cea_extension(edid, &ext_index); - if (cea && cea_revision(cea) >= 3) { + for (;;) { + const u8 *cea, *db, *hdmi = NULL, *video = NULL; + u8 dbl, hdmi_len = 0, video_len = 0; int i, start, end;
+ cea = drm_find_cea_extension(edid, &ext_index); + if (!cea) + break; + + if (cea_revision(cea) < 3) + continue; + if (cea_db_offsets(cea, &start, &end)) - return 0; + continue;
for_each_cea_db(cea, i, start, end) { db = &cea[i]; @@ -4351,15 +4357,15 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid) dbl - 1); } } - }
- /* - * We parse the HDMI VSDB after having added the cea modes as we will - * be patching their flags when the sink supports stereo 3D. - */ - if (hdmi) - modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len, video, - video_len); + /* + * We parse the HDMI VSDB after having added the cea modes as we will + * be patching their flags when the sink supports stereo 3D. + */ + if (hdmi) + modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len, video, + video_len); + }
return modes; }
According to HDMI 2.1 spec.
"The HDMI Forum EDID Extension Override Data Block (HF-EEODB) is utilized by Sink Devices to provide an alternate method to indicate an EDID Extension Block count larger than 1, while avoiding the need to present a VESA Block Map in the first E-EDID Extension Block."
It is a mandatory for HDMI 2.1 protocol compliance as well. This patch help to know how many HF_EEODB blocks report by sink and read allo HF_EEODB blocks back.
v2: support to find CEA block, check EEODB block format, and return available block number in drm_edid_read_hf_eeodb_blk_count().
Cc: Jani Nikula jani.nikula@linux.intel.com Cc: Ville Syrjala ville.syrjala@linux.intel.com Cc: Ankit Nautiyal ankit.k.nautiyal@intel.com Cc: intel-gfx intel-gfx@lists.freedesktop.org Signed-off-by: Lee Shawn C shawn.c.lee@intel.com --- drivers/gpu/drm/drm_connector.c | 8 +++- drivers/gpu/drm/drm_edid.c | 71 +++++++++++++++++++++++++++++++-- include/drm/drm_edid.h | 2 +- 3 files changed, 74 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index a50c82bc2b2f..16011023c12e 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -2129,7 +2129,7 @@ int drm_connector_update_edid_property(struct drm_connector *connector, const struct edid *edid) { struct drm_device *dev = connector->dev; - size_t size = 0; + size_t size = 0, hf_eeodb_blk_count; int ret; const struct edid *old_edid;
@@ -2137,8 +2137,12 @@ int drm_connector_update_edid_property(struct drm_connector *connector, if (connector->override_edid) return 0;
- if (edid) + if (edid) { size = EDID_LENGTH * (1 + edid->extensions); + hf_eeodb_blk_count = drm_edid_read_hf_eeodb_blk_count(edid); + if (hf_eeodb_blk_count) + size = EDID_LENGTH * (1 + hf_eeodb_blk_count); + }
/* Set the display info, using edid if available, otherwise * resetting the values to defaults. This duplicates the work diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7717bf86c07d..9f7fcecae3a2 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1992,6 +1992,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, { int i, j = 0, valid_extensions = 0; u8 *edid, *new; + size_t hf_eeodb_blk_count; struct edid *override;
override = drm_get_override_edid(connector); @@ -2051,7 +2052,35 @@ struct edid *drm_do_get_edid(struct drm_connector *connector, }
kfree(edid); + return (struct edid *)new; + } + + hf_eeodb_blk_count = drm_edid_read_hf_eeodb_blk_count((struct edid *)edid); + if (hf_eeodb_blk_count >= 2) { + new = krealloc(edid, (hf_eeodb_blk_count + 1) * EDID_LENGTH, GFP_KERNEL); + if (!new) + goto out; edid = new; + + valid_extensions = hf_eeodb_blk_count - 1; + for (j = 2; j <= hf_eeodb_blk_count; j++) { + u8 *block = edid + j * EDID_LENGTH; + + for (i = 0; i < 4; i++) { + if (get_edid_block(data, block, j, EDID_LENGTH)) + goto out; + if (drm_edid_block_valid(block, j, false, NULL)) + break; + } + + if (i == 4) + valid_extensions--; + } + + if (valid_extensions != hf_eeodb_blk_count - 1) { + DRM_ERROR("Not able to retrieve proper EDID contain HF-EEODB data.\n"); + goto out; + } }
return (struct edid *)edid; @@ -3315,15 +3344,17 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, #define VIDEO_BLOCK 0x02 #define VENDOR_BLOCK 0x03 #define SPEAKER_BLOCK 0x04 -#define HDR_STATIC_METADATA_BLOCK 0x6 -#define USE_EXTENDED_TAG 0x07 -#define EXT_VIDEO_CAPABILITY_BLOCK 0x00 +#define EXT_VIDEO_CAPABILITY_BLOCK 0x00 +#define HDR_STATIC_METADATA_BLOCK 0x06 +#define USE_EXTENDED_TAG 0x07 #define EXT_VIDEO_DATA_BLOCK_420 0x0E -#define EXT_VIDEO_CAP_BLOCK_Y420CMDB 0x0F +#define EXT_VIDEO_CAP_BLOCK_Y420CMDB 0x0F +#define EXT_VIDEO_HF_EEODB_DATA_BLOCK 0x78 #define EDID_BASIC_AUDIO (1 << 6) #define EDID_CEA_YCRCB444 (1 << 5) #define EDID_CEA_YCRCB422 (1 << 4) #define EDID_CEA_VCDB_QS (1 << 6) +#define HF_EEODB_LENGTH 2
/* * Search EDID for CEA extension block. @@ -4274,9 +4305,41 @@ static bool cea_db_is_y420vdb(const u8 *db) return true; }
+static bool cea_db_is_hdmi_forum_eeodb(const u8 *db) +{ + if (cea_db_tag(db) != USE_EXTENDED_TAG) + return false; + + if (cea_db_payload_len(db) != HF_EEODB_LENGTH) + return false; + + if (cea_db_extended_tag(db) != EXT_VIDEO_HF_EEODB_DATA_BLOCK) + return false; + + return true; +} + #define for_each_cea_db(cea, i, start, end) \ for ((i) = (start); (i) < (end) && (i) + cea_db_payload_len(&(cea)[(i)]) < (end); (i) += cea_db_payload_len(&(cea)[(i)]) + 1)
+size_t drm_edid_read_hf_eeodb_blk_count(const struct edid *edid) +{ + const u8 *cea; + int i, start, end, ext_index = 0; + + if (edid->extensions) { + cea = drm_find_cea_extension(edid, &ext_index); + + if (cea && !cea_db_offsets(cea, &start, &end)) + for_each_cea_db(cea, i, start, end) + if (cea_db_is_hdmi_forum_eeodb(&cea[i])) + return cea[i + 2]; + } + + return 0; +} +EXPORT_SYMBOL_GPL(drm_edid_read_hf_eeodb_blk_count); + static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, const u8 *db) { diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 144c495b99c4..5549da7bd7be 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -592,6 +592,6 @@ drm_display_mode_from_cea_vic(struct drm_device *dev, u8 video_code); const u8 *drm_find_edid_extension(const struct edid *edid, int ext_id, int *ext_index); - +size_t drm_edid_read_hf_eeodb_blk_count(const struct edid *edid);
#endif /* __DRM_EDID_H__ */
While adding CEA modes, try to get available EEODB block number. Then based on it to parse numbers of ext blocks, retrieve CEA information and add more CEA modes.
Cc: Jani Nikula jani.nikula@linux.intel.com Cc: Ville Syrjala ville.syrjala@linux.intel.com Cc: Ankit Nautiyal ankit.k.nautiyal@intel.com Cc: intel-gfx intel-gfx@lists.freedesktop.org Signed-off-by: Lee Shawn C shawn.c.lee@intel.com --- drivers/gpu/drm/drm_displayid.c | 5 ++++- drivers/gpu/drm/drm_edid.c | 35 +++++++++++++++++++-------------- include/drm/drm_edid.h | 2 +- 3 files changed, 25 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c index 32da557b960f..dc649a9efaa2 100644 --- a/drivers/gpu/drm/drm_displayid.c +++ b/drivers/gpu/drm/drm_displayid.c @@ -37,7 +37,10 @@ static const u8 *drm_find_displayid_extension(const struct edid *edid, int *length, int *idx, int *ext_index) { - const u8 *displayid = drm_find_edid_extension(edid, DISPLAYID_EXT, ext_index); + const u8 *displayid = drm_find_edid_extension(edid, + DISPLAYID_EXT, + ext_index, + edid->extensions); const struct displayid_header *base; int ret;
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 9f7fcecae3a2..eac6ce336507 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3360,23 +3360,23 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, * Search EDID for CEA extension block. */ const u8 *drm_find_edid_extension(const struct edid *edid, - int ext_id, int *ext_index) + int ext_id, int *ext_index, int ext_blk_num) { const u8 *edid_ext = NULL; int i;
/* No EDID or EDID extensions */ - if (edid == NULL || edid->extensions == 0) + if (edid == NULL || edid->extensions == 0 || *ext_index >= ext_blk_num) return NULL;
/* Find CEA extension */ - for (i = *ext_index; i < edid->extensions; i++) { + for (i = *ext_index; i < ext_blk_num; i++) { edid_ext = (const u8 *)edid + EDID_LENGTH * (i + 1); if (edid_ext[0] == ext_id) break; }
- if (i >= edid->extensions) + if (i >= ext_blk_num) return NULL;
*ext_index = i + 1; @@ -3384,14 +3384,15 @@ const u8 *drm_find_edid_extension(const struct edid *edid, return edid_ext; }
-static const u8 *drm_find_cea_extension(const struct edid *edid, int *ext_index) +static const u8 *drm_find_cea_extension(const struct edid *edid, + int *ext_index, int ext_blk_num) { const struct displayid_block *block; struct displayid_iter iter; const u8 *cea;
/* Look for a CEA extension block from ext_index */ - cea = drm_find_edid_extension(edid, CEA_EXT, ext_index); + cea = drm_find_edid_extension(edid, CEA_EXT, ext_index, ext_blk_num); if (cea) return cea;
@@ -3676,7 +3677,7 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) int modes = 0, ext_index = 0;
/* Don't add CEA modes if the CEA extension block is missing */ - if (!drm_find_cea_extension(edid, &ext_index)) + if (!drm_find_cea_extension(edid, &ext_index, edid->extensions)) return 0;
/* @@ -4328,7 +4329,7 @@ size_t drm_edid_read_hf_eeodb_blk_count(const struct edid *edid) int i, start, end, ext_index = 0;
if (edid->extensions) { - cea = drm_find_cea_extension(edid, &ext_index); + cea = drm_find_cea_extension(edid, &ext_index, edid->extensions);
if (cea && !cea_db_offsets(cea, &start, &end)) for_each_cea_db(cea, i, start, end) @@ -4384,13 +4385,17 @@ static int add_cea_modes(struct drm_connector *connector, struct edid *edid) { int modes = 0, ext_index = 0; + int ext_blk_num = drm_edid_read_hf_eeodb_blk_count(edid); + + if (!ext_blk_num) + ext_blk_num = edid->extensions;
for (;;) { const u8 *cea, *db, *hdmi = NULL, *video = NULL; u8 dbl, hdmi_len = 0, video_len = 0; int i, start, end;
- cea = drm_find_cea_extension(edid, &ext_index); + cea = drm_find_cea_extension(edid, &ext_index, ext_blk_num); if (!cea) break;
@@ -4639,7 +4644,7 @@ static void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) if (!edid) return;
- cea = drm_find_cea_extension(edid, &ext_index); + cea = drm_find_cea_extension(edid, &ext_index, edid->extensions); if (!cea) { DRM_DEBUG_KMS("ELD: no CEA Extension found\n"); return; @@ -4727,7 +4732,7 @@ int drm_edid_to_sad(struct edid *edid, struct cea_sad **sads) int i, start, end, dbl; const u8 *cea;
- cea = drm_find_cea_extension(edid, &ext_index); + cea = drm_find_cea_extension(edid, &ext_index, edid->extensions); if (!cea) { DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); return 0; @@ -4789,7 +4794,7 @@ int drm_edid_to_speaker_allocation(struct edid *edid, u8 **sadb) int i, start, end, dbl; const u8 *cea;
- cea = drm_find_cea_extension(edid, &ext_index); + cea = drm_find_cea_extension(edid, &ext_index, edid->extensions); if (!cea) { DRM_DEBUG_KMS("SAD: no CEA Extension found\n"); return 0; @@ -4884,7 +4889,7 @@ bool drm_detect_hdmi_monitor(struct edid *edid) int i; int start_offset, end_offset, ext_index = 0;
- edid_ext = drm_find_cea_extension(edid, &ext_index); + edid_ext = drm_find_cea_extension(edid, &ext_index, edid->extensions); if (!edid_ext) return false;
@@ -4923,7 +4928,7 @@ bool drm_detect_monitor_audio(struct edid *edid) bool has_audio = false; int start_offset, end_offset, ext_index = 0;
- edid_ext = drm_find_cea_extension(edid, &ext_index); + edid_ext = drm_find_cea_extension(edid, &ext_index, edid->extensions); if (!edid_ext) goto end;
@@ -5247,7 +5252,7 @@ static void drm_parse_cea_ext(struct drm_connector *connector, const u8 *edid_ext; int i, start, end, ext_index = 0;
- edid_ext = drm_find_cea_extension(edid, &ext_index); + edid_ext = drm_find_cea_extension(edid, &ext_index, edid->extensions); if (!edid_ext) return;
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index 5549da7bd7be..5555b27e92f9 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -591,7 +591,7 @@ struct drm_display_mode * drm_display_mode_from_cea_vic(struct drm_device *dev, u8 video_code); const u8 *drm_find_edid_extension(const struct edid *edid, - int ext_id, int *ext_index); + int ext_id, int *ext_index, int ext_blk_num); size_t drm_edid_read_hf_eeodb_blk_count(const struct edid *edid);
#endif /* __DRM_EDID_H__ */
Find HF-SCDB information in CEA extensions block. And retrieve Max_TMDS_Character_Rate that support by sink device.
v2: HF-SCDB and HF-VSDBS carry the same SCDS data. Reuse drm_parse_hdmi_forum_vsdb() to parse this packet.
Cc: Jani Nikula jani.nikula@linux.intel.com Cc: Ville Syrjala ville.syrjala@linux.intel.com Cc: Ankit Nautiyal ankit.k.nautiyal@intel.com Cc: intel-gfx intel-gfx@lists.freedesktop.org Signed-off-by: Lee Shawn C shawn.c.lee@intel.com --- drivers/gpu/drm/drm_edid.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index eac6ce336507..159e01be6f68 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3350,6 +3350,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid, #define EXT_VIDEO_DATA_BLOCK_420 0x0E #define EXT_VIDEO_CAP_BLOCK_Y420CMDB 0x0F #define EXT_VIDEO_HF_EEODB_DATA_BLOCK 0x78 +#define EXT_VIDEO_HF_SCDB_DATA_BLOCK 0x79 #define EDID_BASIC_AUDIO (1 << 6) #define EDID_CEA_YCRCB444 (1 << 5) #define EDID_CEA_YCRCB422 (1 << 4) @@ -4278,6 +4279,20 @@ static bool cea_db_is_vcdb(const u8 *db) return true; }
+static bool cea_db_is_hdmi_forum_scdb(const u8 *db) +{ + if (cea_db_tag(db) != USE_EXTENDED_TAG) + return false; + + if (cea_db_payload_len(db) < 7) + return false; + + if (cea_db_extended_tag(db) != EXT_VIDEO_HF_SCDB_DATA_BLOCK) + return false; + + return true; +} + static bool cea_db_is_y420cmdb(const u8 *db) { if (cea_db_tag(db) != USE_EXTENDED_TAG) @@ -5273,7 +5288,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector,
if (cea_db_is_hdmi_vsdb(db)) drm_parse_hdmi_vsdb_video(connector, db); - if (cea_db_is_hdmi_forum_vsdb(db)) + if (cea_db_is_hdmi_forum_vsdb(db) || + cea_db_is_hdmi_forum_scdb(db)) drm_parse_hdmi_forum_vsdb(connector, db); if (cea_db_is_microsoft_vsdb(db)) drm_parse_microsoft_vsdb(connector, db);
dri-devel@lists.freedesktop.org