Skip to content

Commit 6ba2bd3

Browse files
Todd Previtedanvet
authored andcommitted
drm: Add edid_corrupt flag for Displayport Link CTS 4.2.2.6
Displayport compliance test 4.2.2.6 requires that a source device be capable of detecting a corrupt EDID. The test specification states that the sink device sets up the EDID with an invalid checksum. To do this, the sink sets up an invalid EDID header, expecting the source device to generate the checksum and compare it to the value stored in the last byte of the block data. Unfortunately, the DRM EDID reading and parsing functions are actually too good in this case; the header is fixed before the checksum is computed and thus the test never sees the invalid checksum. This results in a failure to pass the compliance test. To correct this issue, when the EDID code detects that the header is invalid, a flag is set to indicate that the EDID is corrupted. In this case, it sets edid_corrupt flag and continues with its fix-up code. This flag is also set in the case of a more seriously damaged header (fixup score less than the threshold). For consistency, the edid_corrupt flag is also set when the checksum is invalid as well. V2: - Removed the static bool global - Added a bool to the drm_connector struct to reaplce the static one for holding the status of raw edid header corruption detection - Modified the function signature of the is_valid function to take an additional parameter to store the corruption detected value - Fixed the other callers of the above is_valid function V3: - Updated the commit message to be more clear about what and why this patch does what it does. - Added comment in code to clarify the operations there - Removed compliance variable and check_link_status update; those have been moved to a later patch - Removed variable assignment from the bottom of the test handler V4: - Removed i915 tag from subject line as the patch is not i915-specific V5: - Moved code causing a compilation error to this patch where the variable is actually declared - Maintained blank lines / spacing so as to not contaminate the patch V6: - Removed extra debug messages - Added documentation to for the added parameter on drm_edid_block_valid - Fixed more whitespace issues in check_link_status - Added a clear of the header_corrupt flag to the end of the test handler in intel_dp.c - Changed the usage of the new function prototype in several places to use NULL where it is not needed by compliance testing V7: - Updated to account for long_pulse flag propagation V8: - Removed clearing of header_corrupt flag from the test handler in intel_dp.c - Added clearing of header_corrupt flag in the drm_edid_block_valid function V9: - Renamed header_corrupt flag to edid_corrupt to more accurately reflect its value and purpose - Updated commit message V10: - Updated for versioning and patch swizzle - Revised the title to more accurately reflect the nature and contents of the patch - Fixed formatting/whitespace problems - Added set flag when computed checksum is invalid Signed-off-by: Todd Previte <tprevite@gmail.com> Cc: dri-devel@lists.freedesktop.org Acked-by: Dave Airlie <airlied@redhat.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Reviewed-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
1 parent 83a2497 commit 6ba2bd3

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed

drivers/gpu/drm/drm_edid.c

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,13 +1041,15 @@ static bool drm_edid_is_zero(const u8 *in_edid, int length)
10411041
* @raw_edid: pointer to raw EDID block
10421042
* @block: type of block to validate (0 for base, extension otherwise)
10431043
* @print_bad_edid: if true, dump bad EDID blocks to the console
1044+
* @edid_corrupt: if true, the header or checksum is invalid
10441045
*
10451046
* Validate a base or extension EDID block and optionally dump bad blocks to
10461047
* the console.
10471048
*
10481049
* Return: True if the block is valid, false otherwise.
10491050
*/
1050-
bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
1051+
bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid,
1052+
bool *edid_corrupt)
10511053
{
10521054
u8 csum;
10531055
struct edid *edid = (struct edid *)raw_edid;
@@ -1060,11 +1062,22 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
10601062

10611063
if (block == 0) {
10621064
int score = drm_edid_header_is_valid(raw_edid);
1063-
if (score == 8) ;
1064-
else if (score >= edid_fixup) {
1065+
if (score == 8) {
1066+
if (edid_corrupt)
1067+
*edid_corrupt = 0;
1068+
} else if (score >= edid_fixup) {
1069+
/* Displayport Link CTS Core 1.2 rev1.1 test 4.2.2.6
1070+
* The corrupt flag needs to be set here otherwise, the
1071+
* fix-up code here will correct the problem, the
1072+
* checksum is correct and the test fails
1073+
*/
1074+
if (edid_corrupt)
1075+
*edid_corrupt = 1;
10651076
DRM_DEBUG("Fixing EDID header, your hardware may be failing\n");
10661077
memcpy(raw_edid, edid_header, sizeof(edid_header));
10671078
} else {
1079+
if (edid_corrupt)
1080+
*edid_corrupt = 1;
10681081
goto bad;
10691082
}
10701083
}
@@ -1075,6 +1088,9 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid)
10751088
DRM_ERROR("EDID checksum is invalid, remainder is %d\n", csum);
10761089
}
10771090

1091+
if (edid_corrupt)
1092+
*edid_corrupt = 1;
1093+
10781094
/* allow CEA to slide through, switches mangle this */
10791095
if (raw_edid[0] != 0x02)
10801096
goto bad;
@@ -1129,7 +1145,7 @@ bool drm_edid_is_valid(struct edid *edid)
11291145
return false;
11301146

11311147
for (i = 0; i <= edid->extensions; i++)
1132-
if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true))
1148+
if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i, true, NULL))
11331149
return false;
11341150

11351151
return true;
@@ -1232,7 +1248,8 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
12321248
for (i = 0; i < 4; i++) {
12331249
if (get_edid_block(data, block, 0, EDID_LENGTH))
12341250
goto out;
1235-
if (drm_edid_block_valid(block, 0, print_bad_edid))
1251+
if (drm_edid_block_valid(block, 0, print_bad_edid,
1252+
&connector->edid_corrupt))
12361253
break;
12371254
if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
12381255
connector->null_edid_counter++;
@@ -1257,7 +1274,10 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
12571274
block + (valid_extensions + 1) * EDID_LENGTH,
12581275
j, EDID_LENGTH))
12591276
goto out;
1260-
if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j, print_bad_edid)) {
1277+
if (drm_edid_block_valid(block + (valid_extensions + 1)
1278+
* EDID_LENGTH, j,
1279+
print_bad_edid,
1280+
NULL)) {
12611281
valid_extensions++;
12621282
break;
12631283
}

drivers/gpu/drm/drm_edid_load.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ static void *edid_load(struct drm_connector *connector, const char *name,
216216
goto out;
217217
}
218218

219-
if (!drm_edid_block_valid(edid, 0, print_bad_edid)) {
219+
if (!drm_edid_block_valid(edid, 0, print_bad_edid,
220+
&connector->edid_corrupt)) {
220221
connector->bad_edid_counter++;
221222
DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
222223
name);
@@ -229,7 +230,9 @@ static void *edid_load(struct drm_connector *connector, const char *name,
229230
if (i != valid_extensions + 1)
230231
memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
231232
edid + i * EDID_LENGTH, EDID_LENGTH);
232-
if (drm_edid_block_valid(edid + i * EDID_LENGTH, i, print_bad_edid))
233+
if (drm_edid_block_valid(edid + i * EDID_LENGTH, i,
234+
print_bad_edid,
235+
NULL))
233236
valid_extensions++;
234237
}
235238

include/drm/drm_crtc.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,11 @@ struct drm_connector {
719719
int null_edid_counter; /* needed to workaround some HW bugs where we get all 0s */
720720
unsigned bad_edid_counter;
721721

722+
/* Flag for raw EDID header corruption - used in Displayport
723+
* compliance testing - * Displayport Link CTS Core 1.2 rev1.1 4.2.2.6
724+
*/
725+
bool edid_corrupt;
726+
722727
struct dentry *debugfs_entry;
723728

724729
struct drm_connector_state *state;
@@ -1443,7 +1448,8 @@ extern void drm_set_preferred_mode(struct drm_connector *connector,
14431448
int hpref, int vpref);
14441449

14451450
extern int drm_edid_header_is_valid(const u8 *raw_edid);
1446-
extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid);
1451+
extern bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid,
1452+
bool *edid_corrupt);
14471453
extern bool drm_edid_is_valid(struct edid *edid);
14481454

14491455
extern struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,

0 commit comments

Comments
 (0)