diff mbox

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

Message ID 1412869090-48010-9-git-send-email-tprevite@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Todd Previte Oct. 9, 2014, 3:38 p.m. UTC
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 mbox

Patch

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;
 }