This patch is a proof of concept showing how EDID retrieval could be
decoupled from drm_connector, in order to avoid passing the connector
pointer to the drm_bridge .get_edid() operation. The user of such
bridges (in most case the future drm_bridge_connector helper, see
"[PATCH v2 00/50] drm/omap: Replace custom display drivers with
drm_bridge and drm_panel") would need to duplicate the logic found in
drm_do_get_edid(), and bridges would use the __drm_do_get_edid()
function to retrieve and return a drm_edid structure.

Not-yet-signed-off-by: Laurent Pinchart <[email protected]>
---
 drivers/gpu/drm/drm_edid.c | 157 ++++++++++++++++++++++---------------
 1 file changed, 95 insertions(+), 62 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 4b28635f1050..37b6a6de9f42 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -5119,34 +5119,6 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int 
block, size_t len)
        return ret == xfers ? 0 : -1;
 }
 
-static void connector_bad_edid(struct drm_connector *connector,
-                              u8 *edid, int num_blocks)
-{
-       int i;
-
-       if (connector->bad_edid_counter++ && !(drm_debug & DRM_UT_KMS))
-               return;
-
-       dev_warn(connector->dev->dev,
-                "%s: EDID is invalid:\n",
-                connector->name);
-       for (i = 0; i < num_blocks; i++) {
-               u8 *block = edid + i * EDID_LENGTH;
-               char prefix[20];
-
-               if (drm_edid_is_zero(block, EDID_LENGTH))
-                       sprintf(prefix, "\t[%02x] ZERO ", i);
-               else if (!drm_edid_block_valid(block, i, false, NULL))
-                       sprintf(prefix, "\t[%02x] BAD  ", i);
-               else
-                       sprintf(prefix, "\t[%02x] GOOD ", i);
-
-               print_hex_dump(KERN_WARNING,
-                              prefix, DUMP_PREFIX_NONE, 16, 1,
-                              block, EDID_LENGTH, false);
-       }
-}
-
 /* Get override or firmware EDID */
 static struct edid *drm_get_override_edid(struct drm_connector *connector)
 {
@@ -5201,31 +5173,67 @@ static bool __drm_probe_ddc(int (*get_edid_block)(void 
*data, u8 *buf,
        return (get_edid_block(data, &out, 0, 1) == 0);
 }
 
-static struct edid *__drm_do_get_edid(struct drm_connector *connector,
+struct drm_edid {
+       u8 *data;
+       unsigned int num_blocks;
+
+       unsigned int null_counter;
+       unsigned int bad_counter;
+       bool corrupt;
+};
+
+static void connector_bad_edid(struct drm_device *dev, const char *name,
+                              struct drm_edid *edid)
+{
+       int i;
+
+       if (edid->bad_counter++ && !(drm_debug & DRM_UT_KMS))
+               return;
+
+       dev_warn(dev->dev, "%s: EDID is invalid:\n", name);
+
+       for (i = 0; i < edid->num_blocks; i++) {
+               u8 *block = edid->data + i * EDID_LENGTH;
+               char prefix[20];
+
+               if (drm_edid_is_zero(block, EDID_LENGTH))
+                       sprintf(prefix, "\t[%02x] ZERO ", i);
+               else if (!drm_edid_block_valid(block, i, false, NULL))
+                       sprintf(prefix, "\t[%02x] BAD  ", i);
+               else
+                       sprintf(prefix, "\t[%02x] GOOD ", i);
+
+               print_hex_dump(KERN_WARNING,
+                              prefix, DUMP_PREFIX_NONE, 16, 1,
+                              block, EDID_LENGTH, false);
+       }
+}
+
+static int __drm_do_get_edid(struct drm_device *dev, const char *name,
+                            struct drm_edid *edid,
        int (*get_edid_block)(void *data, u8 *buf, unsigned int block,
                              size_t len),
        void *data)
 {
-       int i, j = 0, valid_extensions = 0;
-       u8 *edid, *new;
-       struct edid *override;
+       unsigned int valid_extensions;
+       unsigned int i, j;
+       u8 *new;
+       int ret;
 
-       override = drm_get_override_edid(connector);
-       if (override)
-               return override;
+       edid->data = kmalloc(EDID_LENGTH, GFP_KERNEL);
+       if (!edid->data)
+               return -ENOMEM;
 
-       if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
-               return NULL;
+       edid->num_blocks = 1;
 
        /* base block fetch */
        for (i = 0; i < 4; i++) {
-               if (get_edid_block(data, edid, 0, EDID_LENGTH))
+               if (get_edid_block(data, edid->data, 0, EDID_LENGTH))
                        goto out;
-               if (drm_edid_block_valid(edid, 0, false,
-                                        &connector->edid_corrupt))
+               if (drm_edid_block_valid(edid->data, 0, false, &edid->corrupt))
                        break;
-               if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) {
-                       connector->null_edid_counter++;
+               if (i == 0 && drm_edid_is_zero(edid->data, EDID_LENGTH)) {
+                       edid->null_counter++;
                        goto carp;
                }
        }
@@ -5233,17 +5241,19 @@ static struct edid *__drm_do_get_edid(struct 
drm_connector *connector,
                goto carp;
 
        /* if there's no extensions, we're done */
-       valid_extensions = edid[0x7e];
+       valid_extensions = edid->data[0x7e] + 1;
        if (valid_extensions == 0)
-               return (struct edid *)edid;
+               return 0;
 
-       new = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
+       edid->num_blocks += valid_extensions;
+
+       new = krealloc(edid->data, edid->num_blocks * EDID_LENGTH, GFP_KERNEL);
        if (!new)
                goto out;
-       edid = new;
+       edid->data = new;
 
-       for (j = 1; j <= edid[0x7e]; j++) {
-               u8 *block = edid + j * EDID_LENGTH;
+       for (j = 1; j < edid->num_blocks; j++) {
+               u8 *block = edid->data + j * EDID_LENGTH;
 
                for (i = 0; i < 4; i++) {
                        if (get_edid_block(data, block, j, EDID_LENGTH))
@@ -5256,22 +5266,25 @@ static struct edid *__drm_do_get_edid(struct 
drm_connector *connector,
                        valid_extensions--;
        }
 
-       if (valid_extensions != edid[0x7e]) {
+       if (valid_extensions != edid->num_blocks - 1) {
                u8 *base;
 
-               connector_bad_edid(connector, edid, edid[0x7e] + 1);
+               connector_bad_edid(dev, name, edid);
 
-               edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
-               edid[0x7e] = valid_extensions;
+               edid->data[EDID_LENGTH-1] += edid->data[0x7e] - 
valid_extensions;
+               edid->data[0x7e] = valid_extensions;
+               edid->num_blocks = valid_extensions + 1;
 
                new = kmalloc_array(valid_extensions + 1, EDID_LENGTH,
                                    GFP_KERNEL);
-               if (!new)
+               if (!new) {
+                       ret = -ENOMEM;
                        goto out;
+               }
 
                base = new;
-               for (i = 0; i <= edid[0x7e]; i++) {
-                       u8 *block = edid + i * EDID_LENGTH;
+               for (i = 0; i < edid->num_blocks; i++) {
+                       u8 *block = edid->data + i * EDID_LENGTH;
 
                        if (!drm_edid_block_valid(block, i, false, NULL))
                                continue;
@@ -5280,17 +5293,19 @@ static struct edid *__drm_do_get_edid(struct 
drm_connector *connector,
                        base += EDID_LENGTH;
                }
 
-               kfree(edid);
-               edid = new;
+               kfree(edid->data);
+               edid->data = new;
        }
 
-       return (struct edid *)edid;
+       return 0;
 
 carp:
-       connector_bad_edid(connector, edid, 1);
+       connector_bad_edid(dev, name, edid);
+       ret = -EINVAL;
 out:
-       kfree(edid);
-       return NULL;
+       kfree(edid->data);
+       edid->data = NULL;
+       return ret;
 }
 
 /**
@@ -5318,6 +5333,9 @@ struct edid *drm_do_get_edid(struct drm_connector 
*connector,
                              size_t len),
        void *data)
 {
+       struct drm_edid edid;
+       struct edid *override;
+
        if (connector->force == DRM_FORCE_OFF)
                return NULL;
 
@@ -5325,7 +5343,22 @@ struct edid *drm_do_get_edid(struct drm_connector 
*connector,
            !__drm_probe_ddc(get_edid_block, data))
                return NULL;
 
-       return __drm_do_get_edid(connector, get_edid_block, data);
+       override = drm_get_override_edid(connector);
+       if (override)
+               return override;
+
+       memset(&edid, 0, sizeof(edid));
+       edid.bad_counter = connector->bad_edid_counter;
+       edid.null_counter = connector->null_edid_counter;
+
+       __drm_do_get_edid(connector->dev, connector->name, &edid,
+                         get_edid_block, data);
+
+       connector->bad_edid_counter = edid.bad_counter;
+       connector->null_edid_counter = edid.null_counter;
+       connector->edid_corrupt = edid.corrupt;
+
+       return (struct edid *)edid.data;
 }
 EXPORT_SYMBOL_GPL(drm_do_get_edid);
 
-- 
Regards,

Laurent Pinchart

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to