]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/displayid: add quirk to ignore DisplayID checksum errors
authorJani Nikula <jani.nikula@intel.com>
Tue, 28 Oct 2025 20:07:27 +0000 (22:07 +0200)
committerJani Nikula <jani.nikula@intel.com>
Tue, 4 Nov 2025 12:49:30 +0000 (14:49 +0200)
Add a mechanism for DisplayID specific quirks, and add the first quirk
to ignore DisplayID section checksum errors.

It would be quite inconvenient to pass existing EDID quirks from
drm_edid.c for DisplayID parsing. Not all places doing DisplayID
iteration have the quirks readily available, and would have to pass it
in all places. Simply add a separate array of DisplayID specific EDID
quirks. We do end up checking it every time we iterate DisplayID blocks,
but hopefully the number of quirks remains small.

There are a few laptop models with DisplayID checksum failures, leading
to higher refresh rates only present in the DisplayID blocks being
ignored. Add a quirk for the panel in the machines.

Reported-by: Tiago Martins Araújo <tiago.martins.araujo@gmail.com>
Closes: https://lore.kernel.org/r/CACRbrPGvLP5LANXuFi6z0S7XMbAG4X5y2YOLBDxfOVtfGGqiKQ@mail.gmail.com
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14703
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Tested-by: Tiago Martins Araújo <tiago.martins.araujo@gmail.com>
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/c04d81ae648c5f21b3f5b7953f924718051f2798.1761681968.git.jani.nikula@intel.com
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
drivers/gpu/drm/drm_displayid.c
drivers/gpu/drm/drm_displayid_internal.h

index 20b453d2b85478aa6718d434f00b9cecffb08184..58d0bb6d267689ae1e358904b420f71db7068f16 100644 (file)
@@ -9,6 +9,34 @@
 #include "drm_crtc_internal.h"
 #include "drm_displayid_internal.h"
 
+enum {
+       QUIRK_IGNORE_CHECKSUM,
+};
+
+struct displayid_quirk {
+       const struct drm_edid_ident ident;
+       u8 quirks;
+};
+
+static const struct displayid_quirk quirks[] = {
+       {
+               .ident = DRM_EDID_IDENT_INIT('C', 'S', 'O', 5142, "MNE007ZA1-5"),
+               .quirks = BIT(QUIRK_IGNORE_CHECKSUM),
+       },
+};
+
+static u8 get_quirks(const struct drm_edid *drm_edid)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(quirks); i++) {
+               if (drm_edid_match(drm_edid, &quirks[i].ident))
+                       return quirks[i].quirks;
+       }
+
+       return 0;
+}
+
 static const struct displayid_header *
 displayid_get_header(const u8 *displayid, int length, int index)
 {
@@ -23,7 +51,7 @@ displayid_get_header(const u8 *displayid, int length, int index)
 }
 
 static const struct displayid_header *
-validate_displayid(const u8 *displayid, int length, int idx)
+validate_displayid(const u8 *displayid, int length, int idx, bool ignore_checksum)
 {
        int i, dispid_length;
        u8 csum = 0;
@@ -41,8 +69,11 @@ validate_displayid(const u8 *displayid, int length, int idx)
        for (i = 0; i < dispid_length; i++)
                csum += displayid[idx + i];
        if (csum) {
-               DRM_NOTE("DisplayID checksum invalid, remainder is %d\n", csum);
-               return ERR_PTR(-EINVAL);
+               DRM_NOTE("DisplayID checksum invalid, remainder is %d%s\n", csum,
+                        ignore_checksum ? " (ignoring)" : "");
+
+               if (!ignore_checksum)
+                       return ERR_PTR(-EINVAL);
        }
 
        return base;
@@ -52,6 +83,7 @@ static const u8 *find_next_displayid_extension(struct displayid_iter *iter)
 {
        const struct displayid_header *base;
        const u8 *displayid;
+       bool ignore_checksum = iter->quirks & BIT(QUIRK_IGNORE_CHECKSUM);
 
        displayid = drm_edid_find_extension(iter->drm_edid, DISPLAYID_EXT, &iter->ext_index);
        if (!displayid)
@@ -61,7 +93,7 @@ static const u8 *find_next_displayid_extension(struct displayid_iter *iter)
        iter->length = EDID_LENGTH - 1;
        iter->idx = 1;
 
-       base = validate_displayid(displayid, iter->length, iter->idx);
+       base = validate_displayid(displayid, iter->length, iter->idx, ignore_checksum);
        if (IS_ERR(base))
                return NULL;
 
@@ -76,6 +108,7 @@ void displayid_iter_edid_begin(const struct drm_edid *drm_edid,
        memset(iter, 0, sizeof(*iter));
 
        iter->drm_edid = drm_edid;
+       iter->quirks = get_quirks(drm_edid);
 }
 
 static const struct displayid_block *
index 957dd0619f5c5c6951463508ef8f952edf78898c..5b1b32f73516620a1bdeec94fdd8622f7af309f2 100644 (file)
@@ -167,6 +167,8 @@ struct displayid_iter {
 
        u8 version;
        u8 primary_use;
+
+       u8 quirks;
 };
 
 void displayid_iter_edid_begin(const struct drm_edid *drm_edid,