[PATCH 08/10] drm/i915: Update the EDID automated compliance test function

Todd Previte
2014-10-09T15:38:57Z

Updates the EDID compliance test function to perform the EDID read as
required by the tests. This read needs to take place in the kernel for
reasons of speed and efficiency. The results of the EDID read are handed
off to userspace so that the remainder of the test can be conducted there.

Signed-off-by: Todd Previte <tprevite@gmail.com>
---
drivers/gpu/drm/i915/intel_dp.c | 85 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 81 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 717cb5d..b7bdb5f 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -41,6 +41,13 @@
#define DP_LINK_CHECK_TIMEOUT (10 * 1000)
#define SIG_DP_COMPLIANCE 47

+/* Compliance test status bits */
+#define INTEL_DP_EDID_OK (0<<0)
+#define INTEL_DP_EDID_CORRUPT (1<<0)
+#define INTEL_DP_RESOLUTION_PREFERRED (1<<2)
+#define INTEL_DP_RESOLUTION_STANDARD (1<<3)
+#define INTEL_DP_RESOLUTION_FAILSAFE (1<<4)
+
struct dp_link_dpll {
int link_bw;
struct dpll dpll;
@@ -4012,11 +4019,81 @@ intel_dp_autotest_video_pattern(struct intel_dp *intel_dp)
return test_result;
}

-/* Displayport compliance testing - EDID operations */
-static uint8_t
-intel_dp_autotest_edid(struct intel_dp *intel_dp)
+static bool intel_dp_compute_edid_checksum(uint8_t *edid_data,
+ uint8_t *edid_checksum)
{
- uint8_t test_result = DP_TEST_NAK;
+ uint32_t byte_total = 0;
+ uint8_t i = 0;
+ bool edid_ok = true;
+
+ /* Compute byte total w/o the checksum value*/
+ for (i = 0; i < EDID_LENGTH - 2; i++)
+ byte_total += edid_data[i];
+
+ DRM_DEBUG_KMS("EDID total = %d, EDID checksum = %d\n",
+ byte_total, edid_data[EDID_LENGTH - 34 - 1]);
+
+ /* Compute the checksum */
+ *edid_checksum = 256 - (byte_total % 256);
+
+ if (*edid_checksum != edid_data[EDID_LENGTH - 1]) {
+ DRM_DEBUG_KMS("Invalid EDID checksum %d, should be %d\n",
+ edid_data[EDID_LENGTH - 40 - 1], *edid_checksum);
+ edid_ok = false;
+ }
+
+ return edid_ok;
+}
+
+
+/* Displayport compliance testing - EDID operations */
+static uint8_t intel_dp_autotest_edid(struct intel_dp *intel_dp)
+{
+ struct drm_connector *connector = &intel_dp->attached_connector->base;
+ struct i2c_adapter *adapter = &intel_dp->aux.ddc;
+ struct edid *edid_read = NULL;
+ uint8_t *edid_data = NULL;
+ uint8_t test_result = DP_TEST_NAK, checksum = 0;
+ uint32_t ret = 0;
+
+ DRM_DEBUG_KMS("Displayport: EDID automated test\n");
+
+ /* Reset the NACK/DEFER counters */
+ intel_dp->aux.i2c_nack_count = 0;
+ intel_dp->aux.i2c_defer_count = 0;
+ /* Now read out the EDID */
+ edid_read = drm_get_edid(connector, adapter);
+
+ if (edid_read == NULL) {
+ /* Check for NACKs/DEFERs, goto failsafe if detected
+ (DP CTS 1.2 Core Rev 1.1, 4.2.2.4, 4.2.2.5) */
+ if (intel_dp->aux.i2c_nack_count > 0 ||
+ intel_dp->aux.i2c_defer_count > 0)
+ DRM_DEBUG_KMS("EDID read had %d NACKs, %d DEFERs\n",
+ intel_dp->aux.i2c_nack_count,
+ intel_dp->aux.i2c_defer_count);
+ intel_dp->compliance_test_data = INTEL_DP_EDID_CORRUPT |
+ INTEL_DP_RESOLUTION_FAILSAFE;
+ } else {
+ edid_data = (uint8_t *) edid_read;
+
+ if (intel_dp_compute_edid_checksum(edid_data, &checksum)) {
+ /* Write the checksum to EDID checksum register */
+ ret = drm_dp_dpcd_write(&intel_dp->aux,
+ DP_TEST_EDID_CHECKSUM,
+ &edid_read->checksum, 1);
+ /* Reponse is ACK and and checksum written */
+ test_result = DP_TEST_ACK |
+ DP_TEST_EDID_CHECKSUM_WRITE;
+ intel_dp->compliance_test_data = INTEL_DP_EDID_OK |
+ INTEL_DP_RESOLUTION_PREFERRED;
+ } else {
+ /* Invalid checksum - EDID corruption detection test */
+ intel_dp->compliance_test_data = INTEL_DP_EDID_CORRUPT |
+ INTEL_DP_RESOLUTION_FAILSAFE;
+ }
+ }
+
return test_result;
}

--
1.9.1