Move the EDID retrieval functions to the end of the file to avoid
forward declarations. While at it fix a typo in a comment
(s/firmare/firmware/). No functional change is included.

Signed-off-by: Laurent Pinchart <[email protected]>
---
 drivers/gpu/drm/drm_edid.c | 637 ++++++++++++++++++-------------------
 1 file changed, 317 insertions(+), 320 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 7c6bc5183b60..bfcb232b9760 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1340,9 +1340,6 @@ module_param_named(edid_fixup, edid_fixup, int, 0400);
 MODULE_PARM_DESC(edid_fixup,
                 "Minimum number of valid EDID header bytes (0-8, default 6)");
 
-static void drm_get_displayid(struct drm_connector *connector,
-                             struct edid *edid);
-
 static int drm_edid_block_checksum(const u8 *raw_edid)
 {
        int i;
@@ -1481,323 +1478,6 @@ bool drm_edid_is_valid(struct edid *edid)
 }
 EXPORT_SYMBOL(drm_edid_is_valid);
 
-#define DDC_SEGMENT_ADDR 0x30
-/**
- * drm_do_probe_ddc_edid() - get EDID information via I2C
- * @data: I2C device adapter
- * @buf: EDID data buffer to be filled
- * @block: 128 byte EDID block to start fetching from
- * @len: EDID data buffer length to fetch
- *
- * Try to fetch EDID information by calling I2C driver functions.
- *
- * Return: 0 on success or -1 on failure.
- */
-static int
-drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len)
-{
-       struct i2c_adapter *adapter = data;
-       unsigned char start = block * EDID_LENGTH;
-       unsigned char segment = block >> 1;
-       unsigned char xfers = segment ? 3 : 2;
-       int ret, retries = 5;
-
-       /*
-        * The core I2C driver will automatically retry the transfer if the
-        * adapter reports EAGAIN. However, we find that bit-banging transfers
-        * are susceptible to errors under a heavily loaded machine and
-        * generate spurious NAKs and timeouts. Retrying the transfer
-        * of the individual block a few times seems to overcome this.
-        */
-       do {
-               struct i2c_msg msgs[] = {
-                       {
-                               .addr   = DDC_SEGMENT_ADDR,
-                               .flags  = 0,
-                               .len    = 1,
-                               .buf    = &segment,
-                       }, {
-                               .addr   = DDC_ADDR,
-                               .flags  = 0,
-                               .len    = 1,
-                               .buf    = &start,
-                       }, {
-                               .addr   = DDC_ADDR,
-                               .flags  = I2C_M_RD,
-                               .len    = len,
-                               .buf    = buf,
-                       }
-               };
-
-               /*
-                * Avoid sending the segment addr to not upset non-compliant
-                * DDC monitors.
-                */
-               ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers);
-
-               if (ret == -ENXIO) {
-                       DRM_DEBUG_KMS("drm: skipping non-existent adapter %s\n",
-                                       adapter->name);
-                       break;
-               }
-       } while (ret != xfers && --retries);
-
-       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)
-{
-       struct edid *override = NULL;
-
-       if (connector->override_edid)
-               override = drm_edid_duplicate(connector->edid_blob_ptr->data);
-
-       if (!override)
-               override = drm_load_edid_firmware(connector);
-
-       return IS_ERR(override) ? NULL : override;
-}
-
-/**
- * drm_add_override_edid_modes - add modes from override/firmware EDID
- * @connector: connector we're probing
- *
- * Add modes from the override/firmware EDID, if available. Only to be used 
from
- * drm_helper_probe_single_connector_modes() as a fallback for when DDC probe
- * failed during drm_get_edid() and caused the override/firmware EDID to be
- * skipped.
- *
- * Return: The number of modes added or 0 if we couldn't find any.
- */
-int drm_add_override_edid_modes(struct drm_connector *connector)
-{
-       struct edid *override;
-       int num_modes = 0;
-
-       override = drm_get_override_edid(connector);
-       if (override) {
-               drm_connector_update_edid_property(connector, override);
-               num_modes = drm_add_edid_modes(connector, override);
-               kfree(override);
-
-               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] adding %d modes via fallback 
override/firmware EDID\n",
-                             connector->base.id, connector->name, num_modes);
-       }
-
-       return num_modes;
-}
-EXPORT_SYMBOL(drm_add_override_edid_modes);
-
-/**
- * drm_do_get_edid - get EDID data using a custom EDID block read function
- * @connector: connector we're probing
- * @get_edid_block: EDID block read function
- * @data: private data passed to the block read function
- *
- * When the I2C adapter connected to the DDC bus is hidden behind a device that
- * exposes a different interface to read EDID blocks this function can be used
- * to get EDID data using a custom block read function.
- *
- * As in the general case the DDC bus is accessible by the kernel at the I2C
- * level, drivers must make all reasonable efforts to expose it as an I2C
- * adapter and use drm_get_edid() instead of abusing this function.
- *
- * The EDID may be overridden using debugfs override_edid or firmare EDID
- * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
- * order. Having either of them bypasses actual EDID reads.
- *
- * Return: Pointer to valid EDID or NULL if we couldn't find any.
- */
-struct edid *drm_do_get_edid(struct drm_connector *connector,
-       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;
-
-       override = drm_get_override_edid(connector);
-       if (override)
-               return override;
-
-       if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
-               return NULL;
-
-       /* base block fetch */
-       for (i = 0; i < 4; i++) {
-               if (get_edid_block(data, edid, 0, EDID_LENGTH))
-                       goto out;
-               if (drm_edid_block_valid(edid, 0, false,
-                                        &connector->edid_corrupt))
-                       break;
-               if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) {
-                       connector->null_edid_counter++;
-                       goto carp;
-               }
-       }
-       if (i == 4)
-               goto carp;
-
-       /* if there's no extensions, we're done */
-       valid_extensions = edid[0x7e];
-       if (valid_extensions == 0)
-               return (struct edid *)edid;
-
-       new = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
-       if (!new)
-               goto out;
-       edid = new;
-
-       for (j = 1; j <= edid[0x7e]; 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 != edid[0x7e]) {
-               u8 *base;
-
-               connector_bad_edid(connector, edid, edid[0x7e] + 1);
-
-               edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
-               edid[0x7e] = valid_extensions;
-
-               new = kmalloc_array(valid_extensions + 1, EDID_LENGTH,
-                                   GFP_KERNEL);
-               if (!new)
-                       goto out;
-
-               base = new;
-               for (i = 0; i <= edid[0x7e]; i++) {
-                       u8 *block = edid + i * EDID_LENGTH;
-
-                       if (!drm_edid_block_valid(block, i, false, NULL))
-                               continue;
-
-                       memcpy(base, block, EDID_LENGTH);
-                       base += EDID_LENGTH;
-               }
-
-               kfree(edid);
-               edid = new;
-       }
-
-       return (struct edid *)edid;
-
-carp:
-       connector_bad_edid(connector, edid, 1);
-out:
-       kfree(edid);
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(drm_do_get_edid);
-
-/**
- * drm_probe_ddc() - probe DDC presence
- * @adapter: I2C adapter to probe
- *
- * Return: True on success, false on failure.
- */
-bool
-drm_probe_ddc(struct i2c_adapter *adapter)
-{
-       unsigned char out;
-
-       return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0);
-}
-EXPORT_SYMBOL(drm_probe_ddc);
-
-/**
- * drm_get_edid - get EDID data, if available
- * @connector: connector we're probing
- * @adapter: I2C adapter to use for DDC
- *
- * Poke the given I2C channel to grab EDID data if possible.  If found,
- * attach it to the connector.
- *
- * Return: Pointer to valid EDID or NULL if we couldn't find any.
- */
-struct edid *drm_get_edid(struct drm_connector *connector,
-                         struct i2c_adapter *adapter)
-{
-       struct edid *edid;
-
-       if (connector->force == DRM_FORCE_OFF)
-               return NULL;
-
-       if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
-               return NULL;
-
-       edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
-       if (edid)
-               drm_get_displayid(connector, edid);
-       return edid;
-}
-EXPORT_SYMBOL(drm_get_edid);
-
-/**
- * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
- * @connector: connector we're probing
- * @adapter: I2C adapter to use for DDC
- *
- * Wrapper around drm_get_edid() for laptops with dual GPUs using one set of
- * outputs. The wrapper adds the requisite vga_switcheroo calls to temporarily
- * switch DDC to the GPU which is retrieving EDID.
- *
- * Return: Pointer to valid EDID or %NULL if we couldn't find any.
- */
-struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
-                                    struct i2c_adapter *adapter)
-{
-       struct pci_dev *pdev = connector->dev->pdev;
-       struct edid *edid;
-
-       vga_switcheroo_lock_ddc(pdev);
-       edid = drm_get_edid(connector, adapter);
-       vga_switcheroo_unlock_ddc(pdev);
-
-       return edid;
-}
-EXPORT_SYMBOL(drm_get_edid_switcheroo);
-
 /**
  * drm_edid_duplicate - duplicate an EDID and the extensions
  * @edid: EDID to duplicate
@@ -5490,3 +5170,320 @@ static void drm_get_displayid(struct drm_connector 
*connector,
                connector->tile_group = NULL;
        }
 }
+
+#define DDC_SEGMENT_ADDR 0x30
+/**
+ * drm_do_probe_ddc_edid() - get EDID information via I2C
+ * @data: I2C device adapter
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Try to fetch EDID information by calling I2C driver functions.
+ *
+ * Return: 0 on success or -1 on failure.
+ */
+static int
+drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+       struct i2c_adapter *adapter = data;
+       unsigned char start = block * EDID_LENGTH;
+       unsigned char segment = block >> 1;
+       unsigned char xfers = segment ? 3 : 2;
+       int ret, retries = 5;
+
+       /*
+        * The core I2C driver will automatically retry the transfer if the
+        * adapter reports EAGAIN. However, we find that bit-banging transfers
+        * are susceptible to errors under a heavily loaded machine and
+        * generate spurious NAKs and timeouts. Retrying the transfer
+        * of the individual block a few times seems to overcome this.
+        */
+       do {
+               struct i2c_msg msgs[] = {
+                       {
+                               .addr   = DDC_SEGMENT_ADDR,
+                               .flags  = 0,
+                               .len    = 1,
+                               .buf    = &segment,
+                       }, {
+                               .addr   = DDC_ADDR,
+                               .flags  = 0,
+                               .len    = 1,
+                               .buf    = &start,
+                       }, {
+                               .addr   = DDC_ADDR,
+                               .flags  = I2C_M_RD,
+                               .len    = len,
+                               .buf    = buf,
+                       }
+               };
+
+               /*
+                * Avoid sending the segment addr to not upset non-compliant
+                * DDC monitors.
+                */
+               ret = i2c_transfer(adapter, &msgs[3 - xfers], xfers);
+
+               if (ret == -ENXIO) {
+                       DRM_DEBUG_KMS("drm: skipping non-existent adapter %s\n",
+                                       adapter->name);
+                       break;
+               }
+       } while (ret != xfers && --retries);
+
+       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)
+{
+       struct edid *override = NULL;
+
+       if (connector->override_edid)
+               override = drm_edid_duplicate(connector->edid_blob_ptr->data);
+
+       if (!override)
+               override = drm_load_edid_firmware(connector);
+
+       return IS_ERR(override) ? NULL : override;
+}
+
+/**
+ * drm_add_override_edid_modes - add modes from override/firmware EDID
+ * @connector: connector we're probing
+ *
+ * Add modes from the override/firmware EDID, if available. Only to be used 
from
+ * drm_helper_probe_single_connector_modes() as a fallback for when DDC probe
+ * failed during drm_get_edid() and caused the override/firmware EDID to be
+ * skipped.
+ *
+ * Return: The number of modes added or 0 if we couldn't find any.
+ */
+int drm_add_override_edid_modes(struct drm_connector *connector)
+{
+       struct edid *override;
+       int num_modes = 0;
+
+       override = drm_get_override_edid(connector);
+       if (override) {
+               drm_connector_update_edid_property(connector, override);
+               num_modes = drm_add_edid_modes(connector, override);
+               kfree(override);
+
+               DRM_DEBUG_KMS("[CONNECTOR:%d:%s] adding %d modes via fallback 
override/firmware EDID\n",
+                             connector->base.id, connector->name, num_modes);
+       }
+
+       return num_modes;
+}
+EXPORT_SYMBOL(drm_add_override_edid_modes);
+
+/**
+ * drm_do_get_edid - get EDID data using a custom EDID block read function
+ * @connector: connector we're probing
+ * @get_edid_block: EDID block read function
+ * @data: private data passed to the block read function
+ *
+ * When the I2C adapter connected to the DDC bus is hidden behind a device that
+ * exposes a different interface to read EDID blocks this function can be used
+ * to get EDID data using a custom block read function.
+ *
+ * As in the general case the DDC bus is accessible by the kernel at the I2C
+ * level, drivers must make all reasonable efforts to expose it as an I2C
+ * adapter and use drm_get_edid() instead of abusing this function.
+ *
+ * The EDID may be overridden using debugfs override_edid or firmware EDID
+ * (drm_load_edid_firmware() and drm.edid_firmware parameter), in this priority
+ * order. Having either of them bypasses actual EDID reads.
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+struct edid *drm_do_get_edid(struct drm_connector *connector,
+       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;
+
+       override = drm_get_override_edid(connector);
+       if (override)
+               return override;
+
+       if ((edid = kmalloc(EDID_LENGTH, GFP_KERNEL)) == NULL)
+               return NULL;
+
+       /* base block fetch */
+       for (i = 0; i < 4; i++) {
+               if (get_edid_block(data, edid, 0, EDID_LENGTH))
+                       goto out;
+               if (drm_edid_block_valid(edid, 0, false,
+                                        &connector->edid_corrupt))
+                       break;
+               if (i == 0 && drm_edid_is_zero(edid, EDID_LENGTH)) {
+                       connector->null_edid_counter++;
+                       goto carp;
+               }
+       }
+       if (i == 4)
+               goto carp;
+
+       /* if there's no extensions, we're done */
+       valid_extensions = edid[0x7e];
+       if (valid_extensions == 0)
+               return (struct edid *)edid;
+
+       new = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH, GFP_KERNEL);
+       if (!new)
+               goto out;
+       edid = new;
+
+       for (j = 1; j <= edid[0x7e]; 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 != edid[0x7e]) {
+               u8 *base;
+
+               connector_bad_edid(connector, edid, edid[0x7e] + 1);
+
+               edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
+               edid[0x7e] = valid_extensions;
+
+               new = kmalloc_array(valid_extensions + 1, EDID_LENGTH,
+                                   GFP_KERNEL);
+               if (!new)
+                       goto out;
+
+               base = new;
+               for (i = 0; i <= edid[0x7e]; i++) {
+                       u8 *block = edid + i * EDID_LENGTH;
+
+                       if (!drm_edid_block_valid(block, i, false, NULL))
+                               continue;
+
+                       memcpy(base, block, EDID_LENGTH);
+                       base += EDID_LENGTH;
+               }
+
+               kfree(edid);
+               edid = new;
+       }
+
+       return (struct edid *)edid;
+
+carp:
+       connector_bad_edid(connector, edid, 1);
+out:
+       kfree(edid);
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(drm_do_get_edid);
+
+/**
+ * drm_probe_ddc() - probe DDC presence
+ * @adapter: I2C adapter to probe
+ *
+ * Return: True on success, false on failure.
+ */
+bool
+drm_probe_ddc(struct i2c_adapter *adapter)
+{
+       unsigned char out;
+
+       return (drm_do_probe_ddc_edid(adapter, &out, 0, 1) == 0);
+}
+EXPORT_SYMBOL(drm_probe_ddc);
+
+/**
+ * drm_get_edid - get EDID data, if available
+ * @connector: connector we're probing
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Poke the given I2C channel to grab EDID data if possible.  If found,
+ * attach it to the connector.
+ *
+ * Return: Pointer to valid EDID or NULL if we couldn't find any.
+ */
+struct edid *drm_get_edid(struct drm_connector *connector,
+                         struct i2c_adapter *adapter)
+{
+       struct edid *edid;
+
+       if (connector->force == DRM_FORCE_OFF)
+               return NULL;
+
+       if (connector->force == DRM_FORCE_UNSPECIFIED && 
!drm_probe_ddc(adapter))
+               return NULL;
+
+       edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
+       if (edid)
+               drm_get_displayid(connector, edid);
+       return edid;
+}
+EXPORT_SYMBOL(drm_get_edid);
+
+/**
+ * drm_get_edid_switcheroo - get EDID data for a vga_switcheroo output
+ * @connector: connector we're probing
+ * @adapter: I2C adapter to use for DDC
+ *
+ * Wrapper around drm_get_edid() for laptops with dual GPUs using one set of
+ * outputs. The wrapper adds the requisite vga_switcheroo calls to temporarily
+ * switch DDC to the GPU which is retrieving EDID.
+ *
+ * Return: Pointer to valid EDID or %NULL if we couldn't find any.
+ */
+struct edid *drm_get_edid_switcheroo(struct drm_connector *connector,
+                                    struct i2c_adapter *adapter)
+{
+       struct pci_dev *pdev = connector->dev->pdev;
+       struct edid *edid;
+
+       vga_switcheroo_lock_ddc(pdev);
+       edid = drm_get_edid(connector, adapter);
+       vga_switcheroo_unlock_ddc(pdev);
+
+       return edid;
+}
+EXPORT_SYMBOL(drm_get_edid_switcheroo);
-- 
Regards,

Laurent Pinchart

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

Reply via email to