@@ -336,6 +336,42 @@ 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
+ * @bad_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;
+ u8 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
@@ -1348,10 +1348,19 @@ static int drm_edid_block_checksum(const u8 *raw_edid)
{
int i;
u8 csum = 0;
- for (i = 0; i < EDID_LENGTH; i++)
+
+ for (i = 0; i < EDID_LENGTH - 1; i++)
csum += raw_edid[i];
- return csum;
+ return (0x100 - csum);
+}
+
+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)
@@ -1409,7 +1418,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;
@@ -1572,6 +1581,9 @@ static void connector_bad_edid(struct drm_connector *connector,
prefix, DUMP_PREFIX_NONE, 16, 1,
block, EDID_LENGTH, false);
}
+
+ /* Calculate real checksum for the last edid extension block data */
+ connector->real_edid_checksum = drm_edid_block_checksum(edid + edid[0x7e] * EDID_LENGTH);
}
/* Get override or firmware EDID */
@@ -1345,6 +1345,13 @@ struct drm_connector {
* rev1.1 4.2.2.6
*/
bool edid_corrupt;
+ /**
+ * @real_edid_checksum: real edid checksum value for corrupted edid block.
+ * Required in Displayport 1.4 compliance testing
+ * rev1.1 4.2.2.6
+ */
+ uint8_t real_edid_checksum;
+
/** @debugfs_entry: debugfs directory for this connector */
struct dentry *debugfs_entry;
@@ -1383,6 +1383,9 @@ static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux,
int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
u8 status[DP_LINK_STATUS_SIZE]);
+bool drm_dp_send_real_edid_checksum(struct drm_dp_aux *aux,
+ u8 real_edid_checksum);
+
/*
* DisplayPort link
*/
DP 1.4 edid corruption test requires source DUT to write calculated CRC, not the corrupted CRC from reference sink. Return the calculated CRC back, and initiate the required sequence. -v2: Have separate routine for returning real CRC -v3: Rewrite checksum computation routine to avoid duplicated code. Rename to avoid confusion Signed-off-by: Jerry (Fangzhi) Zuo <Jerry.Zuo@amd.com> --- drivers/gpu/drm/drm_dp_helper.c | 36 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_edid.c | 18 +++++++++++++++--- include/drm/drm_connector.h | 7 +++++++ include/drm/drm_dp_helper.h | 3 +++ 4 files changed, 61 insertions(+), 3 deletions(-)