patman: Convert camel case in checkpatch.py
[platform/kernel/u-boot.git] / common / edid.c
index 3d0809a..556c4e3 100644 (file)
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (c) 2012 The Chromium OS Authors.
  *
  * (C) Copyright 2010
  * Petr Stetiar <ynezz@true.cz>
  *
- * SPDX-License-Identifier:    GPL-2.0+
- *
  * Contains stolen code from ddcprobe project which is:
  * Copyright (C) Nalin Dahyabhai <bigfun@pobox.com>
  */
@@ -14,6 +13,7 @@
 #include <edid.h>
 #include <errno.h>
 #include <fdtdec.h>
+#include <log.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 
@@ -139,7 +139,7 @@ static void decode_timing(u8 *buf, struct display_timing *timing)
 /**
  * Check if HDMI vendor specific data block is present in CEA block
  * @param info CEA extension block
- * @return true if block is found
+ * Return: true if block is found
  */
 static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info)
 {
@@ -169,42 +169,78 @@ static bool cea_is_hdmi_vsdb_present(struct edid_cea861_info *info)
        return false;
 }
 
-int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
-                   int *panel_bits_per_colourp)
+static bool edid_find_valid_timing(void *buf, int count,
+                                  struct display_timing *timing,
+                                  bool (*mode_valid)(void *priv,
+                                       const struct display_timing *timing),
+                                  void *mode_valid_priv)
 {
-       struct edid1_info *edid = (struct edid1_info *)buf;
-       bool timing_done;
+       struct edid_detailed_timing *t = buf;
+       bool found = false;
        int i;
 
+       for (i = 0; i < count && !found; i++, t++)
+               if (EDID_DETAILED_TIMING_PIXEL_CLOCK(*t) != 0) {
+                       decode_timing((u8 *)t, timing);
+                       if (mode_valid)
+                               found = mode_valid(mode_valid_priv,
+                                                  timing);
+                       else
+                               found = true;
+               }
+
+       return found;
+}
+
+int edid_get_timing_validate(u8 *buf, int buf_size,
+                            struct display_timing *timing,
+                            int *panel_bits_per_colourp,
+                            bool (*mode_valid)(void *priv,
+                                       const struct display_timing *timing),
+                            void *mode_valid_priv)
+{
+       struct edid1_info *edid = (struct edid1_info *)buf;
+       bool found;
+
        if (buf_size < sizeof(*edid) || edid_check_info(edid)) {
                debug("%s: Invalid buffer\n", __func__);
                return -EINVAL;
        }
 
+       if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) {
+               debug("%s: Not a digital display\n", __func__);
+               return -ENOSYS;
+       }
+
        if (!EDID1_INFO_FEATURE_PREFERRED_TIMING_MODE(*edid)) {
                debug("%s: No preferred timing\n", __func__);
                return -ENOENT;
        }
 
-       /* Look for detailed timing */
-       timing_done = false;
-       for (i = 0; i < 4; i++) {
-               struct edid_monitor_descriptor *desc;
+       /* Look for detailed timing in base EDID */
+       found = edid_find_valid_timing(edid->monitor_details.descriptor, 4,
+                                      timing, mode_valid, mode_valid_priv);
 
-               desc = &edid->monitor_details.descriptor[i];
-               if (desc->zero_flag_1 != 0) {
-                       decode_timing((u8 *)desc, timing);
-                       timing_done = true;
-                       break;
+       /* Look for detailed timing in CTA-861 Extension Block */
+       if (!found && 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) {
+                       int count = EDID_CEA861_DTD_COUNT(*info);
+                       int offset = info->dtd_offset;
+                       int size = count * sizeof(struct edid_detailed_timing);
+
+                       if (offset >= 4 && offset + size < EDID_SIZE)
+                               found = edid_find_valid_timing(
+                                       (u8 *)info + offset, count, timing,
+                                       mode_valid, mode_valid_priv);
                }
        }
-       if (!timing_done)
+
+       if (!found)
                return -EINVAL;
 
-       if (!EDID1_INFO_VIDEO_INPUT_DIGITAL(*edid)) {
-               debug("%s: Not a digital display\n", __func__);
-               return -ENOSYS;
-       }
        if (edid->version != 1 || edid->revision < 4) {
                debug("%s: EDID version %d.%d does not have required info\n",
                      __func__, edid->version, edid->revision);
@@ -226,11 +262,19 @@ int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
        return 0;
 }
 
+int edid_get_timing(u8 *buf, int buf_size, struct display_timing *timing,
+                   int *panel_bits_per_colourp)
+{
+       return edid_get_timing_validate(buf, buf_size, timing,
+                                       panel_bits_per_colourp, NULL, NULL);
+}
+
+
 /**
  * Snip the tailing whitespace/return of a string.
  *
  * @param string       The string to be snipped
- * @return the snipped string
+ * Return: the snipped string
  */
 static char *snip(char *string)
 {