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 <[email protected]>
Closes: 
https://lore.kernel.org/r/cacrbrpgvlp5lanxufi6z0s7xmbag4x5y2yolbdxfovtfggq...@mail.gmail.com
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14703
Signed-off-by: Jani Nikula <[email protected]>
---
 drivers/gpu/drm/drm_displayid.c          | 41 +++++++++++++++++++++---
 drivers/gpu/drm/drm_displayid_internal.h |  2 ++
 2 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_displayid.c b/drivers/gpu/drm/drm_displayid.c
index 20b453d2b854..58d0bb6d2676 100644
--- a/drivers/gpu/drm/drm_displayid.c
+++ b/drivers/gpu/drm/drm_displayid.c
@@ -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 *
diff --git a/drivers/gpu/drm/drm_displayid_internal.h 
b/drivers/gpu/drm/drm_displayid_internal.h
index 957dd0619f5c..5b1b32f73516 100644
--- a/drivers/gpu/drm/drm_displayid_internal.h
+++ b/drivers/gpu/drm/drm_displayid_internal.h
@@ -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,
-- 
2.47.3

Reply via email to