intel-gfx.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode
@ 2020-09-22 12:50 Imre Deak
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 1/7] drm/i915: Fix DP link training pattern mask Imre Deak
                   ` (10 more replies)
  0 siblings, 11 replies; 27+ messages in thread
From: Imre Deak @ 2020-09-22 12:50 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

Add the drm-core helpers and register definitions required to detect
LTTPRs and perform the link training in non-transparent mode. In i915
switch to non-transparent link training mode if any LTTPR is detected.

Cc: dri-devel@lists.freedesktop.org

Imre Deak (7):
  drm/i915: Fix DP link training pattern mask
  drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c
  drm/i915: Simplify the link training functions
  drm/i915: Factor out a helper to disable the DPCD training pattern
  drm/dp: Add LTTPR helpers
  drm/i915: Switch to LTTPR transparent mode link training
  drm/i915: Switch to LTTPR non-transparent mode link training

 drivers/gpu/drm/drm_dp_helper.c               | 179 ++++++-
 drivers/gpu/drm/i915/display/intel_ddi.c      |   3 +-
 .../drm/i915/display/intel_display_types.h    |   2 +
 drivers/gpu/drm/i915/display/intel_dp.c       |  38 +-
 drivers/gpu/drm/i915/display/intel_dp.h       |   2 -
 .../drm/i915/display/intel_dp_link_training.c | 492 +++++++++++++++---
 .../drm/i915/display/intel_dp_link_training.h |  10 +-
 include/drm/drm_dp_helper.h                   |  56 ++
 8 files changed, 682 insertions(+), 100 deletions(-)

-- 
2.17.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Intel-gfx] [PATCH 1/7] drm/i915: Fix DP link training pattern mask
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
@ 2020-09-22 12:51 ` Imre Deak
  2020-09-22 13:13   ` Ville Syrjälä
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 2/7] drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c Imre Deak
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Imre Deak @ 2020-09-22 12:51 UTC (permalink / raw)
  To: intel-gfx

An LTTPR can be trained with training pattern 4 even if the DPCD
revision is < 1.4, but drm_dp_training_pattern_mask() would change
pattern 4 to pattern 3 on those DPCD revisions.

Since intel_dp_training_pattern() makes already sure that the proper
training pattern is used, all that needs to be masked out is the
scrambling disable flag, which is or'd to the mask later based on the
training pattern.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_ddi.c              |  3 +--
 drivers/gpu/drm/i915/display/intel_dp.c               | 10 +++++-----
 drivers/gpu/drm/i915/display/intel_dp_link_training.c |  2 +-
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 4d06178cd76c..946a3b6f2d10 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4158,13 +4158,12 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
 				     u8 dp_train_pat)
 {
 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-	u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
 	u32 temp;
 
 	temp = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
 
 	temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
-	switch (dp_train_pat & train_pat_mask) {
+	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {
 	case DP_TRAINING_PATTERN_DISABLE:
 		temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
 		break;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index bf1e9cf1c0f3..2a4a9c0e7427 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3778,7 +3778,7 @@ cpt_set_link_train(struct intel_dp *intel_dp,
 
 	*DP &= ~DP_LINK_TRAIN_MASK_CPT;
 
-	switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {
 	case DP_TRAINING_PATTERN_DISABLE:
 		*DP |= DP_LINK_TRAIN_OFF_CPT;
 		break;
@@ -3808,7 +3808,7 @@ g4x_set_link_train(struct intel_dp *intel_dp,
 
 	*DP &= ~DP_LINK_TRAIN_MASK;
 
-	switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {
 	case DP_TRAINING_PATTERN_DISABLE:
 		*DP |= DP_LINK_TRAIN_OFF;
 		break;
@@ -4498,12 +4498,12 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
 				       u8 dp_train_pat)
 {
 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
-	u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
 
-	if (dp_train_pat & train_pat_mask)
+	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) !=
+	    DP_TRAINING_PATTERN_DISABLE)
 		drm_dbg_kms(&dev_priv->drm,
 			    "Using DP training pattern TPS%d\n",
-			    dp_train_pat & train_pat_mask);
+			    dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE);
 
 	intel_dp->set_link_train(intel_dp, dp_train_pat);
 }
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 f2c8b56be9ea..f8b53c5b5777 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -96,7 +96,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
 	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
 
 	buf[0] = dp_train_pat;
-	if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
+	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
 	    DP_TRAINING_PATTERN_DISABLE) {
 		/* don't write DP_TRAINING_LANEx_SET on disable */
 		len = 1;
-- 
2.17.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Intel-gfx] [PATCH 2/7] drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 1/7] drm/i915: Fix DP link training pattern mask Imre Deak
@ 2020-09-22 12:51 ` Imre Deak
  2020-09-22 13:14   ` Ville Syrjälä
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions Imre Deak
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Imre Deak @ 2020-09-22 12:51 UTC (permalink / raw)
  To: intel-gfx

The link status is used to communicate the parameters of the link
training with the DPRX and determine if the link training is successful
or a retraining is needed. Accordingly move the function to read the
link status to intel_dp_link_training.c

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c          | 11 -----------
 drivers/gpu/drm/i915/display/intel_dp.h          |  2 --
 .../drm/i915/display/intel_dp_link_training.c    | 16 ++++++++++++++++
 .../drm/i915/display/intel_dp_link_training.h    |  3 +++
 4 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 2a4a9c0e7427..ee93a00a4d5e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4126,17 +4126,6 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state,
 	chv_phy_post_pll_disable(encoder, old_crtc_state);
 }
 
-/*
- * Fetch AUX CH registers 0x202 - 0x207 which contain
- * link status information
- */
-bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
-{
-	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
-				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
-}
-
 static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp)
 {
 	return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 08a1c0aa8b94..34ae7988a554 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -100,8 +100,6 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
 			   u8 *link_bw, u8 *rate_select);
 bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
 bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
-bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
 
 bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
 int intel_dp_link_required(int pixel_clock, int bpp);
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 f8b53c5b5777..6d13d00db5e6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -34,6 +34,22 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
 		      link_status[3], link_status[4], link_status[5]);
 }
 
+/**
+ * intel_dp_get_link_status - get the link status information for the DPRX
+ * @intel_dp: DP struct
+ * @link_status: buffer to return the status in
+ *
+ * Fetch the AUX DPCD registers for the DPRX link status.
+ *
+ * Returns true if the information was read successfully, false otherwise.
+ */
+bool
+intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
+{
+	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
+				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
+}
+
 static u8 dp_voltage_max(u8 preemph)
 {
 	switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index 01f1dabbb060..47c97f4a0d57 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -10,6 +10,9 @@
 
 struct intel_dp;
 
+bool intel_dp_get_link_status(struct intel_dp *intel_dp,
+			      u8 link_status[DP_LINK_STATUS_SIZE]);
+
 void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
 			       const u8 link_status[DP_LINK_STATUS_SIZE]);
 void intel_dp_start_link_train(struct intel_dp *intel_dp);
-- 
2.17.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 1/7] drm/i915: Fix DP link training pattern mask Imre Deak
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 2/7] drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c Imre Deak
@ 2020-09-22 12:51 ` Imre Deak
  2020-09-22 13:27   ` Ville Syrjälä
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern Imre Deak
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Imre Deak @ 2020-09-22 12:51 UTC (permalink / raw)
  To: intel-gfx

Split the prepare, link training, fallback-handling steps into their own
functions for clarity and as a preparation for the upcoming LTTPR changes.

While at it also add some documentation to exported functions.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 80 ++++++++++++++-----
 1 file changed, 62 insertions(+), 18 deletions(-)

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 6d13d00db5e6..0c3809891bd2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -162,14 +162,13 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
 	return true;
 }
 
-/* Enable corresponding port and start training pattern 1 */
-static bool
-intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
+/*
+ * Prepare link training by configuring the link parameters and enabling the
+ * corresponding port.
+ */
+static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
 {
 	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
-	u8 voltage;
-	int voltage_tries, cr_tries, max_cr_tries;
-	bool max_vswing_reached = false;
 	u8 link_config[2];
 	u8 link_bw, rate_select;
 
@@ -203,6 +202,16 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
 
 	intel_dp->DP |= DP_PORT_EN;
+}
+
+/* Perform the link training clock recovery phase using training pattern 1. */
+static bool
+intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
+{
+	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+	u8 voltage;
+	int voltage_tries, cr_tries, max_cr_tries;
+	bool max_vswing_reached = false;
 
 	/* clock recovery */
 	if (!intel_dp_reset_link_train(intel_dp,
@@ -325,6 +334,10 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
 	return DP_TRAINING_PATTERN_2;
 }
 
+/*
+ * Perform the link training channel equalization phase using one of training
+ * pattern 2, 3 or 4 depending on the the source and sink capabilities.
+ */
 static bool
 intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 {
@@ -395,6 +408,15 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 
 }
 
+/**
+ * intel_dp_stop_link_train - stop link training
+ * @intel_dp: DP struct
+ *
+ * Stop the link training of the @intel_dp port, programming the port to
+ * output an idle pattern on the link and  disabling the training pattern in
+ * the sink's DPCD.
+ * This function must be called after intel_dp_start_link_train().
+ */
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 {
 	intel_dp->link_trained = true;
@@ -403,30 +425,37 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 				DP_TRAINING_PATTERN_DISABLE);
 }
 
-void
-intel_dp_start_link_train(struct intel_dp *intel_dp)
+static bool
+intel_dp_link_train(struct intel_dp *intel_dp)
 {
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
+	bool ret = false;
+
+	intel_dp_prepare_link_train(intel_dp);
 
 	if (!intel_dp_link_training_clock_recovery(intel_dp))
-		goto failure_handling;
+		goto out;
+
 	if (!intel_dp_link_training_channel_equalization(intel_dp))
-		goto failure_handling;
+		goto out;
 
-	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
-		    "[CONNECTOR:%d:%s] Link Training Passed at Link Rate = %d, Lane count = %d",
-		    intel_connector->base.base.id,
-		    intel_connector->base.name,
-		    intel_dp->link_rate, intel_dp->lane_count);
-	return;
+	ret = true;
 
- failure_handling:
+out:
 	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
-		    "[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
+		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d",
 		    intel_connector->base.base.id,
 		    intel_connector->base.name,
+		    ret ? "passed" : "failed",
 		    intel_dp->link_rate, intel_dp->lane_count);
 
+	return ret;
+}
+
+static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp)
+{
+	struct intel_connector *intel_connector = intel_dp->attached_connector;
+
 	if (intel_dp->hobl_active) {
 		drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
 			    "Link Training failed with HOBL active, not enabling it from now on");
@@ -440,3 +469,18 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
 	/* Schedule a Hotplug Uevent to userspace to start modeset */
 	schedule_work(&intel_connector->modeset_retry_work);
 }
+
+/**
+ * intel_dp_start_link_train - start link training
+ * @intel_dp: DP struct
+ *
+ * Start the link training of the @intel_dp port, scheduling a fallback
+ * retraining with reduced link rate/lane parameters if the link training
+ * fails.
+ * After calling this function intel_dp_stop_link_train() must be called.
+ */
+void intel_dp_start_link_train(struct intel_dp *intel_dp)
+{
+	if (!intel_dp_link_train(intel_dp))
+		intel_dp_schedule_fallback_link_training(intel_dp);
+}
-- 
2.17.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
                   ` (2 preceding siblings ...)
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions Imre Deak
@ 2020-09-22 12:51 ` Imre Deak
  2020-09-22 16:54   ` Ville Syrjälä
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 5/7] drm/dp: Add LTTPR helpers Imre Deak
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Imre Deak @ 2020-09-22 12:51 UTC (permalink / raw)
  To: intel-gfx

To prepare for a follow-up LTTPR change factor out a helper to disable
the training pattern in DPCD. We'll need to do this for each LTTPR
(without programming the port to output the idle pattern) when training
in LTTPR non-transparent mode.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 28 +++++++++++--------
 1 file changed, 16 insertions(+), 12 deletions(-)

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 0c3809891bd2..6994a32244dc 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -102,30 +102,34 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
 		intel_dp->train_set[lane] = v | p;
 }
 
+static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp)
+{
+	u8 val = DP_TRAINING_PATTERN_DISABLE;
+
+	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &val, 1) == 1;
+}
+
 static bool
 intel_dp_set_link_train(struct intel_dp *intel_dp,
 			u8 dp_train_pat)
 {
 	u8 buf[sizeof(intel_dp->train_set) + 1];
-	int ret, len;
+	int len;
 
 	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
 
-	buf[0] = dp_train_pat;
 	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
-	    DP_TRAINING_PATTERN_DISABLE) {
+	    DP_TRAINING_PATTERN_DISABLE)
 		/* don't write DP_TRAINING_LANEx_SET on disable */
-		len = 1;
-	} else {
-		/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
-		memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
-		len = intel_dp->lane_count + 1;
-	}
+		return intel_dp_disable_dpcd_training_pattern(intel_dp);
 
-	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
-				buf, len);
+	buf[0] = dp_train_pat;
+	/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
+	memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
+	len = intel_dp->lane_count + 1;
 
-	return ret == len;
+	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
+				 buf, len) == len;
 }
 
 static bool
-- 
2.17.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Intel-gfx] [PATCH 5/7] drm/dp: Add LTTPR helpers
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
                   ` (3 preceding siblings ...)
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern Imre Deak
@ 2020-09-22 12:51 ` Imre Deak
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 6/7] drm/i915: Switch to LTTPR transparent mode link training Imre Deak
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Imre Deak @ 2020-09-22 12:51 UTC (permalink / raw)
  To: intel-gfx; +Cc: dri-devel

Add the helpers and register definitions needed to read out the common
and per-PHY LTTPR capabilities and perform link training in the LTTPR
non-transparent mode.

Cc: dri-devel@lists.freedesktop.org
Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/drm_dp_helper.c | 179 +++++++++++++++++++++++++++++++-
 include/drm/drm_dp_helper.h     |  56 ++++++++++
 2 files changed, 231 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 90807a6b415c..115d2c3320ef 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -150,11 +150,8 @@ void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
 }
 EXPORT_SYMBOL(drm_dp_link_train_clock_recovery_delay);
 
-void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
+static void __drm_dp_link_train_channel_eq_delay(unsigned long rd_interval)
 {
-	unsigned long rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
-					 DP_TRAINING_AUX_RD_MASK;
-
 	if (rd_interval > 4)
 		DRM_DEBUG_KMS("AUX interval %lu, out of range (max 4)\n",
 			      rd_interval);
@@ -166,8 +163,35 @@ void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
 
 	usleep_range(rd_interval, rd_interval * 2);
 }
+
+void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
+{
+	__drm_dp_link_train_channel_eq_delay(dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
+					     DP_TRAINING_AUX_RD_MASK);
+}
 EXPORT_SYMBOL(drm_dp_link_train_channel_eq_delay);
 
+void drm_dp_lttpr_link_train_clock_recovery_delay(void)
+{
+	usleep_range(100, 200);
+}
+EXPORT_SYMBOL(drm_dp_lttpr_link_train_clock_recovery_delay);
+
+static u8 dp_lttpr_phy_cap(const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE], int r)
+{
+	return phy_cap[r - DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1];
+}
+
+void drm_dp_lttpr_link_train_channel_eq_delay(const u8 phy_cap[DP_LTTPR_PHY_CAP_SIZE])
+{
+	u8 interval = dp_lttpr_phy_cap(phy_cap,
+				       DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1) &
+		      DP_TRAINING_AUX_RD_MASK;
+
+	__drm_dp_link_train_channel_eq_delay(interval);
+}
+EXPORT_SYMBOL(drm_dp_lttpr_link_train_channel_eq_delay);
+
 u8 drm_dp_link_rate_to_bw_code(int link_rate)
 {
 	/* Spec says link_bw = link_rate / 0.27Gbps */
@@ -2093,6 +2117,153 @@ int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_S
 }
 EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs);
 
+/**
+ * drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities
+ * @aux: DisplayPort AUX channel
+ * @caps: buffer to return the capability info in
+ *
+ * Read capabilities common to all LTTPRs.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux,
+				  u8 caps[DP_LTTPR_COMMON_CAP_SIZE])
+{
+	int ret;
+
+	ret = drm_dp_dpcd_read(aux,
+			       DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
+			       caps, DP_LTTPR_COMMON_CAP_SIZE);
+	if (ret < 0)
+		return ret;
+
+	WARN_ON(ret != DP_LTTPR_COMMON_CAP_SIZE);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps);
+
+/**
+ * drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY
+ * @aux: DisplayPort AUX channel
+ * @dp_phy: LTTPR PHY to read the capabilities for
+ * @caps: buffer to return the capability info in
+ *
+ * Read the capabilities for the given LTTPR PHY.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux,
+			       enum drm_dp_phy dp_phy,
+			       u8 caps[DP_LTTPR_PHY_CAP_SIZE])
+{
+	int ret;
+
+	ret = drm_dp_dpcd_read(aux,
+			       DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy),
+			       caps, DP_LTTPR_PHY_CAP_SIZE);
+	if (ret < 0)
+		return ret;
+
+	WARN_ON(ret != DP_LTTPR_PHY_CAP_SIZE);
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps);
+
+static u8 dp_lttpr_common_cap(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE], int r)
+{
+	return caps[r - DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
+}
+
+/**
+ * drm_dp_lttpr_count - get the number of detected LTTPRs
+ * @caps: LTTPR common capabilities
+ *
+ * Get the number of detected LTTPRs from the LTTPR common capabilities info.
+ *
+ * Returns:
+ *   -ERANGE if more than supported number (8) of LTTPRs are detected
+ *   -EINVAL if the DP_PHY_REPEATER_CNT register contains an invalid value
+ *   otherwise the number of detected LTTPRs
+ */
+int drm_dp_lttpr_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE])
+{
+	u8 count = dp_lttpr_common_cap(caps, DP_PHY_REPEATER_CNT);
+
+	switch (hweight8(count)) {
+	case 0:
+		return 0;
+	case 1:
+		return 8 - ilog2(count);
+	case 8:
+		return -ERANGE;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL(drm_dp_lttpr_count);
+
+/**
+ * drm_dp_lttpr_max_link_rate - get the maximum link rate supported by all LTTPRs
+ * @caps: LTTPR common capabilities
+ *
+ * Returns the maximum link rate supported by all detected LTTPRs.
+ */
+int drm_dp_lttpr_max_link_rate(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE])
+{
+	u8 rate = dp_lttpr_common_cap(caps, DP_MAX_LINK_RATE_PHY_REPEATER);
+
+	return drm_dp_bw_code_to_link_rate(rate);
+}
+EXPORT_SYMBOL(drm_dp_lttpr_max_link_rate);
+
+/**
+ * drm_dp_lttpr_max_lane_count - get the maximum lane count supported by all LTTPRs
+ * @caps: LTTPR common capabilities
+ *
+ * Returns the maximum lane count supported by all detected LTTPRs.
+ */
+int drm_dp_lttpr_max_lane_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE])
+{
+	u8 max_lanes = dp_lttpr_common_cap(caps, DP_MAX_LANE_COUNT_PHY_REPEATER);
+
+	return max_lanes & DP_MAX_LANE_COUNT_MASK;
+}
+EXPORT_SYMBOL(drm_dp_lttpr_max_lane_count);
+
+/**
+ * drm_dp_lttpr_voltage_swing_level_3_supported - check for LTTPR vswing3 support
+ * @caps: LTTPR PHY capabilities
+ *
+ * Returns true if the @caps for an LTTPR TX PHY indicate support for
+ * voltage swing level 3.
+ */
+bool
+drm_dp_lttpr_voltage_swing_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE])
+{
+	u8 txcap = dp_lttpr_phy_cap(caps, DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1);
+
+	return txcap & DP_VOLTAGE_SWING_LEVEL_3_SUPPORTED;
+}
+EXPORT_SYMBOL(drm_dp_lttpr_voltage_swing_level_3_supported);
+
+/**
+ * drm_dp_lttpr_pre_emphasis_level_3_supported - check for LTTPR preemph3 support
+ * @caps: LTTPR PHY capabilities
+ *
+ * Returns true if the @caps for an LTTPR TX PHY indicate support for
+ * pre-emphasis level 3.
+ */
+bool
+drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE])
+{
+	u8 txcap = dp_lttpr_phy_cap(caps, DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1);
+
+	return txcap & DP_PRE_EMPHASIS_LEVEL_3_SUPPORTED;
+}
+EXPORT_SYMBOL(drm_dp_lttpr_pre_emphasis_level_3_supported);
+
 /**
  * drm_dp_get_phy_test_pattern() - get the requested pattern from the sink.
  * @aux: DisplayPort AUX channel
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index c9f2851904d0..de9ea7602f80 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -1066,15 +1066,56 @@ struct drm_device;
 #define DP_MAX_LANE_COUNT_PHY_REPEATER			    0xf0004 /* 1.4a */
 #define DP_Repeater_FEC_CAPABILITY			    0xf0004 /* 1.4 */
 #define DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT		    0xf0005 /* 1.4a */
+
+enum drm_dp_phy {
+	DP_PHY_DPRX,
+
+	DP_PHY_LTTPR1,
+	DP_PHY_LTTPR2,
+	DP_PHY_LTTPR3,
+	DP_PHY_LTTPR4,
+	DP_PHY_LTTPR5,
+	DP_PHY_LTTPR6,
+	DP_PHY_LTTPR7,
+	DP_PHY_LTTPR8,
+
+	DP_MAX_LTTPR_COUNT = DP_PHY_LTTPR8,
+};
+
+#define __DP_LTTPR1_BASE				    0xf0010 /* 1.3 */
+#define __DP_LTTPR2_BASE				    0xf0060 /* 1.3 */
+#define DP_LTTPR_BASE(dp_phy) \
+	(__DP_LTTPR1_BASE + (__DP_LTTPR2_BASE - __DP_LTTPR1_BASE) * \
+		((dp_phy) - DP_PHY_LTTPR1))
+
+#define DP_LTTPR_REG(dp_phy, lttpr1_reg) \
+	(DP_LTTPR_BASE(dp_phy) - DP_LTTPR_BASE(DP_PHY_LTTPR1) + (lttpr1_reg))
+
 #define DP_TRAINING_PATTERN_SET_PHY_REPEATER1		    0xf0010 /* 1.3 */
+#define DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy) \
+	DP_LTTPR_REG(dp_phy, DP_TRAINING_PATTERN_SET_PHY_REPEATER1)
+
 #define DP_TRAINING_LANE0_SET_PHY_REPEATER1		    0xf0011 /* 1.3 */
+#define DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy) \
+	DP_LTTPR_REG(dp_phy, DP_TRAINING_LANE0_SET_PHY_REPEATER1)
+
 #define DP_TRAINING_LANE1_SET_PHY_REPEATER1		    0xf0012 /* 1.3 */
 #define DP_TRAINING_LANE2_SET_PHY_REPEATER1		    0xf0013 /* 1.3 */
 #define DP_TRAINING_LANE3_SET_PHY_REPEATER1		    0xf0014 /* 1.3 */
 #define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1	    0xf0020 /* 1.4a */
+#define DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy)	\
+	DP_LTTPR_REG(dp_phy, DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER1)
+
 #define DP_TRANSMITTER_CAPABILITY_PHY_REPEATER1		    0xf0021 /* 1.4a */
+# define DP_VOLTAGE_SWING_LEVEL_3_SUPPORTED		    BIT(0)
+# define DP_PRE_EMPHASIS_LEVEL_3_SUPPORTED		    BIT(1)
+
 #define DP_LANE0_1_STATUS_PHY_REPEATER1			    0xf0030 /* 1.3 */
+#define DP_LANE0_1_STATUS_PHY_REPEATER(dp_phy) \
+	DP_LTTPR_REG(dp_phy, DP_LANE0_1_STATUS_PHY_REPEATER1)
+
 #define DP_LANE2_3_STATUS_PHY_REPEATER1			    0xf0031 /* 1.3 */
+
 #define DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1	    0xf0032 /* 1.3 */
 #define DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1		    0xf0033 /* 1.3 */
 #define DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1		    0xf0034 /* 1.3 */
@@ -1184,9 +1225,13 @@ u8 drm_dp_get_adjust_request_post_cursor(const u8 link_status[DP_LINK_STATUS_SIZ
 #define DP_DSC_RECEIVER_CAP_SIZE        0xf
 #define EDP_PSR_RECEIVER_CAP_SIZE	2
 #define EDP_DISPLAY_CTL_CAP_SIZE	3
+#define DP_LTTPR_COMMON_CAP_SIZE	8
+#define DP_LTTPR_PHY_CAP_SIZE		3
 
 void drm_dp_link_train_clock_recovery_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
+void drm_dp_lttpr_link_train_clock_recovery_delay(void);
 void drm_dp_link_train_channel_eq_delay(const u8 dpcd[DP_RECEIVER_CAP_SIZE]);
+void drm_dp_lttpr_link_train_channel_eq_delay(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]);
 
 u8 drm_dp_link_rate_to_bw_code(int link_rate);
 int drm_dp_bw_code_to_link_rate(u8 link_bw);
@@ -1694,6 +1739,17 @@ bool drm_dp_read_sink_count_cap(struct drm_connector *connector,
 				const struct drm_dp_desc *desc);
 int drm_dp_read_sink_count(struct drm_dp_aux *aux);
 
+int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux,
+				  u8 caps[DP_LTTPR_COMMON_CAP_SIZE]);
+int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux,
+			       enum drm_dp_phy dp_phy,
+			       u8 caps[DP_LTTPR_PHY_CAP_SIZE]);
+int drm_dp_lttpr_count(const u8 cap[DP_LTTPR_COMMON_CAP_SIZE]);
+int drm_dp_lttpr_max_link_rate(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]);
+int drm_dp_lttpr_max_lane_count(const u8 caps[DP_LTTPR_COMMON_CAP_SIZE]);
+bool drm_dp_lttpr_voltage_swing_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]);
+bool drm_dp_lttpr_pre_emphasis_level_3_supported(const u8 caps[DP_LTTPR_PHY_CAP_SIZE]);
+
 void drm_dp_remote_aux_init(struct drm_dp_aux *aux);
 void drm_dp_aux_init(struct drm_dp_aux *aux);
 int drm_dp_aux_register(struct drm_dp_aux *aux);
-- 
2.17.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Intel-gfx] [PATCH 6/7] drm/i915: Switch to LTTPR transparent mode link training
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
                   ` (4 preceding siblings ...)
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 5/7] drm/dp: Add LTTPR helpers Imre Deak
@ 2020-09-22 12:51 ` Imre Deak
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 7/7] drm/i915: Switch to LTTPR non-transparent " Imre Deak
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Imre Deak @ 2020-09-22 12:51 UTC (permalink / raw)
  To: intel-gfx

By default LTTPRs should be in transparent link training mode,
nevertheless in this patch we switch to this default mode explicitly.

The DP Standard recommends this, supposedly because an LTTPR may be left
in the non-transparent mode (by BIOS, previous kernel, or after reset
due to a firmware bug). I haven't seen this happening, but let's follow
the DP Standard.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |  1 +
 drivers/gpu/drm/i915/display/intel_dp.c       |  3 ++
 .../drm/i915/display/intel_dp_link_training.c | 42 +++++++++++++++++++
 .../drm/i915/display/intel_dp_link_training.h |  1 +
 4 files changed, 47 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 3d4bf9b6a0a2..b04921eba73b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1280,6 +1280,7 @@ struct intel_dp {
 	u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
 	u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
 	u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
+	u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
 	u8 fec_capable;
 	/* source rates */
 	int num_source_rates;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index ee93a00a4d5e..d88f327aa9ef 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4721,6 +4721,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
 {
 	int ret;
 
+	if (!intel_dp_is_edp(intel_dp))
+		intel_dp_read_lttpr_caps(intel_dp);
+
 	if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd))
 		return false;
 
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 6994a32244dc..1485602659be 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -50,6 +50,24 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATU
 				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
 }
 
+/**
+ * intel_dp_read_lttpr_caps - read the LTTPR common capabilities
+ * @intel_dp: Intel DP struct
+ *
+ * Read the LTTPR common capabilities.
+ */
+void intel_dp_read_lttpr_caps(struct intel_dp *intel_dp)
+{
+	if (drm_dp_read_lttpr_common_caps(&intel_dp->aux,
+					  intel_dp->lttpr_common_caps) < 0)
+		return;
+
+	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+		    "LTTPR common capabilities: %*ph\n",
+		    (int)sizeof(intel_dp->lttpr_common_caps),
+		    intel_dp->lttpr_common_caps);
+}
+
 static u8 dp_voltage_max(u8 preemph)
 {
 	switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {
@@ -474,6 +492,28 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp)
 	schedule_work(&intel_connector->modeset_retry_work);
 }
 
+static bool
+intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
+{
+	u8 val = enable ? DP_PHY_REPEATER_MODE_TRANSPARENT :
+			  DP_PHY_REPEATER_MODE_NON_TRANSPARENT;
+
+	return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1;
+}
+
+static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
+{
+	if (intel_dp_is_edp(intel_dp))
+		return;
+
+	/*
+	 * TODO: the following re-reading of LTTPR caps can be removed
+	 * after a proper connector HW readout is added.
+	 */
+	intel_dp_read_lttpr_caps(intel_dp);
+	intel_dp_set_lttpr_transparent_mode(intel_dp, true);
+}
+
 /**
  * intel_dp_start_link_train - start link training
  * @intel_dp: DP struct
@@ -485,6 +525,8 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp)
  */
 void intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
+	intel_dp_init_lttpr_mode(intel_dp);
+
 	if (!intel_dp_link_train(intel_dp))
 		intel_dp_schedule_fallback_link_training(intel_dp);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index 47c97f4a0d57..c0be3ff709a0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -12,6 +12,7 @@ struct intel_dp;
 
 bool intel_dp_get_link_status(struct intel_dp *intel_dp,
 			      u8 link_status[DP_LINK_STATUS_SIZE]);
+void intel_dp_read_lttpr_caps(struct intel_dp *intel_dp);
 
 void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
 			       const u8 link_status[DP_LINK_STATUS_SIZE]);
-- 
2.17.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Intel-gfx] [PATCH 7/7] drm/i915: Switch to LTTPR non-transparent mode link training
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
                   ` (5 preceding siblings ...)
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 6/7] drm/i915: Switch to LTTPR transparent mode link training Imre Deak
@ 2020-09-22 12:51 ` Imre Deak
  2020-09-22 17:37   ` Ville Syrjälä
  2020-09-22 13:00 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Add support for LTTPR non-transparent link training mode Patchwork
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Imre Deak @ 2020-09-22 12:51 UTC (permalink / raw)
  To: intel-gfx

The DP Standard's recommendation is to use the LTTPR non-transparent
mode link training if LTTPRs are detected, so let's do this.

Besides power-saving, the advantages of this are that the maximum number
of LTTPRs can only be used in non-transparent mode (the limit is 5-8 in
transparent mode), and it provides a way to narrow down the reason for a
link training failure to a given link segment. Non-transparent mode is
probably also the mode that was tested the most by the industry.

The changes in this patchset:
- Pass the DP PHY that is currently link trained to all LT helpers, so
  that these can access the correct LTTPR/DPRX DPCD registers.
- During LT take into account the LTTPR common lane rate/count and the
  per LTTPR-PHY vswing/pre-emph limits.
- Switch to LTTPR non-transparent LT mode and train each link segment
  according to the sequence in DP Standard v2.0 (complete CR/EQ for
  each segment before continuing with the next segment).

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |   1 +
 drivers/gpu/drm/i915/display/intel_dp.c       |  14 +-
 .../drm/i915/display/intel_dp_link_training.c | 374 +++++++++++++++---
 .../drm/i915/display/intel_dp_link_training.h |  10 +-
 4 files changed, 327 insertions(+), 72 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index b04921eba73b..2fb4e9a6a316 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1281,6 +1281,7 @@ struct intel_dp {
 	u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
 	u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
 	u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
+	u8 lttpr_phy_caps[DP_MAX_LTTPR_COUNT][DP_LTTPR_PHY_CAP_SIZE];
 	u8 fec_capable;
 	/* source rates */
 	int num_source_rates;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index d88f327aa9ef..54ad31044eef 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -161,6 +161,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
 		162000, 270000, 540000, 810000
 	};
 	int i, max_rate;
+	int max_lttpr_rate;
 
 	if (drm_dp_has_quirk(&intel_dp->desc, 0,
 			     DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) {
@@ -174,6 +175,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
 	}
 
 	max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
+	max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps);
+	if (max_lttpr_rate)
+		max_rate = min(max_rate, max_lttpr_rate);
 
 	for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
 		if (dp_rates[i] > max_rate)
@@ -219,6 +223,10 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
 	int source_max = dig_port->max_lanes;
 	int sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
 	int fia_max = intel_tc_port_fia_max_lane_count(dig_port);
+	int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps);
+
+	if (lttpr_max)
+		sink_max = min(sink_max, lttpr_max);
 
 	return min3(source_max, sink_max, fia_max);
 }
@@ -5540,13 +5548,13 @@ void intel_dp_process_phy_request(struct intel_dp *intel_dp)
 		&intel_dp->compliance.test_data.phytest;
 	u8 link_status[DP_LINK_STATUS_SIZE];
 
-	if (!intel_dp_get_link_status(intel_dp, link_status)) {
+	if (!intel_dp_get_link_status(intel_dp, DP_PHY_DPRX, link_status)) {
 		DRM_DEBUG_KMS("failed to get link status\n");
 		return;
 	}
 
 	/* retrieve vswing & pre-emphasis setting */
-	intel_dp_get_adjust_train(intel_dp, link_status);
+	intel_dp_get_adjust_train(intel_dp, DP_PHY_DPRX, link_status);
 
 	intel_dp_autotest_phy_ddi_disable(intel_dp);
 
@@ -5701,7 +5709,7 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 	if (intel_psr_enabled(intel_dp))
 		return false;
 
-	if (!intel_dp_get_link_status(intel_dp, link_status))
+	if (!intel_dp_get_link_status(intel_dp, DP_PHY_DPRX, link_status))
 		return false;
 
 	/*
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 1485602659be..3aa685a9aa2a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -25,6 +25,8 @@
 #include "intel_dp.h"
 #include "intel_dp_link_training.h"
 
+#define DP_PHY_LTTPR(i)		(DP_PHY_LTTPR1 + (i))
+
 static void
 intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
 {
@@ -35,37 +37,140 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
 }
 
 /**
- * intel_dp_get_link_status - get the link status information for the DPRX
+ * intel_dp_get_link_status - get the link status information for a DP PHY
  * @intel_dp: DP struct
+ * @dp_phy: the DP PHY to get the link status for
  * @link_status: buffer to return the status in
  *
- * Fetch the AUX DPCD registers for the DPRX link status.
+ * Fetch the AUX DPCD registers for the DPRX or an LTTPR PHY link status. The
+ * layout of the returned @link_status matches the DPCD register layout of the
+ * DPRX PHY link status.
  *
  * Returns true if the information was read successfully, false otherwise.
  */
 bool
-intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
+intel_dp_get_link_status(struct intel_dp *intel_dp,
+			 enum drm_dp_phy dp_phy,
+			 u8 link_status[DP_LINK_STATUS_SIZE])
 {
-	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
-				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
+	u8 lttpr_status[DP_LINK_STATUS_SIZE - 1];
+
+	if (dp_phy == DP_PHY_DPRX)
+		return drm_dp_dpcd_read(&intel_dp->aux,
+					DP_LANE0_1_STATUS,
+					link_status,
+					DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
+
+	if (drm_dp_dpcd_read(&intel_dp->aux,
+			     DP_LANE0_1_STATUS_PHY_REPEATER(dp_phy),
+			     lttpr_status,
+			     sizeof(lttpr_status)) != sizeof(lttpr_status))
+			return false;
+
+#define link_reg(reg)	link_status[(reg) - DP_LANE0_1_STATUS]
+#define lttpr_reg(reg)	lttpr_status[(reg) - DP_LANE0_1_STATUS_PHY_REPEATER1]
+
+	/* Convert the LTTPR to the sink PHY link status layout */
+	link_reg(DP_LANE0_1_STATUS) = lttpr_reg(DP_LANE0_1_STATUS_PHY_REPEATER1);
+	link_reg(DP_LANE2_3_STATUS) = lttpr_reg(DP_LANE2_3_STATUS_PHY_REPEATER1);
+	link_reg(DP_LANE_ALIGN_STATUS_UPDATED) =
+		lttpr_reg(DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1);
+	link_reg(DP_SINK_STATUS) = 0;
+	link_reg(DP_ADJUST_REQUEST_LANE0_1) =
+		lttpr_reg(DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1);
+	link_reg(DP_ADJUST_REQUEST_LANE2_3) =
+		lttpr_reg(DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1);
+
+#undef link_reg
+#undef lttpr_reg
+
+	return true;
+}
+
+static int intel_dp_lttpr_count(struct intel_dp *intel_dp)
+{
+	int count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps);
+
+	/*
+	 * Pretend no LTTPRs in case of LTTPR detection error, or
+	 * if too many (>8) LTTPRs are detected. This translates to link
+	 * training in transparent mode.
+	 */
+	return count <= 0 ? 0 : count;
+}
+
+static const char *intel_dp_phy_name(enum drm_dp_phy dp_phy,
+				     char *buf, size_t buf_size)
+{
+	if (dp_phy == DP_PHY_DPRX)
+		snprintf(buf, buf_size, "DPRX");
+	else
+		snprintf(buf, buf_size, "LTTPR %d", dp_phy - DP_PHY_LTTPR1 + 1);
+
+	return buf;
+}
+
+static uint8_t *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp,
+					enum drm_dp_phy dp_phy)
+{
+	return &intel_dp->lttpr_phy_caps[dp_phy - DP_PHY_LTTPR1][0];
 }
 
 /**
- * intel_dp_read_lttpr_caps - read the LTTPR common capabilities
+ * intel_dp_read_lttpr_caps - read the LTTPR common and per-PHY capabilities
  * @intel_dp: Intel DP struct
  *
- * Read the LTTPR common capabilities.
+ * Read the LTTPR common capabilities and the PHY capabilities for all
+ * detected LTTPRs. In case of an LTTPR detection error or if the number of
+ * LTTPRs is more than is supported (8), fall back to the no-LTTPR,
+ * transparent mode link training mode.
  */
 void intel_dp_read_lttpr_caps(struct intel_dp *intel_dp)
 {
+	int lttpr_count;
+	int i;
+
 	if (drm_dp_read_lttpr_common_caps(&intel_dp->aux,
-					  intel_dp->lttpr_common_caps) < 0)
+					  intel_dp->lttpr_common_caps) < 0) {
+		memset(intel_dp->lttpr_common_caps, 0,
+		       sizeof(intel_dp->lttpr_common_caps));
 		return;
+	}
 
 	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
 		    "LTTPR common capabilities: %*ph\n",
 		    (int)sizeof(intel_dp->lttpr_common_caps),
 		    intel_dp->lttpr_common_caps);
+
+	lttpr_count = intel_dp_lttpr_count(intel_dp);
+	/*
+	 * In case of unsupported number of LTTPRs fall-back to transparent
+	 * link training mode, still taking into account any LTTPR common
+	 * lane- rate/count limits.
+	 */
+	if (lttpr_count <= 0)
+		return;
+
+	for (i = 0; i < lttpr_count; i++) {
+		enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
+		uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+		char phy_name[10];
+
+		intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name));
+
+		if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) {
+			drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+				    "failed to read the PHY caps for %s\n",
+				    phy_name);
+			continue;
+		}
+
+		drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
+			    "%s PHY capabilities: %*ph\n",
+			    phy_name,
+			    (int)sizeof(intel_dp->lttpr_phy_caps[0]),
+			    phy_caps);
+	}
 }
 
 static u8 dp_voltage_max(u8 preemph)
@@ -83,10 +188,78 @@ static u8 dp_voltage_max(u8 preemph)
 	}
 }
 
+static u8 intel_dp_lttpr_voltage_max(struct intel_dp *intel_dp,
+				     enum drm_dp_phy dp_phy)
+{
+	const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+	if (drm_dp_lttpr_voltage_swing_level_3_supported(phy_caps))
+		return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
+	else
+		return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
+}
+
+static u8 intel_dp_lttpr_preemph_max(struct intel_dp *intel_dp,
+				     enum drm_dp_phy dp_phy)
+{
+	const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+	if (drm_dp_lttpr_pre_emphasis_level_3_supported(phy_caps))
+		return DP_TRAIN_PRE_EMPH_LEVEL_3;
+	else
+		return DP_TRAIN_PRE_EMPH_LEVEL_2;
+}
+
+static u8 intel_dp_phy_voltage_max(struct intel_dp *intel_dp,
+				    enum drm_dp_phy dp_phy)
+{
+	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+	int lttpr_count = intel_dp_lttpr_count(intel_dp);
+	u8 voltage_max;
+
+	/*
+	 * Get voltage_max from the DPTX_PHY (source or LTTPR) upstream from
+	 * the DPRX_PHY we train.
+	 */
+	if (lttpr_count == 0 || dp_phy == DP_PHY_LTTPR(lttpr_count - 1))
+		voltage_max = intel_dp->voltage_max(intel_dp);
+	else
+		voltage_max = intel_dp_lttpr_voltage_max(intel_dp, dp_phy + 1);
+
+	drm_WARN_ON_ONCE(&i915->drm,
+			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
+			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
+
+	return voltage_max;
+}
+
+static u8 intel_dp_phy_preemph_max(struct intel_dp *intel_dp,
+				   enum drm_dp_phy dp_phy)
+{
+	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
+	int lttpr_count = intel_dp_lttpr_count(intel_dp);
+	u8 preemph_max;
+
+	/*
+	 * Get preemph_max from the DPTX_PHY (source or LTTPR) upstream from
+	 * the DPRX_PHY we train.
+	 */
+	if (lttpr_count == 0 || dp_phy == DP_PHY_LTTPR(lttpr_count - 1))
+		preemph_max = intel_dp->preemph_max(intel_dp);
+	else
+		preemph_max = intel_dp_lttpr_preemph_max(intel_dp, dp_phy + 1);
+
+	drm_WARN_ON_ONCE(&i915->drm,
+			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
+			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
+
+	return preemph_max;
+}
+
 void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
+			       enum drm_dp_phy dp_phy,
 			       const u8 link_status[DP_LINK_STATUS_SIZE])
 {
-	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
 	u8 v = 0;
 	u8 p = 0;
 	int lane;
@@ -98,21 +271,13 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
 		p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, lane));
 	}
 
-	preemph_max = intel_dp->preemph_max(intel_dp);
-	drm_WARN_ON_ONCE(&i915->drm,
-			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
-			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
-
+	preemph_max = intel_dp_phy_preemph_max(intel_dp, dp_phy);
 	if (p >= preemph_max)
 		p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
 	v = min(v, dp_voltage_max(p));
 
-	voltage_max = intel_dp->voltage_max(intel_dp);
-	drm_WARN_ON_ONCE(&i915->drm,
-			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
-			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
-
+	voltage_max = intel_dp_phy_voltage_max(intel_dp, dp_phy);
 	if (v >= voltage_max)
 		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
 
@@ -120,17 +285,24 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
 		intel_dp->train_set[lane] = v | p;
 }
 
-static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp)
+static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp,
+						   enum drm_dp_phy dp_phy)
 {
+	int reg = dp_phy == DP_PHY_DPRX ?
+		DP_TRAINING_PATTERN_SET :
+		DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
 	u8 val = DP_TRAINING_PATTERN_DISABLE;
 
-	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &val, 1) == 1;
+	return drm_dp_dpcd_write(&intel_dp->aux, reg, &val, 1) == 1;
 }
 
 static bool
-intel_dp_set_link_train(struct intel_dp *intel_dp,
+intel_dp_set_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
 			u8 dp_train_pat)
 {
+	int reg = dp_phy == DP_PHY_DPRX ?
+		DP_TRAINING_PATTERN_SET :
+		DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
 	u8 buf[sizeof(intel_dp->train_set) + 1];
 	int len;
 
@@ -139,34 +311,36 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
 	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
 	    DP_TRAINING_PATTERN_DISABLE)
 		/* don't write DP_TRAINING_LANEx_SET on disable */
-		return intel_dp_disable_dpcd_training_pattern(intel_dp);
+		return intel_dp_disable_dpcd_training_pattern(intel_dp, dp_phy);
 
 	buf[0] = dp_train_pat;
 	/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
 	memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
 	len = intel_dp->lane_count + 1;
 
-	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
-				 buf, len) == len;
+	return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
 }
 
 static bool
-intel_dp_reset_link_train(struct intel_dp *intel_dp,
+intel_dp_reset_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
 			u8 dp_train_pat)
 {
 	memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
 	intel_dp_set_signal_levels(intel_dp);
-	return intel_dp_set_link_train(intel_dp, dp_train_pat);
+	return intel_dp_set_link_train(intel_dp, dp_phy, dp_train_pat);
 }
 
 static bool
-intel_dp_update_link_train(struct intel_dp *intel_dp)
+intel_dp_update_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy)
 {
+	int reg = dp_phy == DP_PHY_DPRX ?
+		DP_TRAINING_LANE0_SET :
+		DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
 	int ret;
 
 	intel_dp_set_signal_levels(intel_dp);
 
-	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
+	ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
 				intel_dp->train_set, intel_dp->lane_count);
 
 	return ret == intel_dp->lane_count;
@@ -226,9 +400,22 @@ static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
 	intel_dp->DP |= DP_PORT_EN;
 }
 
-/* Perform the link training clock recovery phase using training pattern 1. */
+static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_dp,
+							enum drm_dp_phy dp_phy)
+{
+	if (dp_phy == DP_PHY_DPRX)
+		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+	else
+		drm_dp_lttpr_link_train_clock_recovery_delay();
+}
+
+/*
+ * Perform the link training clock recovery phase on the given DP PHY using
+ * training pattern 1.
+ */
 static bool
-intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
+intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp,
+				      enum drm_dp_phy dp_phy)
 {
 	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
 	u8 voltage;
@@ -236,7 +423,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 	bool max_vswing_reached = false;
 
 	/* clock recovery */
-	if (!intel_dp_reset_link_train(intel_dp,
+	if (!intel_dp_reset_link_train(intel_dp, dp_phy,
 				       DP_TRAINING_PATTERN_1 |
 				       DP_LINK_SCRAMBLING_DISABLE)) {
 		drm_err(&i915->drm, "failed to enable link training\n");
@@ -260,9 +447,9 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 	for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) {
 		u8 link_status[DP_LINK_STATUS_SIZE];
 
-		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+		intel_dp_link_training_clock_recovery_delay(intel_dp, dp_phy);
 
-		if (!intel_dp_get_link_status(intel_dp, link_status)) {
+		if (!intel_dp_get_link_status(intel_dp, dp_phy, link_status)) {
 			drm_err(&i915->drm, "failed to get link status\n");
 			return false;
 		}
@@ -286,8 +473,8 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
 		/* Update training set as requested by target */
-		intel_dp_get_adjust_train(intel_dp, link_status);
-		if (!intel_dp_update_link_train(intel_dp)) {
+		intel_dp_get_adjust_train(intel_dp, dp_phy, link_status);
+		if (!intel_dp_update_link_train(intel_dp, dp_phy)) {
 			drm_err(&i915->drm,
 				"failed to update link training\n");
 			return false;
@@ -313,7 +500,8 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
  * or for 1.4 devices that support it, training Pattern 3 for HBR2
  * or 1.2 devices that support it, Training Pattern 2 otherwise.
  */
-static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
+static u32 intel_dp_training_pattern(struct intel_dp *intel_dp,
+				     enum drm_dp_phy dp_phy)
 {
 	bool source_tps3, sink_tps3, source_tps4, sink_tps4;
 
@@ -322,9 +510,11 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
 	 * for all downstream devices that support HBR3. There are no known eDP
 	 * panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1
 	 * specification.
+	 * LTTPRs must support TPS4.
 	 */
 	source_tps4 = intel_dp_source_supports_hbr3(intel_dp);
-	sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd);
+	sink_tps4 = dp_phy != DP_PHY_DPRX ||
+		    drm_dp_tps4_supported(intel_dp->dpcd);
 	if (source_tps4 && sink_tps4) {
 		return DP_TRAINING_PATTERN_4;
 	} else if (intel_dp->link_rate == 810000) {
@@ -341,7 +531,8 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
 	 * all sinks follow the spec.
 	 */
 	source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
-	sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
+	sink_tps3 = dp_phy != DP_PHY_DPRX ||
+		    drm_dp_tps3_supported(intel_dp->dpcd);
 	if (source_tps3 && sink_tps3) {
 		return  DP_TRAINING_PATTERN_3;
 	} else if (intel_dp->link_rate >= 540000) {
@@ -356,12 +547,27 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
 	return DP_TRAINING_PATTERN_2;
 }
 
+static void
+intel_dp_link_training_channel_equalization_delay(struct intel_dp *intel_dp,
+						  enum drm_dp_phy dp_phy)
+{
+	if (dp_phy == DP_PHY_DPRX) {
+		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
+	} else {
+		const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
+
+		drm_dp_lttpr_link_train_channel_eq_delay(phy_caps);
+	}
+}
+
 /*
- * Perform the link training channel equalization phase using one of training
- * pattern 2, 3 or 4 depending on the the source and sink capabilities.
+ * Perform the link training channel equalization phase on the given DP PHY
+ * using one of training pattern 2, 3 or 4 depending on the the source and
+ * sink capabilities.
  */
 static bool
-intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
+intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp,
+					    enum drm_dp_phy dp_phy)
 {
 	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
 	int tries;
@@ -369,22 +575,21 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 	u8 link_status[DP_LINK_STATUS_SIZE];
 	bool channel_eq = false;
 
-	training_pattern = intel_dp_training_pattern(intel_dp);
+	training_pattern = intel_dp_training_pattern(intel_dp, dp_phy);
 	/* Scrambling is disabled for TPS2/3 and enabled for TPS4 */
 	if (training_pattern != DP_TRAINING_PATTERN_4)
 		training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
 
 	/* channel equalization */
-	if (!intel_dp_set_link_train(intel_dp,
-				     training_pattern)) {
+	if (!intel_dp_set_link_train(intel_dp, dp_phy, training_pattern)) {
 		drm_err(&i915->drm, "failed to start channel equalization\n");
 		return false;
 	}
 
 	for (tries = 0; tries < 5; tries++) {
-
-		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
-		if (!intel_dp_get_link_status(intel_dp, link_status)) {
+		intel_dp_link_training_channel_equalization_delay(intel_dp,
+								  dp_phy);
+		if (!intel_dp_get_link_status(intel_dp, dp_phy, link_status)) {
 			drm_err(&i915->drm,
 				"failed to get link status\n");
 			break;
@@ -409,8 +614,8 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 		}
 
 		/* Update training set as requested by target */
-		intel_dp_get_adjust_train(intel_dp, link_status);
-		if (!intel_dp_update_link_train(intel_dp)) {
+		intel_dp_get_adjust_train(intel_dp, dp_phy, link_status);
+		if (!intel_dp_update_link_train(intel_dp, dp_phy)) {
 			drm_err(&i915->drm,
 				"failed to update link training\n");
 			break;
@@ -424,8 +629,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 			    "Channel equalization failed 5 times\n");
 	}
 
-	intel_dp_set_idle_link_train(intel_dp);
-
 	return channel_eq;
 
 }
@@ -442,34 +645,33 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 {
 	intel_dp->link_trained = true;
-
-	intel_dp_set_link_train(intel_dp,
+	intel_dp_set_link_train(intel_dp, DP_PHY_DPRX,
 				DP_TRAINING_PATTERN_DISABLE);
 }
 
 static bool
-intel_dp_link_train(struct intel_dp *intel_dp)
+intel_dp_link_train_phy(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy)
 {
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
+	char phy_name[10];
 	bool ret = false;
 
-	intel_dp_prepare_link_train(intel_dp);
-
-	if (!intel_dp_link_training_clock_recovery(intel_dp))
+	if (!intel_dp_link_training_clock_recovery(intel_dp, dp_phy))
 		goto out;
 
-	if (!intel_dp_link_training_channel_equalization(intel_dp))
+	if (!intel_dp_link_training_channel_equalization(intel_dp, dp_phy))
 		goto out;
 
 	ret = true;
 
 out:
 	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
-		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d",
+		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d, at %s",
 		    intel_connector->base.base.id,
 		    intel_connector->base.name,
 		    ret ? "passed" : "failed",
-		    intel_dp->link_rate, intel_dp->lane_count);
+		    intel_dp->link_rate, intel_dp->lane_count,
+		    intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)));
 
 	return ret;
 }
@@ -492,6 +694,33 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp)
 	schedule_work(&intel_connector->modeset_retry_work);
 }
 
+/* Perform the link training on all LTTPRs and the DPRX on a link. */
+static bool
+intel_dp_link_train_all_phys(struct intel_dp *intel_dp, int lttpr_count)
+{
+	bool ret = true;
+	int i;
+
+	intel_dp_prepare_link_train(intel_dp);
+
+	for (i = lttpr_count - 1; i >= 0; i--) {
+		enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
+
+		ret = intel_dp_link_train_phy(intel_dp, dp_phy);
+		intel_dp_disable_dpcd_training_pattern(intel_dp, dp_phy);
+
+		if (!ret)
+			break;
+	}
+
+	if (ret)
+		intel_dp_link_train_phy(intel_dp, DP_PHY_DPRX);
+
+	intel_dp_set_idle_link_train(intel_dp);
+
+	return ret;
+}
+
 static bool
 intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
 {
@@ -501,10 +730,12 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
 	return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1;
 }
 
-static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
+static int intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
 {
+	int lttpr_count;
+
 	if (intel_dp_is_edp(intel_dp))
-		return;
+		return 0;
 
 	/*
 	 * TODO: the following re-reading of LTTPR caps can be removed
@@ -512,6 +743,19 @@ static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
 	 */
 	intel_dp_read_lttpr_caps(intel_dp);
 	intel_dp_set_lttpr_transparent_mode(intel_dp, true);
+
+	lttpr_count = intel_dp_lttpr_count(intel_dp);
+	if (lttpr_count) {
+		/*
+		 * If we can't set non-transparent mode fall-back to
+		 * transparent mode, still taking into account any LTTPR
+		 * common lane rate and count limits.
+		 */
+		if (!intel_dp_set_lttpr_transparent_mode(intel_dp, false))
+			lttpr_count = 0;
+	}
+
+	return lttpr_count;
 }
 
 /**
@@ -525,8 +769,8 @@ static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
  */
 void intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-	intel_dp_init_lttpr_mode(intel_dp);
+	int lttpr_count = intel_dp_init_lttpr_mode(intel_dp);
 
-	if (!intel_dp_link_train(intel_dp))
+	if (!intel_dp_link_train_all_phys(intel_dp, lttpr_count))
 		intel_dp_schedule_fallback_link_training(intel_dp);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index c0be3ff709a0..d0393b76ffc1 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -10,12 +10,14 @@
 
 struct intel_dp;
 
-bool intel_dp_get_link_status(struct intel_dp *intel_dp,
-			      u8 link_status[DP_LINK_STATUS_SIZE]);
+bool
+intel_dp_get_link_status(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
+			 u8 link_status[DP_LINK_STATUS_SIZE]);
 void intel_dp_read_lttpr_caps(struct intel_dp *intel_dp);
 
-void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
-			       const u8 link_status[DP_LINK_STATUS_SIZE]);
+void
+intel_dp_get_adjust_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
+			  const u8 link_status[DP_LINK_STATUS_SIZE]);
 void intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 
-- 
2.17.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Add support for LTTPR non-transparent link training mode
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
                   ` (6 preceding siblings ...)
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 7/7] drm/i915: Switch to LTTPR non-transparent " Imre Deak
@ 2020-09-22 13:00 ` Patchwork
  2020-09-22 13:01 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Patchwork @ 2020-09-22 13:00 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Add support for LTTPR non-transparent link training mode
URL   : https://patchwork.freedesktop.org/series/81968/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
154fc7783917 drm/i915: Fix DP link training pattern mask
b688f7336e26 drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c
b7d02e6b76cc drm/i915: Simplify the link training functions
-:60: WARNING:REPEATED_WORD: Possible repeated word: 'the'
#60: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:339:
+ * pattern 2, 3 or 4 depending on the the source and sink capabilities.

total: 0 errors, 1 warnings, 0 checks, 127 lines checked
0b95955d4877 drm/i915: Factor out a helper to disable the DPCD training pattern
6a20187d3dfa drm/dp: Add LTTPR helpers
4fbcfbcb1a33 drm/i915: Switch to LTTPR transparent mode link training
91260e606734 drm/i915: Switch to LTTPR non-transparent mode link training
-:140: WARNING:SUSPECT_CODE_INDENT: suspect code indent for conditional statements (8, 24)
#140: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:64:
+	if (drm_dp_dpcd_read(&intel_dp->aux,
[...]
+			return false;

-:237: CHECK:PREFER_KERNEL_TYPES: Prefer kernel type 'u8' over 'uint8_t'
#237: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:156:
+		uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);

-:265: CHECK:PREFER_KERNEL_TYPES: Prefer kernel type 'u8' over 'uint8_t'
#265: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:194:
+	const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);

-:276: CHECK:PREFER_KERNEL_TYPES: Prefer kernel type 'u8' over 'uint8_t'
#276: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:205:
+	const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);

-:285: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#285: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:214:
+static u8 intel_dp_phy_voltage_max(struct intel_dp *intel_dp,
+				    enum drm_dp_phy dp_phy)

-:410: CHECK:PARENTHESIS_ALIGNMENT: Alignment should match open parenthesis
#410: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:326:
+intel_dp_reset_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
 			u8 dp_train_pat)

-:535: CHECK:PREFER_KERNEL_TYPES: Prefer kernel type 'u8' over 'uint8_t'
#535: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:557:
+		const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);

-:545: WARNING:REPEATED_WORD: Possible repeated word: 'the'
#545: FILE: drivers/gpu/drm/i915/display/intel_dp_link_training.c:565:
+ * using one of training pattern 2, 3 or 4 depending on the the source and

total: 0 errors, 2 warnings, 6 checks, 678 lines checked


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Intel-gfx] ✗ Fi.CI.SPARSE: warning for drm/i915: Add support for LTTPR non-transparent link training mode
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
                   ` (7 preceding siblings ...)
  2020-09-22 13:00 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Add support for LTTPR non-transparent link training mode Patchwork
@ 2020-09-22 13:01 ` Patchwork
  2020-09-22 13:17 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
  2020-09-22 15:17 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork
  10 siblings, 0 replies; 27+ messages in thread
From: Patchwork @ 2020-09-22 13:01 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

== Series Details ==

Series: drm/i915: Add support for LTTPR non-transparent link training mode
URL   : https://patchwork.freedesktop.org/series/81968/
State : warning

== Summary ==

$ dim sparse --fast origin/drm-tip
Sparse version: v0.6.2
Fast mode used, each commit won't be checked separately.
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:1019:47:    expected unsigned int [addressable] [usertype] ulClockParams
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:1019:47:    got restricted __le32 [usertype]
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:1019:47: warning: incorrect type in assignment (different base types)
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:1028:50: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:1029:49: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:1037:47: warning: too many warnings
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:184:44: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:283:14: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:320:14: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:323:14: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:326:14: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:329:18: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:330:26: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:338:30: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:340:38: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:342:30: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:346:30: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:348:30: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:353:33: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:367:43: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:369:38: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:374:67: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:375:53: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:378:66: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:389:80: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:395:57: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:402:69: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:403:53: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:406:66: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:414:66: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:423:69: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:424:69: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:473:30: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:476:45: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:477:45: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:484:54: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:52:28: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:531:35: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:53:29: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:533:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:54:26: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:55:27: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:56:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:57:26: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:577:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:581:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:58:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:583:21: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:586:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:590:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:59:26: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:598:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:600:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:617:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:621:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:623:21: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:630:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:632:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:644:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:648:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:650:21: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:657:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:659:21: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:662:21: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:664:21: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:676:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:688:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:691:47: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:697:25: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:796:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:797:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:800:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:801:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:804:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:805:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:812:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:813:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:816:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:817:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:820:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:821:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:828:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:829:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:832:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:833:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:836:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:837:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:844:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:845:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:848:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:849:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:852:46: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:853:40: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:916:47: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:918:49: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:920:52: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:934:47: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:936:49: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:938:52: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:956:47: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:958:49: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c:960:52: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:328:34: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:365:34: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:395:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:397:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:404:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:418:40: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:441:40: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:44:21: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:482:53: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:486:33: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:489:61: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:490:64: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:492:54: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:518:17: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:521:21: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:64:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:80:17: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:80:17: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:80:17: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:85:30: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:86:24: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c:98:39: warning: cast to restricted __le16
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:222:29: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:226:37: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:226:37: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:226:37: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:227:37: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:233:43: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:236:44: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:239:51: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:458:41: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:458:41: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:458:41: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:464:39: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:465:30: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:466:39: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c:468:24: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:140:26:    expected unsigned long long [usertype] *chunk_array_user
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:140:26:    got void [noderef] __user *
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:140:26: warning: incorrect type in assignment (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:141:41:    expected void const [noderef] __user *from
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:141:41:    got unsigned long long [usertype] *chunk_array_user
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:141:41: warning: incorrect type in argument 2 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:160:27:    expected struct drm_amdgpu_cs_chunk [noderef] __user **chunk_ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:160:27:    got void [noderef] __user *
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:160:27: warning: incorrect type in assignment (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:161:49:    expected void const [noderef] __user *from
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:161:49:    got struct drm_amdgpu_cs_chunk [noderef] __user **chunk_ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:161:49: warning: incorrect type in argument 2 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:1624:21:    expected struct drm_amdgpu_fence *fences_user
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:1624:21:    got void [noderef] __user *
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:1624:21: warning: incorrect type in assignment (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:1625:36:    expected void const [noderef] __user *from
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:1625:36:    got struct drm_amdgpu_fence *fences_user
+drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c:1625:36: warning: incorrect type in argument 2 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1364:25: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1364:25:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1364:25:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1365:17: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1365:17:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1365:17:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1424:17: error: incompatible types in comparison expression (different address spaces):
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1424:17:    struct dma_fence *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:1424:17:    struct dma_fence [noderef] __rcu *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:143:17:    expected restricted __poll_t ( *poll )( ... )
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:143:17:    got unsigned int ( * )( ... )
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:143:17: warning: incorrect type in initializer (different base types)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:266:29: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:268:29: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:359:21: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:417:21: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:478:21: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:536:21: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:597:21: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:655:21: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21:    expected void const volatile [noderef] __user *ptr
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21:    got unsigned int [usertype] *
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21: warning: cast removes address space '__user' of expression
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21: warning: incorrect type in argument 1 (different address spaces)
+drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c:752:21: warning: too many warnings
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1697:65: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1705:55: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1706:50: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1707:50: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1708:56: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1710:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1711:45: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1712:51: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1713:55: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1714:57: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1716:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1717:53: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1719:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1721:25: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1722:46: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1726:73: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1728:33: warning: cast to restricted __le32
+drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:1730:33: warning: cast to restricted __l


_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 1/7] drm/i915: Fix DP link training pattern mask
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 1/7] drm/i915: Fix DP link training pattern mask Imre Deak
@ 2020-09-22 13:13   ` Ville Syrjälä
  2020-09-22 14:41     ` Imre Deak
  0 siblings, 1 reply; 27+ messages in thread
From: Ville Syrjälä @ 2020-09-22 13:13 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 03:51:00PM +0300, Imre Deak wrote:
> An LTTPR can be trained with training pattern 4 even if the DPCD
> revision is < 1.4, but drm_dp_training_pattern_mask() would change
> pattern 4 to pattern 3 on those DPCD revisions.
> 
> Since intel_dp_training_pattern() makes already sure that the proper
> training pattern is used, all that needs to be masked out is the
> scrambling disable flag, which is or'd to the mask later based on the
> training pattern.
> 
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_ddi.c              |  3 +--
>  drivers/gpu/drm/i915/display/intel_dp.c               | 10 +++++-----
>  drivers/gpu/drm/i915/display/intel_dp_link_training.c |  2 +-
>  3 files changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> index 4d06178cd76c..946a3b6f2d10 100644
> --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> @@ -4158,13 +4158,12 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
>  				     u8 dp_train_pat)
>  {
>  	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
>  	u32 temp;
>  
>  	temp = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
>  
>  	temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
> -	switch (dp_train_pat & train_pat_mask) {
> +	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {

Maybe introduce a helper to do the masking for us?

Anyways
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

>  	case DP_TRAINING_PATTERN_DISABLE:
>  		temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
>  		break;
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index bf1e9cf1c0f3..2a4a9c0e7427 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -3778,7 +3778,7 @@ cpt_set_link_train(struct intel_dp *intel_dp,
>  
>  	*DP &= ~DP_LINK_TRAIN_MASK_CPT;
>  
> -	switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
> +	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {
>  	case DP_TRAINING_PATTERN_DISABLE:
>  		*DP |= DP_LINK_TRAIN_OFF_CPT;
>  		break;
> @@ -3808,7 +3808,7 @@ g4x_set_link_train(struct intel_dp *intel_dp,
>  
>  	*DP &= ~DP_LINK_TRAIN_MASK;
>  
> -	switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
> +	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {
>  	case DP_TRAINING_PATTERN_DISABLE:
>  		*DP |= DP_LINK_TRAIN_OFF;
>  		break;
> @@ -4498,12 +4498,12 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
>  				       u8 dp_train_pat)
>  {
>  	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> -	u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
>  
> -	if (dp_train_pat & train_pat_mask)
> +	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) !=
> +	    DP_TRAINING_PATTERN_DISABLE)
>  		drm_dbg_kms(&dev_priv->drm,
>  			    "Using DP training pattern TPS%d\n",
> -			    dp_train_pat & train_pat_mask);
> +			    dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE);
>  
>  	intel_dp->set_link_train(intel_dp, dp_train_pat);
>  }
> 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 f2c8b56be9ea..f8b53c5b5777 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> @@ -96,7 +96,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
>  	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
>  
>  	buf[0] = dp_train_pat;
> -	if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
> +	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
>  	    DP_TRAINING_PATTERN_DISABLE) {
>  		/* don't write DP_TRAINING_LANEx_SET on disable */
>  		len = 1;
> -- 
> 2.17.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 2/7] drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 2/7] drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c Imre Deak
@ 2020-09-22 13:14   ` Ville Syrjälä
  2020-09-22 14:45     ` Imre Deak
  0 siblings, 1 reply; 27+ messages in thread
From: Ville Syrjälä @ 2020-09-22 13:14 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 03:51:01PM +0300, Imre Deak wrote:
> The link status is used to communicate the parameters of the link
> training with the DPRX and determine if the link training is successful
> or a retraining is needed. Accordingly move the function to read the
> link status to intel_dp_link_training.c
> 
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
>  drivers/gpu/drm/i915/display/intel_dp.c          | 11 -----------
>  drivers/gpu/drm/i915/display/intel_dp.h          |  2 --
>  .../drm/i915/display/intel_dp_link_training.c    | 16 ++++++++++++++++
>  .../drm/i915/display/intel_dp_link_training.h    |  3 +++
>  4 files changed, 19 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index 2a4a9c0e7427..ee93a00a4d5e 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -4126,17 +4126,6 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state,
>  	chv_phy_post_pll_disable(encoder, old_crtc_state);
>  }
>  
> -/*
> - * Fetch AUX CH registers 0x202 - 0x207 which contain
> - * link status information
> - */
> -bool
> -intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
> -{
> -	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
> -				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
> -}
> -
>  static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp)
>  {
>  	return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
> index 08a1c0aa8b94..34ae7988a554 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> @@ -100,8 +100,6 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
>  			   u8 *link_bw, u8 *rate_select);
>  bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
>  bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
> -bool
> -intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
>  
>  bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
>  int intel_dp_link_required(int pixel_clock, int bpp);
> 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 f8b53c5b5777..6d13d00db5e6 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> @@ -34,6 +34,22 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
>  		      link_status[3], link_status[4], link_status[5]);
>  }
>  
> +/**
> + * intel_dp_get_link_status - get the link status information for the DPRX
> + * @intel_dp: DP struct
> + * @link_status: buffer to return the status in
> + *
> + * Fetch the AUX DPCD registers for the DPRX link status.
> + *
> + * Returns true if the information was read successfully, false otherwise.
> + */
> +bool
> +intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
> +{
> +	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
> +				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
> +}
> +
>  static u8 dp_voltage_max(u8 preemph)
>  {
>  	switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> index 01f1dabbb060..47c97f4a0d57 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> @@ -10,6 +10,9 @@
>  
>  struct intel_dp;
>  
> +bool intel_dp_get_link_status(struct intel_dp *intel_dp,
> +			      u8 link_status[DP_LINK_STATUS_SIZE]);
> +

Do we still need it outside? Hmm, I guess we do.

Oh well
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

>  void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
>  			       const u8 link_status[DP_LINK_STATUS_SIZE]);
>  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> -- 
> 2.17.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Intel-gfx] ✓ Fi.CI.BAT: success for drm/i915: Add support for LTTPR non-transparent link training mode
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
                   ` (8 preceding siblings ...)
  2020-09-22 13:01 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
@ 2020-09-22 13:17 ` Patchwork
  2020-09-22 15:17 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork
  10 siblings, 0 replies; 27+ messages in thread
From: Patchwork @ 2020-09-22 13:17 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 4340 bytes --]

== Series Details ==

Series: drm/i915: Add support for LTTPR non-transparent link training mode
URL   : https://patchwork.freedesktop.org/series/81968/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_9033 -> Patchwork_18544
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/index.html

Known issues
------------

  Here are the changes found in Patchwork_18544 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@kms_chamelium@dp-crc-fast:
    - fi-kbl-7500u:       [PASS][1] -> [DMESG-WARN][2] ([i915#165])
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/fi-kbl-7500u/igt@kms_chamelium@dp-crc-fast.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/fi-kbl-7500u/igt@kms_chamelium@dp-crc-fast.html

  
#### Possible fixes ####

  * igt@i915_pm_rpm@basic-pci-d3-state:
    - fi-bsw-kefka:       [DMESG-WARN][3] ([i915#1982]) -> [PASS][4]
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/fi-bsw-kefka/igt@i915_pm_rpm@basic-pci-d3-state.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/fi-bsw-kefka/igt@i915_pm_rpm@basic-pci-d3-state.html

  * igt@i915_pm_rpm@module-reload:
    - fi-kbl-x1275:       [DMESG-FAIL][5] ([i915#62] / [i915#95]) -> [PASS][6]
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/fi-kbl-x1275/igt@i915_pm_rpm@module-reload.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/fi-kbl-x1275/igt@i915_pm_rpm@module-reload.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor-atomic:
    - fi-icl-u2:          [DMESG-WARN][7] ([i915#1982]) -> [PASS][8]
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/fi-icl-u2/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-atomic.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/fi-icl-u2/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-atomic.html

  * igt@kms_flip@basic-flip-vs-modeset@b-dp1:
    - fi-kbl-x1275:       [DMESG-WARN][9] ([i915#62] / [i915#92]) -> [PASS][10] +30 similar issues
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/fi-kbl-x1275/igt@kms_flip@basic-flip-vs-modeset@b-dp1.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/fi-kbl-x1275/igt@kms_flip@basic-flip-vs-modeset@b-dp1.html

  * igt@kms_force_connector_basic@prune-stale-modes:
    - fi-kbl-x1275:       [DMESG-WARN][11] ([i915#62] / [i915#92] / [i915#95]) -> [PASS][12] +12 similar issues
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/fi-kbl-x1275/igt@kms_force_connector_basic@prune-stale-modes.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/fi-kbl-x1275/igt@kms_force_connector_basic@prune-stale-modes.html

  
  [i915#165]: https://gitlab.freedesktop.org/drm/intel/issues/165
  [i915#1982]: https://gitlab.freedesktop.org/drm/intel/issues/1982
  [i915#62]: https://gitlab.freedesktop.org/drm/intel/issues/62
  [i915#92]: https://gitlab.freedesktop.org/drm/intel/issues/92
  [i915#95]: https://gitlab.freedesktop.org/drm/intel/issues/95


Participating hosts (43 -> 37)
------------------------------

  Missing    (6): fi-kbl-soraka fi-ilk-m540 fi-byt-squawks fi-bsw-cyan fi-byt-clapper fi-bdw-samus 


Build changes
-------------

  * Linux: CI_DRM_9033 -> Patchwork_18544

  CI-20190529: 20190529
  CI_DRM_9033: afeb3835029ad70d17802a9c7148a8372fb08479 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_5787: 0ec962017c8131de14e0cb038f7f76b1f17ed637 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_18544: 91260e606734a4fc95f326bb4eb13f45f8793794 @ git://anongit.freedesktop.org/gfx-ci/linux


== Linux commits ==

91260e606734 drm/i915: Switch to LTTPR non-transparent mode link training
4fbcfbcb1a33 drm/i915: Switch to LTTPR transparent mode link training
6a20187d3dfa drm/dp: Add LTTPR helpers
0b95955d4877 drm/i915: Factor out a helper to disable the DPCD training pattern
b7d02e6b76cc drm/i915: Simplify the link training functions
b688f7336e26 drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c
154fc7783917 drm/i915: Fix DP link training pattern mask

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/index.html

[-- Attachment #1.2: Type: text/html, Size: 5440 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions Imre Deak
@ 2020-09-22 13:27   ` Ville Syrjälä
  2020-09-22 15:30     ` Imre Deak
  0 siblings, 1 reply; 27+ messages in thread
From: Ville Syrjälä @ 2020-09-22 13:27 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 03:51:02PM +0300, Imre Deak wrote:
> Split the prepare, link training, fallback-handling steps into their own
> functions for clarity and as a preparation for the upcoming LTTPR changes.
> 
> While at it also add some documentation to exported functions.
> 
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
>  .../drm/i915/display/intel_dp_link_training.c | 80 ++++++++++++++-----
>  1 file changed, 62 insertions(+), 18 deletions(-)
> 
> 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 6d13d00db5e6..0c3809891bd2 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> @@ -162,14 +162,13 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
>  	return true;
>  }
>  
> -/* Enable corresponding port and start training pattern 1 */
> -static bool
> -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> +/*
> + * Prepare link training by configuring the link parameters and enabling the
> + * corresponding port.
> + */
> +static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
>  {
>  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> -	u8 voltage;
> -	int voltage_tries, cr_tries, max_cr_tries;
> -	bool max_vswing_reached = false;
>  	u8 link_config[2];
>  	u8 link_bw, rate_select;
>  
> @@ -203,6 +202,16 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>  	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
>  
>  	intel_dp->DP |= DP_PORT_EN;

I guess we no longer actually enable the port here? The comment ^ still says
we do.

Hmm. Seems we do enable the port on ddi platforms, but not on older
platforms. I guess the docs could still use a tweak to reflect
reality a bit better.

> +}
> +
> +/* Perform the link training clock recovery phase using training pattern 1. */
> +static bool
> +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> +{
> +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> +	u8 voltage;
> +	int voltage_tries, cr_tries, max_cr_tries;
> +	bool max_vswing_reached = false;
>  
>  	/* clock recovery */
>  	if (!intel_dp_reset_link_train(intel_dp,
> @@ -325,6 +334,10 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
>  	return DP_TRAINING_PATTERN_2;
>  }
>  
> +/*
> + * Perform the link training channel equalization phase using one of training
> + * pattern 2, 3 or 4 depending on the the source and sink capabilities.
> + */
>  static bool
>  intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  {
> @@ -395,6 +408,15 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  
>  }
>  
> +/**
> + * intel_dp_stop_link_train - stop link training
> + * @intel_dp: DP struct
> + *
> + * Stop the link training of the @intel_dp port, programming the port to
> + * output an idle pattern 

I don't think we use the idle pattern on all platforms.

BTW intel_dp_set_idle_link_train() looks pretty pointless. Could just
inline it into its only caller, or at least move it into
intel_dp_link_training.c.

Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> on the link and  disabling the training pattern in
> + * the sink's DPCD.
> + * This function must be called after intel_dp_start_link_train().
> + */
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>  {
>  	intel_dp->link_trained = true;
> @@ -403,30 +425,37 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
>  
> -void
> -intel_dp_start_link_train(struct intel_dp *intel_dp)
> +static bool
> +intel_dp_link_train(struct intel_dp *intel_dp)
>  {
>  	struct intel_connector *intel_connector = intel_dp->attached_connector;
> +	bool ret = false;
> +
> +	intel_dp_prepare_link_train(intel_dp);
>  
>  	if (!intel_dp_link_training_clock_recovery(intel_dp))
> -		goto failure_handling;
> +		goto out;
> +
>  	if (!intel_dp_link_training_channel_equalization(intel_dp))
> -		goto failure_handling;
> +		goto out;
>  
> -	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> -		    "[CONNECTOR:%d:%s] Link Training Passed at Link Rate = %d, Lane count = %d",
> -		    intel_connector->base.base.id,
> -		    intel_connector->base.name,
> -		    intel_dp->link_rate, intel_dp->lane_count);
> -	return;
> +	ret = true;
>  
> - failure_handling:
> +out:
>  	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> -		    "[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
> +		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d",
>  		    intel_connector->base.base.id,
>  		    intel_connector->base.name,
> +		    ret ? "passed" : "failed",
>  		    intel_dp->link_rate, intel_dp->lane_count);
>  
> +	return ret;
> +}
> +
> +static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp)
> +{
> +	struct intel_connector *intel_connector = intel_dp->attached_connector;
> +
>  	if (intel_dp->hobl_active) {
>  		drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
>  			    "Link Training failed with HOBL active, not enabling it from now on");
> @@ -440,3 +469,18 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
>  	/* Schedule a Hotplug Uevent to userspace to start modeset */
>  	schedule_work(&intel_connector->modeset_retry_work);
>  }
> +
> +/**
> + * intel_dp_start_link_train - start link training
> + * @intel_dp: DP struct
> + *
> + * Start the link training of the @intel_dp port, scheduling a fallback
> + * retraining with reduced link rate/lane parameters if the link training
> + * fails.
> + * After calling this function intel_dp_stop_link_train() must be called.
> + */
> +void intel_dp_start_link_train(struct intel_dp *intel_dp)
> +{
> +	if (!intel_dp_link_train(intel_dp))
> +		intel_dp_schedule_fallback_link_training(intel_dp);
> +}
> -- 
> 2.17.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 1/7] drm/i915: Fix DP link training pattern mask
  2020-09-22 13:13   ` Ville Syrjälä
@ 2020-09-22 14:41     ` Imre Deak
  0 siblings, 0 replies; 27+ messages in thread
From: Imre Deak @ 2020-09-22 14:41 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 04:13:23PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 22, 2020 at 03:51:00PM +0300, Imre Deak wrote:
> > An LTTPR can be trained with training pattern 4 even if the DPCD
> > revision is < 1.4, but drm_dp_training_pattern_mask() would change
> > pattern 4 to pattern 3 on those DPCD revisions.
> > 
> > Since intel_dp_training_pattern() makes already sure that the proper
> > training pattern is used, all that needs to be masked out is the
> > scrambling disable flag, which is or'd to the mask later based on the
> > training pattern.
> > 
> > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_ddi.c              |  3 +--
> >  drivers/gpu/drm/i915/display/intel_dp.c               | 10 +++++-----
> >  drivers/gpu/drm/i915/display/intel_dp_link_training.c |  2 +-
> >  3 files changed, 7 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
> > index 4d06178cd76c..946a3b6f2d10 100644
> > --- a/drivers/gpu/drm/i915/display/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/display/intel_ddi.c
> > @@ -4158,13 +4158,12 @@ static void intel_ddi_set_link_train(struct intel_dp *intel_dp,
> >  				     u8 dp_train_pat)
> >  {
> >  	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> > -	u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
> >  	u32 temp;
> >  
> >  	temp = intel_de_read(dev_priv, intel_dp->regs.dp_tp_ctl);
> >  
> >  	temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;
> > -	switch (dp_train_pat & train_pat_mask) {
> > +	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {
> 
> Maybe introduce a helper to do the masking for us?

Ok, will add intel_dp_training_pattern_symbol().

> 
> Anyways
> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> >  	case DP_TRAINING_PATTERN_DISABLE:
> >  		temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;
> >  		break;
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> > index bf1e9cf1c0f3..2a4a9c0e7427 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> > @@ -3778,7 +3778,7 @@ cpt_set_link_train(struct intel_dp *intel_dp,
> >  
> >  	*DP &= ~DP_LINK_TRAIN_MASK_CPT;
> >  
> > -	switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
> > +	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {
> >  	case DP_TRAINING_PATTERN_DISABLE:
> >  		*DP |= DP_LINK_TRAIN_OFF_CPT;
> >  		break;
> > @@ -3808,7 +3808,7 @@ g4x_set_link_train(struct intel_dp *intel_dp,
> >  
> >  	*DP &= ~DP_LINK_TRAIN_MASK;
> >  
> > -	switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
> > +	switch (dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) {
> >  	case DP_TRAINING_PATTERN_DISABLE:
> >  		*DP |= DP_LINK_TRAIN_OFF;
> >  		break;
> > @@ -4498,12 +4498,12 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
> >  				       u8 dp_train_pat)
> >  {
> >  	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
> > -	u8 train_pat_mask = drm_dp_training_pattern_mask(intel_dp->dpcd);
> >  
> > -	if (dp_train_pat & train_pat_mask)
> > +	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) !=
> > +	    DP_TRAINING_PATTERN_DISABLE)
> >  		drm_dbg_kms(&dev_priv->drm,
> >  			    "Using DP training pattern TPS%d\n",
> > -			    dp_train_pat & train_pat_mask);
> > +			    dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE);
> >  
> >  	intel_dp->set_link_train(intel_dp, dp_train_pat);
> >  }
> > 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 f2c8b56be9ea..f8b53c5b5777 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > @@ -96,7 +96,7 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
> >  	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
> >  
> >  	buf[0] = dp_train_pat;
> > -	if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
> > +	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
> >  	    DP_TRAINING_PATTERN_DISABLE) {
> >  		/* don't write DP_TRAINING_LANEx_SET on disable */
> >  		len = 1;
> > -- 
> > 2.17.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 2/7] drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c
  2020-09-22 13:14   ` Ville Syrjälä
@ 2020-09-22 14:45     ` Imre Deak
  0 siblings, 0 replies; 27+ messages in thread
From: Imre Deak @ 2020-09-22 14:45 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 04:14:24PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 22, 2020 at 03:51:01PM +0300, Imre Deak wrote:
> > The link status is used to communicate the parameters of the link
> > training with the DPRX and determine if the link training is successful
> > or a retraining is needed. Accordingly move the function to read the
> > link status to intel_dp_link_training.c
> > 
> > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > ---
> >  drivers/gpu/drm/i915/display/intel_dp.c          | 11 -----------
> >  drivers/gpu/drm/i915/display/intel_dp.h          |  2 --
> >  .../drm/i915/display/intel_dp_link_training.c    | 16 ++++++++++++++++
> >  .../drm/i915/display/intel_dp_link_training.h    |  3 +++
> >  4 files changed, 19 insertions(+), 13 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> > index 2a4a9c0e7427..ee93a00a4d5e 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> > @@ -4126,17 +4126,6 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state,
> >  	chv_phy_post_pll_disable(encoder, old_crtc_state);
> >  }
> >  
> > -/*
> > - * Fetch AUX CH registers 0x202 - 0x207 which contain
> > - * link status information
> > - */
> > -bool
> > -intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
> > -{
> > -	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
> > -				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
> > -}
> > -
> >  static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp)
> >  {
> >  	return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
> > index 08a1c0aa8b94..34ae7988a554 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp.h
> > +++ b/drivers/gpu/drm/i915/display/intel_dp.h
> > @@ -100,8 +100,6 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
> >  			   u8 *link_bw, u8 *rate_select);
> >  bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
> >  bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
> > -bool
> > -intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
> >  
> >  bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
> >  int intel_dp_link_required(int pixel_clock, int bpp);
> > 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 f8b53c5b5777..6d13d00db5e6 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > @@ -34,6 +34,22 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
> >  		      link_status[3], link_status[4], link_status[5]);
> >  }
> >  
> > +/**
> > + * intel_dp_get_link_status - get the link status information for the DPRX
> > + * @intel_dp: DP struct
> > + * @link_status: buffer to return the status in
> > + *
> > + * Fetch the AUX DPCD registers for the DPRX link status.
> > + *
> > + * Returns true if the information was read successfully, false otherwise.
> > + */
> > +bool
> > +intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
> > +{
> > +	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
> > +				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
> > +}
> > +
> >  static u8 dp_voltage_max(u8 preemph)
> >  {
> >  	switch (preemph & DP_TRAIN_PRE_EMPHASIS_MASK) {
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> > index 01f1dabbb060..47c97f4a0d57 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> > @@ -10,6 +10,9 @@
> >  
> >  struct intel_dp;
> >  
> > +bool intel_dp_get_link_status(struct intel_dp *intel_dp,
> > +			      u8 link_status[DP_LINK_STATUS_SIZE]);
> > +
> 
> Do we still need it outside? Hmm, I guess we do.

Yes, for PHY auto-testing, but I think that should rather depend on the
regular link training sequence as discussed elsewhere.

> 
> Oh well
> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> >  void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> >  			       const u8 link_status[DP_LINK_STATUS_SIZE]);
> >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > -- 
> > 2.17.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Intel-gfx] ✗ Fi.CI.IGT: failure for drm/i915: Add support for LTTPR non-transparent link training mode
  2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
                   ` (9 preceding siblings ...)
  2020-09-22 13:17 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
@ 2020-09-22 15:17 ` Patchwork
  10 siblings, 0 replies; 27+ messages in thread
From: Patchwork @ 2020-09-22 15:17 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx


[-- Attachment #1.1: Type: text/plain, Size: 14672 bytes --]

== Series Details ==

Series: drm/i915: Add support for LTTPR non-transparent link training mode
URL   : https://patchwork.freedesktop.org/series/81968/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_9033_full -> Patchwork_18544_full
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with Patchwork_18544_full absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_18544_full, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in Patchwork_18544_full:

### IGT changes ###

#### Possible regressions ####

  * igt@kms_flip@2x-nonexisting-fb-interruptible@ac-vga1-hdmi-a1:
    - shard-hsw:          [PASS][1] -> [INCOMPLETE][2] +1 similar issue
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-hsw4/igt@kms_flip@2x-nonexisting-fb-interruptible@ac-vga1-hdmi-a1.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-hsw7/igt@kms_flip@2x-nonexisting-fb-interruptible@ac-vga1-hdmi-a1.html

  
Known issues
------------

  Here are the changes found in Patchwork_18544_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_ctx_persistence@legacy-engines-mixed-process@blt:
    - shard-skl:          [PASS][3] -> [FAIL][4] ([i915#2374])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl4/igt@gem_ctx_persistence@legacy-engines-mixed-process@blt.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl1/igt@gem_ctx_persistence@legacy-engines-mixed-process@blt.html

  * igt@gem_eio@kms:
    - shard-skl:          [PASS][5] -> [DMESG-WARN][6] ([i915#1982]) +7 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl2/igt@gem_eio@kms.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl2/igt@gem_eio@kms.html

  * igt@gem_exec_whisper@basic-queues-priority:
    - shard-glk:          [PASS][7] -> [DMESG-WARN][8] ([i915#118] / [i915#95])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-glk5/igt@gem_exec_whisper@basic-queues-priority.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-glk7/igt@gem_exec_whisper@basic-queues-priority.html

  * igt@gen9_exec_parse@allowed-all:
    - shard-kbl:          [PASS][9] -> [DMESG-WARN][10] ([i915#1436] / [i915#716])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-kbl7/igt@gen9_exec_parse@allowed-all.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-kbl7/igt@gen9_exec_parse@allowed-all.html

  * igt@gen9_exec_parse@allowed-single:
    - shard-skl:          [PASS][11] -> [DMESG-WARN][12] ([i915#1436] / [i915#716])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl1/igt@gen9_exec_parse@allowed-single.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl5/igt@gen9_exec_parse@allowed-single.html

  * igt@i915_pm_dc@dc5-dpms:
    - shard-skl:          [PASS][13] -> [INCOMPLETE][14] ([i915#198])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl4/igt@i915_pm_dc@dc5-dpms.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl1/igt@i915_pm_dc@dc5-dpms.html

  * igt@i915_pm_rc6_residency@rc6-fence:
    - shard-hsw:          [PASS][15] -> [WARN][16] ([i915#1519])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-hsw7/igt@i915_pm_rc6_residency@rc6-fence.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-hsw6/igt@i915_pm_rc6_residency@rc6-fence.html

  * igt@kms_cursor_legacy@flip-vs-cursor-legacy:
    - shard-skl:          [PASS][17] -> [FAIL][18] ([i915#2346])
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl3/igt@kms_cursor_legacy@flip-vs-cursor-legacy.html
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl3/igt@kms_cursor_legacy@flip-vs-cursor-legacy.html

  * igt@kms_draw_crc@draw-method-rgb565-pwrite-untiled:
    - shard-skl:          [PASS][19] -> [FAIL][20] ([i915#177] / [i915#52] / [i915#54])
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl7/igt@kms_draw_crc@draw-method-rgb565-pwrite-untiled.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl7/igt@kms_draw_crc@draw-method-rgb565-pwrite-untiled.html

  * igt@kms_flip@flip-vs-expired-vblank-interruptible@b-hdmi-a1:
    - shard-glk:          [PASS][21] -> [FAIL][22] ([i915#2122])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-glk1/igt@kms_flip@flip-vs-expired-vblank-interruptible@b-hdmi-a1.html
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-glk3/igt@kms_flip@flip-vs-expired-vblank-interruptible@b-hdmi-a1.html

  * igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-render:
    - shard-iclb:         [PASS][23] -> [DMESG-WARN][24] ([i915#1982])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-iclb3/igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-render.html
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-iclb3/igt@kms_frontbuffer_tracking@fbc-1p-offscren-pri-shrfb-draw-render.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-rte:
    - shard-tglb:         [PASS][25] -> [DMESG-WARN][26] ([i915#1982]) +4 similar issues
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-tglb3/igt@kms_frontbuffer_tracking@fbcpsr-1p-rte.html
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-tglb7/igt@kms_frontbuffer_tracking@fbcpsr-1p-rte.html

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-mmap-wc:
    - shard-skl:          [PASS][27] -> [FAIL][28] ([i915#49])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl7/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-mmap-wc.html
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl7/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-indfb-draw-mmap-wc.html

  * igt@kms_plane_alpha_blend@pipe-a-coverage-7efc:
    - shard-skl:          [PASS][29] -> [FAIL][30] ([fdo#108145] / [i915#265])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl7/igt@kms_plane_alpha_blend@pipe-a-coverage-7efc.html
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl7/igt@kms_plane_alpha_blend@pipe-a-coverage-7efc.html

  * igt@kms_psr@psr2_primary_mmap_cpu:
    - shard-iclb:         [PASS][31] -> [SKIP][32] ([fdo#109441]) +2 similar issues
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-iclb2/igt@kms_psr@psr2_primary_mmap_cpu.html
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-iclb6/igt@kms_psr@psr2_primary_mmap_cpu.html

  * igt@perf@polling-small-buf:
    - shard-iclb:         [PASS][33] -> [FAIL][34] ([i915#1722])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-iclb5/igt@perf@polling-small-buf.html
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-iclb3/igt@perf@polling-small-buf.html

  
#### Possible fixes ####

  * igt@drm_import_export@prime:
    - shard-tglb:         [INCOMPLETE][35] ([i915#750]) -> [PASS][36]
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-tglb2/igt@drm_import_export@prime.html
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-tglb7/igt@drm_import_export@prime.html

  * igt@gem_userptr_blits@sync-unmap-cycles:
    - shard-skl:          [TIMEOUT][37] ([i915#1958] / [i915#2424]) -> [PASS][38]
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl10/igt@gem_userptr_blits@sync-unmap-cycles.html
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl9/igt@gem_userptr_blits@sync-unmap-cycles.html

  * igt@i915_selftest@mock@requests:
    - shard-apl:          [INCOMPLETE][39] ([i915#1635] / [i915#2278]) -> [PASS][40]
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-apl6/igt@i915_selftest@mock@requests.html
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-apl7/igt@i915_selftest@mock@requests.html

  * igt@kms_cursor_crc@pipe-c-cursor-suspend:
    - shard-kbl:          [DMESG-WARN][41] ([i915#180]) -> [PASS][42] +3 similar issues
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-kbl6/igt@kms_cursor_crc@pipe-c-cursor-suspend.html
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-kbl7/igt@kms_cursor_crc@pipe-c-cursor-suspend.html

  * igt@kms_cursor_legacy@2x-long-flip-vs-cursor-legacy:
    - shard-glk:          [FAIL][43] ([i915#72]) -> [PASS][44]
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-glk3/igt@kms_cursor_legacy@2x-long-flip-vs-cursor-legacy.html
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-glk3/igt@kms_cursor_legacy@2x-long-flip-vs-cursor-legacy.html

  * igt@kms_flip@2x-dpms-vs-vblank-race@ab-vga1-hdmi-a1:
    - shard-hsw:          [DMESG-WARN][45] ([i915#1982]) -> [PASS][46]
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-hsw6/igt@kms_flip@2x-dpms-vs-vblank-race@ab-vga1-hdmi-a1.html
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-hsw2/igt@kms_flip@2x-dpms-vs-vblank-race@ab-vga1-hdmi-a1.html

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-render:
    - shard-tglb:         [DMESG-WARN][47] ([i915#1982]) -> [PASS][48] +2 similar issues
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-tglb8/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-render.html
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-tglb5/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-render.html

  * igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
    - shard-hsw:          [INCOMPLETE][49] -> [PASS][50]
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-hsw4/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-hsw4/igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a.html

  * igt@kms_plane@plane-panning-bottom-right-pipe-b-planes:
    - shard-skl:          [DMESG-WARN][51] ([i915#1982]) -> [PASS][52] +2 similar issues
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl7/igt@kms_plane@plane-panning-bottom-right-pipe-b-planes.html
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl6/igt@kms_plane@plane-panning-bottom-right-pipe-b-planes.html

  * igt@kms_psr@psr2_sprite_plane_onoff:
    - shard-iclb:         [SKIP][53] ([fdo#109441]) -> [PASS][54]
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-iclb5/igt@kms_psr@psr2_sprite_plane_onoff.html
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-iclb2/igt@kms_psr@psr2_sprite_plane_onoff.html

  * igt@perf@blocking:
    - shard-iclb:         [DMESG-WARN][55] ([i915#1982]) -> [PASS][56]
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-iclb2/igt@perf@blocking.html
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-iclb5/igt@perf@blocking.html

  * igt@prime_vgem@sync@bcs0:
    - shard-tglb:         [INCOMPLETE][57] ([i915#409]) -> [PASS][58]
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-tglb8/igt@prime_vgem@sync@bcs0.html
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-tglb5/igt@prime_vgem@sync@bcs0.html

  
#### Warnings ####

  * igt@kms_flip@flip-vs-expired-vblank-interruptible@a-edp1:
    - shard-skl:          [DMESG-FAIL][59] ([i915#1982]) -> [DMESG-WARN][60] ([i915#1982]) +1 similar issue
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_9033/shard-skl3/igt@kms_flip@flip-vs-expired-vblank-interruptible@a-edp1.html
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/shard-skl3/igt@kms_flip@flip-vs-expired-vblank-interruptible@a-edp1.html

  
  [fdo#108145]: https://bugs.freedesktop.org/show_bug.cgi?id=108145
  [fdo#109441]: https://bugs.freedesktop.org/show_bug.cgi?id=109441
  [i915#118]: https://gitlab.freedesktop.org/drm/intel/issues/118
  [i915#1436]: https://gitlab.freedesktop.org/drm/intel/issues/1436
  [i915#1519]: https://gitlab.freedesktop.org/drm/intel/issues/1519
  [i915#1635]: https://gitlab.freedesktop.org/drm/intel/issues/1635
  [i915#1722]: https://gitlab.freedesktop.org/drm/intel/issues/1722
  [i915#177]: https://gitlab.freedesktop.org/drm/intel/issues/177
  [i915#180]: https://gitlab.freedesktop.org/drm/intel/issues/180
  [i915#1958]: https://gitlab.freedesktop.org/drm/intel/issues/1958
  [i915#198]: https://gitlab.freedesktop.org/drm/intel/issues/198
  [i915#1982]: https://gitlab.freedesktop.org/drm/intel/issues/1982
  [i915#2122]: https://gitlab.freedesktop.org/drm/intel/issues/2122
  [i915#2278]: https://gitlab.freedesktop.org/drm/intel/issues/2278
  [i915#2346]: https://gitlab.freedesktop.org/drm/intel/issues/2346
  [i915#2374]: https://gitlab.freedesktop.org/drm/intel/issues/2374
  [i915#2424]: https://gitlab.freedesktop.org/drm/intel/issues/2424
  [i915#265]: https://gitlab.freedesktop.org/drm/intel/issues/265
  [i915#409]: https://gitlab.freedesktop.org/drm/intel/issues/409
  [i915#49]: https://gitlab.freedesktop.org/drm/intel/issues/49
  [i915#52]: https://gitlab.freedesktop.org/drm/intel/issues/52
  [i915#54]: https://gitlab.freedesktop.org/drm/intel/issues/54
  [i915#716]: https://gitlab.freedesktop.org/drm/intel/issues/716
  [i915#72]: https://gitlab.freedesktop.org/drm/intel/issues/72
  [i915#750]: https://gitlab.freedesktop.org/drm/intel/issues/750
  [i915#95]: https://gitlab.freedesktop.org/drm/intel/issues/95


Participating hosts (11 -> 11)
------------------------------

  No changes in participating hosts


Build changes
-------------

  * Linux: CI_DRM_9033 -> Patchwork_18544

  CI-20190529: 20190529
  CI_DRM_9033: afeb3835029ad70d17802a9c7148a8372fb08479 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_5787: 0ec962017c8131de14e0cb038f7f76b1f17ed637 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_18544: 91260e606734a4fc95f326bb4eb13f45f8793794 @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_18544/index.html

[-- Attachment #1.2: Type: text/html, Size: 16752 bytes --]

[-- Attachment #2: Type: text/plain, Size: 160 bytes --]

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions
  2020-09-22 13:27   ` Ville Syrjälä
@ 2020-09-22 15:30     ` Imre Deak
  2020-09-22 16:49       ` Ville Syrjälä
  0 siblings, 1 reply; 27+ messages in thread
From: Imre Deak @ 2020-09-22 15:30 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 04:27:05PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 22, 2020 at 03:51:02PM +0300, Imre Deak wrote:
> > Split the prepare, link training, fallback-handling steps into their own
> > functions for clarity and as a preparation for the upcoming LTTPR changes.
> > 
> > While at it also add some documentation to exported functions.
> > 
> > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > ---
> >  .../drm/i915/display/intel_dp_link_training.c | 80 ++++++++++++++-----
> >  1 file changed, 62 insertions(+), 18 deletions(-)
> > 
> > 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 6d13d00db5e6..0c3809891bd2 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > @@ -162,14 +162,13 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
> >  	return true;
> >  }
> >  
> > -/* Enable corresponding port and start training pattern 1 */
> > -static bool
> > -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > +/*
> > + * Prepare link training by configuring the link parameters and enabling the
> > + * corresponding port.
> > + */
> > +static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
> >  {
> >  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > -	u8 voltage;
> > -	int voltage_tries, cr_tries, max_cr_tries;
> > -	bool max_vswing_reached = false;
> >  	u8 link_config[2];
> >  	u8 link_bw, rate_select;
> >  
> > @@ -203,6 +202,16 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> >  	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
> >  
> >  	intel_dp->DP |= DP_PORT_EN;
> 
> I guess we no longer actually enable the port here? The comment ^ still says
> we do.
> 
> Hmm. Seems we do enable the port on ddi platforms, but not on older
> platforms. I guess the docs could still use a tweak to reflect
> reality a bit better.

Yes, missed the old platform part, will update the comment.

> 
> > +}
> > +
> > +/* Perform the link training clock recovery phase using training pattern 1. */
> > +static bool
> > +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > +{
> > +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > +	u8 voltage;
> > +	int voltage_tries, cr_tries, max_cr_tries;
> > +	bool max_vswing_reached = false;
> >  
> >  	/* clock recovery */
> >  	if (!intel_dp_reset_link_train(intel_dp,
> > @@ -325,6 +334,10 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> >  	return DP_TRAINING_PATTERN_2;
> >  }
> >  
> > +/*
> > + * Perform the link training channel equalization phase using one of training
> > + * pattern 2, 3 or 4 depending on the the source and sink capabilities.
> > + */
> >  static bool
> >  intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  {
> > @@ -395,6 +408,15 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  
> >  }
> >  
> > +/**
> > + * intel_dp_stop_link_train - stop link training
> > + * @intel_dp: DP struct
> > + *
> > + * Stop the link training of the @intel_dp port, programming the port to
> > + * output an idle pattern 
> 
> I don't think we use the idle pattern on all platforms.

Yes, just DDI, this also needs a doc update.

> BTW intel_dp_set_idle_link_train() looks pretty pointless. Could just
> inline it into its only caller, or at least move it into
> intel_dp_link_training.c.

Ok, can unexport/inline it. Btw, this part made me wonder what's the
exact reason for keeping the idle pattern output and corresponding DPCD
programming separate, that is why can't we disable the training pattern
in DPCD after intel_dp_set_idle_link_train()? That would make things
more uniform on all platforms.

> 
> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> > on the link and  disabling the training pattern in
> > + * the sink's DPCD.
> > + * This function must be called after intel_dp_start_link_train().
> > + */
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> >  {
> >  	intel_dp->link_trained = true;
> > @@ -403,30 +425,37 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> >  				DP_TRAINING_PATTERN_DISABLE);
> >  }
> >  
> > -void
> > -intel_dp_start_link_train(struct intel_dp *intel_dp)
> > +static bool
> > +intel_dp_link_train(struct intel_dp *intel_dp)
> >  {
> >  	struct intel_connector *intel_connector = intel_dp->attached_connector;
> > +	bool ret = false;
> > +
> > +	intel_dp_prepare_link_train(intel_dp);
> >  
> >  	if (!intel_dp_link_training_clock_recovery(intel_dp))
> > -		goto failure_handling;
> > +		goto out;
> > +
> >  	if (!intel_dp_link_training_channel_equalization(intel_dp))
> > -		goto failure_handling;
> > +		goto out;
> >  
> > -	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> > -		    "[CONNECTOR:%d:%s] Link Training Passed at Link Rate = %d, Lane count = %d",
> > -		    intel_connector->base.base.id,
> > -		    intel_connector->base.name,
> > -		    intel_dp->link_rate, intel_dp->lane_count);
> > -	return;
> > +	ret = true;
> >  
> > - failure_handling:
> > +out:
> >  	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> > -		    "[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
> > +		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d",
> >  		    intel_connector->base.base.id,
> >  		    intel_connector->base.name,
> > +		    ret ? "passed" : "failed",
> >  		    intel_dp->link_rate, intel_dp->lane_count);
> >  
> > +	return ret;
> > +}
> > +
> > +static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp)
> > +{
> > +	struct intel_connector *intel_connector = intel_dp->attached_connector;
> > +
> >  	if (intel_dp->hobl_active) {
> >  		drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> >  			    "Link Training failed with HOBL active, not enabling it from now on");
> > @@ -440,3 +469,18 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
> >  	/* Schedule a Hotplug Uevent to userspace to start modeset */
> >  	schedule_work(&intel_connector->modeset_retry_work);
> >  }
> > +
> > +/**
> > + * intel_dp_start_link_train - start link training
> > + * @intel_dp: DP struct
> > + *
> > + * Start the link training of the @intel_dp port, scheduling a fallback
> > + * retraining with reduced link rate/lane parameters if the link training
> > + * fails.
> > + * After calling this function intel_dp_stop_link_train() must be called.
> > + */
> > +void intel_dp_start_link_train(struct intel_dp *intel_dp)
> > +{
> > +	if (!intel_dp_link_train(intel_dp))
> > +		intel_dp_schedule_fallback_link_training(intel_dp);
> > +}
> > -- 
> > 2.17.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions
  2020-09-22 15:30     ` Imre Deak
@ 2020-09-22 16:49       ` Ville Syrjälä
  2020-09-22 17:25         ` Imre Deak
  0 siblings, 1 reply; 27+ messages in thread
From: Ville Syrjälä @ 2020-09-22 16:49 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 06:30:35PM +0300, Imre Deak wrote:
> On Tue, Sep 22, 2020 at 04:27:05PM +0300, Ville Syrjälä wrote:
> > On Tue, Sep 22, 2020 at 03:51:02PM +0300, Imre Deak wrote:
> > > Split the prepare, link training, fallback-handling steps into their own
> > > functions for clarity and as a preparation for the upcoming LTTPR changes.
> > > 
> > > While at it also add some documentation to exported functions.
> > > 
> > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > ---
> > >  .../drm/i915/display/intel_dp_link_training.c | 80 ++++++++++++++-----
> > >  1 file changed, 62 insertions(+), 18 deletions(-)
> > > 
> > > 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 6d13d00db5e6..0c3809891bd2 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > @@ -162,14 +162,13 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
> > >  	return true;
> > >  }
> > >  
> > > -/* Enable corresponding port and start training pattern 1 */
> > > -static bool
> > > -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > +/*
> > > + * Prepare link training by configuring the link parameters and enabling the
> > > + * corresponding port.
> > > + */
> > > +static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
> > >  {
> > >  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > > -	u8 voltage;
> > > -	int voltage_tries, cr_tries, max_cr_tries;
> > > -	bool max_vswing_reached = false;
> > >  	u8 link_config[2];
> > >  	u8 link_bw, rate_select;
> > >  
> > > @@ -203,6 +202,16 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > >  	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
> > >  
> > >  	intel_dp->DP |= DP_PORT_EN;
> > 
> > I guess we no longer actually enable the port here? The comment ^ still says
> > we do.
> > 
> > Hmm. Seems we do enable the port on ddi platforms, but not on older
> > platforms. I guess the docs could still use a tweak to reflect
> > reality a bit better.
> 
> Yes, missed the old platform part, will update the comment.
> 
> > 
> > > +}
> > > +
> > > +/* Perform the link training clock recovery phase using training pattern 1. */
> > > +static bool
> > > +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > +{
> > > +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > > +	u8 voltage;
> > > +	int voltage_tries, cr_tries, max_cr_tries;
> > > +	bool max_vswing_reached = false;
> > >  
> > >  	/* clock recovery */
> > >  	if (!intel_dp_reset_link_train(intel_dp,
> > > @@ -325,6 +334,10 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> > >  	return DP_TRAINING_PATTERN_2;
> > >  }
> > >  
> > > +/*
> > > + * Perform the link training channel equalization phase using one of training
> > > + * pattern 2, 3 or 4 depending on the the source and sink capabilities.
> > > + */
> > >  static bool
> > >  intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > >  {
> > > @@ -395,6 +408,15 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > >  
> > >  }
> > >  
> > > +/**
> > > + * intel_dp_stop_link_train - stop link training
> > > + * @intel_dp: DP struct
> > > + *
> > > + * Stop the link training of the @intel_dp port, programming the port to
> > > + * output an idle pattern 
> > 
> > I don't think we use the idle pattern on all platforms.
> 
> Yes, just DDI, this also needs a doc update.
> 
> > BTW intel_dp_set_idle_link_train() looks pretty pointless. Could just
> > inline it into its only caller, or at least move it into
> > intel_dp_link_training.c.
> 
> Ok, can unexport/inline it. Btw, this part made me wonder what's the
> exact reason for keeping the idle pattern output and corresponding DPCD
> programming separate, that is why can't we disable the training pattern
> in DPCD after intel_dp_set_idle_link_train()? That would make things
> more uniform on all platforms.

Hmm. I guess we're violating the DP spec a bit with the current
sequence:
"The Source device shall start sending the idle pattern after it has
 cleared the Training_Pattern byte in the DPCD"

Currently we start sending the idle pattern way earlier. And even
on platform where we don't send the idle pattern [1] we are disabling
the training pattern before we do the corresponding DPCD write.

So we may want to change the order to follow the spec.

[1] I guess the hw must send a few idle patterns automagically
    since IIRC the spec requires it?

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern Imre Deak
@ 2020-09-22 16:54   ` Ville Syrjälä
  2020-09-22 17:41     ` Imre Deak
  0 siblings, 1 reply; 27+ messages in thread
From: Ville Syrjälä @ 2020-09-22 16:54 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 03:51:03PM +0300, Imre Deak wrote:
> To prepare for a follow-up LTTPR change factor out a helper to disable
> the training pattern in DPCD. We'll need to do this for each LTTPR
> (without programming the port to output the idle pattern) when training
> in LTTPR non-transparent mode.
> 
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
>  .../drm/i915/display/intel_dp_link_training.c | 28 +++++++++++--------
>  1 file changed, 16 insertions(+), 12 deletions(-)
> 
> 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 0c3809891bd2..6994a32244dc 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> @@ -102,30 +102,34 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
>  		intel_dp->train_set[lane] = v | p;
>  }
>  
> +static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp)
> +{
> +	u8 val = DP_TRAINING_PATTERN_DISABLE;
> +
> +	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &val, 1) == 1;
> +}


> +
>  static bool
>  intel_dp_set_link_train(struct intel_dp *intel_dp,
>  			u8 dp_train_pat)
>  {
>  	u8 buf[sizeof(intel_dp->train_set) + 1];
> -	int ret, len;
> +	int len;
>  
>  	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
>  
> -	buf[0] = dp_train_pat;
>  	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
> -	    DP_TRAINING_PATTERN_DISABLE) {
> +	    DP_TRAINING_PATTERN_DISABLE)
>  		/* don't write DP_TRAINING_LANEx_SET on disable */

As mentioned in the other patch I think we're doing things in the wrong
order here. I suspect it'll be cleaner to just stop doing
intel_dp_set_link_train(DISABLE) entirely and just have a dedicated
function for disabling link training. We can then trivially do a
followup to swap the order of operations to match the spec.

> -		len = 1;
> -	} else {
> -		/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> -		memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
> -		len = intel_dp->lane_count + 1;
> -	}
> +		return intel_dp_disable_dpcd_training_pattern(intel_dp);
>  
> -	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
> -				buf, len);
> +	buf[0] = dp_train_pat;
> +	/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> +	memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
> +	len = intel_dp->lane_count + 1;
>  
> -	return ret == len;
> +	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
> +				 buf, len) == len;
>  }
>  
>  static bool
> -- 
> 2.17.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions
  2020-09-22 16:49       ` Ville Syrjälä
@ 2020-09-22 17:25         ` Imre Deak
  2020-09-22 17:44           ` Ville Syrjälä
  0 siblings, 1 reply; 27+ messages in thread
From: Imre Deak @ 2020-09-22 17:25 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 07:49:17PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 22, 2020 at 06:30:35PM +0300, Imre Deak wrote:
> > On Tue, Sep 22, 2020 at 04:27:05PM +0300, Ville Syrjälä wrote:
> > > On Tue, Sep 22, 2020 at 03:51:02PM +0300, Imre Deak wrote:
> > > > Split the prepare, link training, fallback-handling steps into their own
> > > > functions for clarity and as a preparation for the upcoming LTTPR changes.
> > > > 
> > > > While at it also add some documentation to exported functions.
> > > > 
> > > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > > ---
> > > >  .../drm/i915/display/intel_dp_link_training.c | 80 ++++++++++++++-----
> > > >  1 file changed, 62 insertions(+), 18 deletions(-)
> > > > 
> > > > 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 6d13d00db5e6..0c3809891bd2 100644
> > > > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > > @@ -162,14 +162,13 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
> > > >  	return true;
> > > >  }
> > > >  
> > > > -/* Enable corresponding port and start training pattern 1 */
> > > > -static bool
> > > > -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > > +/*
> > > > + * Prepare link training by configuring the link parameters and enabling the
> > > > + * corresponding port.
> > > > + */
> > > > +static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
> > > >  {
> > > >  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > > > -	u8 voltage;
> > > > -	int voltage_tries, cr_tries, max_cr_tries;
> > > > -	bool max_vswing_reached = false;
> > > >  	u8 link_config[2];
> > > >  	u8 link_bw, rate_select;
> > > >  
> > > > @@ -203,6 +202,16 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > >  	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
> > > >  
> > > >  	intel_dp->DP |= DP_PORT_EN;
> > > 
> > > I guess we no longer actually enable the port here? The comment ^ still says
> > > we do.
> > > 
> > > Hmm. Seems we do enable the port on ddi platforms, but not on older
> > > platforms. I guess the docs could still use a tweak to reflect
> > > reality a bit better.
> > 
> > Yes, missed the old platform part, will update the comment.
> > 
> > > 
> > > > +}
> > > > +
> > > > +/* Perform the link training clock recovery phase using training pattern 1. */
> > > > +static bool
> > > > +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > > +{
> > > > +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > > > +	u8 voltage;
> > > > +	int voltage_tries, cr_tries, max_cr_tries;
> > > > +	bool max_vswing_reached = false;
> > > >  
> > > >  	/* clock recovery */
> > > >  	if (!intel_dp_reset_link_train(intel_dp,
> > > > @@ -325,6 +334,10 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> > > >  	return DP_TRAINING_PATTERN_2;
> > > >  }
> > > >  
> > > > +/*
> > > > + * Perform the link training channel equalization phase using one of training
> > > > + * pattern 2, 3 or 4 depending on the the source and sink capabilities.
> > > > + */
> > > >  static bool
> > > >  intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > > >  {
> > > > @@ -395,6 +408,15 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > > >  
> > > >  }
> > > >  
> > > > +/**
> > > > + * intel_dp_stop_link_train - stop link training
> > > > + * @intel_dp: DP struct
> > > > + *
> > > > + * Stop the link training of the @intel_dp port, programming the port to
> > > > + * output an idle pattern 
> > > 
> > > I don't think we use the idle pattern on all platforms.
> > 
> > Yes, just DDI, this also needs a doc update.
> > 
> > > BTW intel_dp_set_idle_link_train() looks pretty pointless. Could just
> > > inline it into its only caller, or at least move it into
> > > intel_dp_link_training.c.
> > 
> > Ok, can unexport/inline it. Btw, this part made me wonder what's the
> > exact reason for keeping the idle pattern output and corresponding DPCD
> > programming separate, that is why can't we disable the training pattern
> > in DPCD after intel_dp_set_idle_link_train()? That would make things
> > more uniform on all platforms.
> 
> Hmm. I guess we're violating the DP spec a bit with the current
> sequence:
> "The Source device shall start sending the idle pattern after it has
>  cleared the Training_Pattern byte in the DPCD"

Yep, that order sounds correct. In v2.0 3.6.6.6.10 End of Link Training
suggests the current sequence though, but the sink should be able to
handle the idle pattern after the sink reported symbol lock .

> Currently we start sending the idle pattern way earlier. And even
> on platform where we don't send the idle pattern [1] we are disabling
> the training pattern before we do the corresponding DPCD write.
> 
> So we may want to change the order to follow the spec.
> 
> [1] I guess the hw must send a few idle patterns automagically
>     since IIRC the spec requires it?

Yes, the spec seems to require it (5.1.2). AFAICS (on g4x for instance)
we have the pipe disabled when disabling training pattern generation, so
I suppose the port would send idle patterns until enabling the pipe?

> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 7/7] drm/i915: Switch to LTTPR non-transparent mode link training
  2020-09-22 12:51 ` [Intel-gfx] [PATCH 7/7] drm/i915: Switch to LTTPR non-transparent " Imre Deak
@ 2020-09-22 17:37   ` Ville Syrjälä
  2020-09-22 18:26     ` Imre Deak
  0 siblings, 1 reply; 27+ messages in thread
From: Ville Syrjälä @ 2020-09-22 17:37 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 03:51:06PM +0300, Imre Deak wrote:
> The DP Standard's recommendation is to use the LTTPR non-transparent
> mode link training if LTTPRs are detected, so let's do this.
> 
> Besides power-saving, the advantages of this are that the maximum number
> of LTTPRs can only be used in non-transparent mode (the limit is 5-8 in
> transparent mode), and it provides a way to narrow down the reason for a
> link training failure to a given link segment. Non-transparent mode is
> probably also the mode that was tested the most by the industry.
> 
> The changes in this patchset:
> - Pass the DP PHY that is currently link trained to all LT helpers, so
>   that these can access the correct LTTPR/DPRX DPCD registers.
> - During LT take into account the LTTPR common lane rate/count and the
>   per LTTPR-PHY vswing/pre-emph limits.
> - Switch to LTTPR non-transparent LT mode and train each link segment
>   according to the sequence in DP Standard v2.0 (complete CR/EQ for
>   each segment before continuing with the next segment).
> 
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
>  .../drm/i915/display/intel_display_types.h    |   1 +
>  drivers/gpu/drm/i915/display/intel_dp.c       |  14 +-
>  .../drm/i915/display/intel_dp_link_training.c | 374 +++++++++++++++---
>  .../drm/i915/display/intel_dp_link_training.h |  10 +-
>  4 files changed, 327 insertions(+), 72 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> index b04921eba73b..2fb4e9a6a316 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1281,6 +1281,7 @@ struct intel_dp {
>  	u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
>  	u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
>  	u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
> +	u8 lttpr_phy_caps[DP_MAX_LTTPR_COUNT][DP_LTTPR_PHY_CAP_SIZE];
>  	u8 fec_capable;
>  	/* source rates */
>  	int num_source_rates;
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index d88f327aa9ef..54ad31044eef 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -161,6 +161,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
>  		162000, 270000, 540000, 810000
>  	};
>  	int i, max_rate;
> +	int max_lttpr_rate;
>  
>  	if (drm_dp_has_quirk(&intel_dp->desc, 0,
>  			     DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) {
> @@ -174,6 +175,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
>  	}
>  
>  	max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
> +	max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps);
> +	if (max_lttpr_rate)
> +		max_rate = min(max_rate, max_lttpr_rate);
>  
>  	for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
>  		if (dp_rates[i] > max_rate)
> @@ -219,6 +223,10 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
>  	int source_max = dig_port->max_lanes;
>  	int sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
>  	int fia_max = intel_tc_port_fia_max_lane_count(dig_port);
> +	int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps);
> +
> +	if (lttpr_max)
> +		sink_max = min(sink_max, lttpr_max);
>  
>  	return min3(source_max, sink_max, fia_max);
>  }
> @@ -5540,13 +5548,13 @@ void intel_dp_process_phy_request(struct intel_dp *intel_dp)
>  		&intel_dp->compliance.test_data.phytest;
>  	u8 link_status[DP_LINK_STATUS_SIZE];
>  
> -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> +	if (!intel_dp_get_link_status(intel_dp, DP_PHY_DPRX, link_status)) {
>  		DRM_DEBUG_KMS("failed to get link status\n");
>  		return;
>  	}
>  
>  	/* retrieve vswing & pre-emphasis setting */
> -	intel_dp_get_adjust_train(intel_dp, link_status);
> +	intel_dp_get_adjust_train(intel_dp, DP_PHY_DPRX, link_status);
>  
>  	intel_dp_autotest_phy_ddi_disable(intel_dp);
>  
> @@ -5701,7 +5709,7 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
>  	if (intel_psr_enabled(intel_dp))
>  		return false;
>  
> -	if (!intel_dp_get_link_status(intel_dp, link_status))
> +	if (!intel_dp_get_link_status(intel_dp, DP_PHY_DPRX, link_status))

Should we check all repeaters here too perhaps?
I guess that should be a followup if we need it.

>  		return false;
>  
>  	/*
> 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 1485602659be..3aa685a9aa2a 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> @@ -25,6 +25,8 @@
>  #include "intel_dp.h"
>  #include "intel_dp_link_training.h"
>  
> +#define DP_PHY_LTTPR(i)		(DP_PHY_LTTPR1 + (i))

Maybe just put that into drm_dp_helper.h?

> +
>  static void
>  intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
>  {
> @@ -35,37 +37,140 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
>  }
>  
>  /**
> - * intel_dp_get_link_status - get the link status information for the DPRX
> + * intel_dp_get_link_status - get the link status information for a DP PHY
>   * @intel_dp: DP struct
> + * @dp_phy: the DP PHY to get the link status for
>   * @link_status: buffer to return the status in
>   *
> - * Fetch the AUX DPCD registers for the DPRX link status.
> + * Fetch the AUX DPCD registers for the DPRX or an LTTPR PHY link status. The
> + * layout of the returned @link_status matches the DPCD register layout of the
> + * DPRX PHY link status.
>   *
>   * Returns true if the information was read successfully, false otherwise.
>   */
>  bool
> -intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
> +intel_dp_get_link_status(struct intel_dp *intel_dp,
> +			 enum drm_dp_phy dp_phy,
> +			 u8 link_status[DP_LINK_STATUS_SIZE])
>  {
> -	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
> -				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
> +	u8 lttpr_status[DP_LINK_STATUS_SIZE - 1];
> +
> +	if (dp_phy == DP_PHY_DPRX)
> +		return drm_dp_dpcd_read(&intel_dp->aux,
> +					DP_LANE0_1_STATUS,
> +					link_status,
> +					DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
> +
> +	if (drm_dp_dpcd_read(&intel_dp->aux,
> +			     DP_LANE0_1_STATUS_PHY_REPEATER(dp_phy),
> +			     lttpr_status,
> +			     sizeof(lttpr_status)) != sizeof(lttpr_status))
> +			return false;
> +
> +#define link_reg(reg)	link_status[(reg) - DP_LANE0_1_STATUS]
> +#define lttpr_reg(reg)	lttpr_status[(reg) - DP_LANE0_1_STATUS_PHY_REPEATER1]
> +
> +	/* Convert the LTTPR to the sink PHY link status layout */
> +	link_reg(DP_LANE0_1_STATUS) = lttpr_reg(DP_LANE0_1_STATUS_PHY_REPEATER1);
> +	link_reg(DP_LANE2_3_STATUS) = lttpr_reg(DP_LANE2_3_STATUS_PHY_REPEATER1);
> +	link_reg(DP_LANE_ALIGN_STATUS_UPDATED) =
> +		lttpr_reg(DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1);
> +	link_reg(DP_SINK_STATUS) = 0;

So the difference is just the presence of the SINK_STATUS.
Sad they couldn't be bothered to just stick a 0 placeholder
there for lttprs.

> +	link_reg(DP_ADJUST_REQUEST_LANE0_1) =
> +		lttpr_reg(DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1);
> +	link_reg(DP_ADJUST_REQUEST_LANE2_3) =
> +		lttpr_reg(DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1);
> +
> +#undef link_reg
> +#undef lttpr_reg

Maybe this thing should be in the dp_helper as well? I could
imagine other drivers wanting to do the same exactl thing.

> +
> +	return true;
> +}
> +
> +static int intel_dp_lttpr_count(struct intel_dp *intel_dp)
> +{
> +	int count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps);
> +
> +	/*
> +	 * Pretend no LTTPRs in case of LTTPR detection error, or
> +	 * if too many (>8) LTTPRs are detected. This translates to link
> +	 * training in transparent mode.
> +	 */
> +	return count <= 0 ? 0 : count;
> +}
> +
> +static const char *intel_dp_phy_name(enum drm_dp_phy dp_phy,
> +				     char *buf, size_t buf_size)
> +{
> +	if (dp_phy == DP_PHY_DPRX)
> +		snprintf(buf, buf_size, "DPRX");
> +	else
> +		snprintf(buf, buf_size, "LTTPR %d", dp_phy - DP_PHY_LTTPR1 + 1);
> +
> +	return buf;
> +}
> +
> +static uint8_t *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp,
> +					enum drm_dp_phy dp_phy)
> +{
> +	return &intel_dp->lttpr_phy_caps[dp_phy - DP_PHY_LTTPR1][0];

Why the &...[0] ?

>  }
>  
>  /**
> - * intel_dp_read_lttpr_caps - read the LTTPR common capabilities
> + * intel_dp_read_lttpr_caps - read the LTTPR common and per-PHY capabilities
>   * @intel_dp: Intel DP struct
>   *
> - * Read the LTTPR common capabilities.
> + * Read the LTTPR common capabilities and the PHY capabilities for all
> + * detected LTTPRs. In case of an LTTPR detection error or if the number of
> + * LTTPRs is more than is supported (8), fall back to the no-LTTPR,
> + * transparent mode link training mode.
>   */
>  void intel_dp_read_lttpr_caps(struct intel_dp *intel_dp)
>  {
> +	int lttpr_count;
> +	int i;
> +
>  	if (drm_dp_read_lttpr_common_caps(&intel_dp->aux,
> -					  intel_dp->lttpr_common_caps) < 0)
> +					  intel_dp->lttpr_common_caps) < 0) {
> +		memset(intel_dp->lttpr_common_caps, 0,
> +		       sizeof(intel_dp->lttpr_common_caps));
>  		return;
> +	}
>  
>  	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
>  		    "LTTPR common capabilities: %*ph\n",
>  		    (int)sizeof(intel_dp->lttpr_common_caps),
>  		    intel_dp->lttpr_common_caps);
> +
> +	lttpr_count = intel_dp_lttpr_count(intel_dp);
> +	/*
> +	 * In case of unsupported number of LTTPRs fall-back to transparent
> +	 * link training mode, still taking into account any LTTPR common
> +	 * lane- rate/count limits.
> +	 */
> +	if (lttpr_count <= 0)
> +		return;
> +
> +	for (i = 0; i < lttpr_count; i++) {
> +		enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
> +		uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
> +		char phy_name[10];
> +
> +		intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name));
> +
> +		if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) {
> +			drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> +				    "failed to read the PHY caps for %s\n",
> +				    phy_name);
> +			continue;
> +		}
> +
> +		drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> +			    "%s PHY capabilities: %*ph\n",
> +			    phy_name,
> +			    (int)sizeof(intel_dp->lttpr_phy_caps[0]),
> +			    phy_caps);
> +	}
>  }
>  
>  static u8 dp_voltage_max(u8 preemph)
> @@ -83,10 +188,78 @@ static u8 dp_voltage_max(u8 preemph)
>  	}
>  }
>  
> +static u8 intel_dp_lttpr_voltage_max(struct intel_dp *intel_dp,
> +				     enum drm_dp_phy dp_phy)
> +{
> +	const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
> +
> +	if (drm_dp_lttpr_voltage_swing_level_3_supported(phy_caps))
> +		return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
> +	else
> +		return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
> +}
> +
> +static u8 intel_dp_lttpr_preemph_max(struct intel_dp *intel_dp,
> +				     enum drm_dp_phy dp_phy)
> +{
> +	const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
> +
> +	if (drm_dp_lttpr_pre_emphasis_level_3_supported(phy_caps))
> +		return DP_TRAIN_PRE_EMPH_LEVEL_3;
> +	else
> +		return DP_TRAIN_PRE_EMPH_LEVEL_2;
> +}
> +
> +static u8 intel_dp_phy_voltage_max(struct intel_dp *intel_dp,
> +				    enum drm_dp_phy dp_phy)
> +{
> +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> +	int lttpr_count = intel_dp_lttpr_count(intel_dp);
> +	u8 voltage_max;
> +
> +	/*
> +	 * Get voltage_max from the DPTX_PHY (source or LTTPR) upstream from
> +	 * the DPRX_PHY we train.
> +	 */
> +	if (lttpr_count == 0 || dp_phy == DP_PHY_LTTPR(lttpr_count - 1))

phy_is_downstream_of_source() or somesuch helper maybe?
There must be a better name than that though. But as usual
I can't think of one right now.

> +		voltage_max = intel_dp->voltage_max(intel_dp);
> +	else
> +		voltage_max = intel_dp_lttpr_voltage_max(intel_dp, dp_phy + 1);
> +
> +	drm_WARN_ON_ONCE(&i915->drm,
> +			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
> +			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
> +
> +	return voltage_max;
> +}
> +
> +static u8 intel_dp_phy_preemph_max(struct intel_dp *intel_dp,
> +				   enum drm_dp_phy dp_phy)
> +{
> +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> +	int lttpr_count = intel_dp_lttpr_count(intel_dp);
> +	u8 preemph_max;
> +
> +	/*
> +	 * Get preemph_max from the DPTX_PHY (source or LTTPR) upstream from
> +	 * the DPRX_PHY we train.
> +	 */
> +	if (lttpr_count == 0 || dp_phy == DP_PHY_LTTPR(lttpr_count - 1))
> +		preemph_max = intel_dp->preemph_max(intel_dp);
> +	else
> +		preemph_max = intel_dp_lttpr_preemph_max(intel_dp, dp_phy + 1);
> +
> +	drm_WARN_ON_ONCE(&i915->drm,
> +			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
> +			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
> +
> +	return preemph_max;
> +}
> +
>  void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> +			       enum drm_dp_phy dp_phy,
>  			       const u8 link_status[DP_LINK_STATUS_SIZE])
>  {
> -	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
>  	u8 v = 0;
>  	u8 p = 0;
>  	int lane;
> @@ -98,21 +271,13 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
>  		p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, lane));
>  	}
>  
> -	preemph_max = intel_dp->preemph_max(intel_dp);
> -	drm_WARN_ON_ONCE(&i915->drm,
> -			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
> -			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
> -
> +	preemph_max = intel_dp_phy_preemph_max(intel_dp, dp_phy);
>  	if (p >= preemph_max)
>  		p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
>  
>  	v = min(v, dp_voltage_max(p));
>  
> -	voltage_max = intel_dp->voltage_max(intel_dp);
> -	drm_WARN_ON_ONCE(&i915->drm,
> -			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
> -			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
> -
> +	voltage_max = intel_dp_phy_voltage_max(intel_dp, dp_phy);
>  	if (v >= voltage_max)
>  		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
>  
> @@ -120,17 +285,24 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
>  		intel_dp->train_set[lane] = v | p;
>  }
>  
> -static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp)
> +static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp,
> +						   enum drm_dp_phy dp_phy)
>  {
> +	int reg = dp_phy == DP_PHY_DPRX ?
> +		DP_TRAINING_PATTERN_SET :
> +		DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
>  	u8 val = DP_TRAINING_PATTERN_DISABLE;
>  
> -	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &val, 1) == 1;
> +	return drm_dp_dpcd_write(&intel_dp->aux, reg, &val, 1) == 1;
>  }
>  
>  static bool
> -intel_dp_set_link_train(struct intel_dp *intel_dp,
> +intel_dp_set_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
>  			u8 dp_train_pat)
>  {
> +	int reg = dp_phy == DP_PHY_DPRX ?
> +		DP_TRAINING_PATTERN_SET :
> +		DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
>  	u8 buf[sizeof(intel_dp->train_set) + 1];
>  	int len;
>  
> @@ -139,34 +311,36 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
>  	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
>  	    DP_TRAINING_PATTERN_DISABLE)
>  		/* don't write DP_TRAINING_LANEx_SET on disable */
> -		return intel_dp_disable_dpcd_training_pattern(intel_dp);
> +		return intel_dp_disable_dpcd_training_pattern(intel_dp, dp_phy);
>  
>  	buf[0] = dp_train_pat;
>  	/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
>  	memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
>  	len = intel_dp->lane_count + 1;
>  
> -	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
> -				 buf, len) == len;
> +	return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
>  }
>  
>  static bool
> -intel_dp_reset_link_train(struct intel_dp *intel_dp,
> +intel_dp_reset_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
>  			u8 dp_train_pat)
>  {
>  	memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
>  	intel_dp_set_signal_levels(intel_dp);
> -	return intel_dp_set_link_train(intel_dp, dp_train_pat);
> +	return intel_dp_set_link_train(intel_dp, dp_phy, dp_train_pat);
>  }
>  
>  static bool
> -intel_dp_update_link_train(struct intel_dp *intel_dp)
> +intel_dp_update_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy)
>  {
> +	int reg = dp_phy == DP_PHY_DPRX ?
> +		DP_TRAINING_LANE0_SET :
> +		DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
>  	int ret;
>  
>  	intel_dp_set_signal_levels(intel_dp);
>  
> -	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
> +	ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
>  				intel_dp->train_set, intel_dp->lane_count);
>  
>  	return ret == intel_dp->lane_count;
> @@ -226,9 +400,22 @@ static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
>  	intel_dp->DP |= DP_PORT_EN;
>  }
>  
> -/* Perform the link training clock recovery phase using training pattern 1. */
> +static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_dp,
> +							enum drm_dp_phy dp_phy)
> +{
> +	if (dp_phy == DP_PHY_DPRX)
> +		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
> +	else
> +		drm_dp_lttpr_link_train_clock_recovery_delay();
> +}
> +
> +/*
> + * Perform the link training clock recovery phase on the given DP PHY using
> + * training pattern 1.
> + */
>  static bool
> -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp,
> +				      enum drm_dp_phy dp_phy)
>  {
>  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
>  	u8 voltage;
> @@ -236,7 +423,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>  	bool max_vswing_reached = false;
>  
>  	/* clock recovery */
> -	if (!intel_dp_reset_link_train(intel_dp,
> +	if (!intel_dp_reset_link_train(intel_dp, dp_phy,
>  				       DP_TRAINING_PATTERN_1 |
>  				       DP_LINK_SCRAMBLING_DISABLE)) {
>  		drm_err(&i915->drm, "failed to enable link training\n");
> @@ -260,9 +447,9 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>  	for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) {
>  		u8 link_status[DP_LINK_STATUS_SIZE];
>  
> -		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
> +		intel_dp_link_training_clock_recovery_delay(intel_dp, dp_phy);
>  
> -		if (!intel_dp_get_link_status(intel_dp, link_status)) {
> +		if (!intel_dp_get_link_status(intel_dp, dp_phy, link_status)) {
>  			drm_err(&i915->drm, "failed to get link status\n");
>  			return false;
>  		}
> @@ -286,8 +473,8 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>  		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
>  
>  		/* Update training set as requested by target */
> -		intel_dp_get_adjust_train(intel_dp, link_status);
> -		if (!intel_dp_update_link_train(intel_dp)) {
> +		intel_dp_get_adjust_train(intel_dp, dp_phy, link_status);
> +		if (!intel_dp_update_link_train(intel_dp, dp_phy)) {
>  			drm_err(&i915->drm,
>  				"failed to update link training\n");
>  			return false;
> @@ -313,7 +500,8 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>   * or for 1.4 devices that support it, training Pattern 3 for HBR2
>   * or 1.2 devices that support it, Training Pattern 2 otherwise.
>   */
> -static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> +static u32 intel_dp_training_pattern(struct intel_dp *intel_dp,
> +				     enum drm_dp_phy dp_phy)
>  {
>  	bool source_tps3, sink_tps3, source_tps4, sink_tps4;
>  
> @@ -322,9 +510,11 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
>  	 * for all downstream devices that support HBR3. There are no known eDP
>  	 * panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1
>  	 * specification.
> +	 * LTTPRs must support TPS4.
>  	 */
>  	source_tps4 = intel_dp_source_supports_hbr3(intel_dp);
> -	sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd);
> +	sink_tps4 = dp_phy != DP_PHY_DPRX ||
> +		    drm_dp_tps4_supported(intel_dp->dpcd);
>  	if (source_tps4 && sink_tps4) {
>  		return DP_TRAINING_PATTERN_4;
>  	} else if (intel_dp->link_rate == 810000) {
> @@ -341,7 +531,8 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
>  	 * all sinks follow the spec.
>  	 */
>  	source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
> -	sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
> +	sink_tps3 = dp_phy != DP_PHY_DPRX ||
> +		    drm_dp_tps3_supported(intel_dp->dpcd);
>  	if (source_tps3 && sink_tps3) {
>  		return  DP_TRAINING_PATTERN_3;
>  	} else if (intel_dp->link_rate >= 540000) {
> @@ -356,12 +547,27 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
>  	return DP_TRAINING_PATTERN_2;
>  }
>  
> +static void
> +intel_dp_link_training_channel_equalization_delay(struct intel_dp *intel_dp,
> +						  enum drm_dp_phy dp_phy)
> +{
> +	if (dp_phy == DP_PHY_DPRX) {
> +		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> +	} else {
> +		const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
> +
> +		drm_dp_lttpr_link_train_channel_eq_delay(phy_caps);
> +	}
> +}
> +
>  /*
> - * Perform the link training channel equalization phase using one of training
> - * pattern 2, 3 or 4 depending on the the source and sink capabilities.
> + * Perform the link training channel equalization phase on the given DP PHY
> + * using one of training pattern 2, 3 or 4 depending on the the source and
> + * sink capabilities.
>   */
>  static bool
> -intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> +intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp,
> +					    enum drm_dp_phy dp_phy)
>  {
>  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
>  	int tries;
> @@ -369,22 +575,21 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  	u8 link_status[DP_LINK_STATUS_SIZE];
>  	bool channel_eq = false;
>  
> -	training_pattern = intel_dp_training_pattern(intel_dp);
> +	training_pattern = intel_dp_training_pattern(intel_dp, dp_phy);
>  	/* Scrambling is disabled for TPS2/3 and enabled for TPS4 */
>  	if (training_pattern != DP_TRAINING_PATTERN_4)
>  		training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
>  
>  	/* channel equalization */
> -	if (!intel_dp_set_link_train(intel_dp,
> -				     training_pattern)) {
> +	if (!intel_dp_set_link_train(intel_dp, dp_phy, training_pattern)) {
>  		drm_err(&i915->drm, "failed to start channel equalization\n");
>  		return false;
>  	}
>  
>  	for (tries = 0; tries < 5; tries++) {
> -
> -		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> -		if (!intel_dp_get_link_status(intel_dp, link_status)) {
> +		intel_dp_link_training_channel_equalization_delay(intel_dp,
> +								  dp_phy);
> +		if (!intel_dp_get_link_status(intel_dp, dp_phy, link_status)) {
>  			drm_err(&i915->drm,
>  				"failed to get link status\n");
>  			break;
> @@ -409,8 +614,8 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  		}
>  
>  		/* Update training set as requested by target */
> -		intel_dp_get_adjust_train(intel_dp, link_status);
> -		if (!intel_dp_update_link_train(intel_dp)) {
> +		intel_dp_get_adjust_train(intel_dp, dp_phy, link_status);
> +		if (!intel_dp_update_link_train(intel_dp, dp_phy)) {
>  			drm_err(&i915->drm,
>  				"failed to update link training\n");
>  			break;
> @@ -424,8 +629,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  			    "Channel equalization failed 5 times\n");
>  	}
>  
> -	intel_dp_set_idle_link_train(intel_dp);
> -
>  	return channel_eq;
>  
>  }
> @@ -442,34 +645,33 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>  {
>  	intel_dp->link_trained = true;
> -
> -	intel_dp_set_link_train(intel_dp,
> +	intel_dp_set_link_train(intel_dp, DP_PHY_DPRX,
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
>  
>  static bool
> -intel_dp_link_train(struct intel_dp *intel_dp)
> +intel_dp_link_train_phy(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy)
>  {
>  	struct intel_connector *intel_connector = intel_dp->attached_connector;
> +	char phy_name[10];
>  	bool ret = false;
>  
> -	intel_dp_prepare_link_train(intel_dp);
> -
> -	if (!intel_dp_link_training_clock_recovery(intel_dp))
> +	if (!intel_dp_link_training_clock_recovery(intel_dp, dp_phy))
>  		goto out;
>  
> -	if (!intel_dp_link_training_channel_equalization(intel_dp))
> +	if (!intel_dp_link_training_channel_equalization(intel_dp, dp_phy))
>  		goto out;
>  
>  	ret = true;
>  
>  out:
>  	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> -		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d",
> +		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d, at %s",
>  		    intel_connector->base.base.id,
>  		    intel_connector->base.name,
>  		    ret ? "passed" : "failed",
> -		    intel_dp->link_rate, intel_dp->lane_count);
> +		    intel_dp->link_rate, intel_dp->lane_count,
> +		    intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)));
>  
>  	return ret;
>  }
> @@ -492,6 +694,33 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp)
>  	schedule_work(&intel_connector->modeset_retry_work);
>  }
>  
> +/* Perform the link training on all LTTPRs and the DPRX on a link. */
> +static bool
> +intel_dp_link_train_all_phys(struct intel_dp *intel_dp, int lttpr_count)
> +{
> +	bool ret = true;
> +	int i;
> +
> +	intel_dp_prepare_link_train(intel_dp);
> +
> +	for (i = lttpr_count - 1; i >= 0; i--) {
> +		enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
> +
> +		ret = intel_dp_link_train_phy(intel_dp, dp_phy);
> +		intel_dp_disable_dpcd_training_pattern(intel_dp, dp_phy);
> +
> +		if (!ret)
> +			break;
> +	}
> +
> +	if (ret)
> +		intel_dp_link_train_phy(intel_dp, DP_PHY_DPRX);
> +
> +	intel_dp_set_idle_link_train(intel_dp);
> +
> +	return ret;
> +}
> +
>  static bool
>  intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
>  {
> @@ -501,10 +730,12 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
>  	return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1;
>  }
>  
> -static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
> +static int intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
>  {
> +	int lttpr_count;
> +
>  	if (intel_dp_is_edp(intel_dp))
> -		return;
> +		return 0;
>  
>  	/*
>  	 * TODO: the following re-reading of LTTPR caps can be removed
> @@ -512,6 +743,19 @@ static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
>  	 */
>  	intel_dp_read_lttpr_caps(intel_dp);
>  	intel_dp_set_lttpr_transparent_mode(intel_dp, true);
> +
> +	lttpr_count = intel_dp_lttpr_count(intel_dp);
> +	if (lttpr_count) {
> +		/*
> +		 * If we can't set non-transparent mode fall-back to
> +		 * transparent mode, still taking into account any LTTPR
> +		 * common lane rate and count limits.
> +		 */
> +		if (!intel_dp_set_lttpr_transparent_mode(intel_dp, false))

Is there some magic to the double true+false transparent mode
set here? Or just convenience?

In general looks good, and didn't require too much rewriting which is
nice.
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> +			lttpr_count = 0;
> +	}
> +
> +	return lttpr_count;
>  }
>  
>  /**
> @@ -525,8 +769,8 @@ static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
>   */
>  void intel_dp_start_link_train(struct intel_dp *intel_dp)
>  {
> -	intel_dp_init_lttpr_mode(intel_dp);
> +	int lttpr_count = intel_dp_init_lttpr_mode(intel_dp);
>  
> -	if (!intel_dp_link_train(intel_dp))
> +	if (!intel_dp_link_train_all_phys(intel_dp, lttpr_count))
>  		intel_dp_schedule_fallback_link_training(intel_dp);
>  }
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> index c0be3ff709a0..d0393b76ffc1 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> @@ -10,12 +10,14 @@
>  
>  struct intel_dp;
>  
> -bool intel_dp_get_link_status(struct intel_dp *intel_dp,
> -			      u8 link_status[DP_LINK_STATUS_SIZE]);
> +bool
> +intel_dp_get_link_status(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
> +			 u8 link_status[DP_LINK_STATUS_SIZE]);
>  void intel_dp_read_lttpr_caps(struct intel_dp *intel_dp);
>  
> -void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> -			       const u8 link_status[DP_LINK_STATUS_SIZE]);
> +void
> +intel_dp_get_adjust_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
> +			  const u8 link_status[DP_LINK_STATUS_SIZE]);
>  void intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>  
> -- 
> 2.17.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern
  2020-09-22 16:54   ` Ville Syrjälä
@ 2020-09-22 17:41     ` Imre Deak
  2020-09-22 17:47       ` Ville Syrjälä
  0 siblings, 1 reply; 27+ messages in thread
From: Imre Deak @ 2020-09-22 17:41 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 07:54:20PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 22, 2020 at 03:51:03PM +0300, Imre Deak wrote:
> > To prepare for a follow-up LTTPR change factor out a helper to disable
> > the training pattern in DPCD. We'll need to do this for each LTTPR
> > (without programming the port to output the idle pattern) when training
> > in LTTPR non-transparent mode.
> > 
> > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > ---
> >  .../drm/i915/display/intel_dp_link_training.c | 28 +++++++++++--------
> >  1 file changed, 16 insertions(+), 12 deletions(-)
> > 
> > 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 0c3809891bd2..6994a32244dc 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > @@ -102,30 +102,34 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> >  		intel_dp->train_set[lane] = v | p;
> >  }
> >  
> > +static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp)
> > +{
> > +	u8 val = DP_TRAINING_PATTERN_DISABLE;
> > +
> > +	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &val, 1) == 1;
> > +}
> 
> 
> > +
> >  static bool
> >  intel_dp_set_link_train(struct intel_dp *intel_dp,
> >  			u8 dp_train_pat)
> >  {
> >  	u8 buf[sizeof(intel_dp->train_set) + 1];
> > -	int ret, len;
> > +	int len;
> >  
> >  	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
> >  
> > -	buf[0] = dp_train_pat;
> >  	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
> > -	    DP_TRAINING_PATTERN_DISABLE) {
> > +	    DP_TRAINING_PATTERN_DISABLE)
> >  		/* don't write DP_TRAINING_LANEx_SET on disable */
> 
> As mentioned in the other patch I think we're doing things in the wrong
> order here. I suspect it'll be cleaner to just stop doing
> intel_dp_set_link_train(DISABLE) entirely and just have a dedicated
> function for disabling link training. We can then trivially do a
> followup to swap the order of operations to match the spec.

intel_dp_disable_dpcd_training_pattern() would be needed after each
LTTPR link training phase, where the port should not output idle
patterns, that's the only reason for this change.

Do you mean to remove intel_dp_stop_link_train() then and do the idle
pattern programming + corresponding DPCD training pattern disable
programming at the end of the link training sequence (and remove the
DP_TRAINING_PATTERN_DISABLE case handling from above)? I agree with
that, but I see that too as a follow-up material (along with changing
the order as you suggested).


> 
> > -		len = 1;
> > -	} else {
> > -		/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> > -		memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
> > -		len = intel_dp->lane_count + 1;
> > -	}
> > +		return intel_dp_disable_dpcd_training_pattern(intel_dp);
> >  
> > -	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
> > -				buf, len);
> > +	buf[0] = dp_train_pat;
> > +	/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> > +	memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
> > +	len = intel_dp->lane_count + 1;
> >  
> > -	return ret == len;
> > +	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
> > +				 buf, len) == len;
> >  }
> >  
> >  static bool
> > -- 
> > 2.17.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions
  2020-09-22 17:25         ` Imre Deak
@ 2020-09-22 17:44           ` Ville Syrjälä
  0 siblings, 0 replies; 27+ messages in thread
From: Ville Syrjälä @ 2020-09-22 17:44 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 08:25:35PM +0300, Imre Deak wrote:
> On Tue, Sep 22, 2020 at 07:49:17PM +0300, Ville Syrjälä wrote:
> > On Tue, Sep 22, 2020 at 06:30:35PM +0300, Imre Deak wrote:
> > > On Tue, Sep 22, 2020 at 04:27:05PM +0300, Ville Syrjälä wrote:
> > > > On Tue, Sep 22, 2020 at 03:51:02PM +0300, Imre Deak wrote:
> > > > > Split the prepare, link training, fallback-handling steps into their own
> > > > > functions for clarity and as a preparation for the upcoming LTTPR changes.
> > > > > 
> > > > > While at it also add some documentation to exported functions.
> > > > > 
> > > > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > > > ---
> > > > >  .../drm/i915/display/intel_dp_link_training.c | 80 ++++++++++++++-----
> > > > >  1 file changed, 62 insertions(+), 18 deletions(-)
> > > > > 
> > > > > 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 6d13d00db5e6..0c3809891bd2 100644
> > > > > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > > > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > > > @@ -162,14 +162,13 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
> > > > >  	return true;
> > > > >  }
> > > > >  
> > > > > -/* Enable corresponding port and start training pattern 1 */
> > > > > -static bool
> > > > > -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > > > +/*
> > > > > + * Prepare link training by configuring the link parameters and enabling the
> > > > > + * corresponding port.
> > > > > + */
> > > > > +static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
> > > > >  {
> > > > >  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > > > > -	u8 voltage;
> > > > > -	int voltage_tries, cr_tries, max_cr_tries;
> > > > > -	bool max_vswing_reached = false;
> > > > >  	u8 link_config[2];
> > > > >  	u8 link_bw, rate_select;
> > > > >  
> > > > > @@ -203,6 +202,16 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > > >  	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
> > > > >  
> > > > >  	intel_dp->DP |= DP_PORT_EN;
> > > > 
> > > > I guess we no longer actually enable the port here? The comment ^ still says
> > > > we do.
> > > > 
> > > > Hmm. Seems we do enable the port on ddi platforms, but not on older
> > > > platforms. I guess the docs could still use a tweak to reflect
> > > > reality a bit better.
> > > 
> > > Yes, missed the old platform part, will update the comment.
> > > 
> > > > 
> > > > > +}
> > > > > +
> > > > > +/* Perform the link training clock recovery phase using training pattern 1. */
> > > > > +static bool
> > > > > +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > > > +{
> > > > > +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > > > > +	u8 voltage;
> > > > > +	int voltage_tries, cr_tries, max_cr_tries;
> > > > > +	bool max_vswing_reached = false;
> > > > >  
> > > > >  	/* clock recovery */
> > > > >  	if (!intel_dp_reset_link_train(intel_dp,
> > > > > @@ -325,6 +334,10 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> > > > >  	return DP_TRAINING_PATTERN_2;
> > > > >  }
> > > > >  
> > > > > +/*
> > > > > + * Perform the link training channel equalization phase using one of training
> > > > > + * pattern 2, 3 or 4 depending on the the source and sink capabilities.
> > > > > + */
> > > > >  static bool
> > > > >  intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > > > >  {
> > > > > @@ -395,6 +408,15 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > > > >  
> > > > >  }
> > > > >  
> > > > > +/**
> > > > > + * intel_dp_stop_link_train - stop link training
> > > > > + * @intel_dp: DP struct
> > > > > + *
> > > > > + * Stop the link training of the @intel_dp port, programming the port to
> > > > > + * output an idle pattern 
> > > > 
> > > > I don't think we use the idle pattern on all platforms.
> > > 
> > > Yes, just DDI, this also needs a doc update.
> > > 
> > > > BTW intel_dp_set_idle_link_train() looks pretty pointless. Could just
> > > > inline it into its only caller, or at least move it into
> > > > intel_dp_link_training.c.
> > > 
> > > Ok, can unexport/inline it. Btw, this part made me wonder what's the
> > > exact reason for keeping the idle pattern output and corresponding DPCD
> > > programming separate, that is why can't we disable the training pattern
> > > in DPCD after intel_dp_set_idle_link_train()? That would make things
> > > more uniform on all platforms.
> > 
> > Hmm. I guess we're violating the DP spec a bit with the current
> > sequence:
> > "The Source device shall start sending the idle pattern after it has
> >  cleared the Training_Pattern byte in the DPCD"
> 
> Yep, that order sounds correct. In v2.0 3.6.6.6.10 End of Link Training
> suggests the current sequence though, but the sink should be able to
> handle the idle pattern after the sink reported symbol lock .
> 
> > Currently we start sending the idle pattern way earlier. And even
> > on platform where we don't send the idle pattern [1] we are disabling
> > the training pattern before we do the corresponding DPCD write.
> > 
> > So we may want to change the order to follow the spec.
> > 
> > [1] I guess the hw must send a few idle patterns automagically
> >     since IIRC the spec requires it?
> 
> Yes, the spec seems to require it (5.1.2). AFAICS (on g4x for instance)
> we have the pipe disabled when disabling training pattern generation, so
> I suppose the port would send idle patterns until enabling the pipe?

I think we enable the pipe before we do link training. That is,
link training happens in .enable() rather than .pre_enable().

I suspect we could send idle pattern explicitly on all platforms.
But IIRC the spec says to only use it when we're trying to sync
up multiple pipes (ie. port sync w/o actual hw port sync support),
which we don't support atm.

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern
  2020-09-22 17:41     ` Imre Deak
@ 2020-09-22 17:47       ` Ville Syrjälä
  2020-09-22 17:59         ` Imre Deak
  0 siblings, 1 reply; 27+ messages in thread
From: Ville Syrjälä @ 2020-09-22 17:47 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 08:41:28PM +0300, Imre Deak wrote:
> On Tue, Sep 22, 2020 at 07:54:20PM +0300, Ville Syrjälä wrote:
> > On Tue, Sep 22, 2020 at 03:51:03PM +0300, Imre Deak wrote:
> > > To prepare for a follow-up LTTPR change factor out a helper to disable
> > > the training pattern in DPCD. We'll need to do this for each LTTPR
> > > (without programming the port to output the idle pattern) when training
> > > in LTTPR non-transparent mode.
> > > 
> > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > ---
> > >  .../drm/i915/display/intel_dp_link_training.c | 28 +++++++++++--------
> > >  1 file changed, 16 insertions(+), 12 deletions(-)
> > > 
> > > 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 0c3809891bd2..6994a32244dc 100644
> > > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > @@ -102,30 +102,34 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> > >  		intel_dp->train_set[lane] = v | p;
> > >  }
> > >  
> > > +static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp)
> > > +{
> > > +	u8 val = DP_TRAINING_PATTERN_DISABLE;
> > > +
> > > +	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &val, 1) == 1;
> > > +}
> > 
> > 
> > > +
> > >  static bool
> > >  intel_dp_set_link_train(struct intel_dp *intel_dp,
> > >  			u8 dp_train_pat)
> > >  {
> > >  	u8 buf[sizeof(intel_dp->train_set) + 1];
> > > -	int ret, len;
> > > +	int len;
> > >  
> > >  	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
> > >  
> > > -	buf[0] = dp_train_pat;
> > >  	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
> > > -	    DP_TRAINING_PATTERN_DISABLE) {
> > > +	    DP_TRAINING_PATTERN_DISABLE)
> > >  		/* don't write DP_TRAINING_LANEx_SET on disable */
> > 
> > As mentioned in the other patch I think we're doing things in the wrong
> > order here. I suspect it'll be cleaner to just stop doing
> > intel_dp_set_link_train(DISABLE) entirely and just have a dedicated
> > function for disabling link training. We can then trivially do a
> > followup to swap the order of operations to match the spec.
> 
> intel_dp_disable_dpcd_training_pattern() would be needed after each
> LTTPR link training phase, where the port should not output idle
> patterns, that's the only reason for this change.
> 
> Do you mean to remove intel_dp_stop_link_train() then and do the idle
> pattern programming + corresponding DPCD training pattern disable
> programming at the end of the link training sequence (and remove the
> DP_TRAINING_PATTERN_DISABLE case handling from above)? I agree with
> that, but I see that too as a follow-up material (along with changing
> the order as you suggested).

Yeah, followup shuld be fine. I was just thinking of doing
s/intel_dp_set_link_train(DP_TRAINING_PATTERN_DISABLE)/intel_dp_set_normal_link_train()/
or
s/intel_dp_set_link_train(DP_TRAINING_PATTERN_DISABLE)/intel_dp_disable_link_train()/
or something along those lines.

-- 
Ville Syrjälä
Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern
  2020-09-22 17:47       ` Ville Syrjälä
@ 2020-09-22 17:59         ` Imre Deak
  0 siblings, 0 replies; 27+ messages in thread
From: Imre Deak @ 2020-09-22 17:59 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 08:47:56PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 22, 2020 at 08:41:28PM +0300, Imre Deak wrote:
> > On Tue, Sep 22, 2020 at 07:54:20PM +0300, Ville Syrjälä wrote:
> > > On Tue, Sep 22, 2020 at 03:51:03PM +0300, Imre Deak wrote:
> > > > To prepare for a follow-up LTTPR change factor out a helper to disable
> > > > the training pattern in DPCD. We'll need to do this for each LTTPR
> > > > (without programming the port to output the idle pattern) when training
> > > > in LTTPR non-transparent mode.
> > > > 
> > > > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > > > ---
> > > >  .../drm/i915/display/intel_dp_link_training.c | 28 +++++++++++--------
> > > >  1 file changed, 16 insertions(+), 12 deletions(-)
> > > > 
> > > > 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 0c3809891bd2..6994a32244dc 100644
> > > > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > > > @@ -102,30 +102,34 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> > > >  		intel_dp->train_set[lane] = v | p;
> > > >  }
> > > >  
> > > > +static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp)
> > > > +{
> > > > +	u8 val = DP_TRAINING_PATTERN_DISABLE;
> > > > +
> > > > +	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &val, 1) == 1;
> > > > +}
> > > 
> > > 
> > > > +
> > > >  static bool
> > > >  intel_dp_set_link_train(struct intel_dp *intel_dp,
> > > >  			u8 dp_train_pat)
> > > >  {
> > > >  	u8 buf[sizeof(intel_dp->train_set) + 1];
> > > > -	int ret, len;
> > > > +	int len;
> > > >  
> > > >  	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
> > > >  
> > > > -	buf[0] = dp_train_pat;
> > > >  	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
> > > > -	    DP_TRAINING_PATTERN_DISABLE) {
> > > > +	    DP_TRAINING_PATTERN_DISABLE)
> > > >  		/* don't write DP_TRAINING_LANEx_SET on disable */
> > > 
> > > As mentioned in the other patch I think we're doing things in the wrong
> > > order here. I suspect it'll be cleaner to just stop doing
> > > intel_dp_set_link_train(DISABLE) entirely and just have a dedicated
> > > function for disabling link training. We can then trivially do a
> > > followup to swap the order of operations to match the spec.
> > 
> > intel_dp_disable_dpcd_training_pattern() would be needed after each
> > LTTPR link training phase, where the port should not output idle
> > patterns, that's the only reason for this change.
> > 
> > Do you mean to remove intel_dp_stop_link_train() then and do the idle
> > pattern programming + corresponding DPCD training pattern disable
> > programming at the end of the link training sequence (and remove the
> > DP_TRAINING_PATTERN_DISABLE case handling from above)? I agree with
> > that, but I see that too as a follow-up material (along with changing
> > the order as you suggested).
> 
> Yeah, followup shuld be fine. I was just thinking of doing
> s/intel_dp_set_link_train(DP_TRAINING_PATTERN_DISABLE)/intel_dp_set_normal_link_train()/
> or
> s/intel_dp_set_link_train(DP_TRAINING_PATTERN_DISABLE)/intel_dp_disable_link_train()/
> or something along those lines.

Ok, that's simple enough, will do that instead in this patch.

> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Intel-gfx] [PATCH 7/7] drm/i915: Switch to LTTPR non-transparent mode link training
  2020-09-22 17:37   ` Ville Syrjälä
@ 2020-09-22 18:26     ` Imre Deak
  0 siblings, 0 replies; 27+ messages in thread
From: Imre Deak @ 2020-09-22 18:26 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

On Tue, Sep 22, 2020 at 08:37:44PM +0300, Ville Syrjälä wrote:
> On Tue, Sep 22, 2020 at 03:51:06PM +0300, Imre Deak wrote:
> > The DP Standard's recommendation is to use the LTTPR non-transparent
> > mode link training if LTTPRs are detected, so let's do this.
> > 
> > Besides power-saving, the advantages of this are that the maximum number
> > of LTTPRs can only be used in non-transparent mode (the limit is 5-8 in
> > transparent mode), and it provides a way to narrow down the reason for a
> > link training failure to a given link segment. Non-transparent mode is
> > probably also the mode that was tested the most by the industry.
> > 
> > The changes in this patchset:
> > - Pass the DP PHY that is currently link trained to all LT helpers, so
> >   that these can access the correct LTTPR/DPRX DPCD registers.
> > - During LT take into account the LTTPR common lane rate/count and the
> >   per LTTPR-PHY vswing/pre-emph limits.
> > - Switch to LTTPR non-transparent LT mode and train each link segment
> >   according to the sequence in DP Standard v2.0 (complete CR/EQ for
> >   each segment before continuing with the next segment).
> > 
> > Signed-off-by: Imre Deak <imre.deak@intel.com>
> > ---
> >  .../drm/i915/display/intel_display_types.h    |   1 +
> >  drivers/gpu/drm/i915/display/intel_dp.c       |  14 +-
> >  .../drm/i915/display/intel_dp_link_training.c | 374 +++++++++++++++---
> >  .../drm/i915/display/intel_dp_link_training.h |  10 +-
> >  4 files changed, 327 insertions(+), 72 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
> > index b04921eba73b..2fb4e9a6a316 100644
> > --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> > +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> > @@ -1281,6 +1281,7 @@ struct intel_dp {
> >  	u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
> >  	u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
> >  	u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
> > +	u8 lttpr_phy_caps[DP_MAX_LTTPR_COUNT][DP_LTTPR_PHY_CAP_SIZE];
> >  	u8 fec_capable;
> >  	/* source rates */
> >  	int num_source_rates;
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> > index d88f327aa9ef..54ad31044eef 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> > @@ -161,6 +161,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
> >  		162000, 270000, 540000, 810000
> >  	};
> >  	int i, max_rate;
> > +	int max_lttpr_rate;
> >  
> >  	if (drm_dp_has_quirk(&intel_dp->desc, 0,
> >  			     DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) {
> > @@ -174,6 +175,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
> >  	}
> >  
> >  	max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
> > +	max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps);
> > +	if (max_lttpr_rate)
> > +		max_rate = min(max_rate, max_lttpr_rate);
> >  
> >  	for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
> >  		if (dp_rates[i] > max_rate)
> > @@ -219,6 +223,10 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
> >  	int source_max = dig_port->max_lanes;
> >  	int sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
> >  	int fia_max = intel_tc_port_fia_max_lane_count(dig_port);
> > +	int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps);
> > +
> > +	if (lttpr_max)
> > +		sink_max = min(sink_max, lttpr_max);
> >  
> >  	return min3(source_max, sink_max, fia_max);
> >  }
> > @@ -5540,13 +5548,13 @@ void intel_dp_process_phy_request(struct intel_dp *intel_dp)
> >  		&intel_dp->compliance.test_data.phytest;
> >  	u8 link_status[DP_LINK_STATUS_SIZE];
> >  
> > -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > +	if (!intel_dp_get_link_status(intel_dp, DP_PHY_DPRX, link_status)) {
> >  		DRM_DEBUG_KMS("failed to get link status\n");
> >  		return;
> >  	}
> >  
> >  	/* retrieve vswing & pre-emphasis setting */
> > -	intel_dp_get_adjust_train(intel_dp, link_status);
> > +	intel_dp_get_adjust_train(intel_dp, DP_PHY_DPRX, link_status);
> >  
> >  	intel_dp_autotest_phy_ddi_disable(intel_dp);
> >  
> > @@ -5701,7 +5709,7 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> >  	if (intel_psr_enabled(intel_dp))
> >  		return false;
> >  
> > -	if (!intel_dp_get_link_status(intel_dp, link_status))
> > +	if (!intel_dp_get_link_status(intel_dp, DP_PHY_DPRX, link_status))
> 
> Should we check all repeaters here too perhaps?
> I guess that should be a followup if we need it.

Hm, yea, would be better even if only for debugging; otherwise DPRX should have
a bad link if an LTTPR does.

> 
> >  		return false;
> >  
> >  	/*
> > 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 1485602659be..3aa685a9aa2a 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
> > @@ -25,6 +25,8 @@
> >  #include "intel_dp.h"
> >  #include "intel_dp_link_training.h"
> >  
> > +#define DP_PHY_LTTPR(i)		(DP_PHY_LTTPR1 + (i))
> 
> Maybe just put that into drm_dp_helper.h?

Ok.

> 
> > +
> >  static void
> >  intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
> >  {
> > @@ -35,37 +37,140 @@ intel_dp_dump_link_status(const u8 link_status[DP_LINK_STATUS_SIZE])
> >  }
> >  
> >  /**
> > - * intel_dp_get_link_status - get the link status information for the DPRX
> > + * intel_dp_get_link_status - get the link status information for a DP PHY
> >   * @intel_dp: DP struct
> > + * @dp_phy: the DP PHY to get the link status for
> >   * @link_status: buffer to return the status in
> >   *
> > - * Fetch the AUX DPCD registers for the DPRX link status.
> > + * Fetch the AUX DPCD registers for the DPRX or an LTTPR PHY link status. The
> > + * layout of the returned @link_status matches the DPCD register layout of the
> > + * DPRX PHY link status.
> >   *
> >   * Returns true if the information was read successfully, false otherwise.
> >   */
> >  bool
> > -intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
> > +intel_dp_get_link_status(struct intel_dp *intel_dp,
> > +			 enum drm_dp_phy dp_phy,
> > +			 u8 link_status[DP_LINK_STATUS_SIZE])
> >  {
> > -	return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
> > -				DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
> > +	u8 lttpr_status[DP_LINK_STATUS_SIZE - 1];
> > +
> > +	if (dp_phy == DP_PHY_DPRX)
> > +		return drm_dp_dpcd_read(&intel_dp->aux,
> > +					DP_LANE0_1_STATUS,
> > +					link_status,
> > +					DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
> > +
> > +	if (drm_dp_dpcd_read(&intel_dp->aux,
> > +			     DP_LANE0_1_STATUS_PHY_REPEATER(dp_phy),
> > +			     lttpr_status,
> > +			     sizeof(lttpr_status)) != sizeof(lttpr_status))
> > +			return false;
> > +
> > +#define link_reg(reg)	link_status[(reg) - DP_LANE0_1_STATUS]
> > +#define lttpr_reg(reg)	lttpr_status[(reg) - DP_LANE0_1_STATUS_PHY_REPEATER1]
> > +
> > +	/* Convert the LTTPR to the sink PHY link status layout */
> > +	link_reg(DP_LANE0_1_STATUS) = lttpr_reg(DP_LANE0_1_STATUS_PHY_REPEATER1);
> > +	link_reg(DP_LANE2_3_STATUS) = lttpr_reg(DP_LANE2_3_STATUS_PHY_REPEATER1);
> > +	link_reg(DP_LANE_ALIGN_STATUS_UPDATED) =
> > +		lttpr_reg(DP_LANE_ALIGN_STATUS_UPDATED_PHY_REPEATER1);
> > +	link_reg(DP_SINK_STATUS) = 0;
> 
> So the difference is just the presence of the SINK_STATUS.
> Sad they couldn't be bothered to just stick a 0 placeholder
> there for lttprs.

Yes, could've been better designed.

> 
> > +	link_reg(DP_ADJUST_REQUEST_LANE0_1) =
> > +		lttpr_reg(DP_ADJUST_REQUEST_LANE0_1_PHY_REPEATER1);
> > +	link_reg(DP_ADJUST_REQUEST_LANE2_3) =
> > +		lttpr_reg(DP_ADJUST_REQUEST_LANE2_3_PHY_REPEATER1);
> > +
> > +#undef link_reg
> > +#undef lttpr_reg
> 
> Maybe this thing should be in the dp_helper as well? I could
> imagine other drivers wanting to do the same exactl thing

Ok, can add it to a new drm_dp_dpcd_read_phy_link_status() func, keeping the
exising users of drm_dp_dpcd_read_link_status() as-is.

> 
> > +
> > +	return true;
> > +}
> > +
> > +static int intel_dp_lttpr_count(struct intel_dp *intel_dp)
> > +{
> > +	int count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps);
> > +
> > +	/*
> > +	 * Pretend no LTTPRs in case of LTTPR detection error, or
> > +	 * if too many (>8) LTTPRs are detected. This translates to link
> > +	 * training in transparent mode.
> > +	 */
> > +	return count <= 0 ? 0 : count;
> > +}
> > +
> > +static const char *intel_dp_phy_name(enum drm_dp_phy dp_phy,
> > +				     char *buf, size_t buf_size)
> > +{
> > +	if (dp_phy == DP_PHY_DPRX)
> > +		snprintf(buf, buf_size, "DPRX");
> > +	else
> > +		snprintf(buf, buf_size, "LTTPR %d", dp_phy - DP_PHY_LTTPR1 + 1);
> > +
> > +	return buf;
> > +}
> > +
> > +static uint8_t *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp,
> > +					enum drm_dp_phy dp_phy)
> > +{
> > +	return &intel_dp->lttpr_phy_caps[dp_phy - DP_PHY_LTTPR1][0];
> 
> Why the &...[0] ?

Just didn't realize the two ways are equivalent. Will remove the &..[0].

> 
> >  }
> >  
> >  /**
> > - * intel_dp_read_lttpr_caps - read the LTTPR common capabilities
> > + * intel_dp_read_lttpr_caps - read the LTTPR common and per-PHY capabilities
> >   * @intel_dp: Intel DP struct
> >   *
> > - * Read the LTTPR common capabilities.
> > + * Read the LTTPR common capabilities and the PHY capabilities for all
> > + * detected LTTPRs. In case of an LTTPR detection error or if the number of
> > + * LTTPRs is more than is supported (8), fall back to the no-LTTPR,
> > + * transparent mode link training mode.
> >   */
> >  void intel_dp_read_lttpr_caps(struct intel_dp *intel_dp)
> >  {
> > +	int lttpr_count;
> > +	int i;
> > +
> >  	if (drm_dp_read_lttpr_common_caps(&intel_dp->aux,
> > -					  intel_dp->lttpr_common_caps) < 0)
> > +					  intel_dp->lttpr_common_caps) < 0) {
> > +		memset(intel_dp->lttpr_common_caps, 0,
> > +		       sizeof(intel_dp->lttpr_common_caps));
> >  		return;
> > +	}
> >  
> >  	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> >  		    "LTTPR common capabilities: %*ph\n",
> >  		    (int)sizeof(intel_dp->lttpr_common_caps),
> >  		    intel_dp->lttpr_common_caps);
> > +
> > +	lttpr_count = intel_dp_lttpr_count(intel_dp);
> > +	/*
> > +	 * In case of unsupported number of LTTPRs fall-back to transparent
> > +	 * link training mode, still taking into account any LTTPR common
> > +	 * lane- rate/count limits.
> > +	 */
> > +	if (lttpr_count <= 0)
> > +		return;
> > +
> > +	for (i = 0; i < lttpr_count; i++) {
> > +		enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
> > +		uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
> > +		char phy_name[10];
> > +
> > +		intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name));
> > +
> > +		if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) {
> > +			drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> > +				    "failed to read the PHY caps for %s\n",
> > +				    phy_name);
> > +			continue;
> > +		}
> > +
> > +		drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> > +			    "%s PHY capabilities: %*ph\n",
> > +			    phy_name,
> > +			    (int)sizeof(intel_dp->lttpr_phy_caps[0]),
> > +			    phy_caps);
> > +	}
> >  }
> >  
> >  static u8 dp_voltage_max(u8 preemph)
> > @@ -83,10 +188,78 @@ static u8 dp_voltage_max(u8 preemph)
> >  	}
> >  }
> >  
> > +static u8 intel_dp_lttpr_voltage_max(struct intel_dp *intel_dp,
> > +				     enum drm_dp_phy dp_phy)
> > +{
> > +	const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
> > +
> > +	if (drm_dp_lttpr_voltage_swing_level_3_supported(phy_caps))
> > +		return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
> > +	else
> > +		return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
> > +}
> > +
> > +static u8 intel_dp_lttpr_preemph_max(struct intel_dp *intel_dp,
> > +				     enum drm_dp_phy dp_phy)
> > +{
> > +	const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
> > +
> > +	if (drm_dp_lttpr_pre_emphasis_level_3_supported(phy_caps))
> > +		return DP_TRAIN_PRE_EMPH_LEVEL_3;
> > +	else
> > +		return DP_TRAIN_PRE_EMPH_LEVEL_2;
> > +}
> > +
> > +static u8 intel_dp_phy_voltage_max(struct intel_dp *intel_dp,
> > +				    enum drm_dp_phy dp_phy)
> > +{
> > +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > +	int lttpr_count = intel_dp_lttpr_count(intel_dp);
> > +	u8 voltage_max;
> > +
> > +	/*
> > +	 * Get voltage_max from the DPTX_PHY (source or LTTPR) upstream from
> > +	 * the DPRX_PHY we train.
> > +	 */
> > +	if (lttpr_count == 0 || dp_phy == DP_PHY_LTTPR(lttpr_count - 1))
> 
> phy_is_downstream_of_source() or somesuch helper maybe?
> There must be a better name than that though. But as usual
> I can't think of one right now.

Ok, can add an intel_dp_phy_is_downstream_of_source() helper.

> 
> > +		voltage_max = intel_dp->voltage_max(intel_dp);
> > +	else
> > +		voltage_max = intel_dp_lttpr_voltage_max(intel_dp, dp_phy + 1);
> > +
> > +	drm_WARN_ON_ONCE(&i915->drm,
> > +			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
> > +			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
> > +
> > +	return voltage_max;
> > +}
> > +
> > +static u8 intel_dp_phy_preemph_max(struct intel_dp *intel_dp,
> > +				   enum drm_dp_phy dp_phy)
> > +{
> > +	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> > +	int lttpr_count = intel_dp_lttpr_count(intel_dp);
> > +	u8 preemph_max;
> > +
> > +	/*
> > +	 * Get preemph_max from the DPTX_PHY (source or LTTPR) upstream from
> > +	 * the DPRX_PHY we train.
> > +	 */
> > +	if (lttpr_count == 0 || dp_phy == DP_PHY_LTTPR(lttpr_count - 1))
> > +		preemph_max = intel_dp->preemph_max(intel_dp);
> > +	else
> > +		preemph_max = intel_dp_lttpr_preemph_max(intel_dp, dp_phy + 1);
> > +
> > +	drm_WARN_ON_ONCE(&i915->drm,
> > +			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
> > +			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
> > +
> > +	return preemph_max;
> > +}
> > +
> >  void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> > +			       enum drm_dp_phy dp_phy,
> >  			       const u8 link_status[DP_LINK_STATUS_SIZE])
> >  {
> > -	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> >  	u8 v = 0;
> >  	u8 p = 0;
> >  	int lane;
> > @@ -98,21 +271,13 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> >  		p = max(p, drm_dp_get_adjust_request_pre_emphasis(link_status, lane));
> >  	}
> >  
> > -	preemph_max = intel_dp->preemph_max(intel_dp);
> > -	drm_WARN_ON_ONCE(&i915->drm,
> > -			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_2 &&
> > -			 preemph_max != DP_TRAIN_PRE_EMPH_LEVEL_3);
> > -
> > +	preemph_max = intel_dp_phy_preemph_max(intel_dp, dp_phy);
> >  	if (p >= preemph_max)
> >  		p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
> >  
> >  	v = min(v, dp_voltage_max(p));
> >  
> > -	voltage_max = intel_dp->voltage_max(intel_dp);
> > -	drm_WARN_ON_ONCE(&i915->drm,
> > -			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_2 &&
> > -			 voltage_max != DP_TRAIN_VOLTAGE_SWING_LEVEL_3);
> > -
> > +	voltage_max = intel_dp_phy_voltage_max(intel_dp, dp_phy);
> >  	if (v >= voltage_max)
> >  		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
> >  
> > @@ -120,17 +285,24 @@ void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> >  		intel_dp->train_set[lane] = v | p;
> >  }
> >  
> > -static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp)
> > +static bool intel_dp_disable_dpcd_training_pattern(struct intel_dp *intel_dp,
> > +						   enum drm_dp_phy dp_phy)
> >  {
> > +	int reg = dp_phy == DP_PHY_DPRX ?
> > +		DP_TRAINING_PATTERN_SET :
> > +		DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
> >  	u8 val = DP_TRAINING_PATTERN_DISABLE;
> >  
> > -	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, &val, 1) == 1;
> > +	return drm_dp_dpcd_write(&intel_dp->aux, reg, &val, 1) == 1;
> >  }
> >  
> >  static bool
> > -intel_dp_set_link_train(struct intel_dp *intel_dp,
> > +intel_dp_set_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
> >  			u8 dp_train_pat)
> >  {
> > +	int reg = dp_phy == DP_PHY_DPRX ?
> > +		DP_TRAINING_PATTERN_SET :
> > +		DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
> >  	u8 buf[sizeof(intel_dp->train_set) + 1];
> >  	int len;
> >  
> > @@ -139,34 +311,36 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
> >  	if ((dp_train_pat & ~DP_LINK_SCRAMBLING_DISABLE) ==
> >  	    DP_TRAINING_PATTERN_DISABLE)
> >  		/* don't write DP_TRAINING_LANEx_SET on disable */
> > -		return intel_dp_disable_dpcd_training_pattern(intel_dp);
> > +		return intel_dp_disable_dpcd_training_pattern(intel_dp, dp_phy);
> >  
> >  	buf[0] = dp_train_pat;
> >  	/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> >  	memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
> >  	len = intel_dp->lane_count + 1;
> >  
> > -	return drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
> > -				 buf, len) == len;
> > +	return drm_dp_dpcd_write(&intel_dp->aux, reg, buf, len) == len;
> >  }
> >  
> >  static bool
> > -intel_dp_reset_link_train(struct intel_dp *intel_dp,
> > +intel_dp_reset_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
> >  			u8 dp_train_pat)
> >  {
> >  	memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
> >  	intel_dp_set_signal_levels(intel_dp);
> > -	return intel_dp_set_link_train(intel_dp, dp_train_pat);
> > +	return intel_dp_set_link_train(intel_dp, dp_phy, dp_train_pat);
> >  }
> >  
> >  static bool
> > -intel_dp_update_link_train(struct intel_dp *intel_dp)
> > +intel_dp_update_link_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy)
> >  {
> > +	int reg = dp_phy == DP_PHY_DPRX ?
> > +		DP_TRAINING_LANE0_SET :
> > +		DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
> >  	int ret;
> >  
> >  	intel_dp_set_signal_levels(intel_dp);
> >  
> > -	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
> > +	ret = drm_dp_dpcd_write(&intel_dp->aux, reg,
> >  				intel_dp->train_set, intel_dp->lane_count);
> >  
> >  	return ret == intel_dp->lane_count;
> > @@ -226,9 +400,22 @@ static void intel_dp_prepare_link_train(struct intel_dp *intel_dp)
> >  	intel_dp->DP |= DP_PORT_EN;
> >  }
> >  
> > -/* Perform the link training clock recovery phase using training pattern 1. */
> > +static void intel_dp_link_training_clock_recovery_delay(struct intel_dp *intel_dp,
> > +							enum drm_dp_phy dp_phy)
> > +{
> > +	if (dp_phy == DP_PHY_DPRX)
> > +		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
> > +	else
> > +		drm_dp_lttpr_link_train_clock_recovery_delay();
> > +}
> > +
> > +/*
> > + * Perform the link training clock recovery phase on the given DP PHY using
> > + * training pattern 1.
> > + */
> >  static bool
> > -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp,
> > +				      enum drm_dp_phy dp_phy)
> >  {
> >  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> >  	u8 voltage;
> > @@ -236,7 +423,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> >  	bool max_vswing_reached = false;
> >  
> >  	/* clock recovery */
> > -	if (!intel_dp_reset_link_train(intel_dp,
> > +	if (!intel_dp_reset_link_train(intel_dp, dp_phy,
> >  				       DP_TRAINING_PATTERN_1 |
> >  				       DP_LINK_SCRAMBLING_DISABLE)) {
> >  		drm_err(&i915->drm, "failed to enable link training\n");
> > @@ -260,9 +447,9 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> >  	for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) {
> >  		u8 link_status[DP_LINK_STATUS_SIZE];
> >  
> > -		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
> > +		intel_dp_link_training_clock_recovery_delay(intel_dp, dp_phy);
> >  
> > -		if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > +		if (!intel_dp_get_link_status(intel_dp, dp_phy, link_status)) {
> >  			drm_err(&i915->drm, "failed to get link status\n");
> >  			return false;
> >  		}
> > @@ -286,8 +473,8 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> >  		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
> >  
> >  		/* Update training set as requested by target */
> > -		intel_dp_get_adjust_train(intel_dp, link_status);
> > -		if (!intel_dp_update_link_train(intel_dp)) {
> > +		intel_dp_get_adjust_train(intel_dp, dp_phy, link_status);
> > +		if (!intel_dp_update_link_train(intel_dp, dp_phy)) {
> >  			drm_err(&i915->drm,
> >  				"failed to update link training\n");
> >  			return false;
> > @@ -313,7 +500,8 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> >   * or for 1.4 devices that support it, training Pattern 3 for HBR2
> >   * or 1.2 devices that support it, Training Pattern 2 otherwise.
> >   */
> > -static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> > +static u32 intel_dp_training_pattern(struct intel_dp *intel_dp,
> > +				     enum drm_dp_phy dp_phy)
> >  {
> >  	bool source_tps3, sink_tps3, source_tps4, sink_tps4;
> >  
> > @@ -322,9 +510,11 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> >  	 * for all downstream devices that support HBR3. There are no known eDP
> >  	 * panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1
> >  	 * specification.
> > +	 * LTTPRs must support TPS4.
> >  	 */
> >  	source_tps4 = intel_dp_source_supports_hbr3(intel_dp);
> > -	sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd);
> > +	sink_tps4 = dp_phy != DP_PHY_DPRX ||
> > +		    drm_dp_tps4_supported(intel_dp->dpcd);
> >  	if (source_tps4 && sink_tps4) {
> >  		return DP_TRAINING_PATTERN_4;
> >  	} else if (intel_dp->link_rate == 810000) {
> > @@ -341,7 +531,8 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> >  	 * all sinks follow the spec.
> >  	 */
> >  	source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
> > -	sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
> > +	sink_tps3 = dp_phy != DP_PHY_DPRX ||
> > +		    drm_dp_tps3_supported(intel_dp->dpcd);
> >  	if (source_tps3 && sink_tps3) {
> >  		return  DP_TRAINING_PATTERN_3;
> >  	} else if (intel_dp->link_rate >= 540000) {
> > @@ -356,12 +547,27 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
> >  	return DP_TRAINING_PATTERN_2;
> >  }
> >  
> > +static void
> > +intel_dp_link_training_channel_equalization_delay(struct intel_dp *intel_dp,
> > +						  enum drm_dp_phy dp_phy)
> > +{
> > +	if (dp_phy == DP_PHY_DPRX) {
> > +		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> > +	} else {
> > +		const uint8_t *phy_caps = intel_dp_lttpr_phy_caps(intel_dp, dp_phy);
> > +
> > +		drm_dp_lttpr_link_train_channel_eq_delay(phy_caps);
> > +	}
> > +}
> > +
> >  /*
> > - * Perform the link training channel equalization phase using one of training
> > - * pattern 2, 3 or 4 depending on the the source and sink capabilities.
> > + * Perform the link training channel equalization phase on the given DP PHY
> > + * using one of training pattern 2, 3 or 4 depending on the the source and
> > + * sink capabilities.
> >   */
> >  static bool
> > -intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> > +intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp,
> > +					    enum drm_dp_phy dp_phy)
> >  {
> >  	struct drm_i915_private *i915 = dp_to_i915(intel_dp);
> >  	int tries;
> > @@ -369,22 +575,21 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  	u8 link_status[DP_LINK_STATUS_SIZE];
> >  	bool channel_eq = false;
> >  
> > -	training_pattern = intel_dp_training_pattern(intel_dp);
> > +	training_pattern = intel_dp_training_pattern(intel_dp, dp_phy);
> >  	/* Scrambling is disabled for TPS2/3 and enabled for TPS4 */
> >  	if (training_pattern != DP_TRAINING_PATTERN_4)
> >  		training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
> >  
> >  	/* channel equalization */
> > -	if (!intel_dp_set_link_train(intel_dp,
> > -				     training_pattern)) {
> > +	if (!intel_dp_set_link_train(intel_dp, dp_phy, training_pattern)) {
> >  		drm_err(&i915->drm, "failed to start channel equalization\n");
> >  		return false;
> >  	}
> >  
> >  	for (tries = 0; tries < 5; tries++) {
> > -
> > -		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> > -		if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > +		intel_dp_link_training_channel_equalization_delay(intel_dp,
> > +								  dp_phy);
> > +		if (!intel_dp_get_link_status(intel_dp, dp_phy, link_status)) {
> >  			drm_err(&i915->drm,
> >  				"failed to get link status\n");
> >  			break;
> > @@ -409,8 +614,8 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  		}
> >  
> >  		/* Update training set as requested by target */
> > -		intel_dp_get_adjust_train(intel_dp, link_status);
> > -		if (!intel_dp_update_link_train(intel_dp)) {
> > +		intel_dp_get_adjust_train(intel_dp, dp_phy, link_status);
> > +		if (!intel_dp_update_link_train(intel_dp, dp_phy)) {
> >  			drm_err(&i915->drm,
> >  				"failed to update link training\n");
> >  			break;
> > @@ -424,8 +629,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  			    "Channel equalization failed 5 times\n");
> >  	}
> >  
> > -	intel_dp_set_idle_link_train(intel_dp);
> > -
> >  	return channel_eq;
> >  
> >  }
> > @@ -442,34 +645,33 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> >  {
> >  	intel_dp->link_trained = true;
> > -
> > -	intel_dp_set_link_train(intel_dp,
> > +	intel_dp_set_link_train(intel_dp, DP_PHY_DPRX,
> >  				DP_TRAINING_PATTERN_DISABLE);
> >  }
> >  
> >  static bool
> > -intel_dp_link_train(struct intel_dp *intel_dp)
> > +intel_dp_link_train_phy(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy)
> >  {
> >  	struct intel_connector *intel_connector = intel_dp->attached_connector;
> > +	char phy_name[10];
> >  	bool ret = false;
> >  
> > -	intel_dp_prepare_link_train(intel_dp);
> > -
> > -	if (!intel_dp_link_training_clock_recovery(intel_dp))
> > +	if (!intel_dp_link_training_clock_recovery(intel_dp, dp_phy))
> >  		goto out;
> >  
> > -	if (!intel_dp_link_training_channel_equalization(intel_dp))
> > +	if (!intel_dp_link_training_channel_equalization(intel_dp, dp_phy))
> >  		goto out;
> >  
> >  	ret = true;
> >  
> >  out:
> >  	drm_dbg_kms(&dp_to_i915(intel_dp)->drm,
> > -		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d",
> > +		    "[CONNECTOR:%d:%s] Link Training %s at Link Rate = %d, Lane count = %d, at %s",
> >  		    intel_connector->base.base.id,
> >  		    intel_connector->base.name,
> >  		    ret ? "passed" : "failed",
> > -		    intel_dp->link_rate, intel_dp->lane_count);
> > +		    intel_dp->link_rate, intel_dp->lane_count,
> > +		    intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)));
> >  
> >  	return ret;
> >  }
> > @@ -492,6 +694,33 @@ static void intel_dp_schedule_fallback_link_training(struct intel_dp *intel_dp)
> >  	schedule_work(&intel_connector->modeset_retry_work);
> >  }
> >  
> > +/* Perform the link training on all LTTPRs and the DPRX on a link. */
> > +static bool
> > +intel_dp_link_train_all_phys(struct intel_dp *intel_dp, int lttpr_count)
> > +{
> > +	bool ret = true;
> > +	int i;
> > +
> > +	intel_dp_prepare_link_train(intel_dp);
> > +
> > +	for (i = lttpr_count - 1; i >= 0; i--) {
> > +		enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
> > +
> > +		ret = intel_dp_link_train_phy(intel_dp, dp_phy);
> > +		intel_dp_disable_dpcd_training_pattern(intel_dp, dp_phy);
> > +
> > +		if (!ret)
> > +			break;
> > +	}
> > +
> > +	if (ret)
> > +		intel_dp_link_train_phy(intel_dp, DP_PHY_DPRX);
> > +
> > +	intel_dp_set_idle_link_train(intel_dp);
> > +
> > +	return ret;
> > +}
> > +
> >  static bool
> >  intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
> >  {
> > @@ -501,10 +730,12 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable)
> >  	return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1;
> >  }
> >  
> > -static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
> > +static int intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
> >  {
> > +	int lttpr_count;
> > +
> >  	if (intel_dp_is_edp(intel_dp))
> > -		return;
> > +		return 0;
> >  
> >  	/*
> >  	 * TODO: the following re-reading of LTTPR caps can be removed
> > @@ -512,6 +743,19 @@ static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
> >  	 */
> >  	intel_dp_read_lttpr_caps(intel_dp);
> >  	intel_dp_set_lttpr_transparent_mode(intel_dp, true);
> > +
> > +	lttpr_count = intel_dp_lttpr_count(intel_dp);
> > +	if (lttpr_count) {
> > +		/*
> > +		 * If we can't set non-transparent mode fall-back to
> > +		 * transparent mode, still taking into account any LTTPR
> > +		 * common lane rate and count limits.
> > +		 */
> > +		if (!intel_dp_set_lttpr_transparent_mode(intel_dp, false))
> 
> Is there some magic to the double true+false transparent mode
> set here? Or just convenience?

Nope, v2.0 3.6.6.1 without explaining the reason:
"""
Before performing link training with LTTPR(s), the DPTX may place the LTTPR(s) in
Non-transparent mode by first writing 55h to the PHY_REPEATER_MODE register, and
then writing AAh.
"""

> 
> In general looks good, and didn't require too much rewriting which is
> nice.
> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> > +			lttpr_count = 0;
> > +	}
> > +
> > +	return lttpr_count;
> >  }
> >  
> >  /**
> > @@ -525,8 +769,8 @@ static void intel_dp_init_lttpr_mode(struct intel_dp *intel_dp)
> >   */
> >  void intel_dp_start_link_train(struct intel_dp *intel_dp)
> >  {
> > -	intel_dp_init_lttpr_mode(intel_dp);
> > +	int lttpr_count = intel_dp_init_lttpr_mode(intel_dp);
> >  
> > -	if (!intel_dp_link_train(intel_dp))
> > +	if (!intel_dp_link_train_all_phys(intel_dp, lttpr_count))
> >  		intel_dp_schedule_fallback_link_training(intel_dp);
> >  }
> > diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> > index c0be3ff709a0..d0393b76ffc1 100644
> > --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> > +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
> > @@ -10,12 +10,14 @@
> >  
> >  struct intel_dp;
> >  
> > -bool intel_dp_get_link_status(struct intel_dp *intel_dp,
> > -			      u8 link_status[DP_LINK_STATUS_SIZE]);
> > +bool
> > +intel_dp_get_link_status(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
> > +			 u8 link_status[DP_LINK_STATUS_SIZE]);
> >  void intel_dp_read_lttpr_caps(struct intel_dp *intel_dp);
> >  
> > -void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
> > -			       const u8 link_status[DP_LINK_STATUS_SIZE]);
> > +void
> > +intel_dp_get_adjust_train(struct intel_dp *intel_dp, enum drm_dp_phy dp_phy,
> > +			  const u8 link_status[DP_LINK_STATUS_SIZE]);
> >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> >  
> > -- 
> > 2.17.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> 
> -- 
> Ville Syrjälä
> Intel
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2020-09-22 18:27 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-22 12:50 [Intel-gfx] [PATCH 0/7] drm/i915: Add support for LTTPR non-transparent link training mode Imre Deak
2020-09-22 12:51 ` [Intel-gfx] [PATCH 1/7] drm/i915: Fix DP link training pattern mask Imre Deak
2020-09-22 13:13   ` Ville Syrjälä
2020-09-22 14:41     ` Imre Deak
2020-09-22 12:51 ` [Intel-gfx] [PATCH 2/7] drm/i915: Move intel_dp_get_link_status to intel_dp_link_training.c Imre Deak
2020-09-22 13:14   ` Ville Syrjälä
2020-09-22 14:45     ` Imre Deak
2020-09-22 12:51 ` [Intel-gfx] [PATCH 3/7] drm/i915: Simplify the link training functions Imre Deak
2020-09-22 13:27   ` Ville Syrjälä
2020-09-22 15:30     ` Imre Deak
2020-09-22 16:49       ` Ville Syrjälä
2020-09-22 17:25         ` Imre Deak
2020-09-22 17:44           ` Ville Syrjälä
2020-09-22 12:51 ` [Intel-gfx] [PATCH 4/7] drm/i915: Factor out a helper to disable the DPCD training pattern Imre Deak
2020-09-22 16:54   ` Ville Syrjälä
2020-09-22 17:41     ` Imre Deak
2020-09-22 17:47       ` Ville Syrjälä
2020-09-22 17:59         ` Imre Deak
2020-09-22 12:51 ` [Intel-gfx] [PATCH 5/7] drm/dp: Add LTTPR helpers Imre Deak
2020-09-22 12:51 ` [Intel-gfx] [PATCH 6/7] drm/i915: Switch to LTTPR transparent mode link training Imre Deak
2020-09-22 12:51 ` [Intel-gfx] [PATCH 7/7] drm/i915: Switch to LTTPR non-transparent " Imre Deak
2020-09-22 17:37   ` Ville Syrjälä
2020-09-22 18:26     ` Imre Deak
2020-09-22 13:00 ` [Intel-gfx] ✗ Fi.CI.CHECKPATCH: warning for drm/i915: Add support for LTTPR non-transparent link training mode Patchwork
2020-09-22 13:01 ` [Intel-gfx] ✗ Fi.CI.SPARSE: " Patchwork
2020-09-22 13:17 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2020-09-22 15:17 ` [Intel-gfx] ✗ Fi.CI.IGT: failure " Patchwork

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).