drm/amd/display: Fetch the EDID from _DDC if available for eDP
authorMario Limonciello <mario.limonciello@amd.com>
Fri, 27 Sep 2024 23:06:00 +0000 (18:06 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 7 Oct 2024 18:32:08 +0000 (14:32 -0400)
Some manufacturers have intentionally put an EDID that differs from
the EDID on the internal panel on laptops.

Attempt to fetch this EDID if it exists and prefer it over the EDID
that is provided by the panel. If a user prefers to use the EDID from
the panel, offer a DC debugging parameter that would disable this.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Alex Hung <alex.hung@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
drivers/gpu/drm/amd/include/amd_shared.h

index ad8d64e6dd4400c3e3eea205b9114137d894abcb..6923184a65363f983e69e75a078b678f911d7f96 100644 (file)
@@ -23,6 +23,8 @@
  *
  */
 
+#include <acpi/video.h>
+
 #include <linux/string.h>
 #include <linux/acpi.h>
 #include <linux/i2c.h>
@@ -891,6 +893,60 @@ bool dm_helpers_is_dp_sink_present(struct dc_link *link)
        return dp_sink_present;
 }
 
+static int
+dm_helpers_probe_acpi_edid(void *data, u8 *buf, unsigned int block, size_t len)
+{
+       struct drm_connector *connector = data;
+       struct acpi_device *acpidev = ACPI_COMPANION(connector->dev->dev);
+       unsigned char start = block * EDID_LENGTH;
+       void *edid;
+       int r;
+
+       if (!acpidev)
+               return -ENODEV;
+
+       /* fetch the entire edid from BIOS */
+       r = acpi_video_get_edid(acpidev, ACPI_VIDEO_DISPLAY_LCD, -1, &edid);
+       if (r < 0) {
+               drm_dbg(connector->dev, "Failed to get EDID from ACPI: %d\n", r);
+               return r;
+       }
+       if (len > r || start > r || start + len > r) {
+               r = -EINVAL;
+               goto cleanup;
+       }
+
+       memcpy(buf, edid + start, len);
+       r = 0;
+
+cleanup:
+       kfree(edid);
+
+       return r;
+}
+
+static const struct drm_edid *
+dm_helpers_read_acpi_edid(struct amdgpu_dm_connector *aconnector)
+{
+       struct drm_connector *connector = &aconnector->base;
+
+       if (amdgpu_dc_debug_mask & DC_DISABLE_ACPI_EDID)
+               return NULL;
+
+       switch (connector->connector_type) {
+       case DRM_MODE_CONNECTOR_LVDS:
+       case DRM_MODE_CONNECTOR_eDP:
+               break;
+       default:
+               return NULL;
+       }
+
+       if (connector->force == DRM_FORCE_OFF)
+               return NULL;
+
+       return drm_edid_read_custom(connector, dm_helpers_probe_acpi_edid, connector);
+}
+
 enum dc_edid_status dm_helpers_read_local_edid(
                struct dc_context *ctx,
                struct dc_link *link,
@@ -913,8 +969,11 @@ enum dc_edid_status dm_helpers_read_local_edid(
         * do check sum and retry to make sure read correct edid.
         */
        do {
-
-               drm_edid = drm_edid_read_ddc(connector, ddc);
+               drm_edid = dm_helpers_read_acpi_edid(aconnector);
+               if (drm_edid)
+                       drm_info(connector->dev, "Using ACPI provided EDID for %s\n", connector->name);
+               else
+                       drm_edid = drm_edid_read_ddc(connector, ddc);
                drm_edid_connector_update(connector, drm_edid);
 
                /* DP Compliance Test 4.2.2.6 */
@@ -1295,4 +1354,4 @@ bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream
 {
        // TODO
        return false;
-}
\ No newline at end of file
+}
index f98b3a5444779c1218909dae84e16d5248ba4b63..7eefcb0f50703f7b7e9a4146678b79520437cc67 100644 (file)
@@ -339,6 +339,11 @@ enum DC_DEBUG_MASK {
         * @DC_FORCE_IPS_ENABLE: If set, force enable all IPS, all the time.
         */
        DC_FORCE_IPS_ENABLE = 0x4000,
+       /**
+        * @DC_DISABLE_ACPI_EDID: If set, don't attempt to fetch EDID for
+        * eDP display from ACPI _DDC method.
+        */
+       DC_DISABLE_ACPI_EDID = 0x8000,
 };
 
 enum amd_dpm_forced_level;