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 <[email protected]>
Tested-by: Da Xue <[email protected]>
Signed-off-by: Jerome Brunet <[email protected]>
---
 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;
 }
-- 
2.28.0

Reply via email to