FIXME: drm/i915/dp: Added support for dp phy compliance.

Submitted by Animesh Manna on July 3, 2019, 4:08 p.m.

Details

Message ID 20190703160829.28552-1-animesh.manna@intel.com
State New
Headers show
Series "FIXME: drm/i915/dp: Added support for dp phy compliance." ( rev: 1 ) in Intel GFX - Try Bot

Not browsing as part of any series.

Commit Message

Animesh Manna July 3, 2019, 4:08 p.m.
Signed-off-by: Animesh Manna <animesh.manna@intel.com>
---
 drivers/gpu/drm/drm_dp_helper.c               |  36 +++
 drivers/gpu/drm/i915/display/intel_dp.c       | 268 +++++++++++++++++-
 .../drm/i915/display/intel_dp_link_training.c |   4 +-
 drivers/gpu/drm/i915/i915_debugfs.c           |  10 +
 drivers/gpu/drm/i915/i915_reg.h               |  18 ++
 drivers/gpu/drm/i915/intel_drv.h              |   3 +
 include/drm/drm_dp_helper.h                   |  33 ++-
 7 files changed, 361 insertions(+), 11 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 0b994d083a89..83d112b51628 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -1466,6 +1466,42 @@  u8 drm_dp_dsc_sink_line_buf_depth(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE])
 }
 EXPORT_SYMBOL(drm_dp_dsc_sink_line_buf_depth);
 
+int drm_dp_get_phy_test_parameters(struct drm_dp_aux *aux, struct drm_dp_phy_test_params *phy_params)
+{
+	int num_bytes = 0;
+	if (phy_params != NULL) {
+		if (drm_dp_dpcd_read(aux, DP_TEST_PHY_PATTERN, &phy_params->phy_pattern, 1) < 0)
+		{
+			DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n");
+			return 0;
+		}
+		num_bytes += 1;
+		DRM_DEBUG_KMS("pat = %u", phy_params->phy_pattern);
+		switch (phy_params->phy_pattern){
+		case DP_TEST_PHY_PATTERN_80BIT_CUSTOM:
+			if (drm_dp_dpcd_read(aux, DP_TEST_80BIT_CUSTOM_PATTERN_7_0, &phy_params->custom80, 10) < 0)
+			{
+				DRM_DEBUG_KMS("DP Phy custom80 pattern AUX read failure\n");
+				return 0;
+			}
+			num_bytes += 10;
+			break;
+		case DP_TEST_PHY_PATTERN_CP2520_1:
+			if (drm_dp_dpcd_read(aux, DP_TEST_HBR2_SCRAMBLER_RESET, &phy_params->hbr2_reset, 2) < 0)
+			{
+				DRM_DEBUG_KMS("DP Phy scrambler reset AUX read failure\n");
+				return 0;
+			}
+			num_bytes += 2;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return num_bytes;
+}
+
 /**
  * drm_dp_dsc_sink_supported_input_bpcs() - Get all the input bits per component
  * values supported by the DSC sink.
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4336df46fe78..26f3e31bfb76 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4552,7 +4552,7 @@  static u8 intel_dp_autotest_link_training(struct intel_dp *intel_dp)
 
 	intel_dp->compliance.test_lane_count = test_lane_count;
 	intel_dp->compliance.test_link_rate = test_link_rate;
-
+	DRM_DEBUG_KMS("lc = %u, lr = %u", test_lane_count, test_link_rate);
 	return DP_TEST_ACK;
 }
 
@@ -4613,6 +4613,11 @@  static u8 intel_dp_autotest_video_pattern(struct intel_dp *intel_dp)
 	intel_dp->compliance.test_data.vdisplay = be16_to_cpu(v_height);
 	/* Set test active flag here so userspace doesn't interrupt things */
 	intel_dp->compliance.test_active = 1;
+	DRM_DEBUG_KMS("pat = %u, h = %u, v = %u, bpc = %u",
+				   test_pattern,
+				   h_width,
+				   v_height,
+				   intel_dp->compliance.test_data.bpc);
 
 	return DP_TEST_ACK;
 }
@@ -4653,6 +4658,7 @@  static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
 
 		test_result = DP_TEST_ACK | DP_TEST_EDID_CHECKSUM_WRITE;
 		intel_dp->compliance.test_data.edid = INTEL_DP_RESOLUTION_PREFERRED;
+		DRM_DEBUG_KMS("checksum = %u", block->checksum);
 	}
 
 	/* Set test active flag here so userspace doesn't interrupt things */
@@ -4661,10 +4667,256 @@  static u8 intel_dp_autotest_edid(struct intel_dp *intel_dp)
 	return test_result;
 }
 
+static u8 intel_dp_phy_pattern_update(struct intel_dp *intel_dp)
+{
+	struct drm_i915_private *dev_priv =
+		to_i915(dp_to_dig_port(intel_dp)->base.base.dev);
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	uint8_t pattern;
+	int i;
+
+	switch (intel_dp->compliance.test_data.phy_pattern) {
+	case DP_TEST_PHY_PATTERN_NONE:
+		DRM_DEBUG_KMS("Disable Phy Test Pattern\n");
+		I915_WRITE(DDI_DP_COMP_CTL(intel_dig_port->base.port), 0x0);
+		pattern = DP_LINK_QUAL_PATTERN_DISABLE;
+		break;
+	case DP_TEST_PHY_PATTERN_D10_2:
+		DRM_DEBUG_KMS("Set D10.2 Phy Test Pattern\n");
+		I915_WRITE(DDI_DP_COMP_CTL(intel_dig_port->base.port),
+			   DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_D10_2);
+		pattern = DP_LINK_QUAL_PATTERN_D10_2;
+		break;
+	case DP_TEST_PHY_PATTERN_ERROR_COUNT:
+		DRM_DEBUG_KMS("Set Error Count Phy Test Pattern\n");
+		I915_WRITE(DDI_DP_COMP_CTL(intel_dig_port->base.port),
+			   DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_SCRAMBLED_0);
+		pattern = DP_LINK_QUAL_PATTERN_ERROR_RATE;
+		break;
+	case DP_TEST_PHY_PATTERN_PRBS7:
+		DRM_DEBUG_KMS("Set PRBS7 Phy Test Pattern\n");
+		I915_WRITE(DDI_DP_COMP_CTL(intel_dig_port->base.port),
+			   DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_PRBS7);
+		pattern = DP_LINK_QUAL_PATTERN_PRBS7;
+		break;
+	case DP_TEST_PHY_PATTERN_80BIT_CUSTOM:
+		DRM_DEBUG_KMS("Set 80Bit Custom Phy Test Pattern\n");
+		for (i = 0 ; i <= 2 ; i++) {
+			I915_WRITE(DDI_DP_COMP_PAT(intel_dig_port->base.port, i),
+				   intel_dp->compliance.test_data.custom80[i]);
+			DRM_DEBUG_KMS("   0x%08X\n",intel_dp->compliance.test_data.custom80[i]);
+		}
+		I915_WRITE(DDI_DP_COMP_CTL(intel_dig_port->base.port),
+			   DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_CUSTOM80);
+		pattern = DP_LINK_QUAL_PATTERN_80BIT_CUSTOM;
+		break;
+	case DP_TEST_PHY_PATTERN_CP2520_1: /* DP_PHY_PATTERN_HBR2_EYE */
+		DRM_DEBUG_KMS("Set HBR2 compliance Phy Test Pattern\n");
+		I915_WRITE(DDI_DP_COMP_CTL(intel_dig_port->base.port),
+			   DDI_DP_COMP_CTL_ENABLE | DDI_DP_COMP_CTL_HBR2 |
+			   intel_dp->compliance.test_data.scrambler_reset );
+		DRM_DEBUG_KMS("   0x%04X\n", intel_dp->compliance.test_data.scrambler_reset);
+		pattern = DP_LINK_QUAL_PATTERN_HBR2_EYE;
+		break;
+	case DP_TEST_PHY_PATTERN_CP2520_2:
+	case DP_TEST_PHY_PATTERN_CP2520_3:
+	default:
+		DRM_ERROR("Invalid Phy Test PAttern\n");
+		pattern = DP_LINK_QUAL_PATTERN_DISABLE;
+		break;
+	}
+
+	return pattern;
+}
+
+static u8 intel_dp_get_phy_test_pattern(struct intel_dp *intel_dp)
+{
+	struct drm_dp_phy_test_params phy_params;
+
+	if (drm_dp_get_phy_test_parameters(&intel_dp->aux, &phy_params) == 0)
+	{
+		DRM_DEBUG_KMS("DP Phy Test pattern AUX read failure\n");
+		return DP_TEST_NAK;
+	}
+
+	intel_dp->compliance.test_data.phy_pattern = phy_params.phy_pattern;
+
+	switch (intel_dp->compliance.test_data.phy_pattern) {
+		case DP_TEST_PHY_PATTERN_NONE:
+			intel_dp->compliance.test_active = 0;
+			intel_dp->compliance.test_data.phy_pattern = 0;
+			return DP_TEST_ACK;
+		case DP_TEST_PHY_PATTERN_D10_2:
+		case DP_TEST_PHY_PATTERN_ERROR_COUNT:
+		case DP_TEST_PHY_PATTERN_PRBS7:
+			break;
+		case DP_TEST_PHY_PATTERN_80BIT_CUSTOM:
+			intel_dp->compliance.test_data.custom80[0] = (phy_params.custom80[0] << 24 |
+								      phy_params.custom80[1] << 16 |
+								      phy_params.custom80[2] << 8 |
+								      phy_params.custom80[3]);
+			intel_dp->compliance.test_data.custom80[1] = (phy_params.custom80[4] << 24 |
+								      phy_params.custom80[5] << 16 |
+								      phy_params.custom80[6] << 8 |
+								      phy_params.custom80[7]);
+			intel_dp->compliance.test_data.custom80[2] = (phy_params.custom80[8] << 8 |
+								      phy_params.custom80[9] );
+			break;
+		case DP_TEST_PHY_PATTERN_CP2520_1: /* DP_PHY_PATTERN_HBR2_EYE */
+			DRM_DEBUG_KMS("Set HBR2 compliance Phy Test Pattern\n");
+			intel_dp->compliance.test_data.scrambler_reset = ((phy_params.hbr2_reset[1] << 8) |
+									  phy_params.hbr2_reset[0]);
+			break;
+		case DP_TEST_PHY_PATTERN_CP2520_2:
+		case DP_TEST_PHY_PATTERN_CP2520_3:
+		default:
+			DRM_DEBUG_KMS("Phy Test Pattern Invalid\n");
+			intel_dp->compliance.test_active = 0;
+			return DP_TEST_NAK;
+	}
+
+	return DP_TEST_ACK;
+}
+
+static void
+intel_dp_autotest_phy_ddi_disable(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	enum port port = intel_dig_port->base.port;
+	uint32_t ddi_buf_ctl_value, dp_tp_ctl_value, trans_ddi_func_ctl_value;
+
+	ddi_buf_ctl_value = I915_READ(DDI_BUF_CTL(port));
+	dp_tp_ctl_value = I915_READ(DP_TP_CTL(port));
+	trans_ddi_func_ctl_value = I915_READ(TRANS_DDI_FUNC_CTL(port));
+
+	ddi_buf_ctl_value        &= ~(DDI_BUF_CTL_ENABLE|DDI_PORT_WIDTH_MASK);
+	dp_tp_ctl_value          &= ~DP_TP_CTL_ENABLE;
+	trans_ddi_func_ctl_value &= ~(TRANS_DDI_FUNC_ENABLE|DDI_PORT_WIDTH_MASK);
+
+	I915_WRITE(DDI_BUF_CTL(port), ddi_buf_ctl_value);
+	usleep_range(10, 20);
+	I915_WRITE(DP_TP_CTL(port), dp_tp_ctl_value);
+	usleep_range(10, 20);
+	I915_WRITE(TRANS_DDI_FUNC_CTL(port), trans_ddi_func_ctl_value);
+}
+
+static void
+intel_dp_autotest_phy_ddi_enable(struct intel_dp *intel_dp, uint8_t lane_cnt)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct drm_device *dev = intel_dig_port->base.base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	enum port port = intel_dig_port->base.port;
+	uint32_t ddi_buf_ctl_value, dp_tp_ctl_value, trans_ddi_func_ctl_value;
+
+	ddi_buf_ctl_value = I915_READ(DDI_BUF_CTL(port));
+	dp_tp_ctl_value = I915_READ(DP_TP_CTL(port));
+	trans_ddi_func_ctl_value = I915_READ(TRANS_DDI_FUNC_CTL(port));
+
+	ddi_buf_ctl_value        |= DDI_BUF_CTL_ENABLE | DDI_PORT_WIDTH(lane_cnt);
+	dp_tp_ctl_value          |= DP_TP_CTL_ENABLE;
+	trans_ddi_func_ctl_value |= TRANS_DDI_FUNC_ENABLE | DDI_PORT_WIDTH(lane_cnt);
+	msleep(50);
+
+	I915_WRITE(TRANS_DDI_FUNC_CTL(port), trans_ddi_func_ctl_value);
+	usleep_range(10, 20);
+	I915_WRITE(DP_TP_CTL(port), dp_tp_ctl_value);
+	usleep_range(10, 20);
+	I915_WRITE(DDI_BUF_CTL(port), ddi_buf_ctl_value);
+	msleep(50);
+}
+
+extern void
+intel_get_adjust_train(struct intel_dp *intel_dp,
+                      const uint8_t link_status[DP_LINK_STATUS_SIZE]);
+
 static u8 intel_dp_autotest_phy_pattern(struct intel_dp *intel_dp)
 {
-	u8 test_result = DP_TEST_NAK;
-	return test_result;
+	uint8_t test_link_rate, test_lane_cnt, test_pattern;
+	uint8_t link_status[DP_LINK_STATUS_SIZE];
+	uint8_t link_config[2] = {0,0};
+	uint8_t test_result;
+	//uint8_t test_down_spread;
+	int ret;
+
+	ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LINK_RATE, &test_link_rate);
+	if (ret <= 0) {
+		DRM_ERROR("Could not read DPCD 0x%x from sink\n", DP_TEST_LINK_RATE);
+		goto __exit_phy_test;
+	}
+	DRM_DEBUG_KMS("lr = %u", test_link_rate);
+	ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_LANE_COUNT, &test_lane_cnt);
+	if (ret <= 0) {
+		DRM_ERROR("Could not read DPCD 0x%x from sink\n", DP_TEST_LANE_COUNT);
+		goto __exit_phy_test;
+	}
+	DRM_DEBUG_KMS("lc = %u", test_lane_cnt);
+	test_result = intel_dp_get_phy_test_pattern(intel_dp);
+	if (test_result != DP_TEST_ACK) {
+		DRM_ERROR("Could not read DPCD 0x%x from sink\n", DP_TEST_PHY_PATTERN);
+		goto __exit_phy_test;
+	}
+/*
+	ret = drm_dp_dpcd_readb(&intel_dp->aux, DP_MAX_DOWNSPREAD, &test_down_spread);
+	if (ret <= 0) {
+		DRM_ERROR("Could not read DPCD 0x%x from sink\n", DP_MAX_DOWNSPREAD);
+		goto __exit_phy_test;
+	}
+
+	test_down_spread &= DP_MAX_DOWNSPREAD_0_5;
+*/
+
+	if (!intel_dp_get_link_status(intel_dp, link_status)) {
+		DRM_ERROR("failed to get link status\n");
+		goto __exit_phy_test;
+	}
+
+	intel_dp->lane_count = test_lane_cnt;
+	intel_dp->link_mst = false;
+
+	intel_dp_autotest_phy_ddi_disable(intel_dp);
+
+	// retrieve vswing & pre-emphasis setting
+	intel_get_adjust_train(intel_dp, link_status);
+	usleep_range(50, 100);
+
+	// reconfigure output signal
+	intel_dp_set_signal_levels(intel_dp);
+
+	// setup test pattern
+	test_pattern = intel_dp_phy_pattern_update(intel_dp);
+
+	intel_dp_autotest_phy_ddi_enable(intel_dp, test_lane_cnt);
+
+	// Write the changed config to sink through DPCD.
+	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
+							intel_dp->train_set, test_lane_cnt);
+
+	/* Write the link configuration data */
+	link_config[0] = test_link_rate;
+	link_config[1] = test_lane_cnt;
+	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
+		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+
+	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+
+	if ( intel_dp->dpcd[DP_DPCD_REV] < 0x12 ) {
+		test_pattern = (test_pattern << 2) & DP_LINK_QUAL_PATTERN_11_MASK;
+		drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &test_pattern, 1);
+	} else {
+		int i=0;
+		for (;i<test_lane_cnt;i++)
+			drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_QUAL_LANE0_SET+i, &test_pattern, 1);
+	}
+
+	/* Set test active flag here so userspace doesn't interrupt things */
+	intel_dp->compliance.test_active = 1;
+
+__exit_phy_test:
+	test_result = DP_TEST_ACK;
+	return DP_TEST_ACK;
 }
 
 static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
@@ -4681,19 +4933,19 @@  static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
 
 	switch (request) {
 	case DP_TEST_LINK_TRAINING:
-		DRM_DEBUG_KMS("LINK_TRAINING test requested\n");
+		DRM_DEBUG_KMS("LINK:");
 		response = intel_dp_autotest_link_training(intel_dp);
 		break;
 	case DP_TEST_LINK_VIDEO_PATTERN:
-		DRM_DEBUG_KMS("TEST_PATTERN test requested\n");
+		DRM_DEBUG_KMS("VID:");
 		response = intel_dp_autotest_video_pattern(intel_dp);
 		break;
 	case DP_TEST_LINK_EDID_READ:
-		DRM_DEBUG_KMS("EDID test requested\n");
+		DRM_DEBUG_KMS("EDID:");
 		response = intel_dp_autotest_edid(intel_dp);
 		break;
 	case DP_TEST_LINK_PHY_TEST_PATTERN:
-		DRM_DEBUG_KMS("PHY_PATTERN test requested\n");
+		DRM_DEBUG_KMS("PHY:");
 		response = intel_dp_autotest_phy_pattern(intel_dp);
 		break;
 	default:
@@ -4701,6 +4953,8 @@  static void intel_dp_handle_test_request(struct intel_dp *intel_dp)
 		break;
 	}
 
+	DRM_DEBUG_KMS("\n");
+
 	if (response & DP_TEST_ACK)
 		intel_dp->compliance.test_type = request;
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 9b1fccea966b..49d086e9c951 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -34,7 +34,7 @@  intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
 		      link_status[3], link_status[4], link_status[5]);
 }
 
-static void
+void
 intel_get_adjust_train(struct intel_dp *intel_dp,
 		       const u8 link_status[DP_LINK_STATUS_SIZE])
 {
@@ -53,7 +53,7 @@  intel_get_adjust_train(struct intel_dp *intel_dp,
 		if (this_p > p)
 			p = this_p;
 	}
-
+	DRM_DEBUG_KMS("v = %u, p = %u", v, p);
 	voltage_max = intel_dp_voltage_max(intel_dp);
 	if (v >= voltage_max)
 		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index eeecdad0e3ca..8d938a31544d 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -3336,6 +3336,16 @@  static int i915_displayport_test_data_show(struct seq_file *m, void *data)
 					   intel_dp->compliance.test_data.vdisplay);
 				seq_printf(m, "bpc: %u\n",
 					   intel_dp->compliance.test_data.bpc);
+			} else if (intel_dp->compliance.test_type ==
+				   DP_TEST_LINK_PHY_TEST_PATTERN) {
+				seq_printf(m, "pattern: %d\n",
+						intel_dp->compliance.test_data.phy_pattern);
+				seq_printf(m, "Number of lanes: %d\n",
+						intel_dp->compliance.test_lane_count);
+				seq_printf(m, "Link Rate: %d\n",
+						intel_dp->compliance.test_link_rate);
+				seq_printf(m, "level: %02x\n",
+						intel_dp->train_set[0]);
 			}
 		} else
 			seq_puts(m, "0");
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 7e6009cefb18..dd7a6469f283 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -9435,6 +9435,24 @@  enum skl_power_gate {
 #define  DDI_BUF_BALANCE_LEG_ENABLE	(1 << 31)
 #define DDI_BUF_TRANS_HI(port, i)	_MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8 + 4)
 
+/* DDI DP Compliance Control */
+#define DDI_DP_COMP_CTL_A                      0x640F0
+#define DDI_DP_COMP_CTL_B                      0x641F0
+#define DDI_DP_COMP_CTL(port) _MMIO_PORT(port, DDI_DP_COMP_CTL_A, DDI_DP_COMP_CTL_B)
+#define  DDI_DP_COMP_CTL_ENABLE                        (1 << 31)
+#define  DDI_DP_COMP_CTL_D10_2                 (0 << 28)
+#define  DDI_DP_COMP_CTL_SCRAMBLED_0           (1 << 28)
+#define  DDI_DP_COMP_CTL_PRBS7                 (2 << 28)
+#define  DDI_DP_COMP_CTL_CUSTOM80                      (3 << 28)
+#define  DDI_DP_COMP_CTL_HBR2                  (4 << 28)
+#define  DDI_DP_COMP_CTL_SCRAMBLED_1           (5 << 28)
+#define  DDI_DP_COMP_CTL_HBR2_RESET            (0xFC << 0)
+
+/* DDI DP Compliance Pattern */
+#define DDI_DP_COMP_PAT_A                      0x640f4
+#define DDI_DP_COMP_PAT_B                      0x641f4
+#define DDI_DP_COMP_PAT(port, i) _MMIO(_PORT(port, DDI_DP_COMP_PAT_A, DDI_DP_COMP_PAT_B) + (i) * 4) /* 3 dwords */
+
 /* Sideband Interface (SBI) is programmed indirectly, via
  * SBI_ADDR, which contains the register offset; and SBI_DATA,
  * which contains the payload */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1d58f7ec5d84..c1fd0881db76 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1095,6 +1095,9 @@  struct intel_dp_compliance_data {
 	u8 video_pattern;
 	u16 hdisplay, vdisplay;
 	u8 bpc;
+	uint32_t phy_pattern;
+	uint32_t custom80[3];
+	uint16_t scrambler_reset;
 };
 
 struct intel_dp_compliance {
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 397896b5b21a..226b5032d9d9 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -573,8 +573,10 @@ 
 # define DP_TEST_LINK_AUDIO_DISABLED_VIDEO  (1 << 6) /* DPCD >= 1.2 */
 
 #define DP_TEST_LINK_RATE		    0x219
-# define DP_LINK_RATE_162		    (0x6)
-# define DP_LINK_RATE_27		    (0xa)
+# define DP_TEST_LINK_RATE_162	      0x6
+# define DP_TEST_LINK_RATE_27	      0xa
+# define DP_TEST_LINK_RATE_54	     0x14
+# define DP_TEST_LINK_RATE_81	     0x1e
 
 #define DP_TEST_LANE_COUNT		    0x220
 
@@ -649,6 +651,17 @@ 
 # define DP_TEST_COUNT_MASK		    0xf
 
 #define DP_TEST_PHY_PATTERN                 0x248
+# define DP_TEST_PHY_PATTERN_NONE		    0
+# define DP_TEST_PHY_PATTERN_D10_2		    1
+# define DP_TEST_PHY_PATTERN_ERROR_COUNT	    2
+# define DP_TEST_PHY_PATTERN_PRBS7		    3
+# define DP_TEST_PHY_PATTERN_80BIT_CUSTOM	    4
+# define DP_TEST_PHY_PATTERN_CP2520_1	    5 /* was HBR2 Compliance */
+# define DP_TEST_PHY_PATTERN_CP2520_2	    6 /* DP 1.4 */
+# define DP_TEST_PHY_PATTERN_CP2520_3	    7 /* DP 1.4 TPS4 */
+
+#define DP_TEST_HBR2_SCRAMBLER_RESET	0x24A
+
 #define DP_TEST_80BIT_CUSTOM_PATTERN_7_0    0x250
 #define	DP_TEST_80BIT_CUSTOM_PATTERN_15_8   0x251
 #define	DP_TEST_80BIT_CUSTOM_PATTERN_23_16  0x252
@@ -1476,6 +1489,22 @@  static inline void drm_dp_cec_unset_edid(struct drm_dp_aux *aux)
 {
 }
 
+/**
+ * struct drm_dp_phy_test_params - DP Phy Compliance parameters
+ * @phy_pattern: DP Phy test pattern from DPCD 0x248 (sink)
+ * @hb2_reset: DP HBR2_COMPLIANCE_SCRAMBLER_RESET from DCPD
+ *            0x24A and 0x24B (sink)
+ * @custom80: DP Test_80BIT_CUSTOM_PATTERN from DPCDs 0x250
+ *               through 0x259.
+ */
+struct drm_dp_phy_test_params {
+	u8 phy_pattern;
+	u8 hbr2_reset[2];
+	u8 custom80[10];
+};
+
+int drm_dp_get_phy_test_parameters(struct drm_dp_aux *aux, struct drm_dp_phy_test_params *phy_params);
+
 #endif
 
 #endif /* _DRM_DP_HELPER_H_ */