
If no valid detailed timing can be found in the edid base block, check the detailed timing provided in the cea861 extension block, if any.
Reported-by: Da Xue da@libre.computer Tested-by: Da Xue da@libre.computer Signed-off-by: Jerome Brunet jbrunet@baylibre.com --- common/edid.c | 72 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 23 deletions(-)
diff --git a/common/edid.c b/common/edid.c index 553ab8fd01a1..7dd0c924c24a 100644 --- a/common/edid.c +++ b/common/edid.c @@ -169,6 +169,33 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info) return false; }
+bool edid_get_dtd_timing_validate(struct edid_monitor_descriptor *desc, + unsigned int dtd_count, + struct display_timing *timing, + bool (*mode_valid)(void *priv, + const struct display_timing *timing), + void *mode_valid_priv) +{ + bool timing_done = false; + int i; + + for (i = 0; i < dtd_count; i++, desc++) { + if (desc->zero_flag_1 != 0) { + decode_timing((u8 *)desc, timing); + if (mode_valid) + timing_done = mode_valid(mode_valid_priv, + timing); + else + timing_done = true; + + if (timing_done) + break; + } + } + + return timing_done; +} + int edid_get_timing_validate(u8 *buf, int buf_size, struct display_timing *timing, int *panel_bits_per_colourp, @@ -177,8 +204,9 @@ int edid_get_timing_validate(u8 *buf, int buf_size, void *mode_valid_priv) { struct edid1_info *edid = (struct edid1_info *)buf; + struct edid_cea861_info *info = NULL; + struct edid_monitor_descriptor *desc; bool timing_done; - int i;
if (buf_size < sizeof(*edid) || edid_check_info(edid)) { debug("%s: Invalid buffer\n", __func__); @@ -190,24 +218,27 @@ int edid_get_timing_validate(u8 *buf, int buf_size, return -ENOENT; }
- /* Look for detailed timing */ - timing_done = false; - for (i = 0; i < 4; i++) { - struct edid_monitor_descriptor *desc; + desc = edid->monitor_details.descriptor; + timing_done = edid_get_dtd_timing_validate(desc, 4, timing, + mode_valid, mode_valid_priv);
- desc = &edid->monitor_details.descriptor[i]; - if (desc->zero_flag_1 != 0) { - decode_timing((u8 *)desc, timing); - if (mode_valid) - timing_done = mode_valid(mode_valid_priv, - timing); - else - timing_done = true; + if (edid->extension_flag && (buf_size >= EDID_EXT_SIZE)) { + info = (struct edid_cea861_info *)(buf + sizeof(*edid));
- if (timing_done) - break; - } + if (info->extension_tag != EDID_CEA861_EXTENSION_TAG) + info = NULL; + } + + /* Check CEA861 info block for timing if don't have one yet */ + if (info && !timing_done && info->dtd_offset) { + unsigned int dtd_count = EDID_CEA861_DTD_COUNT(*info); + + desc = (struct edid_monitor_descriptor *)((u8 *)info + + info->dtd_offset); + timing_done = edid_get_dtd_timing_validate(desc, dtd_count, timing, + mode_valid, mode_valid_priv); } + if (!timing_done) return -EINVAL;
@@ -225,13 +256,8 @@ int edid_get_timing_validate(u8 *buf, int buf_size, }
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); - } + if (info) + timing->hdmi_monitor = cea_is_hdmi_vsdb_present(info);
return 0; }