diff options
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/drm_dp_helper.c | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 24 |
2 files changed, 79 insertions, 4 deletions
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index f629fc5494a4..43e9f1968af4 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -352,6 +352,65 @@ 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; + + if (drm_dp_dpcd_read(aux, DP_DEVICE_SERVICE_IRQ_VECTOR, + &auto_test_req, 1) < 1) { + DRM_ERROR("DPCD failed read at register 0x%x\n", + DP_DEVICE_SERVICE_IRQ_VECTOR); + return false; + } + auto_test_req &= DP_AUTOMATED_TEST_REQUEST; + + if (drm_dp_dpcd_read(aux, DP_TEST_REQUEST, &link_edid_read, 1) < 1) { + DRM_ERROR("DPCD failed read at register 0x%x\n", + DP_TEST_REQUEST); + return false; + } + 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; + } + + if (drm_dp_dpcd_write(aux, DP_DEVICE_SERVICE_IRQ_VECTOR, + &auto_test_req, 1) < 1) { + DRM_ERROR("DPCD failed write at register 0x%x\n", + DP_DEVICE_SERVICE_IRQ_VECTOR); + return false; + } + + /* send back checksum for the last edid extension block data */ + if (drm_dp_dpcd_write(aux, DP_TEST_EDID_CHECKSUM, + &real_edid_checksum, 1) < 1) { + DRM_ERROR("DPCD failed write at register 0x%x\n", + DP_TEST_EDID_CHECKSUM); + return false; + } + + test_resp |= DP_TEST_EDID_CHECKSUM_WRITE; + if (drm_dp_dpcd_write(aux, DP_TEST_RESPONSE, &test_resp, 1) < 1) { + DRM_ERROR("DPCD failed write at register 0x%x\n", + DP_TEST_RESPONSE); + return false; + } + + return true; +} +EXPORT_SYMBOL(drm_dp_send_real_edid_checksum); + +/** * drm_dp_downstream_max_clock() - extract branch device max * pixel rate for legacy VGA * converter or max TMDS clock diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 99769d6c9f84..1fcec5f4c3ec 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1590,11 +1590,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) @@ -1652,7 +1663,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; @@ -1793,6 +1804,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_enabled(DRM_UT_KMS)) return; |