diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index ffc68d305afe..37f360e6ad50 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -336,6 +336,41 @@ int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux, } EXPORT_SYMBOL(drm_dp_dpcd_read_link_status); +/** + * drm_dp_send_real_edid_checksum() - send back real edid checksum value + * @aux: DisplayPort AUX channel + * @real_edid_checksum: real edid checksum for the last block + * + * Returns true on success + */ +bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux, + u8 real_edid_checksum) +{ + u8 link_edid_read = 0, auto_test_req = 0, test_resp = 0; + + drm_dp_dpcd_read(aux, DP_DEVICE_SERVICE_IRQ_VECTOR, &auto_test_req, 1); + auto_test_req &= DP_AUTOMATED_TEST_REQUEST; + + drm_dp_dpcd_read(aux, DP_TEST_REQUEST, &link_edid_read, 1); + link_edid_read &= DP_TEST_LINK_EDID_READ; + + if (!auto_test_req || !link_edid_read) { + DRM_DEBUG_KMS("Source DUT does not support TEST_EDID_READ\n"); + return false; + } + + drm_dp_dpcd_write(aux, DP_DEVICE_SERVICE_IRQ_VECTOR, &auto_test_req, 1); + + /* send back checksum for the last edid extension block data */ + drm_dp_dpcd_write(aux, DP_TEST_EDID_CHECKSUM, &real_edid_checksum, 1); + + test_resp |= DP_TEST_EDID_CHECKSUM_WRITE; + drm_dp_dpcd_write(aux, DP_TEST_RESPONSE, &test_resp, 1); + + return true; +} +EXPORT_SYMBOL(drm_dp_send_real_edid_checksum); + /** * drm_dp_link_probe() - probe a DisplayPort link for capabilities * @aux: DisplayPort AUX channel diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 86603562dba2..e734742486c7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1358,11 +1358,22 @@ static int validate_displayid(u8 *displayid, int length, int idx); static int drm_edid_block_checksum(const u8 *raw_edid) { int i; - u8 csum = 0; - for (i = 0; i < EDID_LENGTH; i++) + u8 csum = 0, crc = 0; + + for (i = 0; i < EDID_LENGTH - 1; i++) csum += raw_edid[i]; - return csum; + crc = 0x100 - csum; + + return crc; +} + +static bool drm_edid_block_checksum_diff(const u8 *raw_edid, u8 real_checksum) +{ + if (raw_edid[EDID_LENGTH - 1] != real_checksum) + return true; + else + return false; } static bool drm_edid_is_zero(const u8 *in_edid, int length) @@ -1420,7 +1431,7 @@ bool drm_edid_block_valid(u8 *raw_edid, int block, bool print_bad_edid, } csum = drm_edid_block_checksum(raw_edid); - if (csum) { + if (drm_edid_block_checksum_diff(raw_edid, csum)) { if (edid_corrupt) *edid_corrupt = true; @@ -1561,6 +1572,11 @@ static void connector_bad_edid(struct drm_connector *connector, u8 *edid, int num_blocks) { int i; + u8 num_of_ext = edid[0x7e]; + + /* Calculate real checksum for the last edid extension block data */ + connector->real_edid_checksum = + drm_edid_block_checksum(edid + num_of_ext * EDID_LENGTH); if (connector->bad_edid_counter++ && !(drm_debug & DRM_UT_KMS)) return; diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 555d16fb383b..d1dd028b33fa 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1401,6 +1401,12 @@ struct drm_connector { * rev1.1 4.2.2.6 */ bool edid_corrupt; + /** + * @real_edid_checksum: real edid checksum for corrupted edid block. + * Required in Displayport 1.4 compliance testing + * rev1.1 4.2.2.6 + */ + u8 real_edid_checksum; /** @debugfs_entry: debugfs directory for this connector */ struct dentry *debugfs_entry; diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 8b4ff9f26c32..5258e97f071f 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -1377,6 +1377,8 @@ int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link); int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link); +bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux, + u8 real_edid_checksum); int drm_dp_downstream_max_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4]); int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE],