drm/displayid: add quirk to ignore DisplayID checksum errors

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>
This commit is contained in:
Jani Nikula
2025-10-28 22:07:27 +02:00
parent 8b61583f99
commit 83cbb4d33d
2 changed files with 39 additions and 4 deletions

View 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 *

View 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,