Re: [PATCH V6] drm: Add support for DP 1.4 Compliance edid corruption test

2020-02-07 Thread Rodrigo Siqueira
On 02/05, Jerry (Fangzhi) Zuo wrote:
> Unlike DP 1.2 edid corruption test, DP 1.4 requires to calculate
> real CRC value of the last edid data block, and write it back.
> Current edid CRC calculates routine adds the last CRC byte,
> and check if non-zero.
> 
> This behavior is not accurate; actually, we need to return
> the actual CRC value when corruption is detected.
> This commit changes this issue by returning the calculated CRC,
> and initiate the required sequence.
> 
> Change since v6
> - Add return check
> 
> Change since v5
> - Obtain real CRC value before dumping bad edid
> 
> Change since v4
> - Fix for CI.CHECKPATCH
> 
> Change since v3
> - Fix a minor typo.
> 
> Change since v2
> - Rewrite checksum computation routine to avoid duplicated code.
> - Rename to avoid confusion.
> 
> Change since v1
> - Have separate routine for returning real CRC.
> 
> Signed-off-by: Jerry (Fangzhi) Zuo 
> ---
>  drivers/gpu/drm/drm_dp_helper.c | 51 +
>  drivers/gpu/drm/drm_edid.c  | 23 ---
>  include/drm/drm_connector.h |  6 
>  include/drm/drm_dp_helper.h |  3 ++
>  4 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..1efd609df402 100644
> --- a/drivers/gpu/drm/drm_dp_helper.c
> +++ b/drivers/gpu/drm/drm_dp_helper.c
> @@ -351,6 +351,57 @@ 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, _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, _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, 
> _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, _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, _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
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 99769d6c9f84..f064e75fb4c5 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,10 @@ static void connector_bad_edid(struct drm_connector 
> *connector,
>  

Re: [PATCH V6] drm: Add support for DP 1.4 Compliance edid corruption test

2020-02-05 Thread Harry Wentland



On 2020-02-05 10:22 a.m., Jerry (Fangzhi) Zuo wrote:
> Unlike DP 1.2 edid corruption test, DP 1.4 requires to calculate
> real CRC value of the last edid data block, and write it back.
> Current edid CRC calculates routine adds the last CRC byte,
> and check if non-zero.
> 
> This behavior is not accurate; actually, we need to return
> the actual CRC value when corruption is detected.
> This commit changes this issue by returning the calculated CRC,
> and initiate the required sequence.
> 
> Change since v6
> - Add return check
> 
> Change since v5
> - Obtain real CRC value before dumping bad edid
> 
> Change since v4
> - Fix for CI.CHECKPATCH
> 
> Change since v3
> - Fix a minor typo.
> 
> Change since v2
> - Rewrite checksum computation routine to avoid duplicated code.
> - Rename to avoid confusion.
> 
> Change since v1
> - Have separate routine for returning real CRC.
> 
> Signed-off-by: Jerry (Fangzhi) Zuo 

Please make sure to add the Reviewed-bys you've received on previous
versions. I've already reviewed v5 and an earlier one. Please add my
Reviewed-by.

Harry

> ---
>  drivers/gpu/drm/drm_dp_helper.c | 51 +
>  drivers/gpu/drm/drm_edid.c  | 23 ---
>  include/drm/drm_connector.h |  6 
>  include/drm/drm_dp_helper.h |  3 ++
>  4 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..1efd609df402 100644
> --- a/drivers/gpu/drm/drm_dp_helper.c
> +++ b/drivers/gpu/drm/drm_dp_helper.c
> @@ -351,6 +351,57 @@ 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, _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, _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, 
> _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, _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, _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
> diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
> index 99769d6c9f84..f064e75fb4c5 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)) {

[PATCH V6] drm: Add support for DP 1.4 Compliance edid corruption test

2020-02-05 Thread Jerry (Fangzhi) Zuo
Unlike DP 1.2 edid corruption test, DP 1.4 requires to calculate
real CRC value of the last edid data block, and write it back.
Current edid CRC calculates routine adds the last CRC byte,
and check if non-zero.

This behavior is not accurate; actually, we need to return
the actual CRC value when corruption is detected.
This commit changes this issue by returning the calculated CRC,
and initiate the required sequence.

Change since v6
- Add return check

Change since v5
- Obtain real CRC value before dumping bad edid

Change since v4
- Fix for CI.CHECKPATCH

Change since v3
- Fix a minor typo.

Change since v2
- Rewrite checksum computation routine to avoid duplicated code.
- Rename to avoid confusion.

Change since v1
- Have separate routine for returning real CRC.

Signed-off-by: Jerry (Fangzhi) Zuo 
---
 drivers/gpu/drm/drm_dp_helper.c | 51 +
 drivers/gpu/drm/drm_edid.c  | 23 ---
 include/drm/drm_connector.h |  6 
 include/drm/drm_dp_helper.h |  3 ++
 4 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..1efd609df402 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -351,6 +351,57 @@ 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, _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, _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, 
_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, _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, _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
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 99769d6c9f84..f064e75fb4c5 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,10 @@ 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 =