All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/14] Enable Upfront Link Training on DDI platforms
@ 2016-09-01 22:08 Manasi Navare
  2016-09-01 22:08 ` [PATCH v2 01/14] drm/i915: Don't pass crtc_state to intel_dp_set_link_params() Manasi Navare
                   ` (15 more replies)
  0 siblings, 16 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx

This patch series enables upfront link training on DDI platforms
(SKL/BDW/HSW/BXT) for DP SST and MST.
They are based on some of the patches submitted earlier by
Ander and Durgadoss.

The upfront link training had to be factored out of long pulse
hanlder because of deadlock issues seen on DP MST cases.
Now the upfront link training takes place in intel_dp_mode_valid()
to find the maximum lane count and link rate at which the DP link
can be successfully trained. These values are used to prune the
invalid modes before modeset. Modeset makes use the upfront lane
count and link train values.

These patches have been validated for DP SST on DDI platforms
(SKL/HSW/BDW/BXT). They have also been tested for any regressions
on non DDI platforms (CHV). 

The existing implementation of link training does not implement fallback
for link rate/lane count as per the DP spec.
This patch series adds fixes to the clock recovery and
Channel EQ sequences according to the DP Spec.
It also implements fallback loop to lower link rate
and lane count on CR and/or Channel EQ failures during link training.

Ander Conselvan de Oliveira (2):
  drm/i915: Don't pass crtc_state to intel_dp_set_link_params()
  drm/i915: Remove ddi_pll_sel from intel_crtc_state

Dhinakaran Pandiyan (2):
  drm/i915/dp: Move max. vswing check to it's own function
  drm/dp/i915: Make clock recovery in the link training compliant with
    DP Spec 1.2

Durgadoss R (2):
  drm/i915: Split bxt_ddi_pll_select()
  drm/i915/dp: Enable Upfront link training for typeC DP support on
    HSW/BDW/SKL/BXT (DDI platforms)

Jim Bride (3):
  drm/i915: Split skl_get_dpll()
  drm/i915/dp: Add a standalone function to obtain shared dpll for
    HSW/BDW/SKL/BXT
  drm/i915/dp/mst: Add support for upfront link training for DP MST

Manasi Navare (5):
  drm/i915: Split intel_ddi_pre_enable() into DP and HDMI versions
  drm/i915: Split hsw_get_dpll()
  drm/i915: Make DP link training channel equalization DP 1.2 Spec
    compliant
  drm/i915: Fallback to lower link rate and lane count during link
    training
  drm/i915: Reverse the loop in intel_dp_compute_config

 drivers/gpu/drm/i915/intel_ddi.c              | 283 +++++++++++++---
 drivers/gpu/drm/i915/intel_display.c          |  43 +--
 drivers/gpu/drm/i915/intel_dp.c               | 400 ++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp_link_training.c | 141 ++++----
 drivers/gpu/drm/i915/intel_dp_mst.c           |  71 +++-
 drivers/gpu/drm/i915/intel_dpll_mgr.c         | 454 ++++++++++++++++----------
 drivers/gpu/drm/i915/intel_dpll_mgr.h         |  15 +
 drivers/gpu/drm/i915/intel_drv.h              |  34 +-
 8 files changed, 973 insertions(+), 468 deletions(-)

-- 
1.9.1

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

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

* [PATCH v2 01/14] drm/i915: Don't pass crtc_state to intel_dp_set_link_params()
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-01 22:08 ` [PATCH v2 02/14] drm/i915: Remove ddi_pll_sel from intel_crtc_state Manasi Navare
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ander Conselvan de Oliveira

From: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>

Decouple intel_dp_set_link_params() from struct intel_crtc_state. This
will be useful for implementing DP upfront link training.

v2:
* Rebased on atomic state changes (Manasi)

Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c    |  5 ++++-
 drivers/gpu/drm/i915/intel_dp.c     | 14 +++++++++-----
 drivers/gpu/drm/i915/intel_dp_mst.c |  6 ++++--
 drivers/gpu/drm/i915/intel_drv.h    |  3 ++-
 4 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index ce369c2..d825b68 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1639,7 +1639,10 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
 
 		intel_prepare_dp_ddi_buffers(intel_encoder);
 
-		intel_dp_set_link_params(intel_dp, crtc->config);
+		intel_dp_set_link_params(intel_dp, crtc->config->port_clock,
+					 crtc->config->lane_count,
+					 intel_crtc_has_type(crtc->config,
+							     INTEL_OUTPUT_DP_MST));
 
 		intel_ddi_init_dp_buf_reg(intel_encoder);
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e4a2566..dfdbe65 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1641,11 +1641,12 @@ found:
 }
 
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
-			      const struct intel_crtc_state *pipe_config)
+			      int link_rate, uint8_t lane_count,
+			      bool link_mst)
 {
-	intel_dp->link_rate = pipe_config->port_clock;
-	intel_dp->lane_count = pipe_config->lane_count;
-	intel_dp->link_mst = intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST);
+	intel_dp->link_rate = link_rate;
+	intel_dp->lane_count = lane_count;
+	intel_dp->link_mst = link_mst;
 }
 
 static void intel_dp_prepare(struct intel_encoder *encoder,
@@ -1658,7 +1659,10 @@ static void intel_dp_prepare(struct intel_encoder *encoder,
 	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
 	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
 
-	intel_dp_set_link_params(intel_dp, pipe_config);
+	intel_dp_set_link_params(intel_dp, pipe_config->port_clock,
+				 pipe_config->lane_count,
+				 intel_crtc_has_type(pipe_config,
+						     INTEL_OUTPUT_DP_MST));
 
 	/*
 	 * There are four kinds of DP registers:
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 29ba4f6..b228b46 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -153,8 +153,10 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
 		intel_ddi_clk_select(&intel_dig_port->base, pipe_config);
 
 		intel_prepare_dp_ddi_buffers(&intel_dig_port->base);
-
-		intel_dp_set_link_params(intel_dp, pipe_config);
+		intel_dp_set_link_params(intel_dp,
+					 pipe_config->port_clock,
+					 pipe_config->lane_count,
+					 true);
 
 		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 570a7ca..44b0ec77 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1383,7 +1383,8 @@ bool intel_dp_init(struct drm_device *dev, i915_reg_t output_reg, enum port port
 bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 			     struct intel_connector *intel_connector);
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
-			      const struct intel_crtc_state *pipe_config);
+			      int link_rate, uint8_t lane_count,
+			      bool link_mst);
 void intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
-- 
1.9.1

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

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

* [PATCH v2 02/14] drm/i915: Remove ddi_pll_sel from intel_crtc_state
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
  2016-09-01 22:08 ` [PATCH v2 01/14] drm/i915: Don't pass crtc_state to intel_dp_set_link_params() Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-01 22:08 ` [PATCH v3 03/14] drm/i915: Split intel_ddi_pre_enable() into DP and HDMI versions Manasi Navare
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ander Conselvan de Oliveira

From: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>

The value of ddi_pll_sel is derived from the selection of shared dpll,
so just calculate the final value when necessary.

v2: Actually remove it from crtc state and delete remaining usages. (CI)

Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c      | 45 ++++++++++++++++++++++++++---------
 drivers/gpu/drm/i915/intel_display.c  | 43 +++++++--------------------------
 drivers/gpu/drm/i915/intel_dp_mst.c   |  3 ++-
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 27 ---------------------
 drivers/gpu/drm/i915/intel_drv.h      |  8 +------
 5 files changed, 45 insertions(+), 81 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index d825b68..f798760 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -546,6 +546,27 @@ static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv,
 	DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port));
 }
 
+static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
+{
+	switch (pll->id) {
+	case DPLL_ID_WRPLL1:
+		return PORT_CLK_SEL_WRPLL1;
+	case DPLL_ID_WRPLL2:
+		return PORT_CLK_SEL_WRPLL2;
+	case DPLL_ID_SPLL:
+		return PORT_CLK_SEL_SPLL;
+	case DPLL_ID_LCPLL_810:
+		return PORT_CLK_SEL_LCPLL_810;
+	case DPLL_ID_LCPLL_1350:
+		return PORT_CLK_SEL_LCPLL_1350;
+	case DPLL_ID_LCPLL_2700:
+		return PORT_CLK_SEL_LCPLL_2700;
+	default:
+		MISSING_CASE(pll->id);
+		return PORT_CLK_SEL_NONE;
+	}
+}
+
 /* Starting with Haswell, different DDI ports can work in FDI mode for
  * connection to the PCH-located connectors. For this, it is necessary to train
  * both the DDI port and PCH receiver for the desired DDI buffer settings.
@@ -561,7 +582,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct intel_encoder *encoder;
-	u32 temp, i, rx_ctl_val;
+	u32 temp, i, rx_ctl_val, ddi_pll_sel;
 
 	for_each_encoder_on_crtc(dev, crtc, encoder) {
 		WARN_ON(encoder->type != INTEL_OUTPUT_ANALOG);
@@ -592,8 +613,9 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
 	I915_WRITE(FDI_RX_CTL(PIPE_A), rx_ctl_val);
 
 	/* Configure Port Clock Select */
-	I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel);
-	WARN_ON(intel_crtc->config->ddi_pll_sel != PORT_CLK_SEL_SPLL);
+	ddi_pll_sel = hsw_pll_to_ddi_pll_sel(intel_crtc->config->shared_dpll);
+	I915_WRITE(PORT_CLK_SEL(PORT_E), ddi_pll_sel);
+	WARN_ON(ddi_pll_sel != PORT_CLK_SEL_SPLL);
 
 	/* Start the training iterating through available voltages and emphasis,
 	 * testing each value twice. */
@@ -870,7 +892,7 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder,
 	int link_clock = 0;
 	uint32_t dpll_ctl1, dpll;
 
-	dpll = pipe_config->ddi_pll_sel;
+	dpll = intel_get_shared_dpll_id(dev_priv, pipe_config->shared_dpll);
 
 	dpll_ctl1 = I915_READ(DPLL_CTRL1);
 
@@ -918,7 +940,7 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder,
 	int link_clock = 0;
 	u32 val, pll;
 
-	val = pipe_config->ddi_pll_sel;
+	val = hsw_pll_to_ddi_pll_sel(pipe_config->shared_dpll);
 	switch (val & PORT_CLK_SEL_MASK) {
 	case PORT_CLK_SEL_LCPLL_810:
 		link_clock = 81000;
@@ -1586,13 +1608,15 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp)
 }
 
 void intel_ddi_clk_select(struct intel_encoder *encoder,
-			  const struct intel_crtc_state *pipe_config)
+			  struct intel_shared_dpll *pll)
 {
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum port port = intel_ddi_get_encoder_port(encoder);
 
+	if (WARN_ON(!pll))
+		return;
+
 	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
-		uint32_t dpll = pipe_config->ddi_pll_sel;
 		uint32_t val;
 
 		/* DDI -> PLL mapping  */
@@ -1600,14 +1624,13 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
 
 		val &= ~(DPLL_CTRL2_DDI_CLK_OFF(port) |
 			DPLL_CTRL2_DDI_CLK_SEL_MASK(port));
-		val |= (DPLL_CTRL2_DDI_CLK_SEL(dpll, port) |
+		val |= (DPLL_CTRL2_DDI_CLK_SEL(pll->id, port) |
 			DPLL_CTRL2_DDI_SEL_OVERRIDE(port));
 
 		I915_WRITE(DPLL_CTRL2, val);
 
 	} else if (INTEL_INFO(dev_priv)->gen < 9) {
-		WARN_ON(pipe_config->ddi_pll_sel == PORT_CLK_SEL_NONE);
-		I915_WRITE(PORT_CLK_SEL(port), pipe_config->ddi_pll_sel);
+		I915_WRITE(PORT_CLK_SEL(port), hsw_pll_to_ddi_pll_sel(pll));
 	}
 }
 
@@ -1632,7 +1655,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
 		intel_edp_panel_on(intel_dp);
 	}
 
-	intel_ddi_clk_select(intel_encoder, crtc->config);
+	intel_ddi_clk_select(intel_encoder, crtc->config->shared_dpll);
 
 	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 19ffd02..6dda8f5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10432,15 +10432,12 @@ static void bxt_get_ddi_pll(struct drm_i915_private *dev_priv,
 
 	switch (port) {
 	case PORT_A:
-		pipe_config->ddi_pll_sel = SKL_DPLL0;
 		id = DPLL_ID_SKL_DPLL0;
 		break;
 	case PORT_B:
-		pipe_config->ddi_pll_sel = SKL_DPLL1;
 		id = DPLL_ID_SKL_DPLL1;
 		break;
 	case PORT_C:
-		pipe_config->ddi_pll_sel = SKL_DPLL2;
 		id = DPLL_ID_SKL_DPLL2;
 		break;
 	default:
@@ -10459,25 +10456,10 @@ static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
 	u32 temp;
 
 	temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
-	pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
+	id = temp >> (port * 3 + 1);
 
-	switch (pipe_config->ddi_pll_sel) {
-	case SKL_DPLL0:
-		id = DPLL_ID_SKL_DPLL0;
-		break;
-	case SKL_DPLL1:
-		id = DPLL_ID_SKL_DPLL1;
-		break;
-	case SKL_DPLL2:
-		id = DPLL_ID_SKL_DPLL2;
-		break;
-	case SKL_DPLL3:
-		id = DPLL_ID_SKL_DPLL3;
-		break;
-	default:
-		MISSING_CASE(pipe_config->ddi_pll_sel);
+	if (WARN_ON(id < SKL_DPLL0 || id > SKL_DPLL3))
 		return;
-	}
 
 	pipe_config->shared_dpll = intel_get_shared_dpll_by_id(dev_priv, id);
 }
@@ -10487,10 +10469,9 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
 				struct intel_crtc_state *pipe_config)
 {
 	enum intel_dpll_id id;
+	uint32_t ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
 
-	pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
-
-	switch (pipe_config->ddi_pll_sel) {
+	switch (ddi_pll_sel) {
 	case PORT_CLK_SEL_WRPLL1:
 		id = DPLL_ID_WRPLL1;
 		break;
@@ -10510,7 +10491,7 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
 		id = DPLL_ID_LCPLL_2700;
 		break;
 	default:
-		MISSING_CASE(pipe_config->ddi_pll_sel);
+		MISSING_CASE(ddi_pll_sel);
 		/* fall through */
 	case PORT_CLK_SEL_NONE:
 		return;
@@ -12794,10 +12775,9 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
 	DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide);
 
 	if (IS_BROXTON(dev)) {
-		DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x,"
+		DRM_DEBUG_KMS("dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x,"
 			      "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, "
 			      "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n",
-			      pipe_config->ddi_pll_sel,
 			      pipe_config->dpll_hw_state.ebb0,
 			      pipe_config->dpll_hw_state.ebb4,
 			      pipe_config->dpll_hw_state.pll0,
@@ -12810,15 +12790,13 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
 			      pipe_config->dpll_hw_state.pll10,
 			      pipe_config->dpll_hw_state.pcsdw12);
 	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
-		DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: "
+		DRM_DEBUG_KMS("dpll_hw_state: "
 			      "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n",
-			      pipe_config->ddi_pll_sel,
 			      pipe_config->dpll_hw_state.ctrl1,
 			      pipe_config->dpll_hw_state.cfgcr1,
 			      pipe_config->dpll_hw_state.cfgcr2);
 	} else if (HAS_DDI(dev)) {
-		DRM_DEBUG_KMS("ddi_pll_sel: 0x%x; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
-			      pipe_config->ddi_pll_sel,
+		DRM_DEBUG_KMS("dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
 			      pipe_config->dpll_hw_state.wrpll,
 			      pipe_config->dpll_hw_state.spll);
 	} else {
@@ -12931,7 +12909,6 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
 	struct intel_crtc_scaler_state scaler_state;
 	struct intel_dpll_hw_state dpll_hw_state;
 	struct intel_shared_dpll *shared_dpll;
-	uint32_t ddi_pll_sel;
 	bool force_thru;
 
 	/* FIXME: before the switch to atomic started, a new pipe_config was
@@ -12943,7 +12920,6 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
 	scaler_state = crtc_state->scaler_state;
 	shared_dpll = crtc_state->shared_dpll;
 	dpll_hw_state = crtc_state->dpll_hw_state;
-	ddi_pll_sel = crtc_state->ddi_pll_sel;
 	force_thru = crtc_state->pch_pfit.force_thru;
 
 	memset(crtc_state, 0, sizeof *crtc_state);
@@ -12952,7 +12928,6 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state)
 	crtc_state->scaler_state = scaler_state;
 	crtc_state->shared_dpll = shared_dpll;
 	crtc_state->dpll_hw_state = dpll_hw_state;
-	crtc_state->ddi_pll_sel = ddi_pll_sel;
 	crtc_state->pch_pfit.force_thru = force_thru;
 }
 
@@ -13375,8 +13350,6 @@ intel_pipe_config_compare(struct drm_device *dev,
 
 	PIPE_CONF_CHECK_I(double_wide);
 
-	PIPE_CONF_CHECK_X(ddi_pll_sel);
-
 	PIPE_CONF_CHECK_P(shared_dpll);
 	PIPE_CONF_CHECK_X(dpll_hw_state.dpll);
 	PIPE_CONF_CHECK_X(dpll_hw_state.dpll_md);
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index b228b46..54a9d76 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -150,7 +150,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
 	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
 
 	if (intel_dp->active_mst_links == 0) {
-		intel_ddi_clk_select(&intel_dig_port->base, pipe_config);
+		intel_ddi_clk_select(&intel_dig_port->base,
+				     pipe_config->shared_dpll);
 
 		intel_prepare_dp_ddi_buffers(&intel_dig_port->base);
 		intel_dp_set_link_params(intel_dp,
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index 655a5b3..caf5ad2 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -452,26 +452,6 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
 	return val & SPLL_PLL_ENABLE;
 }
 
-static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
-{
-	switch (pll->id) {
-	case DPLL_ID_WRPLL1:
-		return PORT_CLK_SEL_WRPLL1;
-	case DPLL_ID_WRPLL2:
-		return PORT_CLK_SEL_WRPLL2;
-	case DPLL_ID_SPLL:
-		return PORT_CLK_SEL_SPLL;
-	case DPLL_ID_LCPLL_810:
-		return PORT_CLK_SEL_LCPLL_810;
-	case DPLL_ID_LCPLL_1350:
-		return PORT_CLK_SEL_LCPLL_1350;
-	case DPLL_ID_LCPLL_2700:
-		return PORT_CLK_SEL_LCPLL_2700;
-	default:
-		return PORT_CLK_SEL_NONE;
-	}
-}
-
 #define LC_FREQ 2700
 #define LC_FREQ_2K U64_C(LC_FREQ * 2000)
 
@@ -751,8 +731,6 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	if (!pll)
 		return NULL;
 
-	crtc_state->ddi_pll_sel = hsw_pll_to_ddi_pll_sel(pll);
-
 	intel_reference_shared_dpll(pll, crtc_state);
 
 	return pll;
@@ -1274,8 +1252,6 @@ skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	if (!pll)
 		return NULL;
 
-	crtc_state->ddi_pll_sel = pll->id;
-
 	intel_reference_shared_dpll(pll, crtc_state);
 
 	return pll;
@@ -1628,9 +1604,6 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 
 	intel_reference_shared_dpll(pll, crtc_state);
 
-	/* shared DPLL id 0 is DPLL A */
-	crtc_state->ddi_pll_sel = pll->id;
-
 	return pll;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 44b0ec77..529fa7b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -590,12 +590,6 @@ struct intel_crtc_state {
 	/* Selected dpll when shared or NULL. */
 	struct intel_shared_dpll *shared_dpll;
 
-	/*
-	 * - PORT_CLK_SEL for DDI ports on HSW/BDW.
-	 * - enum skl_dpll on SKL
-	 */
-	uint32_t ddi_pll_sel;
-
 	/* Actual register state of the dpll, for shared dpll cross-checking. */
 	struct intel_dpll_hw_state dpll_hw_state;
 
@@ -1136,7 +1130,7 @@ void intel_crt_reset(struct drm_encoder *encoder);
 
 /* intel_ddi.c */
 void intel_ddi_clk_select(struct intel_encoder *encoder,
-			  const struct intel_crtc_state *pipe_config);
+			  struct intel_shared_dpll *pll);
 void intel_ddi_fdi_post_disable(struct intel_encoder *intel_encoder,
 				struct intel_crtc_state *old_crtc_state,
 				struct drm_connector_state *old_conn_state);
-- 
1.9.1

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

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

* [PATCH v3 03/14] drm/i915: Split intel_ddi_pre_enable() into DP and HDMI versions
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
  2016-09-01 22:08 ` [PATCH v2 01/14] drm/i915: Don't pass crtc_state to intel_dp_set_link_params() Manasi Navare
  2016-09-01 22:08 ` [PATCH v2 02/14] drm/i915: Remove ddi_pll_sel from intel_crtc_state Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-01 22:08 ` [PATCH v2 04/14] drm/i915: Split bxt_ddi_pll_select() Manasi Navare
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ander Conselvan de Oliveira

Split intel_ddi_pre_enable() into encoder type specific versions that
don't depend on crtc_state. The necessary parameters are passed as
function arguments. This split will be necessary for implementing DP
upfront link training.

v3:
* Rebased onto latest kernel (Manasi)
v2:
* Rebased onto kernel v4.7 (Jim)

Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c | 105 ++++++++++++++++++++++-----------------
 1 file changed, 60 insertions(+), 45 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index f798760..e4b875e 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1634,60 +1634,75 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
 	}
 }
 
-static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
-				 struct intel_crtc_state *pipe_config,
-				 struct drm_connector_state *conn_state)
+static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+				    int link_rate, uint32_t lane_count,
+				    struct intel_shared_dpll *pll,
+				    bool link_mst)
 {
-	struct drm_encoder *encoder = &intel_encoder->base;
-	struct drm_i915_private *dev_priv = to_i915(encoder->dev);
-	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
-	enum port port = intel_ddi_get_encoder_port(intel_encoder);
-	int type = intel_encoder->type;
-
-	if (type == INTEL_OUTPUT_HDMI) {
-		struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-
-		intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
-	}
+	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	enum port port = intel_ddi_get_encoder_port(encoder);
 
-	if (type == INTEL_OUTPUT_EDP) {
-		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
+				 link_mst);
+	if (encoder->type == INTEL_OUTPUT_EDP)
 		intel_edp_panel_on(intel_dp);
-	}
-
-	intel_ddi_clk_select(intel_encoder, crtc->config->shared_dpll);
-
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
-		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
-		intel_prepare_dp_ddi_buffers(intel_encoder);
-
-		intel_dp_set_link_params(intel_dp, crtc->config->port_clock,
-					 crtc->config->lane_count,
-					 intel_crtc_has_type(crtc->config,
-							     INTEL_OUTPUT_DP_MST));
+	intel_ddi_clk_select(encoder, pll);
+	intel_prepare_dp_ddi_buffers(encoder);
+	intel_ddi_init_dp_buf_reg(encoder);
+	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+	intel_dp_start_link_train(intel_dp);
+	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
+		intel_dp_stop_link_train(intel_dp);
+}
 
-		intel_ddi_init_dp_buf_reg(intel_encoder);
+static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
+				      bool has_hdmi_sink,
+				      struct drm_display_mode *adjusted_mode,
+				      struct intel_shared_dpll *pll)
+{
+	struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct drm_encoder *drm_encoder = &encoder->base;
+	enum port port = intel_ddi_get_encoder_port(encoder);
+	int level = intel_ddi_hdmi_level(dev_priv, port);
 
-		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
-		intel_dp_start_link_train(intel_dp);
-		if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
-			intel_dp_stop_link_train(intel_dp);
-	} else if (type == INTEL_OUTPUT_HDMI) {
-		struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
-		int level = intel_ddi_hdmi_level(dev_priv, port);
+	intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
+	intel_ddi_clk_select(encoder, pll);
+	intel_prepare_hdmi_ddi_buffers(encoder);
+	if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
+		skl_ddi_set_iboost(encoder, level);
+	else if (IS_BROXTON(dev_priv))
+		bxt_ddi_vswing_sequence(dev_priv, level, port,
+					INTEL_OUTPUT_HDMI);
 
-		intel_prepare_hdmi_ddi_buffers(intel_encoder);
+	intel_hdmi->set_infoframes(drm_encoder,
+				   has_hdmi_sink,
+				   adjusted_mode);
+}
 
-		if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv))
-			skl_ddi_set_iboost(intel_encoder, level);
-		else if (IS_BROXTON(dev_priv))
-			bxt_ddi_vswing_sequence(dev_priv, level, port,
-						INTEL_OUTPUT_HDMI);
+static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
+				 struct intel_crtc_state *pipe_config,
+				 struct drm_connector_state *conn_state)
+{
+	struct drm_encoder *encoder = &intel_encoder->base;
+	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
+	int type = intel_encoder->type;
 
-		intel_hdmi->set_infoframes(encoder,
-					   crtc->config->has_hdmi_sink,
-					   &crtc->config->base.adjusted_mode);
+	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+		intel_ddi_pre_enable_dp(intel_encoder,
+					crtc->config->port_clock,
+					crtc->config->lane_count,
+					crtc->config->shared_dpll,
+					intel_crtc_has_type(crtc->config,
+							    INTEL_OUTPUT_DP_MST));
+	}
+	if (type == INTEL_OUTPUT_HDMI) {
+		intel_ddi_pre_enable_hdmi(intel_encoder,
+					  crtc->config->has_hdmi_sink,
+					  &crtc->config->base.adjusted_mode,
+					  crtc->config->shared_dpll);
 	}
 }
 
-- 
1.9.1

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

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

* [PATCH v2 04/14] drm/i915: Split bxt_ddi_pll_select()
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (2 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH v3 03/14] drm/i915: Split intel_ddi_pre_enable() into DP and HDMI versions Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-01 22:08 ` [PATCH 05/14] drm/i915: Split skl_get_dpll() Manasi Navare
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx; +Cc: Ander Conselvan de Oliveira

From: Durgadoss R <durgadoss.r@intel.com>

Split out of bxt_ddi_pll_select() the logic that calculates the pll
dividers and dpll_hw_state into a new function that doesn't depend on
crtc state. This will be used for enabling the port pll when doing
upfront link training.

v2:
* Refactored code so that bxt_clk_div need not be exported (Durga)
v1:
* Rebased on top of intel_dpll_mgr.c (Durga)
* Initial version from Ander on top of intel_ddi.c

Reviewed-by: Manasi Navare <manasi.d.navare@intel.com>
Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
---
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 168 +++++++++++++++++++++-------------
 drivers/gpu/drm/i915/intel_dpll_mgr.h |   3 +
 2 files changed, 105 insertions(+), 66 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index caf5ad2..6fc32cf 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -1460,6 +1460,8 @@ struct bxt_clk_div {
 	uint32_t m2_frac;
 	bool m2_frac_en;
 	uint32_t n;
+
+	int vco;
 };
 
 /* pre-calculated values for DP linkrates */
@@ -1473,58 +1475,60 @@ static const struct bxt_clk_div bxt_dp_clk_val[] = {
 	{432000, 3, 1, 32, 1677722, 1, 1}
 };
 
-static struct intel_shared_dpll *
-bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
-	     struct intel_encoder *encoder)
+static bool
+bxt_ddi_hdmi_pll_dividers(struct intel_crtc *intel_crtc,
+			  struct intel_crtc_state *crtc_state, int clock,
+			  struct bxt_clk_div *clk_div)
 {
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	struct intel_shared_dpll *pll;
-	enum intel_dpll_id i;
-	struct intel_digital_port *intel_dig_port;
-	struct bxt_clk_div clk_div = {0};
-	int vco = 0;
-	uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
-	uint32_t lanestagger;
-	int clock = crtc_state->port_clock;
+	struct dpll best_clock;
 
-	if (encoder->type == INTEL_OUTPUT_HDMI) {
-		struct dpll best_clock;
+	/* Calculate HDMI div */
+	/*
+	 * FIXME: tie the following calculation into
+	 * i9xx_crtc_compute_clock
+	 */
+	if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
+		DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
+				 clock, pipe_name(intel_crtc->pipe));
+		return false;
+	}
 
-		/* Calculate HDMI div */
-		/*
-		 * FIXME: tie the following calculation into
-		 * i9xx_crtc_compute_clock
-		 */
-		if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
-			DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe %c\n",
-					 clock, pipe_name(crtc->pipe));
-			return NULL;
-		}
+	clk_div->p1 = best_clock.p1;
+	clk_div->p2 = best_clock.p2;
+	WARN_ON(best_clock.m1 != 2);
+	clk_div->n = best_clock.n;
+	clk_div->m2_int = best_clock.m2 >> 22;
+	clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1);
+	clk_div->m2_frac_en = clk_div->m2_frac != 0;
 
-		clk_div.p1 = best_clock.p1;
-		clk_div.p2 = best_clock.p2;
-		WARN_ON(best_clock.m1 != 2);
-		clk_div.n = best_clock.n;
-		clk_div.m2_int = best_clock.m2 >> 22;
-		clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1);
-		clk_div.m2_frac_en = clk_div.m2_frac != 0;
+	clk_div->vco = best_clock.vco;
 
-		vco = best_clock.vco;
-	} else if (encoder->type == INTEL_OUTPUT_DP ||
-		   encoder->type == INTEL_OUTPUT_EDP ||
-		   encoder->type == INTEL_OUTPUT_DP_MST) {
-		int i;
-
-		clk_div = bxt_dp_clk_val[0];
-		for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
-			if (bxt_dp_clk_val[i].clock == clock) {
-				clk_div = bxt_dp_clk_val[i];
-				break;
-			}
+	return true;
+}
+
+static void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div)
+{
+	int i;
+
+	*clk_div = bxt_dp_clk_val[0];
+	for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
+		if (bxt_dp_clk_val[i].clock == clock) {
+			*clk_div = bxt_dp_clk_val[i];
+			break;
 		}
-		vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2;
 	}
 
+	clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2;
+}
+
+static bool bxt_ddi_set_dpll_hw_state(int clock,
+			  struct bxt_clk_div *clk_div,
+			  struct intel_dpll_hw_state *dpll_hw_state)
+{
+	int vco = clk_div->vco;
+	uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
+	uint32_t lanestagger;
+
 	if (vco >= 6200000 && vco <= 6700000) {
 		prop_coef = 4;
 		int_coef = 9;
@@ -1543,12 +1547,9 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 		targ_cnt = 9;
 	} else {
 		DRM_ERROR("Invalid VCO\n");
-		return NULL;
+		return false;
 	}
 
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
 	if (clock > 270000)
 		lanestagger = 0x18;
 	else if (clock > 135000)
@@ -1560,33 +1561,68 @@ bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	else
 		lanestagger = 0x02;
 
-	crtc_state->dpll_hw_state.ebb0 =
-		PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2);
-	crtc_state->dpll_hw_state.pll0 = clk_div.m2_int;
-	crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n);
-	crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac;
+	dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div->p2);
+	dpll_hw_state->pll0 = clk_div->m2_int;
+	dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
+	dpll_hw_state->pll2 = clk_div->m2_frac;
 
-	if (clk_div.m2_frac_en)
-		crtc_state->dpll_hw_state.pll3 =
-			PORT_PLL_M2_FRAC_ENABLE;
+	if (clk_div->m2_frac_en)
+		dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
 
-	crtc_state->dpll_hw_state.pll6 =
-		prop_coef | PORT_PLL_INT_COEFF(int_coef);
-	crtc_state->dpll_hw_state.pll6 |=
-		PORT_PLL_GAIN_CTL(gain_ctl);
+	dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef);
+	dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl);
 
-	crtc_state->dpll_hw_state.pll8 = targ_cnt;
+	dpll_hw_state->pll8 = targ_cnt;
 
-	crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
+	dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
 
-	crtc_state->dpll_hw_state.pll10 =
+	dpll_hw_state->pll10 =
 		PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
 		| PORT_PLL_DCO_AMP_OVR_EN_H;
 
-	crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
+	dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
+
+	dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
+
+	return true;
+}
+
+bool bxt_ddi_dp_set_dpll_hw_state(int clock,
+			  struct intel_dpll_hw_state *dpll_hw_state)
+{
+	struct bxt_clk_div clk_div = {0};
+
+	bxt_ddi_dp_pll_dividers(clock, &clk_div);
+
+	return bxt_ddi_set_dpll_hw_state(clock, &clk_div, dpll_hw_state);
+}
+
+static struct intel_shared_dpll *
+bxt_get_dpll(struct intel_crtc *crtc,
+		struct intel_crtc_state *crtc_state,
+		struct intel_encoder *encoder)
+{
+	struct bxt_clk_div clk_div = {0};
+	struct intel_dpll_hw_state dpll_hw_state = {0};
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	struct intel_digital_port *intel_dig_port;
+	struct intel_shared_dpll *pll;
+	int i, clock = crtc_state->port_clock;
+
+	if (encoder->type == INTEL_OUTPUT_HDMI
+	    && !bxt_ddi_hdmi_pll_dividers(crtc, crtc_state,
+					  clock, &clk_div))
+		return false;
+
+	if ((encoder->type == INTEL_OUTPUT_DP ||
+	     encoder->type == INTEL_OUTPUT_EDP) &&
+	    !bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
+		return false;
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
 
-	crtc_state->dpll_hw_state.pcsdw12 =
-		LANESTAGGER_STRAP_OVRD | lanestagger;
+	crtc_state->dpll_hw_state = dpll_hw_state;
 
 	if (encoder->type == INTEL_OUTPUT_DP_MST) {
 		struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
index 89c5ada..11a85a5 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
@@ -160,5 +160,8 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc);
 void intel_shared_dpll_commit(struct drm_atomic_state *state);
 void intel_shared_dpll_init(struct drm_device *dev);
 
+/* BXT dpll related functions */
+bool bxt_ddi_dp_set_dpll_hw_state(int clock,
+			  struct intel_dpll_hw_state *dpll_hw_state);
 
 #endif /* _INTEL_DPLL_MGR_H_ */
-- 
1.9.1

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

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

* [PATCH 05/14] drm/i915: Split skl_get_dpll()
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (3 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH v2 04/14] drm/i915: Split bxt_ddi_pll_select() Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-01 22:08 ` [PATCH 06/14] drm/i915: Split hsw_get_dpll() Manasi Navare
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx

From: Jim Bride <jim.bride@linux.intel.com>

Split out the DisplayPort and HDMI pll setup code into separate
functions and refactor the DP code does not directly depend on
crtc state, so that the code can be used for upfront link training.

Reviewed-by: Manasi Navare <manasi.d.navare@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 131 +++++++++++++++++++++-------------
 drivers/gpu/drm/i915/intel_dpll_mgr.h |   4 ++
 2 files changed, 87 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index 6fc32cf..c6d6895 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -1172,75 +1172,110 @@ skip_remaining_dividers:
 	return true;
 }
 
-static struct intel_shared_dpll *
-skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
-	     struct intel_encoder *encoder)
+static bool skl_ddi_hdmi_pll_dividers(struct intel_crtc *crtc,
+				      struct intel_crtc_state *crtc_state,
+				      int clock)
 {
-	struct intel_shared_dpll *pll;
 	uint32_t ctrl1, cfgcr1, cfgcr2;
-	int clock = crtc_state->port_clock;
+	struct skl_wrpll_params wrpll_params = { 0, };
 
 	/*
 	 * See comment in intel_dpll_hw_state to understand why we always use 0
 	 * as the DPLL id in this function.
 	 */
-
 	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
 
-	if (encoder->type == INTEL_OUTPUT_HDMI) {
-		struct skl_wrpll_params wrpll_params = { 0, };
+	ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
 
-		ctrl1 |= DPLL_CTRL1_HDMI_MODE(0);
+	if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
+		return false;
 
-		if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params))
-			return NULL;
+	cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
+		DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
+		wrpll_params.dco_integer;
+
+	cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
+		DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
+		DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
+		DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
+		wrpll_params.central_freq;
+
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
+	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
+	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
+	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
+	return true;
+}
+
+
+bool skl_ddi_dp_set_dpll_hw_state(int clock,
+				  struct intel_dpll_hw_state *dpll_hw_state)
+{
+	uint32_t ctrl1;
+
+	/*
+	 * See comment in intel_dpll_hw_state to understand why we always use 0
+	 * as the DPLL id in this function.
+	 */
+	ctrl1 = DPLL_CTRL1_OVERRIDE(0);
+	switch (clock / 2) {
+	case 81000:
+		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
+		break;
+	case 135000:
+		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
+		break;
+	case 270000:
+		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
+		break;
+		/* eDP 1.4 rates */
+	case 162000:
+		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
+		break;
+	case 108000:
+		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
+		break;
+	case 216000:
+		ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
+		break;
+	}
 
-		cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE |
-			 DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) |
-			 wrpll_params.dco_integer;
+	dpll_hw_state->ctrl1 = ctrl1;
+	return true;
+}
 
-		cfgcr2 = DPLL_CFGCR2_QDIV_RATIO(wrpll_params.qdiv_ratio) |
-			 DPLL_CFGCR2_QDIV_MODE(wrpll_params.qdiv_mode) |
-			 DPLL_CFGCR2_KDIV(wrpll_params.kdiv) |
-			 DPLL_CFGCR2_PDIV(wrpll_params.pdiv) |
-			 wrpll_params.central_freq;
+static struct intel_shared_dpll *
+skl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
+	     struct intel_encoder *encoder)
+{
+	struct intel_shared_dpll *pll;
+	int clock = crtc_state->port_clock;
+	bool bret;
+	struct intel_dpll_hw_state dpll_hw_state;
+
+	memset(&dpll_hw_state, 0, sizeof(dpll_hw_state));
+
+	if (encoder->type == INTEL_OUTPUT_HDMI) {
+		bret = skl_ddi_hdmi_pll_dividers(crtc, crtc_state, clock);
+		if (!bret) {
+			DRM_DEBUG_KMS("Could not get HDMI pll dividers.\n");
+			return NULL;
+		}
 	} else if (encoder->type == INTEL_OUTPUT_DP ||
 		   encoder->type == INTEL_OUTPUT_DP_MST ||
 		   encoder->type == INTEL_OUTPUT_EDP) {
-		switch (crtc_state->port_clock / 2) {
-		case 81000:
-			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0);
-			break;
-		case 135000:
-			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0);
-			break;
-		case 270000:
-			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0);
-			break;
-		/* eDP 1.4 rates */
-		case 162000:
-			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1620, 0);
-			break;
-		case 108000:
-			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1080, 0);
-			break;
-		case 216000:
-			ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2160, 0);
-			break;
+		bret = skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state);
+		if (!bret) {
+			DRM_DEBUG_KMS("Could not set DP dpll HW state.\n");
+			return NULL;
 		}
-
-		cfgcr1 = cfgcr2 = 0;
+		crtc_state->dpll_hw_state = dpll_hw_state;
 	} else {
 		return NULL;
 	}
 
-	memset(&crtc_state->dpll_hw_state, 0,
-	       sizeof(crtc_state->dpll_hw_state));
-
-	crtc_state->dpll_hw_state.ctrl1 = ctrl1;
-	crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
-	crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
-
 	if (encoder->type == INTEL_OUTPUT_EDP)
 		pll = intel_find_shared_dpll(crtc, crtc_state,
 					     DPLL_ID_SKL_DPLL0,
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
index 11a85a5..cb28f8d 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
@@ -164,4 +164,8 @@ void intel_shared_dpll_init(struct drm_device *dev);
 bool bxt_ddi_dp_set_dpll_hw_state(int clock,
 			  struct intel_dpll_hw_state *dpll_hw_state);
 
+/* SKL dpll related functions */
+bool skl_ddi_dp_set_dpll_hw_state(int clock,
+				  struct intel_dpll_hw_state *dpll_hw_state);
+
 #endif /* _INTEL_DPLL_MGR_H_ */
-- 
1.9.1

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

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

* [PATCH 06/14] drm/i915: Split hsw_get_dpll()
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (4 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH 05/14] drm/i915: Split skl_get_dpll() Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-01 22:08 ` [PATCH v3 07/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT Manasi Navare
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx

Split out the DisplayPort and HDMI pll setup code into separate
functions and refactor the DP code that calculates the pll
so that it doesn't depend on crtc state.
This will be used for acquiring port pll when doing
upfront link training.

Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 90 ++++++++++++++++++++++-------------
 drivers/gpu/drm/i915/intel_dpll_mgr.h |  6 +++
 2 files changed, 63 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index c6d6895..9a1da98 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -667,11 +667,65 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
 	*r2_out = best.r2;
 }
 
+static struct intel_shared_dpll *hsw_ddi_hdmi_get_dpll(int clock,
+						       struct intel_crtc *crtc,
+						       struct intel_crtc_state *crtc_state)
+{
+	struct intel_shared_dpll *pll;
+	uint32_t val;
+	unsigned int p, n2, r2;
+
+	hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
+
+	val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
+	      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
+	      WRPLL_DIVIDER_POST(p);
+
+	crtc_state->dpll_hw_state.wrpll = val;
+
+	pll = intel_find_shared_dpll(crtc, crtc_state,
+				     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
+
+	if (!pll)
+		return NULL;
+
+	return pll;
+}
+
+struct intel_shared_dpll *hsw_ddi_dp_get_dpll(struct intel_encoder *encoder,
+					      int clock)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll *pll;
+	enum intel_dpll_id pll_id;
+
+	switch (clock / 2) {
+	case 81000:
+		pll_id = DPLL_ID_LCPLL_810;
+		break;
+	case 135000:
+		pll_id = DPLL_ID_LCPLL_1350;
+		break;
+	case 270000:
+		pll_id = DPLL_ID_LCPLL_2700;
+		break;
+	default:
+		DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
+		return NULL;
+	}
+
+	pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
+
+	if (!pll)
+		return NULL;
+
+	return pll;
+}
+
 static struct intel_shared_dpll *
 hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	     struct intel_encoder *encoder)
 {
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	struct intel_shared_dpll *pll;
 	int clock = crtc_state->port_clock;
 
@@ -679,41 +733,12 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	       sizeof(crtc_state->dpll_hw_state));
 
 	if (encoder->type == INTEL_OUTPUT_HDMI) {
-		uint32_t val;
-		unsigned p, n2, r2;
-
-		hsw_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
-
-		val = WRPLL_PLL_ENABLE | WRPLL_PLL_LCPLL |
-		      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
-		      WRPLL_DIVIDER_POST(p);
-
-		crtc_state->dpll_hw_state.wrpll = val;
-
-		pll = intel_find_shared_dpll(crtc, crtc_state,
-					     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
+		pll = hsw_ddi_hdmi_get_dpll(clock, crtc, crtc_state);
 
 	} else if (encoder->type == INTEL_OUTPUT_DP ||
 		   encoder->type == INTEL_OUTPUT_DP_MST ||
 		   encoder->type == INTEL_OUTPUT_EDP) {
-		enum intel_dpll_id pll_id;
-
-		switch (clock / 2) {
-		case 81000:
-			pll_id = DPLL_ID_LCPLL_810;
-			break;
-		case 135000:
-			pll_id = DPLL_ID_LCPLL_1350;
-			break;
-		case 270000:
-			pll_id = DPLL_ID_LCPLL_2700;
-			break;
-		default:
-			DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
-			return NULL;
-		}
-
-		pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
+		pll = hsw_ddi_dp_get_dpll(encoder, clock);
 
 	} else if (encoder->type == INTEL_OUTPUT_ANALOG) {
 		if (WARN_ON(crtc_state->port_clock / 2 != 135000))
@@ -736,7 +761,6 @@ hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	return pll;
 }
 
-
 static const struct intel_shared_dpll_funcs hsw_ddi_wrpll_funcs = {
 	.enable = hsw_ddi_wrpll_enable,
 	.disable = hsw_ddi_wrpll_disable,
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
index cb28f8d..aed7408 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
@@ -164,8 +164,14 @@ void intel_shared_dpll_init(struct drm_device *dev);
 bool bxt_ddi_dp_set_dpll_hw_state(int clock,
 			  struct intel_dpll_hw_state *dpll_hw_state);
 
+
 /* SKL dpll related functions */
 bool skl_ddi_dp_set_dpll_hw_state(int clock,
 				  struct intel_dpll_hw_state *dpll_hw_state);
 
+
+/* HSW dpll related functions */
+struct intel_shared_dpll *hsw_ddi_dp_get_dpll(struct intel_encoder *encoder,
+					      int clock);
+
 #endif /* _INTEL_DPLL_MGR_H_ */
-- 
1.9.1

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

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

* [PATCH v3 07/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (5 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH 06/14] drm/i915: Split hsw_get_dpll() Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-02 20:06   ` Pandiyan, Dhinakaran
  2016-09-07 22:47   ` [PATCH v4 7/14] " Manasi Navare
  2016-09-01 22:08 ` [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function Manasi Navare
                   ` (8 subsequent siblings)
  15 siblings, 2 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx

From: Jim Bride <jim.bride@linux.intel.com>

Add the PLL selection code for HSW/BDW/BXT/SKL into a stand-alone function
in order to allow for the implementation of a platform neutral upfront
link training function.

v3:
* Add Hooks for all DDI platforms into this standalone function

v2:
* Change the macro to use dev_priv instead of dev (David Weinehall)

Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c      | 38 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 38 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_dpll_mgr.h |  2 ++
 drivers/gpu/drm/i915/intel_drv.h      |  3 ++-
 4 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e4b875e..67a6a0b 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2393,6 +2393,44 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
 	return connector;
 }
 
+struct intel_shared_dpll *
+intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct intel_encoder *encoder = connector->encoder;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct intel_shared_dpll *pll = NULL;
+	struct intel_shared_dpll_config tmp_pll_config;
+	enum intel_dpll_id dpll_id;
+
+	if (IS_BROXTON(dev_priv)) {
+		dpll_id =  (enum intel_dpll_id)dig_port->port;
+		/*
+		 * Select the required PLL. This works for platforms where
+		 * there is no shared DPLL.
+		 */
+		pll = &dev_priv->shared_dplls[dpll_id];
+		if (WARN_ON(pll->active_mask)) {
+
+			DRM_ERROR("Shared DPLL in use. active_mask:%x\n",
+				  pll->active_mask);
+			pll = NULL;
+		}
+		tmp_pll_config = pll->config;
+		if (!bxt_ddi_dp_set_dpll_hw_state(clock,
+						  &pll->config.hw_state)) {
+			DRM_ERROR("Could not setup DPLL\n");
+			pll->config = tmp_pll_config;
+		}
+	} else if (IS_SKYLAKE(dev_priv)) {
+		pll = skl_find_link_pll(dev_priv, clock);
+	} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
+		pll = hsw_ddi_dp_get_dpll(encoder, clock);
+	}
+	return pll;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index 9a1da98..4b067ac 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -24,6 +24,44 @@
 #include "intel_drv.h"
 
 struct intel_shared_dpll *
+skl_find_link_pll(struct drm_i915_private *dev_priv, int clock)
+{
+	struct intel_shared_dpll *pll = NULL;
+	struct intel_dpll_hw_state dpll_hw_state;
+	enum intel_dpll_id i;
+	bool found = false;
+
+	if (!skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
+		return pll;
+
+	for (i = DPLL_ID_SKL_DPLL1; i <= DPLL_ID_SKL_DPLL3; i++) {
+		pll = &dev_priv->shared_dplls[i];
+
+		/* Only want to check enabled timings first */
+		if (pll->config.crtc_mask == 0)
+			continue;
+
+		if (memcmp(&dpll_hw_state, &pll->config.hw_state,
+			   sizeof(pll->config.hw_state)) == 0) {
+			found = true;
+			break;
+		}
+	}
+
+	/* Ok no matching timings, maybe there's a free one? */
+	for (i = DPLL_ID_SKL_DPLL1;
+	     ((found == false) && (i <= DPLL_ID_SKL_DPLL3)); i++) {
+		pll = &dev_priv->shared_dplls[i];
+		if (pll->config.crtc_mask == 0) {
+			pll->config.hw_state = dpll_hw_state;
+			break;
+		}
+	}
+
+	return pll;
+}
+
+struct intel_shared_dpll *
 intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
 			    enum intel_dpll_id id)
 {
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
index aed7408..f438535 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
@@ -168,6 +168,8 @@ bool bxt_ddi_dp_set_dpll_hw_state(int clock,
 /* SKL dpll related functions */
 bool skl_ddi_dp_set_dpll_hw_state(int clock,
 				  struct intel_dpll_hw_state *dpll_hw_state);
+struct intel_shared_dpll *skl_find_link_pll(struct drm_i915_private *dev_priv,
+					    int clock);
 
 
 /* HSW dpll related functions */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 529fa7b..efcd80b 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1159,7 +1159,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
-
+struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
+						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
 				   unsigned int height,
 				   uint32_t pixel_format,
-- 
1.9.1

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

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

* [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (6 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH v3 07/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-02  8:05   ` Mika Kahola
  2016-09-07  0:13   ` [PATCH v2 8/14] " Manasi Navare
  2016-09-01 22:08 ` [PATCH 09/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2 Manasi Navare
                   ` (7 subsequent siblings)
  15 siblings, 2 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan

From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

Wrap the max. vswing check in a separate function.
This makes the clock recovery phase of DP link training cleaner

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
---
 drivers/gpu/drm/i915/intel_dp_link_training.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 0deebed..9145e5a 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -112,6 +112,17 @@ intel_dp_update_link_train(struct intel_dp *intel_dp)
 	return ret == intel_dp->lane_count;
 }
 
+static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
+{
+	int lane;
+
+	for (lane = 0; lane < intel_dp->lane_count; lane++)
+		if (intel_dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED == 0)
+			return false;
+
+	return true;
+}
+
 /* Enable corresponding port and start training pattern 1 */
 static void
 intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
@@ -170,10 +181,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 		}
 
 		/* Check to see if we've tried the max voltage */
-		for (i = 0; i < intel_dp->lane_count; i++)
-			if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
-				break;
-		if (i == intel_dp->lane_count) {
+		if (intel_dp_link_max_vswing_reached(intel_dp)) {
 			++loop_tries;
 			if (loop_tries == 5) {
 				DRM_ERROR("too many full retries, give up\n");
-- 
1.9.1

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

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

* [PATCH 09/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (7 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-02  9:16   ` Mika Kahola
  2016-09-07  0:13   ` [PATCH v2 9/14] " Manasi Navare
  2016-09-01 22:08 ` [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant Manasi Navare
                   ` (6 subsequent siblings)
  15 siblings, 2 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan

From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

This function cleans up clock recovery loop in link training compliant
tp Dp Spec 1.2. It tries the clock recovery 5 times for the same voltage
or until max voltage swing is reached and removes the additional non
compliant retries. This function now returns a boolean values based on
if clock recovery passed or failed.

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
---
 drivers/gpu/drm/i915/intel_dp_link_training.c | 59 ++++++++++++---------------
 1 file changed, 26 insertions(+), 33 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 9145e5a..13a0341 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -117,19 +117,19 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
 	int lane;
 
 	for (lane = 0; lane < intel_dp->lane_count; lane++)
-		if (intel_dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED == 0)
+		if ((intel_dp->train_set[lane] &
+		     DP_TRAIN_MAX_SWING_REACHED) == 0)
 			return false;
 
 	return true;
 }
 
 /* Enable corresponding port and start training pattern 1 */
-static void
+static bool
 intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 {
-	int i;
 	uint8_t voltage;
-	int voltage_tries, loop_tries;
+	int voltage_tries, max_vswing_tries;
 	uint8_t link_config[2];
 	uint8_t link_bw, rate_select;
 
@@ -145,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
 		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
 	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+
 	if (intel_dp->num_sink_rates)
 		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
 				  &rate_select, 1);
@@ -160,58 +161,50 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 				       DP_TRAINING_PATTERN_1 |
 				       DP_LINK_SCRAMBLING_DISABLE)) {
 		DRM_ERROR("failed to enable link training\n");
-		return;
+		return false;
 	}
 
-	voltage = 0xff;
-	voltage_tries = 0;
-	loop_tries = 0;
+	voltage_tries = 1;
+	max_vswing_tries = 0;
 	for (;;) {
 		uint8_t link_status[DP_LINK_STATUS_SIZE];
 
 		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+
 		if (!intel_dp_get_link_status(intel_dp, link_status)) {
 			DRM_ERROR("failed to get link status\n");
-			break;
+			return false;
 		}
 
 		if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
 			DRM_DEBUG_KMS("clock recovery OK\n");
-			break;
+			return true;
 		}
 
-		/* Check to see if we've tried the max voltage */
-		if (intel_dp_link_max_vswing_reached(intel_dp)) {
-			++loop_tries;
-			if (loop_tries == 5) {
-				DRM_ERROR("too many full retries, give up\n");
-				intel_dp_dump_link_status(link_status);
-				break;
-			}
-			intel_dp_reset_link_train(intel_dp,
-						  DP_TRAINING_PATTERN_1 |
-						  DP_LINK_SCRAMBLING_DISABLE);
-			voltage_tries = 0;
-			continue;
+		if (voltage_tries == 5 || max_vswing_tries == 1) {
+			DRM_DEBUG_KMS("Max. vswing reached or same voltage "
+				      "tried 5 times\n");
+			return false;
 		}
 
-		/* Check to see if we've tried the same voltage 5 times */
-		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-			++voltage_tries;
-			if (voltage_tries == 5) {
-				DRM_ERROR("too many voltage retries, give up\n");
-				break;
-			}
-		} else
-			voltage_tries = 0;
 		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
 		/* Update training set as requested by target */
 		intel_get_adjust_train(intel_dp, link_status);
 		if (!intel_dp_update_link_train(intel_dp)) {
 			DRM_ERROR("failed to update link training\n");
-			break;
+			return false;
 		}
+
+		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
+		    voltage)
+			++voltage_tries;
+		else
+			voltage_tries = 1;
+
+		if (intel_dp_link_max_vswing_reached(intel_dp))
+			++max_vswing_tries;
+
 	}
 }
 
-- 
1.9.1

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

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

* [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (8 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH 09/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2 Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-02 11:20   ` Mika Kahola
  2016-09-01 22:08 ` [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan

Fix the number of tries in channel euqalization link training sequence
according to DP 1.2 Spec. It returns a boolean depending on channel
equalization pass or failure.

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dp_link_training.c | 57 ++++++++++-----------------
 drivers/gpu/drm/i915/intel_drv.h              |  1 +
 2 files changed, 22 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 13a0341..07f0159 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -240,12 +240,12 @@ static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
 	return training_pattern;
 }
 
-static void
+static bool
 intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 {
-	bool channel_eq = false;
-	int tries, cr_tries;
+	int tries;
 	u32 training_pattern;
+	uint8_t link_status[DP_LINK_STATUS_SIZE];
 
 	training_pattern = intel_dp_training_pattern(intel_dp);
 
@@ -254,20 +254,11 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 				     training_pattern |
 				     DP_LINK_SCRAMBLING_DISABLE)) {
 		DRM_ERROR("failed to start channel equalization\n");
-		return;
+		return false;
 	}
 
-	tries = 0;
-	cr_tries = 0;
-	channel_eq = false;
-	for (;;) {
-		uint8_t link_status[DP_LINK_STATUS_SIZE];
-
-		if (cr_tries > 5) {
-			DRM_ERROR("failed to train DP, aborting\n");
-			intel_dp_dump_link_status(link_status);
-			break;
-		}
+	intel_dp->channel_eq_status = 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)) {
@@ -278,44 +269,38 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 		/* Make sure clock is still ok */
 		if (!drm_dp_clock_recovery_ok(link_status,
 					      intel_dp->lane_count)) {
-			intel_dp_link_training_clock_recovery(intel_dp);
-			intel_dp_set_link_train(intel_dp,
-						training_pattern |
-						DP_LINK_SCRAMBLING_DISABLE);
-			cr_tries++;
-			continue;
+			intel_dp_dump_link_status(link_status);
+			DRM_DEBUG_KMS("Clock recovery check failed, cannot "
+				      "continue channel equalization\n");
+			break;
 		}
 
 		if (drm_dp_channel_eq_ok(link_status,
 					 intel_dp->lane_count)) {
-			channel_eq = true;
+			intel_dp->channel_eq_status = true;
+			DRM_DEBUG_KMS("Channel EQ done. DP Training "
+				      "successful\n");
 			break;
 		}
 
-		/* Try 5 times, then try clock recovery if that fails */
-		if (tries > 5) {
-			intel_dp_link_training_clock_recovery(intel_dp);
-			intel_dp_set_link_train(intel_dp,
-						training_pattern |
-						DP_LINK_SCRAMBLING_DISABLE);
-			tries = 0;
-			cr_tries++;
-			continue;
-		}
-
 		/* Update training set as requested by target */
 		intel_get_adjust_train(intel_dp, link_status);
 		if (!intel_dp_update_link_train(intel_dp)) {
 			DRM_ERROR("failed to update link training\n");
 			break;
 		}
-		++tries;
+	}
+
+	/* Try 5 times, else fail and try at lower BW */
+	if (tries == 5) {
+		intel_dp_dump_link_status(link_status);
+		DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
 	}
 
 	intel_dp_set_idle_link_train(intel_dp);
 
-	if (channel_eq)
-		DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
+	return intel_dp->channel_eq_status;
+
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index efcd80b..e5bc976 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -878,6 +878,7 @@ struct intel_dp {
 	bool link_mst;
 	bool has_audio;
 	bool detect_done;
+	bool channel_eq_status;
 	enum hdmi_force_audio force_audio;
 	bool limited_color_range;
 	bool color_range_auto;
-- 
1.9.1

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

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

* [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (9 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-02 12:03   ` David Weinehall
                     ` (4 more replies)
  2016-09-01 22:08 ` [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config Manasi Navare
                   ` (4 subsequent siblings)
  15 siblings, 5 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx

According to the DisplayPort Spec, in case of Clock Recovery failure
the link training sequence should fall back to the lower link rate
followed by lower lane count until CR succeeds.
On CR success, the sequence proceeds with Channel EQ.
In case of Channel EQ failures, it should fallback to
lower link rate and lane count and start the CR phase again.

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
 drivers/gpu/drm/i915/intel_drv.h              |   4 +-
 3 files changed, 110 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 67a6a0b..78d6687 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
 	}
 }
 
-static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
 				    int link_rate, uint32_t lane_count,
-				    struct intel_shared_dpll *pll,
-				    bool link_mst)
+				    struct intel_shared_dpll *pll)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum port port = intel_ddi_get_encoder_port(encoder);
 
 	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
-				 link_mst);
-	if (encoder->type == INTEL_OUTPUT_EDP)
-		intel_edp_panel_on(intel_dp);
+				 false);
+
+	intel_edp_panel_on(intel_dp);
 
 	intel_ddi_clk_select(encoder, pll);
 	intel_prepare_dp_ddi_buffers(encoder);
 	intel_ddi_init_dp_buf_reg(encoder);
 	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
 	intel_dp_start_link_train(intel_dp);
-	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
+	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
 		intel_dp_stop_link_train(intel_dp);
 }
 
+static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+				    int link_rate, uint32_t lane_count,
+				    struct intel_shared_dpll *pll,
+				    bool link_mst)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll_config tmp_pll_config;
+
+	/* Disable the PLL and obtain the PLL for Link Training
+	 * that starts with highest link rate and lane count.
+	 */
+	tmp_pll_config = pll->config;
+	pll->funcs.disable(dev_priv, pll);
+	pll->config.crtc_mask = 0;
+
+	/* If Link Training fails, send a uevent to generate a hotplug */
+	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
+		drm_kms_helper_hotplug_event(encoder->base.dev);
+	pll->config = tmp_pll_config;
+}
+
 static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
 				      bool has_hdmi_sink,
 				      struct drm_display_mode *adjusted_mode,
@@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	int type = intel_encoder->type;
 
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+	if (type == INTEL_OUTPUT_EDP)
+		intel_ddi_pre_enable_edp(intel_encoder,
+					crtc->config->port_clock,
+					crtc->config->lane_count,
+					crtc->config->shared_dpll);
+
+	if (type == INTEL_OUTPUT_DP)
 		intel_ddi_pre_enable_dp(intel_encoder,
 					crtc->config->port_clock,
 					crtc->config->lane_count,
 					crtc->config->shared_dpll,
 					intel_crtc_has_type(crtc->config,
 							    INTEL_OUTPUT_DP_MST));
-	}
-	if (type == INTEL_OUTPUT_HDMI) {
+
+	if (type == INTEL_OUTPUT_HDMI)
 		intel_ddi_pre_enable_hdmi(intel_encoder,
 					  crtc->config->has_hdmi_sink,
 					  &crtc->config->base.adjusted_mode,
 					  crtc->config->shared_dpll);
-	}
+
 }
 
 static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
@@ -2431,6 +2458,66 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 	return pll;
 }
 
+bool
+intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+		    uint8_t max_lane_count, bool link_mst)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct intel_encoder *encoder = connector->encoder;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	int link_rate;
+	uint8_t lane_count;
+	bool link_rate_not_found = true;
+	bool ret = false;
+
+	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
+
+		link_rate = max_link_rate;
+		while (link_rate_not_found) {
+			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
+			if (pll == NULL) {
+				DRM_ERROR("Could not find DPLL for link "
+					  "training.\n");
+				return false;
+			}
+			tmp_pll_config = pll->config;
+			pll->funcs.enable(dev_priv, pll);
+
+			intel_dp_set_link_params(intel_dp, link_rate,
+						 lane_count, link_mst);
+
+			intel_ddi_clk_select(encoder, pll);
+			intel_prepare_dp_ddi_buffers(encoder);
+			intel_ddi_init_dp_buf_reg(encoder);
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+			ret = intel_dp_start_link_train(intel_dp);
+			if (ret)
+				break;
+
+			/* Disable port followed by PLL for next retry/clean up */
+			intel_ddi_post_disable(encoder, NULL, NULL);
+			pll->funcs.disable(dev_priv, pll);
+			if (link_rate == 540000)
+				link_rate = 270000;
+			else if (link_rate == 270000)
+				link_rate = 162000;
+			else
+				link_rate_not_found = false;
+		}
+		if (ret) {
+			DRM_DEBUG_KMS("Link Training successful\n");
+			intel_dp_stop_link_train(intel_dp);
+			break;
+		}
+	}
+	if (!lane_count)
+		DRM_ERROR("Link Training Failed\n");
+
+	return ret;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 07f0159..0df49e8 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 				DP_TRAINING_PATTERN_DISABLE);
 }
 
-void
+bool
 intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-	intel_dp_link_training_clock_recovery(intel_dp);
-	intel_dp_link_training_channel_equalization(intel_dp);
+	bool ret;
+
+	if (intel_dp_link_training_clock_recovery(intel_dp)) {
+		ret = intel_dp_link_training_channel_equalization(intel_dp);
+		if (ret)
+			return true;
+	}
+	return false;
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e5bc976..342a2d5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
+bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+			 uint8_t max_lane_count, bool link_mst);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
@@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
 			      int link_rate, uint8_t lane_count,
 			      bool link_mst);
-void intel_dp_start_link_train(struct intel_dp *intel_dp);
+bool intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 void intel_dp_encoder_reset(struct drm_encoder *encoder);
-- 
1.9.1

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

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

* [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (10 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-02 13:08   ` Mika Kahola
                     ` (2 more replies)
  2016-09-01 22:08 ` [PATCH v11 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms) Manasi Navare
                   ` (3 subsequent siblings)
  15 siblings, 3 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx

While configuring the pipe during modeset, it should loop
starting from max clock and max lane count reducing the
lane count and clock in each iteration until the requested mode
rate is less than or equal to available link BW.

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index dfdbe65..e094b25 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1552,11 +1552,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	for (; bpp >= 6*3; bpp -= 2*3) {
 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
 						   bpp);
-
-		for (clock = min_clock; clock <= max_clock; clock++) {
-			for (lane_count = min_lane_count;
-				lane_count <= max_lane_count;
-				lane_count <<= 1) {
+		for (clock = max_clock; clock >= max_clock; clock--) {
+			for (lane_count = max_lane_count;
+			     lane_count >= min_lane_count;
+			     lane_count >>= 1) {
 
 				link_clock = common_rates[clock];
 				link_avail = intel_dp_max_data_rate(link_clock,
-- 
1.9.1

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

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

* [PATCH v11 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (11 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-07  0:13   ` [PATCH v12 " Manasi Navare
  2016-09-01 22:08 ` [PATCH 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST Manasi Navare
                   ` (2 subsequent siblings)
  15 siblings, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx

From: Durgadoss R <durgadoss.r@intel.com>

To support USB type C alternate DP mode, the display driver needs to
know the number of lanes required by the DP panel as well as number
of lanes that can be supported by the type-C cable. Sometimes, the
type-C cable may limit the bandwidth even if Panel can support
more lanes. To address these scenarios, the display driver will
start link training with max lanes, and if that fails, the driver
falls back to x2 lanes; and repeats this procedure for all
bandwidth/lane configurations.

* Since link training is done before modeset only the port
  (and not pipe/planes) and its associated PLLs are enabled.
* On DP hotplug: Directly start link training on the DP encoder.
* On Connected boot scenarios: When booted with an LFP and a DP,
  sometimes BIOS brings up DP. In these cases, we disable the
  crtc and then do upfront link training; and bring it back up.
* All local changes made for upfront link training are reset
  to their previous values once it is done; so that the
  subsequent modeset is not aware of these changes.

Changes since v10:
* Use the ddi link train function that loops through all the link rates
and lane counts starting from the highest supported (Manasi)
* For upfront link training, set the upfront flag so that the link can
be disabled after caching upfront values (Manasi)
Changes since v9:
* Change the macros to use dev_priv in place of dev (David Weinehall)
Changes since v8:
* Reset upfront lane count and link rate values on HPD
for DP connector physical disconnect (Manasi)
Changes since v7:
* Move the upfront link training to intel_dp_mode_valid()
  to avoid a race condition with DP MST sideband comms. (Ville)
Changes since v6:
* Fix some initialization bugs on link_rate (Jim Bride)
* Use link_rate (and not link_bw) for upfront (Ville)
* Make intel_dp_upfront*() as a vfunc (Ander)
* The train_set_valid variable in intel_dp was removed due to
  issues in fast link training. So, to indicate the link train
  status, move the channel_eq inside intel_dp.
Changes since v5:
* Moved retry logic in upfront to intel_dp.c so that it
  can be used for all platforms.
Changes since v4:
* Removed usage of crtc_state in upfront link training;
  Hence no need to find free crtc to do upfront now.
* Re-enable crtc if it was disabled for upfront.
* Use separate variables to track max lane count
  and link rate found by upfront, without modifying
  the original DPCD read from panel.
Changes since v3:
* Fixed a return value on BXT check
* Reworked on top of bxt_ddi_pll_select split from Ander
* Renamed from ddi_upfront to bxt_upfront since the
  upfront logic includes BXT specific functions for now.
Changes since v2:
* Rebased on top of latest dpll_mgr.c code and
  latest HPD related clean ups.
* Corrected return values from upfront (Ander)
* Corrected atomic locking for upfront in intel_dp.c (Ville)
Changes since v1:
*  all pll related functions inside ddi.c

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              |  23 +-
 drivers/gpu/drm/i915/intel_dp.c               | 376 +++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
 drivers/gpu/drm/i915/intel_drv.h              |  14 +-
 4 files changed, 312 insertions(+), 102 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 78d6687..0543448 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 	pll->config.crtc_mask = 0;
 
 	/* If Link Training fails, send a uevent to generate a hotplug */
-	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
+	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst,
+				   false)))
 		drm_kms_helper_hotplug_event(encoder->base.dev);
 	pll->config = tmp_pll_config;
 }
@@ -2460,7 +2461,8 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 
 bool
 intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-		    uint8_t max_lane_count, bool link_mst)
+		     uint8_t max_lane_count, bool link_mst,
+		     bool is_upfront)
 {
 	struct intel_connector *connector = intel_dp->attached_connector;
 	struct intel_encoder *encoder = connector->encoder;
@@ -2499,6 +2501,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 			/* Disable port followed by PLL for next retry/clean up */
 			intel_ddi_post_disable(encoder, NULL, NULL);
 			pll->funcs.disable(dev_priv, pll);
+			pll->config = tmp_pll_config;
 			if (link_rate == 540000)
 				link_rate = 270000;
 			else if (link_rate == 270000)
@@ -2506,12 +2509,28 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 			else
 				link_rate_not_found = false;
 		}
+
 		if (ret) {
 			DRM_DEBUG_KMS("Link Training successful\n");
 			intel_dp_stop_link_train(intel_dp);
 			break;
 		}
 	}
+
+	if (is_upfront) {
+		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d lanes:%d\n",
+			      ret ? "Passed" : "Failed",
+			      link_rate, lane_count);
+		/* Disable port followed by PLL for next retry/clean up */
+		intel_ddi_post_disable(encoder, NULL, NULL);
+		pll->funcs.disable(dev_priv, pll);
+		pll->config = tmp_pll_config;
+		if (ret) {
+			/* Save the upfront values */
+			intel_dp->max_lanes_upfront = lane_count;
+			intel_dp->max_link_rate_upfront = link_rate;
+		}
+	}
 	if (!lane_count)
 		DRM_ERROR("Link Training Failed\n");
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e094b25..5a8ef69 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	u8 source_max, sink_max;
+	u8 temp, source_max, sink_max;
 
 	source_max = intel_dig_port->max_lanes;
 	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
 
-	return min(source_max, sink_max);
+	temp = min(source_max, sink_max);
+
+	/*
+	 * Limit max lanes w.r.t to the max value found
+	 * using Upfront link training also.
+	 */
+	if (intel_dp->max_lanes_upfront)
+		return min(temp, intel_dp->max_lanes_upfront);
+	else
+		return temp;
 }
 
 /*
@@ -190,6 +199,229 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 	return (max_link_clock * max_lanes * 8) / 10;
 }
 
+static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
+				struct drm_modeset_acquire_ctx *ctx,
+				bool enable)
+{
+	int ret;
+	struct drm_atomic_state *state;
+	struct intel_crtc_state *crtc_state;
+	struct drm_device *dev = crtc->base.dev;
+	enum pipe pipe = crtc->pipe;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	crtc_state = intel_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		drm_atomic_state_free(state);
+		return ret;
+	}
+
+	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
+			enable ? "En" : "Dis",
+			pipe_name(pipe),
+			enable ? "after" : "before");
+
+	crtc_state->base.active = enable;
+	ret = drm_atomic_commit(state);
+	if (ret)
+		drm_atomic_state_free(state);
+
+	return ret;
+}
+
+static int
+intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
+{
+	if (intel_dp->num_sink_rates) {
+		*sink_rates = intel_dp->sink_rates;
+		return intel_dp->num_sink_rates;
+	}
+
+	*sink_rates = default_rates;
+
+	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
+}
+
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+
+	/* WaDisableHBR2:skl */
+	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
+		return false;
+
+	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
+	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
+		return true;
+	else
+		return false;
+}
+
+static int
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+	int size;
+
+	if (IS_BROXTON(dev_priv)) {
+		*source_rates = bxt_rates;
+		size = ARRAY_SIZE(bxt_rates);
+	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+		*source_rates = skl_rates;
+		size = ARRAY_SIZE(skl_rates);
+	} else {
+		*source_rates = default_rates;
+		size = ARRAY_SIZE(default_rates);
+	}
+
+	/* This depends on the fact that 5.4 is last value in the array */
+	if (!intel_dp_source_supports_hbr2(intel_dp))
+		size--;
+
+	return size;
+}
+
+static int intersect_rates(const int *source_rates, int source_len,
+			   const int *sink_rates, int sink_len,
+			   int *common_rates)
+{
+	int i = 0, j = 0, k = 0;
+
+	while (i < source_len && j < sink_len) {
+		if (source_rates[i] == sink_rates[j]) {
+			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+				return k;
+			common_rates[k] = source_rates[i];
+			++k;
+			++i;
+			++j;
+		} else if (source_rates[i] < sink_rates[j]) {
+			++i;
+		} else {
+			++j;
+		}
+	}
+	return k;
+}
+
+static int intel_dp_common_rates(struct intel_dp *intel_dp,
+				 int *common_rates)
+{
+	const int *source_rates, *sink_rates;
+	int source_len, sink_len;
+
+	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+
+	/* Cap sink rates w.r.t upfront values */
+	if (intel_dp->max_link_rate_upfront) {
+		int len = sink_len - 1;
+		while (len > 0 && sink_rates[len] >
+		       intel_dp->max_link_rate_upfront)
+			len--;
+		sink_len = len + 1;
+	}
+
+	source_len = intel_dp_source_rates(intel_dp, &source_rates);
+
+	return intersect_rates(source_rates, source_len,
+			       sink_rates, sink_len,
+			       common_rates);
+}
+
+static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct intel_encoder *intel_encoder = &intel_dig_port->base;
+	struct drm_device *dev = intel_encoder->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_modeset_acquire_ctx ctx;
+	struct intel_crtc *intel_crtc;
+	struct drm_crtc *crtc = NULL;
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	bool disable_dpll = false;
+	int ret;
+	bool done = false, has_mst = false;
+	uint8_t max_lanes;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	int common_len;
+	enum intel_display_power_domain power_domain;
+
+	power_domain = intel_display_port_power_domain(intel_encoder);
+	intel_display_power_get(dev_priv, power_domain);
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	max_lanes = intel_dp_max_lane_count(intel_dp);
+	if (WARN_ON(common_len <= 0))
+		return true;
+
+	drm_modeset_acquire_init(&ctx, 0);
+retry:
+	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
+	if (ret)
+		goto exit_fail;
+
+	if (intel_encoder->base.crtc) {
+		crtc = intel_encoder->base.crtc;
+
+		ret = drm_modeset_lock(&crtc->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		intel_crtc = to_intel_crtc(crtc);
+		pll = intel_crtc->config->shared_dpll;
+		disable_dpll = true;
+		has_mst = intel_crtc_has_type(intel_crtc->config,
+					      INTEL_OUTPUT_DP_MST);
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, false);
+		if (ret)
+			goto exit_fail;
+	}
+
+	mutex_lock(&dev_priv->dpll_lock);
+	if (disable_dpll) {
+		/* Clear the PLL config state */
+		tmp_pll_config = pll->config;
+		pll->config.crtc_mask = 0;
+	}
+
+	done = intel_dp->upfront_link_train(intel_dp,
+					    common_rates[common_len-1],
+					    max_lanes,
+					    has_mst,
+					    true);
+	if (disable_dpll)
+		pll->config = tmp_pll_config;
+
+	mutex_unlock(&dev_priv->dpll_lock);
+
+	if (crtc)
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, true);
+
+exit_fail:
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	intel_display_power_put(dev_priv, power_domain);
+	return done;
+}
+
 static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
@@ -211,6 +443,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
 		target_clock = fixed_mode->clock;
 	}
 
+	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
+		bool do_upfront_link_train;
+		/* Do not do upfront link train, if it is a compliance
+		 * request
+		 */
+		do_upfront_link_train = !intel_dp->upfront_done &&
+			(intel_dp->compliance_test_type !=
+			 DP_TEST_LINK_TRAINING);
+
+		if (do_upfront_link_train)
+			intel_dp->upfront_done = intel_dp_upfront_link_train(intel_dp);
+	}
+
 	max_link_clock = intel_dp_max_link_rate(intel_dp);
 	max_lanes = intel_dp_max_lane_count(intel_dp);
 
@@ -1256,60 +1501,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 	intel_dp->aux.transfer = intel_dp_aux_transfer;
 }
 
-static int
-intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
-{
-	if (intel_dp->num_sink_rates) {
-		*sink_rates = intel_dp->sink_rates;
-		return intel_dp->num_sink_rates;
-	}
-
-	*sink_rates = default_rates;
-
-	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
-}
-
-bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-
-	/* WaDisableHBR2:skl */
-	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
-		return false;
-
-	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
-	    (INTEL_INFO(dev)->gen >= 9))
-		return true;
-	else
-		return false;
-}
-
-static int
-intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-	int size;
-
-	if (IS_BROXTON(dev)) {
-		*source_rates = bxt_rates;
-		size = ARRAY_SIZE(bxt_rates);
-	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
-		*source_rates = skl_rates;
-		size = ARRAY_SIZE(skl_rates);
-	} else {
-		*source_rates = default_rates;
-		size = ARRAY_SIZE(default_rates);
-	}
-
-	/* This depends on the fact that 5.4 is last value in the array */
-	if (!intel_dp_source_supports_hbr2(intel_dp))
-		size--;
-
-	return size;
-}
-
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
 		   struct intel_crtc_state *pipe_config)
@@ -1343,42 +1534,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
 	}
 }
 
-static int intersect_rates(const int *source_rates, int source_len,
-			   const int *sink_rates, int sink_len,
-			   int *common_rates)
-{
-	int i = 0, j = 0, k = 0;
-
-	while (i < source_len && j < sink_len) {
-		if (source_rates[i] == sink_rates[j]) {
-			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
-				return k;
-			common_rates[k] = source_rates[i];
-			++k;
-			++i;
-			++j;
-		} else if (source_rates[i] < sink_rates[j]) {
-			++i;
-		} else {
-			++j;
-		}
-	}
-	return k;
-}
-
-static int intel_dp_common_rates(struct intel_dp *intel_dp,
-				 int *common_rates)
-{
-	const int *source_rates, *sink_rates;
-	int source_len, sink_len;
-
-	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-	source_len = intel_dp_source_rates(intel_dp, &source_rates);
-
-	return intersect_rates(source_rates, source_len,
-			       sink_rates, sink_len,
-			       common_rates);
-}
 
 static void snprintf_int_array(char *str, size_t len,
 			       const int *array, int nelem)
@@ -1436,6 +1591,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	int rates[DP_MAX_SUPPORTED_RATES] = {};
 	int len;
 
+	if (intel_dp->max_link_rate_upfront)
+		return intel_dp->max_link_rate_upfront;
+
 	len = intel_dp_common_rates(intel_dp, rates);
 	if (WARN_ON(len <= 0))
 		return 162000;
@@ -1473,7 +1631,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
-	int lane_count, clock;
+	int lane_count, clock = 0;
 	int min_lane_count = 1;
 	int max_lane_count = intel_dp_max_lane_count(intel_dp);
 	/* Conveniently, the link BW constants become indices with a shift...*/
@@ -1552,11 +1710,24 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	for (; bpp >= 6*3; bpp -= 2*3) {
 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
 						   bpp);
+		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
+			clock = max_clock;
+			lane_count = intel_dp->max_lanes_upfront;
+			link_clock = intel_dp->max_link_rate_upfront;
+			link_avail = intel_dp_max_data_rate(link_clock,
+							    lane_count);
+			mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+							   bpp);
+			if (mode_rate <= link_avail)
+				goto found;
+			else
+				continue;
+		}
+
 		for (clock = max_clock; clock >= max_clock; clock--) {
 			for (lane_count = max_lane_count;
 			     lane_count >= min_lane_count;
 			     lane_count >>= 1) {
-
 				link_clock = common_rates[clock];
 				link_avail = intel_dp_max_data_rate(link_clock,
 								    lane_count);
@@ -1585,7 +1756,6 @@ found:
 	}
 
 	pipe_config->lane_count = lane_count;
-
 	pipe_config->pipe_bpp = bpp;
 	pipe_config->port_clock = common_rates[clock];
 
@@ -4269,7 +4439,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	struct drm_device *dev = connector->dev;
 	enum drm_connector_status status;
 	enum intel_display_power_domain power_domain;
-	u8 sink_irq_vector = 0;
+	u8 sink_irq_vector;
 
 	power_domain = intel_display_port_aux_power_domain(intel_encoder);
 	intel_display_power_get(to_i915(dev), power_domain);
@@ -4362,9 +4532,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	}
 
 out:
-	if ((status != connector_status_connected) &&
-	    (intel_dp->is_mst == false))
+	if (status != connector_status_connected) {
 		intel_dp_unset_edid(intel_dp);
+		intel_dp->upfront_done = false;
+		intel_dp->max_lanes_upfront = 0;
+		intel_dp->max_link_rate_upfront = 0;
+	}
 
 	intel_display_power_put(to_i915(dev), power_domain);
 	return;
@@ -5608,6 +5781,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	if (type == DRM_MODE_CONNECTOR_eDP)
 		intel_encoder->type = INTEL_OUTPUT_EDP;
 
+	/* Initialize upfront link training vfunc for DP */
+	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
+		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
+		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+			intel_dp->upfront_link_train = intel_ddi_link_train;
+	}
+
 	/* eDP only on port B and/or C on vlv/chv */
 	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
 		    is_edp(intel_dp) && port != PORT_B && port != PORT_C))
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 0df49e8..bb581be 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -300,7 +300,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 	intel_dp_set_idle_link_train(intel_dp);
 
 	return intel_dp->channel_eq_status;
-
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 342a2d5..776beec 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -882,6 +882,12 @@ struct intel_dp {
 	enum hdmi_force_audio force_audio;
 	bool limited_color_range;
 	bool color_range_auto;
+
+	/* Upfront link train parameters */
+	int max_link_rate_upfront;
+	uint8_t max_lanes_upfront;
+	bool upfront_done;
+
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
 	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
@@ -939,6 +945,11 @@ struct intel_dp {
 	/* This is called before a link training is starterd */
 	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
 
+	/* For Upfront link training */
+	bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
+				   uint8_t lane_count, bool link_mst,
+				   bool is_upfront);
+
 	/* Displayport compliance testing */
 	unsigned long compliance_test_type;
 	unsigned long compliance_test_data;
@@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
 bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-			 uint8_t max_lane_count, bool link_mst);
+			  uint8_t max_lane_count, bool link_mst,
+			  bool is_upfront);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
-- 
1.9.1

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

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

* [PATCH 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (12 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH v11 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms) Manasi Navare
@ 2016-09-01 22:08 ` Manasi Navare
  2016-09-07  0:13   ` [PATCH v2 " Manasi Navare
  2016-09-01 22:48 ` ✗ Fi.CI.BAT: failure for Enable upfront link training on DDI platforms (rev3) Patchwork
  2016-09-07  0:54 ` ✗ Fi.CI.BAT: warning for Enable upfront link training on DDI platforms (rev8) Patchwork
  15 siblings, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-01 22:08 UTC (permalink / raw)
  To: intel-gfx

From: Jim Bride <jim.bride@linux.intel.com>

Add upfront link training to intel_dp_mst_mode_valid() so that we know
topology constraints before we validate the legality of modes to be
checked.
Call the function that loops through the link rates and lane counts
starting from highest supported link rate and lane count for training
the link in compliance with DP spec

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c     |  9 ++---
 drivers/gpu/drm/i915/intel_dp_mst.c | 74 +++++++++++++++++++++++++++----------
 drivers/gpu/drm/i915/intel_drv.h    |  3 ++
 3 files changed, 61 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 5a8ef69..83e882b 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -131,7 +131,7 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
 				      enum pipe pipe);
 static void intel_dp_unset_edid(struct intel_dp *intel_dp);
 
-static int
+int
 intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 {
 	int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
@@ -150,7 +150,7 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 	return max_link_bw;
 }
 
-static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
+u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	u8 temp, source_max, sink_max;
@@ -312,8 +312,7 @@ static int intersect_rates(const int *source_rates, int source_len,
 	return k;
 }
 
-static int intel_dp_common_rates(struct intel_dp *intel_dp,
-				 int *common_rates)
+int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates)
 {
 	const int *source_rates, *sink_rates;
 	int source_len, sink_len;
@@ -336,7 +335,7 @@ static int intel_dp_common_rates(struct intel_dp *intel_dp,
 			       common_rates);
 }
 
-static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
+bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 54a9d76..98d45a4 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -41,21 +41,30 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 	int bpp;
 	int lane_count, slots;
 	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-	int mst_pbn;
+	int mst_pbn, common_len;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
 
 	pipe_config->dp_encoder_is_mst = true;
 	pipe_config->has_pch_encoder = false;
-	bpp = 24;
+
 	/*
-	 * for MST we always configure max link bw - the spec doesn't
-	 * seem to suggest we should do otherwise.
+	 * For MST we always configure for the maximum trainable link bw -
+	 * the spec doesn't seem to suggest we should do otherwise.  The
+	 * calls to intel_dp_max_lane_count() and intel_dp_common_rates()
+	 * both take successful upfront link training into account, and
+	 * return the DisplayPort max supported values in the event that
+	 * upfront link training was not done.
 	 */
-	lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
+	lane_count = intel_dp_max_lane_count(intel_dp);
 
 	pipe_config->lane_count = lane_count;
 
-	pipe_config->pipe_bpp = 24;
-	pipe_config->port_clock = intel_dp_max_link_rate(intel_dp);
+	pipe_config->pipe_bpp = bpp = 24;
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	pipe_config->port_clock = common_rates[common_len - 1];
+
+	DRM_DEBUG_KMS("DP MST link configured for %d lanes @ %d.\n",
+		      pipe_config->lane_count, pipe_config->port_clock);
 
 	state = pipe_config->base.state;
 
@@ -137,6 +146,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
 	enum port port = intel_dig_port->port;
 	struct intel_connector *connector =
 		to_intel_connector(conn_state->connector);
+	struct intel_shared_dpll *pll = pipe_config->shared_dpll;
+	struct intel_shared_dpll_config tmp_pll_config;
 	int ret;
 	uint32_t temp;
 	int slots;
@@ -150,21 +161,23 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
 	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
 
 	if (intel_dp->active_mst_links == 0) {
-		intel_ddi_clk_select(&intel_dig_port->base,
-				     pipe_config->shared_dpll);
-
-		intel_prepare_dp_ddi_buffers(&intel_dig_port->base);
-		intel_dp_set_link_params(intel_dp,
-					 pipe_config->port_clock,
-					 pipe_config->lane_count,
-					 true);
-
-		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
 
-		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		/* Disable the PLL since we need to acquire the PLL
+		 * based on the link rate in the link training sequence
+		 */
+		tmp_pll_config = pll->config;
+		pll->funcs.disable(dev_priv, pll);
+		pll->config.crtc_mask = 0;
+
+		/* If Link Training fails, send a uevent to generate a
+		 *hotplug
+		 */
+		if (!(intel_ddi_link_train(intel_dp, pipe_config->port_clock,
+					   pipe_config->lane_count, true,
+					   false)))
+			drm_kms_helper_hotplug_event(encoder->base.dev);
+		pll->config = tmp_pll_config;
 
-		intel_dp_start_link_train(intel_dp);
-		intel_dp_stop_link_train(intel_dp);
 	}
 
 	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
@@ -336,6 +349,27 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
 			struct drm_display_mode *mode)
 {
 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_dp *intel_dp = intel_connector->mst_port;
+
+	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
+		bool do_upfront_link_train;
+
+		do_upfront_link_train = intel_dp->compliance_test_type !=
+			DP_TEST_LINK_TRAINING;
+		if (do_upfront_link_train) {
+			intel_dp->upfront_done =
+				intel_dp_upfront_link_train(intel_dp);
+			if (intel_dp->upfront_done) {
+				DRM_DEBUG_KMS("MST upfront trained at "
+					      "%d lanes @ %d.",
+					      intel_dp->max_lanes_upfront,
+					      intel_dp->max_link_rate_upfront);
+			} else
+				DRM_DEBUG_KMS("MST upfront link training "
+					      "failed.");
+		}
+	}
 
 	/* TODO - validate mode against available PBN for link */
 	if (mode->clock < 10000)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 776beec..90fba17 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1416,6 +1416,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
+u8 intel_dp_max_lane_count(struct intel_dp *intel_dp);
 int intel_dp_max_link_rate(struct intel_dp *intel_dp);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
@@ -1446,6 +1447,8 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing);
 void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
 			   uint8_t *link_bw, uint8_t *rate_select);
 bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
+int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates);
+bool intel_dp_upfront_link_train(struct intel_dp *intel_dp);
 bool
 intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]);
 
-- 
1.9.1

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

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

* ✗ Fi.CI.BAT: failure for Enable upfront link training on DDI platforms (rev3)
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (13 preceding siblings ...)
  2016-09-01 22:08 ` [PATCH 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST Manasi Navare
@ 2016-09-01 22:48 ` Patchwork
  2016-09-07  0:54 ` ✗ Fi.CI.BAT: warning for Enable upfront link training on DDI platforms (rev8) Patchwork
  15 siblings, 0 replies; 81+ messages in thread
From: Patchwork @ 2016-09-01 22:48 UTC (permalink / raw)
  To: Navare, Manasi D; +Cc: intel-gfx

== Series Details ==

Series: Enable upfront link training on DDI platforms (rev3)
URL   : https://patchwork.freedesktop.org/series/10821/
State : failure

== Summary ==

Series 10821v3 Enable upfront link training on DDI platforms
http://patchwork.freedesktop.org/api/1.0/series/10821/revisions/3/mbox/

Test gem_mmap_gtt:
        Subgroup basic-wc:
                fail       -> PASS       (fi-byt-n2820)
Test kms_cursor_legacy:
        Subgroup basic-cursor-vs-flip-legacy:
                fail       -> PASS       (fi-byt-n2820)
        Subgroup basic-cursor-vs-flip-varying-size:
                fail       -> PASS       (fi-byt-n2820)
Test kms_flip:
        Subgroup basic-flip-vs-dpms:
                pass       -> DMESG-FAIL (fi-byt-n2820)
        Subgroup basic-flip-vs-modeset:
                pass       -> DMESG-WARN (fi-byt-n2820)
        Subgroup basic-flip-vs-wf_vblank:
                pass       -> DMESG-WARN (fi-byt-n2820)
Test kms_pipe_crc_basic:
        Subgroup hang-read-crc-pipe-b:
                skip       -> PASS       (fi-hsw-4770r)
        Subgroup suspend-read-crc-pipe-b:
                skip       -> PASS       (fi-byt-n2820)
Test prime_busy:
        Subgroup basic-after-default:
                fail       -> PASS       (fi-byt-n2820)
        Subgroup basic-before-default:
                fail       -> PASS       (fi-byt-n2820)
        Subgroup basic-wait-after-default:
                fail       -> PASS       (fi-byt-n2820)
        Subgroup basic-wait-before-default:
                fail       -> PASS       (fi-byt-n2820)
Test prime_vgem:
        Subgroup basic-busy-default:
                fail       -> PASS       (fi-byt-n2820)
        Subgroup basic-sync-default:
                fail       -> PASS       (fi-byt-n2820)
        Subgroup basic-wait-default:
                fail       -> PASS       (fi-byt-n2820)

fi-bdw-5557u     total:252  pass:233  dwarn:2   dfail:1   fail:1   skip:15 
fi-bsw-n3050     total:252  pass:203  dwarn:1   dfail:1   fail:1   skip:46 
fi-byt-n2820     total:252  pass:206  dwarn:2   dfail:1   fail:2   skip:41 
fi-hsw-4770k     total:252  pass:226  dwarn:2   dfail:1   fail:1   skip:22 
fi-hsw-4770r     total:252  pass:222  dwarn:2   dfail:1   fail:1   skip:26 
fi-ivb-3520m     total:252  pass:217  dwarn:2   dfail:1   fail:1   skip:31 
fi-skl-6260u     total:252  pass:234  dwarn:2   dfail:1   fail:1   skip:14 
fi-skl-6700k     total:252  pass:219  dwarn:3   dfail:1   fail:1   skip:28 
fi-snb-2520m     total:252  pass:204  dwarn:2   dfail:1   fail:2   skip:43 
fi-snb-2600      total:252  pass:204  dwarn:2   dfail:1   fail:2   skip:43 

Results at /archive/results/CI_IGT_test/Patchwork_2462/

e86e853d531af69111a41258650ec73650a59810 drm-intel-nightly: 2016y-09m-01d-18h-16m-46s UTC integration manifest
72c79f1 drm/i915/dp/mst: Add support for upfront link training for DP MST
645e2b7 drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
0d2222b drm/i915: Reverse the loop in intel_dp_compute_config
d8d1c9a9 drm/i915: Fallback to lower link rate and lane count during link training
1b9f8e1 drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant
1cc2484 drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2
325eea2 drm/i915/dp: Move max. vswing check to it's own function
b3c34be drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT
ebb5d40 drm/i915: Split hsw_get_dpll()
c441042 drm/i915: Split skl_get_dpll()
d40a544 drm/i915: Split bxt_ddi_pll_select()
c515f49 drm/i915: Split intel_ddi_pre_enable() into DP and HDMI versions
c37be1c drm/i915: Remove ddi_pll_sel from intel_crtc_state
926be20 drm/i915: Don't pass crtc_state to intel_dp_set_link_params()

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

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

* Re: [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-01 22:08 ` [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function Manasi Navare
@ 2016-09-02  8:05   ` Mika Kahola
  2016-09-06  9:58     ` Mika Kahola
  2016-09-07  0:13   ` [PATCH v2 8/14] " Manasi Navare
  1 sibling, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-02  8:05 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

+1 for this cleanup

Reviewed-by: Mika Kahola <mika.kahola@intel.com>

On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> 
> Wrap the max. vswing check in a separate function.
> This makes the clock recovery phase of DP link training cleaner
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 0deebed..9145e5a 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -112,6 +112,17 @@ intel_dp_update_link_train(struct intel_dp
> *intel_dp)
>  	return ret == intel_dp->lane_count;
>  }
>  
> +static bool intel_dp_link_max_vswing_reached(struct intel_dp
> *intel_dp)
> +{
> +	int lane;
> +
> +	for (lane = 0; lane < intel_dp->lane_count; lane++)
> +		if (intel_dp->train_set[lane] &
> DP_TRAIN_MAX_SWING_REACHED == 0)
> +			return false;
> +
> +	return true;
> +}
> +
>  /* Enable corresponding port and start training pattern 1 */
>  static void
>  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> @@ -170,10 +181,7 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  		}
>  
>  		/* Check to see if we've tried the max voltage */
> -		for (i = 0; i < intel_dp->lane_count; i++)
> -			if ((intel_dp->train_set[i] &
> DP_TRAIN_MAX_SWING_REACHED) == 0)
> -				break;
> -		if (i == intel_dp->lane_count) {
> +		if (intel_dp_link_max_vswing_reached(intel_dp)) {
>  			++loop_tries;
>  			if (loop_tries == 5) {
>  				DRM_ERROR("too many full retries,
> give up\n");
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 09/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2
  2016-09-01 22:08 ` [PATCH 09/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2 Manasi Navare
@ 2016-09-02  9:16   ` Mika Kahola
  2016-09-02 17:55     ` Pandiyan, Dhinakaran
  2016-09-07  0:13   ` [PATCH v2 9/14] " Manasi Navare
  1 sibling, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-02  9:16 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> 
> This function cleans up clock recovery loop in link training
> compliant
> tp Dp Spec 1.2. It tries the clock recovery 5 times for the same
> voltage
> or until max voltage swing is reached and removes the additional non
> compliant retries. This function now returns a boolean values based
> on
> if clock recovery passed or failed.
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 59 ++++++++++++-----
> ----------
>  1 file changed, 26 insertions(+), 33 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 9145e5a..13a0341 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -117,19 +117,19 @@ static bool
> intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
>  	int lane;
>  
>  	for (lane = 0; lane < intel_dp->lane_count; lane++)
> -		if (intel_dp->train_set[lane] &
> DP_TRAIN_MAX_SWING_REACHED == 0)
> +		if ((intel_dp->train_set[lane] &
> +		     DP_TRAIN_MAX_SWING_REACHED) == 0)
>  			return false;
>  
This function was defined in the previous patch. Do we need to split
this if(...) line into separate lines in this patch? 

>  	return true;
>  }
>  
>  /* Enable corresponding port and start training pattern 1 */
> -static void
> +static bool
>  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>  {
> -	int i;
>  	uint8_t voltage;
> -	int voltage_tries, loop_tries;
> +	int voltage_tries, max_vswing_tries;
>  	uint8_t link_config[2];
>  	uint8_t link_bw, rate_select;
>  
> @@ -145,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
>  		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
>  	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET,
> link_config, 2);
> +
>  	if (intel_dp->num_sink_rates)
>  		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
>  				  &rate_select, 1);
> @@ -160,58 +161,50 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  				       DP_TRAINING_PATTERN_1 |
>  				       DP_LINK_SCRAMBLING_DISABLE))
> {
>  		DRM_ERROR("failed to enable link training\n");
> -		return;
> +		return false;
>  	}
>  
> -	voltage = 0xff;
> -	voltage_tries = 0;
> -	loop_tries = 0;
> +	voltage_tries = 1;
> +	max_vswing_tries = 0;
>  	for (;;) {
>  		uint8_t link_status[DP_LINK_STATUS_SIZE];
>  
>  		drm_dp_link_train_clock_recovery_delay(intel_dp-
> >dpcd);
> +
>  		if (!intel_dp_get_link_status(intel_dp,
> link_status)) {
>  			DRM_ERROR("failed to get link status\n");
> -			break;
> +			return false;
>  		}
>  
>  		if (drm_dp_clock_recovery_ok(link_status, intel_dp-
> >lane_count)) {
>  			DRM_DEBUG_KMS("clock recovery OK\n");
> -			break;
> +			return true;
>  		}
>  
> -		/* Check to see if we've tried the max voltage */
> -		if (intel_dp_link_max_vswing_reached(intel_dp)) {
> -			++loop_tries;
> -			if (loop_tries == 5) {
> -				DRM_ERROR("too many full retries,
> give up\n");
> -				intel_dp_dump_link_status(link_statu
> s);
> -				break;
> -			}
> -			intel_dp_reset_link_train(intel_dp,
> -						  DP_TRAINING_PATTER
> N_1 |
> -						  DP_LINK_SCRAMBLING
> _DISABLE);
> -			voltage_tries = 0;
> -			continue;
> +		if (voltage_tries == 5 || max_vswing_tries == 1) {
> +			DRM_DEBUG_KMS("Max. vswing reached or same
> voltage "
> +				      "tried 5 times\n");
> +			return false;
>  		}
I think it would be beneficial to know which one we hit if the clock
recovery fails. Therefore, I would split these debug messages so that
there would be separate debug messages when reaching max vswing or
trying out the same voltage for five times.

>  
> -		/* Check to see if we've tried the same voltage 5
> times */
> -		if ((intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
> -			++voltage_tries;
> -			if (voltage_tries == 5) {
> -				DRM_ERROR("too many voltage retries,
> give up\n");
> -				break;
> -			}
> -		} else
> -			voltage_tries = 0;
>  		voltage = intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK;
>  
>  		/* Update training set as requested by target */
>  		intel_get_adjust_train(intel_dp, link_status);
>  		if (!intel_dp_update_link_train(intel_dp)) {
>  			DRM_ERROR("failed to update link
> training\n");
> -			break;
> +			return false;
>  		}
> +
> +		if ((intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK) ==
> +		    voltage)
> +			++voltage_tries;
> +		else
> +			voltage_tries = 1;
> +
> +		if (intel_dp_link_max_vswing_reached(intel_dp))
> +			++max_vswing_tries;
> +
>  	}
>  }
>  
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant
  2016-09-01 22:08 ` [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant Manasi Navare
@ 2016-09-02 11:20   ` Mika Kahola
  2016-09-02 19:05     ` Pandiyan, Dhinakaran
  0 siblings, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-02 11:20 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> Fix the number of tries in channel euqalization link training
> sequence
> according to DP 1.2 Spec. It returns a boolean depending on channel
> equalization pass or failure.
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 57 ++++++++++-------
> ----------
>  drivers/gpu/drm/i915/intel_drv.h              |  1 +
>  2 files changed, 22 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 13a0341..07f0159 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -240,12 +240,12 @@ static u32 intel_dp_training_pattern(struct
> intel_dp *intel_dp)
>  	return training_pattern;
>  }
>  
> -static void
> +static bool
>  intel_dp_link_training_channel_equalization(struct intel_dp
> *intel_dp)
>  {
> -	bool channel_eq = false;
> -	int tries, cr_tries;
> +	int tries;
>  	u32 training_pattern;
> +	uint8_t link_status[DP_LINK_STATUS_SIZE];
>  
>  	training_pattern = intel_dp_training_pattern(intel_dp);
>  
> @@ -254,20 +254,11 @@
> intel_dp_link_training_channel_equalization(struct intel_dp
> *intel_dp)
>  				     training_pattern |
>  				     DP_LINK_SCRAMBLING_DISABLE)) {
>  		DRM_ERROR("failed to start channel equalization\n");
> -		return;
> +		return false;
>  	}
>  
> -	tries = 0;
> -	cr_tries = 0;
> -	channel_eq = false;
> -	for (;;) {
> -		uint8_t link_status[DP_LINK_STATUS_SIZE];
> -
> -		if (cr_tries > 5) {
> -			DRM_ERROR("failed to train DP, aborting\n");
> -			intel_dp_dump_link_status(link_status);
> -			break;
> -		}
> +	intel_dp->channel_eq_status = 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)) {
> @@ -278,44 +269,38 @@
> intel_dp_link_training_channel_equalization(struct intel_dp
> *intel_dp)
>  		/* Make sure clock is still ok */
>  		if (!drm_dp_clock_recovery_ok(link_status,
>  					      intel_dp->lane_count)) 
> {
> -			intel_dp_link_training_clock_recovery(intel_
> dp);
> -			intel_dp_set_link_train(intel_dp,
> -						training_pattern |
> -						DP_LINK_SCRAMBLING_D
> ISABLE);
> -			cr_tries++;
> -			continue;
> +			intel_dp_dump_link_status(link_status);
> +			DRM_DEBUG_KMS("Clock recovery check failed,
> cannot "
> +				      "continue channel
> equalization\n");
> +			break;
>  		}
This clock recovery check got me thinking. Do we really need to check
if clock recovery is still ok within a loop? Could we move this outside
the loop and return early if we have failed in clock recovery? One idea
that I have in mind is that we wouldn't need to enter in channel
equalization if we have failed with clock recovery earlier.

>  
>  		if (drm_dp_channel_eq_ok(link_status,
>  					 intel_dp->lane_count)) {
> -			channel_eq = true;
> +			intel_dp->channel_eq_status = true;
> +			DRM_DEBUG_KMS("Channel EQ done. DP Training
> "
> +				      "successful\n");
>  			break;
>  		}
>  
> -		/* Try 5 times, then try clock recovery if that
> fails */
> -		if (tries > 5) {
> -			intel_dp_link_training_clock_recovery(intel_
> dp);
> -			intel_dp_set_link_train(intel_dp,
> -						training_pattern |
> -						DP_LINK_SCRAMBLING_D
> ISABLE);
> -			tries = 0;
> -			cr_tries++;
> -			continue;
> -		}
> -
>  		/* Update training set as requested by target */
>  		intel_get_adjust_train(intel_dp, link_status);
>  		if (!intel_dp_update_link_train(intel_dp)) {
>  			DRM_ERROR("failed to update link
> training\n");
>  			break;
>  		}
> -		++tries;
> +	}
> +
> +	/* Try 5 times, else fail and try at lower BW */
> +	if (tries == 5) {
> +		intel_dp_dump_link_status(link_status);
> +		DRM_DEBUG_KMS("Channel equalization failed 5
> times\n");
>  	}
>  
>  	intel_dp_set_idle_link_train(intel_dp);
>  
> -	if (channel_eq)
> -		DRM_DEBUG_KMS("Channel EQ done. DP Training
> successful\n");
> +	return intel_dp->channel_eq_status;
> +
>  }
>  
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index efcd80b..e5bc976 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -878,6 +878,7 @@ struct intel_dp {
>  	bool link_mst;
>  	bool has_audio;
>  	bool detect_done;
> +	bool channel_eq_status;
>  	enum hdmi_force_audio force_audio;
>  	bool limited_color_range;
>  	bool color_range_auto;
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-01 22:08 ` [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
@ 2016-09-02 12:03   ` David Weinehall
  2016-09-06 17:34     ` Manasi Navare
  2016-09-02 12:49   ` David Weinehall
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 81+ messages in thread
From: David Weinehall @ 2016-09-02 12:03 UTC (permalink / raw)
  To: Manasi Navare; +Cc: intel-gfx

On Thu, Sep 01, 2016 at 03:08:16PM -0700, Manasi Navare wrote:
> According to the DisplayPort Spec, in case of Clock Recovery failure
> the link training sequence should fall back to the lower link rate
> followed by lower lane count until CR succeeds.
> On CR success, the sequence proceeds with Channel EQ.
> In case of Channel EQ failures, it should fallback to
> lower link rate and lane count and start the CR phase again.
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>  drivers/gpu/drm/i915/intel_drv.h              |   4 +-
>  3 files changed, 110 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 67a6a0b..78d6687 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
>  	}
>  }
>  
> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>  				    int link_rate, uint32_t lane_count,
> -				    struct intel_shared_dpll *pll,
> -				    bool link_mst)
> +				    struct intel_shared_dpll *pll)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum port port = intel_ddi_get_encoder_port(encoder);
>  
>  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> -				 link_mst);
> -	if (encoder->type == INTEL_OUTPUT_EDP)
> -		intel_edp_panel_on(intel_dp);
> +				 false);
> +
> +	intel_edp_panel_on(intel_dp);
>  
>  	intel_ddi_clk_select(encoder, pll);
>  	intel_prepare_dp_ddi_buffers(encoder);
>  	intel_ddi_init_dp_buf_reg(encoder);
>  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>  	intel_dp_start_link_train(intel_dp);
> -	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
> +	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)

I think you got this backwards. We *want* to use INTEL_GEN().

[snip]


Kind regards, David Weinehall
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-01 22:08 ` [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
  2016-09-02 12:03   ` David Weinehall
@ 2016-09-02 12:49   ` David Weinehall
  2016-09-06 17:54     ` Manasi Navare
  2016-09-02 13:00   ` Mika Kahola
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 81+ messages in thread
From: David Weinehall @ 2016-09-02 12:49 UTC (permalink / raw)
  To: Manasi Navare; +Cc: intel-gfx

On Thu, Sep 01, 2016 at 03:08:16PM -0700, Manasi Navare wrote:
> According to the DisplayPort Spec, in case of Clock Recovery failure
> the link training sequence should fall back to the lower link rate
> followed by lower lane count until CR succeeds.
> On CR success, the sequence proceeds with Channel EQ.
> In case of Channel EQ failures, it should fallback to
> lower link rate and lane count and start the CR phase again.
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>  drivers/gpu/drm/i915/intel_drv.h              |   4 +-
>  3 files changed, 110 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 67a6a0b..78d6687 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
>  	}
>  }
>  
> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>  				    int link_rate, uint32_t lane_count,
> -				    struct intel_shared_dpll *pll,
> -				    bool link_mst)
> +				    struct intel_shared_dpll *pll)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum port port = intel_ddi_get_encoder_port(encoder);
>  
>  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> -				 link_mst);
> -	if (encoder->type == INTEL_OUTPUT_EDP)
> -		intel_edp_panel_on(intel_dp);
> +				 false);
> +
> +	intel_edp_panel_on(intel_dp);
>  
>  	intel_ddi_clk_select(encoder, pll);
>  	intel_prepare_dp_ddi_buffers(encoder);
>  	intel_ddi_init_dp_buf_reg(encoder);
>  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>  	intel_dp_start_link_train(intel_dp);
> -	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
> +	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
>  		intel_dp_stop_link_train(intel_dp);
>  }
>  
> +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +				    int link_rate, uint32_t lane_count,
> +				    struct intel_shared_dpll *pll,
> +				    bool link_mst)
> +{
> +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_shared_dpll_config tmp_pll_config;
> +
> +	/* Disable the PLL and obtain the PLL for Link Training
> +	 * that starts with highest link rate and lane count.
> +	 */
> +	tmp_pll_config = pll->config;
> +	pll->funcs.disable(dev_priv, pll);
> +	pll->config.crtc_mask = 0;
> +
> +	/* If Link Training fails, send a uevent to generate a hotplug */
> +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
> +		drm_kms_helper_hotplug_event(encoder->base.dev);
> +	pll->config = tmp_pll_config;
> +}
> +
>  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>  				      bool has_hdmi_sink,
>  				      struct drm_display_mode *adjusted_mode,
> @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
>  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>  	int type = intel_encoder->type;
>  
> -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> +	if (type == INTEL_OUTPUT_EDP)
> +		intel_ddi_pre_enable_edp(intel_encoder,
> +					crtc->config->port_clock,
> +					crtc->config->lane_count,
> +					crtc->config->shared_dpll);
> +
> +	if (type == INTEL_OUTPUT_DP)
>  		intel_ddi_pre_enable_dp(intel_encoder,
>  					crtc->config->port_clock,
>  					crtc->config->lane_count,
>  					crtc->config->shared_dpll,
>  					intel_crtc_has_type(crtc->config,
>  							    INTEL_OUTPUT_DP_MST));
> -	}
> -	if (type == INTEL_OUTPUT_HDMI) {
> +
> +	if (type == INTEL_OUTPUT_HDMI)
>  		intel_ddi_pre_enable_hdmi(intel_encoder,
>  					  crtc->config->has_hdmi_sink,
>  					  &crtc->config->base.adjusted_mode,
>  					  crtc->config->shared_dpll);
> -	}
> +
>  }
>  
>  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
> @@ -2431,6 +2458,66 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
>  	return pll;
>  }
>  
> +bool
> +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +		    uint8_t max_lane_count, bool link_mst)
> +{
> +	struct intel_connector *connector = intel_dp->attached_connector;
> +	struct intel_encoder *encoder = connector->encoder;
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_shared_dpll *pll;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	int link_rate;
> +	uint8_t lane_count;
> +	bool link_rate_not_found = true;
> +	bool ret = false;
> +
> +	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
> +
> +		link_rate = max_link_rate;
> +		while (link_rate_not_found) {
> +			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
> +			if (pll == NULL) {
> +				DRM_ERROR("Could not find DPLL for link "
> +					  "training.\n");
> +				return false;
> +			}
> +			tmp_pll_config = pll->config;
> +			pll->funcs.enable(dev_priv, pll);
> +
> +			intel_dp_set_link_params(intel_dp, link_rate,
> +						 lane_count, link_mst);
> +
> +			intel_ddi_clk_select(encoder, pll);
> +			intel_prepare_dp_ddi_buffers(encoder);
> +			intel_ddi_init_dp_buf_reg(encoder);

Do you really need to run these two for every link rate?

> +			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> +			ret = intel_dp_start_link_train(intel_dp);
> +			if (ret)
> +				break;

Where do you stop link training on failure? Perhaps:

ret = intel_dp_start_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
if (ret)
	break;

and remove the stop on the success path?

> +
> +			/* Disable port followed by PLL for next retry/clean up */
> +			intel_ddi_post_disable(encoder, NULL, NULL);
> +			pll->funcs.disable(dev_priv, pll);
> +			if (link_rate == 540000)
> +				link_rate = 270000;
> +			else if (link_rate == 270000)
> +				link_rate = 162000;
> +			else
> +				link_rate_not_found = false;
> +		}
> +		if (ret) {
> +			DRM_DEBUG_KMS("Link Training successful\n");
> +			intel_dp_stop_link_train(intel_dp);
> +			break;
> +		}
> +	}
> +	if (!lane_count)
> +		DRM_ERROR("Link Training Failed\n");
> +
> +	return ret;
> +}
> +
>  void intel_ddi_init(struct drm_device *dev, enum port port)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 07f0159..0df49e8 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
>  
> -void
> +bool
>  intel_dp_start_link_train(struct intel_dp *intel_dp)
>  {
> -	intel_dp_link_training_clock_recovery(intel_dp);
> -	intel_dp_link_training_channel_equalization(intel_dp);
> +	bool ret;
> +
> +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> +		ret = intel_dp_link_training_channel_equalization(intel_dp);
> +		if (ret)
> +			return true;
> +	}
> +	return false;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e5bc976..342a2d5 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>  			 struct intel_crtc_state *pipe_config);
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> +bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +			 uint8_t max_lane_count, bool link_mst);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
> @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>  void intel_dp_set_link_params(struct intel_dp *intel_dp,
>  			      int link_rate, uint8_t lane_count,
>  			      bool link_mst);
> -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> -- 
> 1.9.1
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-01 22:08 ` [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
  2016-09-02 12:03   ` David Weinehall
  2016-09-02 12:49   ` David Weinehall
@ 2016-09-02 13:00   ` Mika Kahola
  2016-09-06 18:01     ` Manasi Navare
  2016-09-02 19:52   ` Pandiyan, Dhinakaran
  2016-09-07  0:13   ` [PATCH v2 " Manasi Navare
  4 siblings, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-02 13:00 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> According to the DisplayPort Spec, in case of Clock Recovery failure
> the link training sequence should fall back to the lower link rate
> followed by lower lane count until CR succeeds.
> On CR success, the sequence proceeds with Channel EQ.
> In case of Channel EQ failures, it should fallback to
> lower link rate and lane count and start the CR phase again.
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              | 109
> +++++++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>  drivers/gpu/drm/i915/intel_drv.h              |   4 +-
>  3 files changed, 110 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index 67a6a0b..78d6687 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct
> intel_encoder *encoder,
>  	}
>  }
>  
> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>  				    int link_rate, uint32_t
> lane_count,
> -				    struct intel_shared_dpll *pll,
> -				    bool link_mst)
> +				    struct intel_shared_dpll *pll)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
>  	enum port port = intel_ddi_get_encoder_port(encoder);
>  
>  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> -				 link_mst);
> -	if (encoder->type == INTEL_OUTPUT_EDP)
> -		intel_edp_panel_on(intel_dp);
> +				 false);
> +
> +	intel_edp_panel_on(intel_dp);
>  
>  	intel_ddi_clk_select(encoder, pll);
>  	intel_prepare_dp_ddi_buffers(encoder);
>  	intel_ddi_init_dp_buf_reg(encoder);
>  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>  	intel_dp_start_link_train(intel_dp);
> -	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
> +	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
>  		intel_dp_stop_link_train(intel_dp);
>  }
>  
> +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +				    int link_rate, uint32_t
> lane_count,
> +				    struct intel_shared_dpll *pll,
> +				    bool link_mst)
> +{
> +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
> +	struct intel_shared_dpll_config tmp_pll_config;
> +
> +	/* Disable the PLL and obtain the PLL for Link Training
> +	 * that starts with highest link rate and lane count.
> +	 */
> +	tmp_pll_config = pll->config;
> +	pll->funcs.disable(dev_priv, pll);
> +	pll->config.crtc_mask = 0;
> +
> +	/* If Link Training fails, send a uevent to generate a
> hotplug */
> +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> link_mst)))
> +		drm_kms_helper_hotplug_event(encoder->base.dev);
At first glance, this seems that hotplug events are generated every
time when link training fails. Is there a way to limit the number of
link training tries so that we don't end up generating hotplug events
over and over again?

> +	pll->config = tmp_pll_config;
> +}
> +
>  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>  				      bool has_hdmi_sink,
>  				      struct drm_display_mode
> *adjusted_mode,
> @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct
> intel_encoder *intel_encoder,
>  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>  	int type = intel_encoder->type;
>  
> -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> +	if (type == INTEL_OUTPUT_EDP)
> +		intel_ddi_pre_enable_edp(intel_encoder,
> +					crtc->config->port_clock,
> +					crtc->config->lane_count,
> +					crtc->config->shared_dpll);
> +
> +	if (type == INTEL_OUTPUT_DP)
>  		intel_ddi_pre_enable_dp(intel_encoder,
>  					crtc->config->port_clock,
>  					crtc->config->lane_count,
>  					crtc->config->shared_dpll,
>  					intel_crtc_has_type(crtc-
> >config,
>  							    INTEL_OU
> TPUT_DP_MST));
> -	}
> -	if (type == INTEL_OUTPUT_HDMI) {
> +
> +	if (type == INTEL_OUTPUT_HDMI)
>  		intel_ddi_pre_enable_hdmi(intel_encoder,
>  					  crtc->config-
> >has_hdmi_sink,
>  					  &crtc->config-
> >base.adjusted_mode,
>  					  crtc->config-
> >shared_dpll);
> -	}
> +
>  }
>  
>  static void intel_ddi_post_disable(struct intel_encoder
> *intel_encoder,
> @@ -2431,6 +2458,66 @@ intel_ddi_get_link_dpll(struct intel_dp
> *intel_dp, int clock)
>  	return pll;
>  }
>  
> +bool
> +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +		    uint8_t max_lane_count, bool link_mst)
> +{
> +	struct intel_connector *connector = intel_dp-
> >attached_connector;
> +	struct intel_encoder *encoder = connector->encoder;
> +	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
> +	struct intel_shared_dpll *pll;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	int link_rate;
> +	uint8_t lane_count;
> +	bool link_rate_not_found = true;
> +	bool ret = false;
> +
> +	for (lane_count = max_lane_count; lane_count > 0; lane_count
> >>= 1) {
> +
> +		link_rate = max_link_rate;
> +		while (link_rate_not_found) {
At first glance, I read this as we haven't found the link rate yet and
start from 0. This is not the case here as we have found the link rate
which is the maximum link rate available. As we iterate link rates from
max to min should we switch the logic here too? I mean something like
this

bool link_rate_not_found = false;
...
while (!link_rate_not_found) {
	...
}

The other way of doing this is not to use the boolean
link_rate_not_found parameter at all but utilize the link_rate
parameter only and iterate in a loop as long as the link_rate exceeds
zero value. Anyway, this was just a thought and is more related on
personal preference than the functionality.  

> +			pll = intel_ddi_get_link_dpll(intel_dp,
> link_rate);
> +			if (pll == NULL) {
> +				DRM_ERROR("Could not find DPLL for
> link "
> +					  "training.\n");
> +				return false;
> +			}
> +			tmp_pll_config = pll->config;
> +			pll->funcs.enable(dev_priv, pll);
> +
> +			intel_dp_set_link_params(intel_dp,
> link_rate,
> +						 lane_count,
> link_mst);
> +
> +			intel_ddi_clk_select(encoder, pll);
> +			intel_prepare_dp_ddi_buffers(encoder);
It should be safe to move this ddi buffer initialization outside the
loop.

> +			intel_ddi_init_dp_buf_reg(encoder);
> +			intel_dp_sink_dpms(intel_dp,
> DRM_MODE_DPMS_ON);
> +			ret = intel_dp_start_link_train(intel_dp);
> +			if (ret)
> +				break;
> +
> +			/* Disable port followed by PLL for next
> retry/clean up */
> +			intel_ddi_post_disable(encoder, NULL, NULL);
> +			pll->funcs.disable(dev_priv, pll);
> +			if (link_rate == 540000)
> +				link_rate = 270000;
> +			else if (link_rate == 270000)
> +				link_rate = 162000;
> +			else
> +				link_rate_not_found = false;
> +		}
> +		if (ret) {
> +			DRM_DEBUG_KMS("Link Training successful\n");
> +			intel_dp_stop_link_train(intel_dp);
> +			break;
> +		}
> +	}
> +	if (!lane_count)
> +		DRM_ERROR("Link Training Failed\n");
In case of failure, I think we should still stop the link training and
call 'intel_dp_stop_link_train()'

> +
> +	return ret;
> +}
> +
>  void intel_ddi_init(struct drm_device *dev, enum port port)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 07f0159..0df49e8 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp
> *intel_dp)
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
>  
> -void
> +bool
>  intel_dp_start_link_train(struct intel_dp *intel_dp)
>  {
> -	intel_dp_link_training_clock_recovery(intel_dp);
> -	intel_dp_link_training_channel_equalization(intel_dp);
> +	bool ret;
> +
> +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> +		ret =
> intel_dp_link_training_channel_equalization(intel_dp);
> +		if (ret)
> +			return true;
> +	}
> +	return false;
yep, this is what I had in mind when I reviewed the previous patch.

>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index e5bc976..342a2d5 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder
> *encoder,
>  			 struct intel_crtc_state *pipe_config);
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool
> state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> +bool intel_ddi_link_train(struct intel_dp *intel_dp, int
> max_link_rate,
> +			 uint8_t max_lane_count, bool link_mst);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp
> *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
> @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct
> intel_digital_port *intel_dig_port,
>  void intel_dp_set_link_params(struct intel_dp *intel_dp,
>  			      int link_rate, uint8_t lane_count,
>  			      bool link_mst);
> -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>  void intel_dp_encoder_reset(struct drm_encoder *encoder);
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config
  2016-09-01 22:08 ` [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config Manasi Navare
@ 2016-09-02 13:08   ` Mika Kahola
  2016-09-08 14:47     ` Manasi Navare
  2016-09-02 20:24   ` Pandiyan, Dhinakaran
  2016-09-08 20:02   ` [PATCH v2 12/14] drm/i915: Remove the link rate and lane count loop in compute config Manasi Navare
  2 siblings, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-02 13:08 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> While configuring the pipe during modeset, it should loop
> starting from max clock and max lane count reducing the
> lane count and clock in each iteration until the requested mode
> rate is less than or equal to available link BW.
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp.c
> b/drivers/gpu/drm/i915/intel_dp.c
> index dfdbe65..e094b25 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1552,11 +1552,10 @@ intel_dp_compute_config(struct intel_encoder
> *encoder,
>  	for (; bpp >= 6*3; bpp -= 2*3) {
>  		mode_rate = intel_dp_link_required(adjusted_mode-
> >crtc_clock,
>  						   bpp);
> -
> -		for (clock = min_clock; clock <= max_clock; clock++)
> {
> -			for (lane_count = min_lane_count;
> -				lane_count <= max_lane_count;
> -				lane_count <<= 1) {
> +		for (clock = max_clock; clock >= max_clock; clock--)
The clock should be higher than or equal to min_clock.
> {
> +			for (lane_count = max_lane_count;
> +			     lane_count >= min_lane_count;
> +			     lane_count >>= 1) {
>  
>  				link_clock = common_rates[clock];
>  				link_avail =
> intel_dp_max_data_rate(link_clock,
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH 09/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2
  2016-09-02  9:16   ` Mika Kahola
@ 2016-09-02 17:55     ` Pandiyan, Dhinakaran
  0 siblings, 0 replies; 81+ messages in thread
From: Pandiyan, Dhinakaran @ 2016-09-02 17:55 UTC (permalink / raw)
  To: Kahola, Mika; +Cc: intel-gfx

On Fri, 2016-09-02 at 12:16 +0300, Mika Kahola wrote:
> On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > 
> > This function cleans up clock recovery loop in link training
> > compliant
> > tp Dp Spec 1.2. It tries the clock recovery 5 times for the same
> > voltage
> > or until max voltage swing is reached and removes the additional non
> > compliant retries. This function now returns a boolean values based
> > on
> > if clock recovery passed or failed.
> > 
> > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_dp_link_training.c | 59 ++++++++++++-----
> > ----------
> >  1 file changed, 26 insertions(+), 33 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 9145e5a..13a0341 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -117,19 +117,19 @@ static bool
> > intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
> >  	int lane;
> >  
> >  	for (lane = 0; lane < intel_dp->lane_count; lane++)
> > -		if (intel_dp->train_set[lane] &
> > DP_TRAIN_MAX_SWING_REACHED == 0)
> > +		if ((intel_dp->train_set[lane] &
> > +		     DP_TRAIN_MAX_SWING_REACHED) == 0)
> >  			return false;
> >  
> This function was defined in the previous patch. Do we need to split
> this if(...) line into separate lines in this patch? 
> 

Ah! That was not intended, I will re-submit. 

> >  	return true;
> >  }
> >  
> >  /* Enable corresponding port and start training pattern 1 */
> > -static void
> > +static bool
> >  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> >  {
> > -	int i;
> >  	uint8_t voltage;
> > -	int voltage_tries, loop_tries;
> > +	int voltage_tries, max_vswing_tries;
> >  	uint8_t link_config[2];
> >  	uint8_t link_bw, rate_select;
> >  
> > @@ -145,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct
> > intel_dp *intel_dp)
> >  	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
> >  		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
> >  	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET,
> > link_config, 2);
> > +
> >  	if (intel_dp->num_sink_rates)
> >  		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
> >  				  &rate_select, 1);
> > @@ -160,58 +161,50 @@ intel_dp_link_training_clock_recovery(struct
> > intel_dp *intel_dp)
> >  				       DP_TRAINING_PATTERN_1 |
> >  				       DP_LINK_SCRAMBLING_DISABLE))
> > {
> >  		DRM_ERROR("failed to enable link training\n");
> > -		return;
> > +		return false;
> >  	}
> >  
> > -	voltage = 0xff;
> > -	voltage_tries = 0;
> > -	loop_tries = 0;
> > +	voltage_tries = 1;
> > +	max_vswing_tries = 0;
> >  	for (;;) {
> >  		uint8_t link_status[DP_LINK_STATUS_SIZE];
> >  
> >  		drm_dp_link_train_clock_recovery_delay(intel_dp-
> > >dpcd);
> > +
> >  		if (!intel_dp_get_link_status(intel_dp,
> > link_status)) {
> >  			DRM_ERROR("failed to get link status\n");
> > -			break;
> > +			return false;
> >  		}
> >  
> >  		if (drm_dp_clock_recovery_ok(link_status, intel_dp-
> > >lane_count)) {
> >  			DRM_DEBUG_KMS("clock recovery OK\n");
> > -			break;
> > +			return true;
> >  		}
> >  
> > -		/* Check to see if we've tried the max voltage */
> > -		if (intel_dp_link_max_vswing_reached(intel_dp)) {
> > -			++loop_tries;
> > -			if (loop_tries == 5) {
> > -				DRM_ERROR("too many full retries,
> > give up\n");
> > -				intel_dp_dump_link_status(link_statu
> > s);
> > -				break;
> > -			}
> > -			intel_dp_reset_link_train(intel_dp,
> > -						  DP_TRAINING_PATTER
> > N_1 |
> > -						  DP_LINK_SCRAMBLING
> > _DISABLE);
> > -			voltage_tries = 0;
> > -			continue;
> > +		if (voltage_tries == 5 || max_vswing_tries == 1) {
> > +			DRM_DEBUG_KMS("Max. vswing reached or same
> > voltage "
> > +				      "tried 5 times\n");
> > +			return false;
> >  		}
> I think it would be beneficial to know which one we hit if the clock
> recovery fails. Therefore, I would split these debug messages so that
> there would be separate debug messages when reaching max vswing or
> trying out the same voltage for five times.

Agreed.

Also, I don't think we need the 'max_vswing_tries' local at all. We
could just call intel_dp_link_max_vswing_reached() here and remove the
call below.



> 
> >  
> > -		/* Check to see if we've tried the same voltage 5
> > times */
> > -		if ((intel_dp->train_set[0] &
> > DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
> > -			++voltage_tries;
> > -			if (voltage_tries == 5) {
> > -				DRM_ERROR("too many voltage retries,
> > give up\n");
> > -				break;
> > -			}
> > -		} else
> > -			voltage_tries = 0;
> >  		voltage = intel_dp->train_set[0] &
> > DP_TRAIN_VOLTAGE_SWING_MASK;
> >  
> >  		/* Update training set as requested by target */
> >  		intel_get_adjust_train(intel_dp, link_status);
> >  		if (!intel_dp_update_link_train(intel_dp)) {
> >  			DRM_ERROR("failed to update link
> > training\n");
> > -			break;
> > +			return false;
> >  		}
> > +
> > +		if ((intel_dp->train_set[0] &
> > DP_TRAIN_VOLTAGE_SWING_MASK) ==
> > +		    voltage)
> > +			++voltage_tries;
> > +		else
> > +			voltage_tries = 1;
> > +
> > +		if (intel_dp_link_max_vswing_reached(intel_dp))
> > +			++max_vswing_tries;
> > +
> >  	}
> >  }
> >  

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

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

* Re: [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant
  2016-09-02 11:20   ` Mika Kahola
@ 2016-09-02 19:05     ` Pandiyan, Dhinakaran
  2016-09-07  7:50       ` Mika Kahola
  0 siblings, 1 reply; 81+ messages in thread
From: Pandiyan, Dhinakaran @ 2016-09-02 19:05 UTC (permalink / raw)
  To: Kahola, Mika; +Cc: intel-gfx

On Fri, 2016-09-02 at 14:20 +0300, Mika Kahola wrote:
> On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > Fix the number of tries in channel euqalization link training
> > sequence
> > according to DP 1.2 Spec. It returns a boolean depending on channel
> > equalization pass or failure.
> > 
> > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_dp_link_training.c | 57 ++++++++++-------
> > ----------
> >  drivers/gpu/drm/i915/intel_drv.h              |  1 +
> >  2 files changed, 22 insertions(+), 36 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 13a0341..07f0159 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -240,12 +240,12 @@ static u32 intel_dp_training_pattern(struct
> > intel_dp *intel_dp)
> >  	return training_pattern;
> >  }
> >  
> > -static void
> > +static bool
> >  intel_dp_link_training_channel_equalization(struct intel_dp
> > *intel_dp)
> >  {
> > -	bool channel_eq = false;
> > -	int tries, cr_tries;
> > +	int tries;
> >  	u32 training_pattern;
> > +	uint8_t link_status[DP_LINK_STATUS_SIZE];
> >  
> >  	training_pattern = intel_dp_training_pattern(intel_dp);
> >  
> > @@ -254,20 +254,11 @@
> > intel_dp_link_training_channel_equalization(struct intel_dp
> > *intel_dp)
> >  				     training_pattern |
> >  				     DP_LINK_SCRAMBLING_DISABLE)) {
> >  		DRM_ERROR("failed to start channel equalization\n");
> > -		return;
> > +		return false;
> >  	}
> >  
> > -	tries = 0;
> > -	cr_tries = 0;
> > -	channel_eq = false;
> > -	for (;;) {
> > -		uint8_t link_status[DP_LINK_STATUS_SIZE];
> > -
> > -		if (cr_tries > 5) {
> > -			DRM_ERROR("failed to train DP, aborting\n");
> > -			intel_dp_dump_link_status(link_status);
> > -			break;
> > -		}
> > +	intel_dp->channel_eq_status = 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)) {
> > @@ -278,44 +269,38 @@
> > intel_dp_link_training_channel_equalization(struct intel_dp
> > *intel_dp)
> >  		/* Make sure clock is still ok */
> >  		if (!drm_dp_clock_recovery_ok(link_status,
> >  					      intel_dp->lane_count)) 
> > {
> > -			intel_dp_link_training_clock_recovery(intel_
> > dp);
> > -			intel_dp_set_link_train(intel_dp,
> > -						training_pattern |
> > -						DP_LINK_SCRAMBLING_D
> > ISABLE);
> > -			cr_tries++;
> > -			continue;
> > +			intel_dp_dump_link_status(link_status);
> > +			DRM_DEBUG_KMS("Clock recovery check failed,
> > cannot "
> > +				      "continue channel
> > equalization\n");
> > +			break;
> >  		}
> This clock recovery check got me thinking. Do we really need to check
> if clock recovery is still ok within a loop? Could we move this outside
> the loop and return early if we have failed in clock recovery? One idea
> that I have in mind is that we wouldn't need to enter in channel
> equalization if we have failed with clock recovery earlier.
> 

Looks like we do. This check helps us to break out of the loop for link
rate reduction after adjusting drive setting. 


> >  
> >  		if (drm_dp_channel_eq_ok(link_status,
> >  					 intel_dp->lane_count)) {
> > -			channel_eq = true;
> > +			intel_dp->channel_eq_status = true;
> > +			DRM_DEBUG_KMS("Channel EQ done. DP Training
> > "
> > +				      "successful\n");
> >  			break;
> >  		}
> >  
> > -		/* Try 5 times, then try clock recovery if that
> > fails */
> > -		if (tries > 5) {
> > -			intel_dp_link_training_clock_recovery(intel_
> > dp);
> > -			intel_dp_set_link_train(intel_dp,
> > -						training_pattern |
> > -						DP_LINK_SCRAMBLING_D
> > ISABLE);
> > -			tries = 0;
> > -			cr_tries++;
> > -			continue;
> > -		}
> > -
> >  		/* Update training set as requested by target */
> >  		intel_get_adjust_train(intel_dp, link_status);
> >  		if (!intel_dp_update_link_train(intel_dp)) {
> >  			DRM_ERROR("failed to update link
> > training\n");
> >  			break;
> >  		}
> > -		++tries;
> > +	}
> > +
> > +	/* Try 5 times, else fail and try at lower BW */
> > +	if (tries == 5) {
> > +		intel_dp_dump_link_status(link_status);
> > +		DRM_DEBUG_KMS("Channel equalization failed 5
> > times\n");
> >  	}
> >  
> >  	intel_dp_set_idle_link_train(intel_dp);
> >  
> > -	if (channel_eq)
> > -		DRM_DEBUG_KMS("Channel EQ done. DP Training
> > successful\n");
> > +	return intel_dp->channel_eq_status;
> > +
> >  }
> >  
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index efcd80b..e5bc976 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -878,6 +878,7 @@ struct intel_dp {
> >  	bool link_mst;
> >  	bool has_audio;
> >  	bool detect_done;
> > +	bool channel_eq_status;
> >  	enum hdmi_force_audio force_audio;
> >  	bool limited_color_range;
> >  	bool color_range_auto;

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

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

* Re: [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-01 22:08 ` [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
                     ` (2 preceding siblings ...)
  2016-09-02 13:00   ` Mika Kahola
@ 2016-09-02 19:52   ` Pandiyan, Dhinakaran
  2016-09-02 20:01     ` Jim Bride
  2016-09-07  0:13   ` [PATCH v2 " Manasi Navare
  4 siblings, 1 reply; 81+ messages in thread
From: Pandiyan, Dhinakaran @ 2016-09-02 19:52 UTC (permalink / raw)
  To: Navare, Manasi D; +Cc: intel-gfx

On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> According to the DisplayPort Spec, in case of Clock Recovery failure
> the link training sequence should fall back to the lower link rate
> followed by lower lane count until CR succeeds.
> On CR success, the sequence proceeds with Channel EQ.
> In case of Channel EQ failures, it should fallback to
> lower link rate and lane count and start the CR phase again.
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>  drivers/gpu/drm/i915/intel_drv.h              |   4 +-
>  3 files changed, 110 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 67a6a0b..78d6687 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
>  	}
>  }
>  
> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>  				    int link_rate, uint32_t lane_count,
> -				    struct intel_shared_dpll *pll,
> -				    bool link_mst)
> +				    struct intel_shared_dpll *pll)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum port port = intel_ddi_get_encoder_port(encoder);
>  
>  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> -				 link_mst);
> -	if (encoder->type == INTEL_OUTPUT_EDP)
> -		intel_edp_panel_on(intel_dp);
> +				 false);
> +
> +	intel_edp_panel_on(intel_dp);
>  
>  	intel_ddi_clk_select(encoder, pll);
>  	intel_prepare_dp_ddi_buffers(encoder);
>  	intel_ddi_init_dp_buf_reg(encoder);
>  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>  	intel_dp_start_link_train(intel_dp);
> -	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
> +	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
>  		intel_dp_stop_link_train(intel_dp);
>  }
>  
> +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +				    int link_rate, uint32_t lane_count,
> +				    struct intel_shared_dpll *pll,
> +				    bool link_mst)
> +{
> +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_shared_dpll_config tmp_pll_config;
> +
> +	/* Disable the PLL and obtain the PLL for Link Training
> +	 * that starts with highest link rate and lane count.
> +	 */
> +	tmp_pll_config = pll->config;
> +	pll->funcs.disable(dev_priv, pll);
> +	pll->config.crtc_mask = 0;
> +
> +	/* If Link Training fails, send a uevent to generate a hotplug */
> +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
> +		drm_kms_helper_hotplug_event(encoder->base.dev);
> +	pll->config = tmp_pll_config;
> +}
> +
>  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>  				      bool has_hdmi_sink,
>  				      struct drm_display_mode *adjusted_mode,
> @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
>  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>  	int type = intel_encoder->type;
>  
> -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> +	if (type == INTEL_OUTPUT_EDP)
> +		intel_ddi_pre_enable_edp(intel_encoder,
> +					crtc->config->port_clock,
> +					crtc->config->lane_count,
> +					crtc->config->shared_dpll);
> +
> +	if (type == INTEL_OUTPUT_DP)
>  		intel_ddi_pre_enable_dp(intel_encoder,
>  					crtc->config->port_clock,
>  					crtc->config->lane_count,
>  					crtc->config->shared_dpll,
>  					intel_crtc_has_type(crtc->config,
>  							    INTEL_OUTPUT_DP_MST));
> -	}
> -	if (type == INTEL_OUTPUT_HDMI) {
> +
> +	if (type == INTEL_OUTPUT_HDMI)
>  		intel_ddi_pre_enable_hdmi(intel_encoder,
>  					  crtc->config->has_hdmi_sink,
>  					  &crtc->config->base.adjusted_mode,
>  					  crtc->config->shared_dpll);
> -	}
> +
>  }
>  
>  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
> @@ -2431,6 +2458,66 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
>  	return pll;
>  }
>  
> +bool
> +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +		    uint8_t max_lane_count, bool link_mst)
> +{
> +	struct intel_connector *connector = intel_dp->attached_connector;
> +	struct intel_encoder *encoder = connector->encoder;
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_shared_dpll *pll;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	int link_rate;
> +	uint8_t lane_count;
> +	bool link_rate_not_found = true;
> +	bool ret = false;
> +
> +	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
> +
> +		link_rate = max_link_rate;
> +		while (link_rate_not_found) {
> +			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
> +			if (pll == NULL) {
> +				DRM_ERROR("Could not find DPLL for link "
> +					  "training.\n");
> +				return false;
> +			}
> +			tmp_pll_config = pll->config;
> +			pll->funcs.enable(dev_priv, pll);
> +
> +			intel_dp_set_link_params(intel_dp, link_rate,
> +						 lane_count, link_mst);
> +
> +			intel_ddi_clk_select(encoder, pll);
> +			intel_prepare_dp_ddi_buffers(encoder);
> +			intel_ddi_init_dp_buf_reg(encoder);
> +			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> +			ret = intel_dp_start_link_train(intel_dp);
> +			if (ret)
> +				break;
> +
> +			/* Disable port followed by PLL for next retry/clean up */
> +			intel_ddi_post_disable(encoder, NULL, NULL);
> +			pll->funcs.disable(dev_priv, pll);
> +			if (link_rate == 540000)
> +				link_rate = 270000;
> +			else if (link_rate == 270000)
> +				link_rate = 162000;
> +			else
> +				link_rate_not_found = false;

1. Aren't the supported rates platform dependent? I see these
definitions in intel_dp.c

static const int bxt_rates[] = { 162000, 216000, 243000, 270000,
                                  324000, 432000, 540000 };
static const int skl_rates[] = { 162000, 216000, 270000,
                                  324000, 432000, 540000 };


2. Also, it is good to have the standard rates defined in a array within
a header instead of having literals here.

Or even better, re-use what's available in intel_dp.c
static const int default_rates[] = { 162000, 270000, 540000 };


> +		}
> +		if (ret) {
> +			DRM_DEBUG_KMS("Link Training successful\n");
> +			intel_dp_stop_link_train(intel_dp);
> +			break;
> +		}
> +	}
> +	if (!lane_count)
> +		DRM_ERROR("Link Training Failed\n");
> +
> +	return ret;
> +}
> +
>  void intel_ddi_init(struct drm_device *dev, enum port port)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 07f0159..0df49e8 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
>  
> -void
> +bool
>  intel_dp_start_link_train(struct intel_dp *intel_dp)
>  {
> -	intel_dp_link_training_clock_recovery(intel_dp);
> -	intel_dp_link_training_channel_equalization(intel_dp);
> +	bool ret;
> +
> +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> +		ret = intel_dp_link_training_channel_equalization(intel_dp);
> +		if (ret)
> +			return true;
> +	}
> +	return false;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index e5bc976..342a2d5 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>  			 struct intel_crtc_state *pipe_config);
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> +bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +			 uint8_t max_lane_count, bool link_mst);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
> @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>  void intel_dp_set_link_params(struct intel_dp *intel_dp,
>  			      int link_rate, uint8_t lane_count,
>  			      bool link_mst);
> -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>  void intel_dp_encoder_reset(struct drm_encoder *encoder);

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

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

* Re: [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-02 19:52   ` Pandiyan, Dhinakaran
@ 2016-09-02 20:01     ` Jim Bride
  0 siblings, 0 replies; 81+ messages in thread
From: Jim Bride @ 2016-09-02 20:01 UTC (permalink / raw)
  To: Pandiyan, Dhinakaran; +Cc: intel-gfx

On Fri, Sep 02, 2016 at 07:52:53PM +0000, Pandiyan, Dhinakaran wrote:
> On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > According to the DisplayPort Spec, in case of Clock Recovery failure
> > the link training sequence should fall back to the lower link rate
> > followed by lower lane count until CR succeeds.
> > On CR success, the sequence proceeds with Channel EQ.
> > In case of Channel EQ failures, it should fallback to
> > lower link rate and lane count and start the CR phase again.
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
> >  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
> >  drivers/gpu/drm/i915/intel_drv.h              |   4 +-
> >  3 files changed, 110 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index 67a6a0b..78d6687 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
> >  	}
> >  }
> >  
> > -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
> >  				    int link_rate, uint32_t lane_count,
> > -				    struct intel_shared_dpll *pll,
> > -				    bool link_mst)
> > +				    struct intel_shared_dpll *pll)
> >  {
> >  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> >  	enum port port = intel_ddi_get_encoder_port(encoder);
> >  
> >  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> > -				 link_mst);
> > -	if (encoder->type == INTEL_OUTPUT_EDP)
> > -		intel_edp_panel_on(intel_dp);
> > +				 false);
> > +
> > +	intel_edp_panel_on(intel_dp);
> >  
> >  	intel_ddi_clk_select(encoder, pll);
> >  	intel_prepare_dp_ddi_buffers(encoder);
> >  	intel_ddi_init_dp_buf_reg(encoder);
> >  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> >  	intel_dp_start_link_train(intel_dp);
> > -	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
> > +	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
> >  		intel_dp_stop_link_train(intel_dp);
> >  }
> >  
> > +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +				    int link_rate, uint32_t lane_count,
> > +				    struct intel_shared_dpll *pll,
> > +				    bool link_mst)
> > +{
> > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +
> > +	/* Disable the PLL and obtain the PLL for Link Training
> > +	 * that starts with highest link rate and lane count.
> > +	 */
> > +	tmp_pll_config = pll->config;
> > +	pll->funcs.disable(dev_priv, pll);
> > +	pll->config.crtc_mask = 0;
> > +
> > +	/* If Link Training fails, send a uevent to generate a hotplug */
> > +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
> > +		drm_kms_helper_hotplug_event(encoder->base.dev);
> > +	pll->config = tmp_pll_config;
> > +}
> > +
> >  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
> >  				      bool has_hdmi_sink,
> >  				      struct drm_display_mode *adjusted_mode,
> > @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
> >  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
> >  	int type = intel_encoder->type;
> >  
> > -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> > +	if (type == INTEL_OUTPUT_EDP)
> > +		intel_ddi_pre_enable_edp(intel_encoder,
> > +					crtc->config->port_clock,
> > +					crtc->config->lane_count,
> > +					crtc->config->shared_dpll);
> > +
> > +	if (type == INTEL_OUTPUT_DP)
> >  		intel_ddi_pre_enable_dp(intel_encoder,
> >  					crtc->config->port_clock,
> >  					crtc->config->lane_count,
> >  					crtc->config->shared_dpll,
> >  					intel_crtc_has_type(crtc->config,
> >  							    INTEL_OUTPUT_DP_MST));
> > -	}
> > -	if (type == INTEL_OUTPUT_HDMI) {
> > +
> > +	if (type == INTEL_OUTPUT_HDMI)
> >  		intel_ddi_pre_enable_hdmi(intel_encoder,
> >  					  crtc->config->has_hdmi_sink,
> >  					  &crtc->config->base.adjusted_mode,
> >  					  crtc->config->shared_dpll);
> > -	}
> > +
> >  }
> >  
> >  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
> > @@ -2431,6 +2458,66 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
> >  	return pll;
> >  }
> >  
> > +bool
> > +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +		    uint8_t max_lane_count, bool link_mst)
> > +{
> > +	struct intel_connector *connector = intel_dp->attached_connector;
> > +	struct intel_encoder *encoder = connector->encoder;
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_shared_dpll *pll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +	int link_rate;
> > +	uint8_t lane_count;
> > +	bool link_rate_not_found = true;
> > +	bool ret = false;
> > +
> > +	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
> > +
> > +		link_rate = max_link_rate;
> > +		while (link_rate_not_found) {
> > +			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
> > +			if (pll == NULL) {
> > +				DRM_ERROR("Could not find DPLL for link "
> > +					  "training.\n");
> > +				return false;
> > +			}
> > +			tmp_pll_config = pll->config;
> > +			pll->funcs.enable(dev_priv, pll);
> > +
> > +			intel_dp_set_link_params(intel_dp, link_rate,
> > +						 lane_count, link_mst);
> > +
> > +			intel_ddi_clk_select(encoder, pll);
> > +			intel_prepare_dp_ddi_buffers(encoder);
> > +			intel_ddi_init_dp_buf_reg(encoder);
> > +			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> > +			ret = intel_dp_start_link_train(intel_dp);
> > +			if (ret)
> > +				break;
> > +
> > +			/* Disable port followed by PLL for next retry/clean up */
> > +			intel_ddi_post_disable(encoder, NULL, NULL);
> > +			pll->funcs.disable(dev_priv, pll);
> > +			if (link_rate == 540000)
> > +				link_rate = 270000;
> > +			else if (link_rate == 270000)
> > +				link_rate = 162000;
> > +			else
> > +				link_rate_not_found = false;
> 
> 1. Aren't the supported rates platform dependent? I see these
> definitions in intel_dp.c
> 
> static const int bxt_rates[] = { 162000, 216000, 243000, 270000,
>                                   324000, 432000, 540000 };
> static const int skl_rates[] = { 162000, 216000, 270000,
>                                   324000, 432000, 540000 };
> 
> 
> 2. Also, it is good to have the standard rates defined in a array within
> a header instead of having literals here.
> 
> Or even better, re-use what's available in intel_dp.c
> static const int default_rates[] = { 162000, 270000, 540000 };

Actually, we should be fetching and using the common rates here.  There's
already code to take the union of what the source and sink support.

Jim


> 
> > +		}
> > +		if (ret) {
> > +			DRM_DEBUG_KMS("Link Training successful\n");
> > +			intel_dp_stop_link_train(intel_dp);
> > +			break;
> > +		}
> > +	}
> > +	if (!lane_count)
> > +		DRM_ERROR("Link Training Failed\n");
> > +
> > +	return ret;
> > +}
> > +
> >  void intel_ddi_init(struct drm_device *dev, enum port port)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 07f0159..0df49e8 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> >  				DP_TRAINING_PATTERN_DISABLE);
> >  }
> >  
> > -void
> > +bool
> >  intel_dp_start_link_train(struct intel_dp *intel_dp)
> >  {
> > -	intel_dp_link_training_clock_recovery(intel_dp);
> > -	intel_dp_link_training_channel_equalization(intel_dp);
> > +	bool ret;
> > +
> > +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> > +		ret = intel_dp_link_training_channel_equalization(intel_dp);
> > +		if (ret)
> > +			return true;
> > +	}
> > +	return false;
> >  }
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index e5bc976..342a2d5 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
> >  			 struct intel_crtc_state *pipe_config);
> >  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
> >  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> > +bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +			 uint8_t max_lane_count, bool link_mst);
> >  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
> >  						  int clock);
> >  unsigned int intel_fb_align_height(struct drm_device *dev,
> > @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
> >  void intel_dp_set_link_params(struct intel_dp *intel_dp,
> >  			      int link_rate, uint8_t lane_count,
> >  			      bool link_mst);
> > -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v3 07/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT
  2016-09-01 22:08 ` [PATCH v3 07/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT Manasi Navare
@ 2016-09-02 20:06   ` Pandiyan, Dhinakaran
  2016-09-07 22:08     ` Manasi Navare
  2016-09-07 22:47   ` [PATCH v4 7/14] " Manasi Navare
  1 sibling, 1 reply; 81+ messages in thread
From: Pandiyan, Dhinakaran @ 2016-09-02 20:06 UTC (permalink / raw)
  To: Navare, Manasi D; +Cc: intel-gfx

On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> From: Jim Bride <jim.bride@linux.intel.com>
> 
> Add the PLL selection code for HSW/BDW/BXT/SKL into a stand-alone function
> in order to allow for the implementation of a platform neutral upfront
> link training function.
> 
> v3:
> * Add Hooks for all DDI platforms into this standalone function
> 
> v2:
> * Change the macro to use dev_priv instead of dev (David Weinehall)
> 
> Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c      | 38 +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_dpll_mgr.c | 38 +++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/i915/intel_dpll_mgr.h |  2 ++
>  drivers/gpu/drm/i915/intel_drv.h      |  3 ++-
>  4 files changed, 80 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index e4b875e..67a6a0b 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -2393,6 +2393,44 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
>  	return connector;
>  }
>  
> +struct intel_shared_dpll *
> +intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
> +{
> +	struct intel_connector *connector = intel_dp->attached_connector;
> +	struct intel_encoder *encoder = connector->encoder;
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct intel_shared_dpll *pll = NULL;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	enum intel_dpll_id dpll_id;
> +
> +	if (IS_BROXTON(dev_priv)) {
> +		dpll_id =  (enum intel_dpll_id)dig_port->port;
> +		/*
> +		 * Select the required PLL. This works for platforms where
> +		 * there is no shared DPLL.
> +		 */
> +		pll = &dev_priv->shared_dplls[dpll_id];
> +		if (WARN_ON(pll->active_mask)) {
> +
> +			DRM_ERROR("Shared DPLL in use. active_mask:%x\n",
> +				  pll->active_mask);
> +			pll = NULL;
> +		}
> +		tmp_pll_config = pll->config;

NULL dereference when pll is in use? 

> +		if (!bxt_ddi_dp_set_dpll_hw_state(clock,
> +						  &pll->config.hw_state)) {
> +			DRM_ERROR("Could not setup DPLL\n");
> +			pll->config = tmp_pll_config;
> +		}
> +	} else if (IS_SKYLAKE(dev_priv)) {
> +		pll = skl_find_link_pll(dev_priv, clock);
> +	} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
> +		pll = hsw_ddi_dp_get_dpll(encoder, clock);
> +	}
> +	return pll;
> +}
> +
>  void intel_ddi_init(struct drm_device *dev, enum port port)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> index 9a1da98..4b067ac 100644
> --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> @@ -24,6 +24,44 @@
>  #include "intel_drv.h"
>  
>  struct intel_shared_dpll *
> +skl_find_link_pll(struct drm_i915_private *dev_priv, int clock)
> +{
> +	struct intel_shared_dpll *pll = NULL;
> +	struct intel_dpll_hw_state dpll_hw_state;
> +	enum intel_dpll_id i;
> +	bool found = false;
> +
> +	if (!skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
> +		return pll;
> +
> +	for (i = DPLL_ID_SKL_DPLL1; i <= DPLL_ID_SKL_DPLL3; i++) {
> +		pll = &dev_priv->shared_dplls[i];
> +
> +		/* Only want to check enabled timings first */
> +		if (pll->config.crtc_mask == 0)
> +			continue;
> +
> +		if (memcmp(&dpll_hw_state, &pll->config.hw_state,
> +			   sizeof(pll->config.hw_state)) == 0) {
> +			found = true;
> +			break;
> +		}
> +	}
> +
> +	/* Ok no matching timings, maybe there's a free one? */
> +	for (i = DPLL_ID_SKL_DPLL1;
> +	     ((found == false) && (i <= DPLL_ID_SKL_DPLL3)); i++) {
> +		pll = &dev_priv->shared_dplls[i];
> +		if (pll->config.crtc_mask == 0) {
> +			pll->config.hw_state = dpll_hw_state;
> +			break;
> +		}
> +	}
> +
> +	return pll;
> +}
> +
> +struct intel_shared_dpll *
>  intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
>  			    enum intel_dpll_id id)
>  {
> diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> index aed7408..f438535 100644
> --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
> +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> @@ -168,6 +168,8 @@ bool bxt_ddi_dp_set_dpll_hw_state(int clock,
>  /* SKL dpll related functions */
>  bool skl_ddi_dp_set_dpll_hw_state(int clock,
>  				  struct intel_dpll_hw_state *dpll_hw_state);
> +struct intel_shared_dpll *skl_find_link_pll(struct drm_i915_private *dev_priv,
> +					    int clock);
>  
> 
>  /* HSW dpll related functions */
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 529fa7b..efcd80b 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1159,7 +1159,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>  			 struct intel_crtc_state *pipe_config);
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> -
> +struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
> +						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
>  				   unsigned int height,
>  				   uint32_t pixel_format,

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

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

* Re: [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config
  2016-09-01 22:08 ` [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config Manasi Navare
  2016-09-02 13:08   ` Mika Kahola
@ 2016-09-02 20:24   ` Pandiyan, Dhinakaran
  2016-09-08 20:02   ` [PATCH v2 12/14] drm/i915: Remove the link rate and lane count loop in compute config Manasi Navare
  2 siblings, 0 replies; 81+ messages in thread
From: Pandiyan, Dhinakaran @ 2016-09-02 20:24 UTC (permalink / raw)
  To: Navare, Manasi D; +Cc: intel-gfx

On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> While configuring the pipe during modeset, it should loop
> starting from max clock and max lane count reducing the
> lane count and clock in each iteration until the requested mode
> rate is less than or equal to available link BW.
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index dfdbe65..e094b25 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1552,11 +1552,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  	for (; bpp >= 6*3; bpp -= 2*3) {
>  		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
>  						   bpp);
> -
> -		for (clock = min_clock; clock <= max_clock; clock++) {
> -			for (lane_count = min_lane_count;
> -				lane_count <= max_lane_count;
> -				lane_count <<= 1) {
> +		for (clock = max_clock; clock >= max_clock; clock--) {
> +			for (lane_count = max_lane_count;
> +			     lane_count >= min_lane_count;
> +			     lane_count >>= 1) {
>  
>  				link_clock = common_rates[clock];
>  				link_avail = intel_dp_max_data_rate(link_clock,


I don't understand why the loop is still here? We are starting with the
max.link rate and max.lane count. If that is not good enough for the
mode rate, then lowering link bandwidth won't help.
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-02  8:05   ` Mika Kahola
@ 2016-09-06  9:58     ` Mika Kahola
  2016-09-06 21:25       ` Manasi Navare
  0 siblings, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-06  9:58 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

On Fri, 2016-09-02 at 11:05 +0300, Mika Kahola wrote:
> +1 for this cleanup
> 
> Reviewed-by: Mika Kahola <mika.kahola@intel.com>
Received couple of compiler warnings to be cleaned up

drivers/gpu/drm/i915/intel_dp_link_training.c: In function
‘intel_dp_link_max_vswing_reached’:
drivers/gpu/drm/i915/intel_dp_link_training.c:120:33: warning: suggest
parentheses around comparison in operand of ‘&’ [-Wparentheses]
   if (intel_dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED == 0)
                                 ^
drivers/gpu/drm/i915/intel_dp_link_training.c: In function
‘intel_dp_link_training_clock_recovery’:
drivers/gpu/drm/i915/intel_dp_link_training.c:130:6: warning: unused
variable ‘i’ [-Wunused-variable]

> 
> On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > 
> > From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > 
> > Wrap the max. vswing check in a separate function.
> > This makes the clock recovery phase of DP link training cleaner
> > 
> > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_dp_link_training.c | 16 ++++++++++++---
> > -
> >  1 file changed, 12 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 0deebed..9145e5a 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -112,6 +112,17 @@ intel_dp_update_link_train(struct intel_dp
> > *intel_dp)
> >  	return ret == intel_dp->lane_count;
> >  }
> >  
> > +static bool intel_dp_link_max_vswing_reached(struct intel_dp
> > *intel_dp)
> > +{
> > +	int lane;
> > +
> > +	for (lane = 0; lane < intel_dp->lane_count; lane++)
> > +		if (intel_dp->train_set[lane] &
> > DP_TRAIN_MAX_SWING_REACHED == 0)
> > +			return false;
> > +
> > +	return true;
> > +}
> > +
> >  /* Enable corresponding port and start training pattern 1 */
> >  static void
> >  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > @@ -170,10 +181,7 @@ intel_dp_link_training_clock_recovery(struct
> > intel_dp *intel_dp)
> >  		}
> >  
> >  		/* Check to see if we've tried the max voltage */
> > -		for (i = 0; i < intel_dp->lane_count; i++)
> > -			if ((intel_dp->train_set[i] &
> > DP_TRAIN_MAX_SWING_REACHED) == 0)
> > -				break;
> > -		if (i == intel_dp->lane_count) {
> > +		if (intel_dp_link_max_vswing_reached(intel_dp)) {
> >  			++loop_tries;
> >  			if (loop_tries == 5) {
> >  				DRM_ERROR("too many full retries,
> > give up\n");
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-02 12:03   ` David Weinehall
@ 2016-09-06 17:34     ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-06 17:34 UTC (permalink / raw)
  To: intel-gfx

On Fri, Sep 02, 2016 at 03:03:22PM +0300, David Weinehall wrote:
> On Thu, Sep 01, 2016 at 03:08:16PM -0700, Manasi Navare wrote:
> > According to the DisplayPort Spec, in case of Clock Recovery failure
> > the link training sequence should fall back to the lower link rate
> > followed by lower lane count until CR succeeds.
> > On CR success, the sequence proceeds with Channel EQ.
> > In case of Channel EQ failures, it should fallback to
> > lower link rate and lane count and start the CR phase again.
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
> >  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
> >  drivers/gpu/drm/i915/intel_drv.h              |   4 +-
> >  3 files changed, 110 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index 67a6a0b..78d6687 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
> >  	}
> >  }
> >  
> > -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
> >  				    int link_rate, uint32_t lane_count,
> > -				    struct intel_shared_dpll *pll,
> > -				    bool link_mst)
> > +				    struct intel_shared_dpll *pll)
> >  {
> >  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> >  	enum port port = intel_ddi_get_encoder_port(encoder);
> >  
> >  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> > -				 link_mst);
> > -	if (encoder->type == INTEL_OUTPUT_EDP)
> > -		intel_edp_panel_on(intel_dp);
> > +				 false);
> > +
> > +	intel_edp_panel_on(intel_dp);
> >  
> >  	intel_ddi_clk_select(encoder, pll);
> >  	intel_prepare_dp_ddi_buffers(encoder);
> >  	intel_ddi_init_dp_buf_reg(encoder);
> >  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> >  	intel_dp_start_link_train(intel_dp);
> > -	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
> > +	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
> 
> I think you got this backwards. We *want* to use INTEL_GEN().

Thanks for your review. I think it got reverted due to rebasing.
I will correct it and resend the patch.

Manasi
> 
> [snip]
> 
> 
> Kind regards, David Weinehall
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-02 12:49   ` David Weinehall
@ 2016-09-06 17:54     ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-06 17:54 UTC (permalink / raw)
  To: intel-gfx

On Fri, Sep 02, 2016 at 03:49:02PM +0300, David Weinehall wrote:
> On Thu, Sep 01, 2016 at 03:08:16PM -0700, Manasi Navare wrote:
> > According to the DisplayPort Spec, in case of Clock Recovery failure
> > the link training sequence should fall back to the lower link rate
> > followed by lower lane count until CR succeeds.
> > On CR success, the sequence proceeds with Channel EQ.
> > In case of Channel EQ failures, it should fallback to
> > lower link rate and lane count and start the CR phase again.
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
> >  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
> >  drivers/gpu/drm/i915/intel_drv.h              |   4 +-
> >  3 files changed, 110 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index 67a6a0b..78d6687 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
> >  	}
> >  }
> >  
> > -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
> >  				    int link_rate, uint32_t lane_count,
> > -				    struct intel_shared_dpll *pll,
> > -				    bool link_mst)
> > +				    struct intel_shared_dpll *pll)
> >  {
> >  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> >  	enum port port = intel_ddi_get_encoder_port(encoder);
> >  
> >  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> > -				 link_mst);
> > -	if (encoder->type == INTEL_OUTPUT_EDP)
> > -		intel_edp_panel_on(intel_dp);
> > +				 false);
> > +
> > +	intel_edp_panel_on(intel_dp);
> >  
> >  	intel_ddi_clk_select(encoder, pll);
> >  	intel_prepare_dp_ddi_buffers(encoder);
> >  	intel_ddi_init_dp_buf_reg(encoder);
> >  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> >  	intel_dp_start_link_train(intel_dp);
> > -	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
> > +	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
> >  		intel_dp_stop_link_train(intel_dp);
> >  }
> >  
> > +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +				    int link_rate, uint32_t lane_count,
> > +				    struct intel_shared_dpll *pll,
> > +				    bool link_mst)
> > +{
> > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +
> > +	/* Disable the PLL and obtain the PLL for Link Training
> > +	 * that starts with highest link rate and lane count.
> > +	 */
> > +	tmp_pll_config = pll->config;
> > +	pll->funcs.disable(dev_priv, pll);
> > +	pll->config.crtc_mask = 0;
> > +
> > +	/* If Link Training fails, send a uevent to generate a hotplug */
> > +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
> > +		drm_kms_helper_hotplug_event(encoder->base.dev);
> > +	pll->config = tmp_pll_config;
> > +}
> > +
> >  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
> >  				      bool has_hdmi_sink,
> >  				      struct drm_display_mode *adjusted_mode,
> > @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
> >  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
> >  	int type = intel_encoder->type;
> >  
> > -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> > +	if (type == INTEL_OUTPUT_EDP)
> > +		intel_ddi_pre_enable_edp(intel_encoder,
> > +					crtc->config->port_clock,
> > +					crtc->config->lane_count,
> > +					crtc->config->shared_dpll);
> > +
> > +	if (type == INTEL_OUTPUT_DP)
> >  		intel_ddi_pre_enable_dp(intel_encoder,
> >  					crtc->config->port_clock,
> >  					crtc->config->lane_count,
> >  					crtc->config->shared_dpll,
> >  					intel_crtc_has_type(crtc->config,
> >  							    INTEL_OUTPUT_DP_MST));
> > -	}
> > -	if (type == INTEL_OUTPUT_HDMI) {
> > +
> > +	if (type == INTEL_OUTPUT_HDMI)
> >  		intel_ddi_pre_enable_hdmi(intel_encoder,
> >  					  crtc->config->has_hdmi_sink,
> >  					  &crtc->config->base.adjusted_mode,
> >  					  crtc->config->shared_dpll);
> > -	}
> > +
> >  }
> >  
> >  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
> > @@ -2431,6 +2458,66 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
> >  	return pll;
> >  }
> >  
> > +bool
> > +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +		    uint8_t max_lane_count, bool link_mst)
> > +{
> > +	struct intel_connector *connector = intel_dp->attached_connector;
> > +	struct intel_encoder *encoder = connector->encoder;
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_shared_dpll *pll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +	int link_rate;
> > +	uint8_t lane_count;
> > +	bool link_rate_not_found = true;
> > +	bool ret = false;
> > +
> > +	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
> > +
> > +		link_rate = max_link_rate;
> > +		while (link_rate_not_found) {
> > +			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
> > +			if (pll == NULL) {
> > +				DRM_ERROR("Could not find DPLL for link "
> > +					  "training.\n");
> > +				return false;
> > +			}
> > +			tmp_pll_config = pll->config;
> > +			pll->funcs.enable(dev_priv, pll);
> > +
> > +			intel_dp_set_link_params(intel_dp, link_rate,
> > +						 lane_count, link_mst);
> > +
> > +			intel_ddi_clk_select(encoder, pll);
> > +			intel_prepare_dp_ddi_buffers(encoder);
> > +			intel_ddi_init_dp_buf_reg(encoder);
> 
> Do you really need to run these two for every link rate?

According to Bspec on link training failure when we change the frequency,
it should follow the enable sequence steps to enable PLL and port which
include configuring DDI_BUF_TRANS and DDI_BUF_CTL.


> 
> > +			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> > +			ret = intel_dp_start_link_train(intel_dp);
> > +			if (ret)
> > +				break;
> 
> Where do you stop link training on failure? Perhaps:
> 
> ret = intel_dp_start_link_train(intel_dp);
> intel_dp_stop_link_train(intel_dp);
> if (ret)
> 	break;
> 
> and remove the stop on the success path?
>

I will make this change and resubmit.

 
> > +
> > +			/* Disable port followed by PLL for next retry/clean up */
> > +			intel_ddi_post_disable(encoder, NULL, NULL);
> > +			pll->funcs.disable(dev_priv, pll);
> > +			if (link_rate == 540000)
> > +				link_rate = 270000;
> > +			else if (link_rate == 270000)
> > +				link_rate = 162000;
> > +			else
> > +				link_rate_not_found = false;
> > +		}
> > +		if (ret) {
> > +			DRM_DEBUG_KMS("Link Training successful\n");
> > +			intel_dp_stop_link_train(intel_dp);
> > +			break;
> > +		}
> > +	}
> > +	if (!lane_count)
> > +		DRM_ERROR("Link Training Failed\n");
> > +
> > +	return ret;
> > +}
> > +
> >  void intel_ddi_init(struct drm_device *dev, enum port port)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 07f0159..0df49e8 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> >  				DP_TRAINING_PATTERN_DISABLE);
> >  }
> >  
> > -void
> > +bool
> >  intel_dp_start_link_train(struct intel_dp *intel_dp)
> >  {
> > -	intel_dp_link_training_clock_recovery(intel_dp);
> > -	intel_dp_link_training_channel_equalization(intel_dp);
> > +	bool ret;
> > +
> > +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> > +		ret = intel_dp_link_training_channel_equalization(intel_dp);
> > +		if (ret)
> > +			return true;
> > +	}
> > +	return false;
> >  }
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index e5bc976..342a2d5 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
> >  			 struct intel_crtc_state *pipe_config);
> >  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
> >  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> > +bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +			 uint8_t max_lane_count, bool link_mst);
> >  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
> >  						  int clock);
> >  unsigned int intel_fb_align_height(struct drm_device *dev,
> > @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
> >  void intel_dp_set_link_params(struct intel_dp *intel_dp,
> >  			      int link_rate, uint8_t lane_count,
> >  			      bool link_mst);
> > -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > -- 
> > 1.9.1
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-02 13:00   ` Mika Kahola
@ 2016-09-06 18:01     ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-06 18:01 UTC (permalink / raw)
  To: Mika Kahola; +Cc: intel-gfx

On Fri, Sep 02, 2016 at 04:00:20PM +0300, Mika Kahola wrote:
> On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > According to the DisplayPort Spec, in case of Clock Recovery failure
> > the link training sequence should fall back to the lower link rate
> > followed by lower lane count until CR succeeds.
> > On CR success, the sequence proceeds with Channel EQ.
> > In case of Channel EQ failures, it should fallback to
> > lower link rate and lane count and start the CR phase again.
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c              | 109
> > +++++++++++++++++++++++---
> >  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
> >  drivers/gpu/drm/i915/intel_drv.h              |   4 +-
> >  3 files changed, 110 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > b/drivers/gpu/drm/i915/intel_ddi.c
> > index 67a6a0b..78d6687 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1634,29 +1634,50 @@ void intel_ddi_clk_select(struct
> > intel_encoder *encoder,
> >  	}
> >  }
> >  
> > -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
> >  				    int link_rate, uint32_t
> > lane_count,
> > -				    struct intel_shared_dpll *pll,
> > -				    bool link_mst)
> > +				    struct intel_shared_dpll *pll)
> >  {
> >  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> >  	enum port port = intel_ddi_get_encoder_port(encoder);
> >  
> >  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> > -				 link_mst);
> > -	if (encoder->type == INTEL_OUTPUT_EDP)
> > -		intel_edp_panel_on(intel_dp);
> > +				 false);
> > +
> > +	intel_edp_panel_on(intel_dp);
> >  
> >  	intel_ddi_clk_select(encoder, pll);
> >  	intel_prepare_dp_ddi_buffers(encoder);
> >  	intel_ddi_init_dp_buf_reg(encoder);
> >  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> >  	intel_dp_start_link_train(intel_dp);
> > -	if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
> > +	if (port != PORT_A || INTEL_INFO(dev_priv)->gen >= 9)
> >  		intel_dp_stop_link_train(intel_dp);
> >  }
> >  
> > +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +				    int link_rate, uint32_t
> > lane_count,
> > +				    struct intel_shared_dpll *pll,
> > +				    bool link_mst)
> > +{
> > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > +	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +
> > +	/* Disable the PLL and obtain the PLL for Link Training
> > +	 * that starts with highest link rate and lane count.
> > +	 */
> > +	tmp_pll_config = pll->config;
> > +	pll->funcs.disable(dev_priv, pll);
> > +	pll->config.crtc_mask = 0;
> > +
> > +	/* If Link Training fails, send a uevent to generate a
> > hotplug */
> > +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> > link_mst)))
> > +		drm_kms_helper_hotplug_event(encoder->base.dev);
> At first glance, this seems that hotplug events are generated every
> time when link training fails. Is there a way to limit the number of
> link training tries so that we don't end up generating hotplug events
> over and over again?

This uevent will be sent only after retrying all the volatge swings/pre emphasis
and trying at all all possible lane counts and link rates. Also since we are 
doing upfront link training, link training failing at this point and generating a 
hotplug event is very rare.
I could possibly add a ERROR message to indicate that link training has failed
after all retries before it generates a hotplug event.

Manasi


> 
> > +	pll->config = tmp_pll_config;
> > +}
> > +
> >  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
> >  				      bool has_hdmi_sink,
> >  				      struct drm_display_mode
> > *adjusted_mode,
> > @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct
> > intel_encoder *intel_encoder,
> >  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
> >  	int type = intel_encoder->type;
> >  
> > -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> > +	if (type == INTEL_OUTPUT_EDP)
> > +		intel_ddi_pre_enable_edp(intel_encoder,
> > +					crtc->config->port_clock,
> > +					crtc->config->lane_count,
> > +					crtc->config->shared_dpll);
> > +
> > +	if (type == INTEL_OUTPUT_DP)
> >  		intel_ddi_pre_enable_dp(intel_encoder,
> >  					crtc->config->port_clock,
> >  					crtc->config->lane_count,
> >  					crtc->config->shared_dpll,
> >  					intel_crtc_has_type(crtc-
> > >config,
> >  							    INTEL_OU
> > TPUT_DP_MST));
> > -	}
> > -	if (type == INTEL_OUTPUT_HDMI) {
> > +
> > +	if (type == INTEL_OUTPUT_HDMI)
> >  		intel_ddi_pre_enable_hdmi(intel_encoder,
> >  					  crtc->config-
> > >has_hdmi_sink,
> >  					  &crtc->config-
> > >base.adjusted_mode,
> >  					  crtc->config-
> > >shared_dpll);
> > -	}
> > +
> >  }
> >  
> >  static void intel_ddi_post_disable(struct intel_encoder
> > *intel_encoder,
> > @@ -2431,6 +2458,66 @@ intel_ddi_get_link_dpll(struct intel_dp
> > *intel_dp, int clock)
> >  	return pll;
> >  }
> >  
> > +bool
> > +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +		    uint8_t max_lane_count, bool link_mst)
> > +{
> > +	struct intel_connector *connector = intel_dp-
> > >attached_connector;
> > +	struct intel_encoder *encoder = connector->encoder;
> > +	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> > +	struct intel_shared_dpll *pll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +	int link_rate;
> > +	uint8_t lane_count;
> > +	bool link_rate_not_found = true;
> > +	bool ret = false;
> > +
> > +	for (lane_count = max_lane_count; lane_count > 0; lane_count
> > >>= 1) {
> > +
> > +		link_rate = max_link_rate;
> > +		while (link_rate_not_found) {
> At first glance, I read this as we haven't found the link rate yet and
> start from 0. This is not the case here as we have found the link rate
> which is the maximum link rate available. As we iterate link rates from
> max to min should we switch the logic here too? I mean something like
> this
> 
> bool link_rate_not_found = false;
> ...
> while (!link_rate_not_found) {
> 	...
> }
> 
> The other way of doing this is not to use the boolean
> link_rate_not_found parameter at all but utilize the link_rate
> parameter only and iterate in a loop as long as the link_rate exceeds
> zero value. Anyway, this was just a thought and is more related on
> personal preference than the functionality.  

Thanks for the review comment. I will rework this logic to use the 
link rates/common rates array to iterate through the link rates
from max to min.

Manasi


> 
> > +			pll = intel_ddi_get_link_dpll(intel_dp,
> > link_rate);
> > +			if (pll == NULL) {
> > +				DRM_ERROR("Could not find DPLL for
> > link "
> > +					  "training.\n");
> > +				return false;
> > +			}
> > +			tmp_pll_config = pll->config;
> > +			pll->funcs.enable(dev_priv, pll);
> > +
> > +			intel_dp_set_link_params(intel_dp,
> > link_rate,
> > +						 lane_count,
> > link_mst);
> > +
> > +			intel_ddi_clk_select(encoder, pll);
> > +			intel_prepare_dp_ddi_buffers(encoder);
> It should be safe to move this ddi buffer initialization outside the
> loop.
> 
> > +			intel_ddi_init_dp_buf_reg(encoder);
> > +			intel_dp_sink_dpms(intel_dp,
> > DRM_MODE_DPMS_ON);
> > +			ret = intel_dp_start_link_train(intel_dp);
> > +			if (ret)
> > +				break;
> > +
> > +			/* Disable port followed by PLL for next
> > retry/clean up */
> > +			intel_ddi_post_disable(encoder, NULL, NULL);
> > +			pll->funcs.disable(dev_priv, pll);
> > +			if (link_rate == 540000)
> > +				link_rate = 270000;
> > +			else if (link_rate == 270000)
> > +				link_rate = 162000;
> > +			else
> > +				link_rate_not_found = false;
> > +		}
> > +		if (ret) {
> > +			DRM_DEBUG_KMS("Link Training successful\n");
> > +			intel_dp_stop_link_train(intel_dp);
> > +			break;
> > +		}
> > +	}
> > +	if (!lane_count)
> > +		DRM_ERROR("Link Training Failed\n");
> In case of failure, I think we should still stop the link training and
> call 'intel_dp_stop_link_train()'
> 
> > +
> > +	return ret;
> > +}
> > +
> >  void intel_ddi_init(struct drm_device *dev, enum port port)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 07f0159..0df49e8 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp
> > *intel_dp)
> >  				DP_TRAINING_PATTERN_DISABLE);
> >  }
> >  
> > -void
> > +bool
> >  intel_dp_start_link_train(struct intel_dp *intel_dp)
> >  {
> > -	intel_dp_link_training_clock_recovery(intel_dp);
> > -	intel_dp_link_training_channel_equalization(intel_dp);
> > +	bool ret;
> > +
> > +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> > +		ret =
> > intel_dp_link_training_channel_equalization(intel_dp);
> > +		if (ret)
> > +			return true;
> > +	}
> > +	return false;
> yep, this is what I had in mind when I reviewed the previous patch.
> 
> >  }
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index e5bc976..342a2d5 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder
> > *encoder,
> >  			 struct intel_crtc_state *pipe_config);
> >  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool
> > state);
> >  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> > +bool intel_ddi_link_train(struct intel_dp *intel_dp, int
> > max_link_rate,
> > +			 uint8_t max_lane_count, bool link_mst);
> >  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp
> > *intel_dp,
> >  						  int clock);
> >  unsigned int intel_fb_align_height(struct drm_device *dev,
> > @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct
> > intel_digital_port *intel_dig_port,
> >  void intel_dp_set_link_params(struct intel_dp *intel_dp,
> >  			      int link_rate, uint8_t lane_count,
> >  			      bool link_mst);
> > -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> -- 
> Mika Kahola - Intel OTC
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-06  9:58     ` Mika Kahola
@ 2016-09-06 21:25       ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-06 21:25 UTC (permalink / raw)
  To: Mika Kahola; +Cc: intel-gfx, Dhinakaran Pandiyan

On Tue, Sep 06, 2016 at 12:58:29PM +0300, Mika Kahola wrote:
> On Fri, 2016-09-02 at 11:05 +0300, Mika Kahola wrote:
> > +1 for this cleanup
> > 
> > Reviewed-by: Mika Kahola <mika.kahola@intel.com>
> Received couple of compiler warnings to be cleaned up
> 
> drivers/gpu/drm/i915/intel_dp_link_training.c: In function
> ‘intel_dp_link_max_vswing_reached’:
> drivers/gpu/drm/i915/intel_dp_link_training.c:120:33: warning: suggest
> parentheses around comparison in operand of ‘&’ [-Wparentheses]
>    if (intel_dp->train_set[lane] & DP_TRAIN_MAX_SWING_REACHED == 0)

Yep, will fix this warning and resubmit

Manasi

>                                  ^
> drivers/gpu/drm/i915/intel_dp_link_training.c: In function
> ‘intel_dp_link_training_clock_recovery’:
> drivers/gpu/drm/i915/intel_dp_link_training.c:130:6: warning: unused
> variable ‘i’ [-Wunused-variable]
>

This unused variable 'i' gets removed in the following patch for 
making clock recovery DP compliant.

Manasi
 
> > 
> > On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > > 
> > > From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > > 
> > > Wrap the max. vswing check in a separate function.
> > > This makes the clock recovery phase of DP link training cleaner
> > > 
> > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/intel_dp_link_training.c | 16 ++++++++++++---
> > > -
> > >  1 file changed, 12 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > index 0deebed..9145e5a 100644
> > > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > @@ -112,6 +112,17 @@ intel_dp_update_link_train(struct intel_dp
> > > *intel_dp)
> > >  	return ret == intel_dp->lane_count;
> > >  }
> > >  
> > > +static bool intel_dp_link_max_vswing_reached(struct intel_dp
> > > *intel_dp)
> > > +{
> > > +	int lane;
> > > +
> > > +	for (lane = 0; lane < intel_dp->lane_count; lane++)
> > > +		if (intel_dp->train_set[lane] &
> > > DP_TRAIN_MAX_SWING_REACHED == 0)
> > > +			return false;
> > > +
> > > +	return true;
> > > +}
> > > +
> > >  /* Enable corresponding port and start training pattern 1 */
> > >  static void
> > >  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> > > @@ -170,10 +181,7 @@ intel_dp_link_training_clock_recovery(struct
> > > intel_dp *intel_dp)
> > >  		}
> > >  
> > >  		/* Check to see if we've tried the max voltage */
> > > -		for (i = 0; i < intel_dp->lane_count; i++)
> > > -			if ((intel_dp->train_set[i] &
> > > DP_TRAIN_MAX_SWING_REACHED) == 0)
> > > -				break;
> > > -		if (i == intel_dp->lane_count) {
> > > +		if (intel_dp_link_max_vswing_reached(intel_dp)) {
> > >  			++loop_tries;
> > >  			if (loop_tries == 5) {
> > >  				DRM_ERROR("too many full retries,
> > > give up\n");
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH v2 8/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-01 22:08 ` [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function Manasi Navare
  2016-09-02  8:05   ` Mika Kahola
@ 2016-09-07  0:13   ` Manasi Navare
  2016-09-07  7:00     ` Mika Kahola
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
  1 sibling, 2 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-07  0:13 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan

From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

Wrap the max. vswing check in a separate function.
This makes the clock recovery phase of DP link training cleaner

v2:
Fixed the Compiler warning (Mika Kahola)

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dp_link_training.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 0deebed..b1eee5b 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -112,6 +112,18 @@ intel_dp_update_link_train(struct intel_dp *intel_dp)
 	return ret == intel_dp->lane_count;
 }
 
+static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
+{
+	int lane;
+
+	for (lane = 0; lane < intel_dp->lane_count; lane++)
+		if (intel_dp->train_set[lane] &
+		    (DP_TRAIN_MAX_SWING_REACHED == 0))
+			return false;
+
+	return true;
+}
+
 /* Enable corresponding port and start training pattern 1 */
 static void
 intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
@@ -170,10 +182,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 		}
 
 		/* Check to see if we've tried the max voltage */
-		for (i = 0; i < intel_dp->lane_count; i++)
-			if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
-				break;
-		if (i == intel_dp->lane_count) {
+		if (intel_dp_link_max_vswing_reached(intel_dp)) {
 			++loop_tries;
 			if (loop_tries == 5) {
 				DRM_ERROR("too many full retries, give up\n");
-- 
1.9.1

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

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

* [PATCH v2 9/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2
  2016-09-01 22:08 ` [PATCH 09/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2 Manasi Navare
  2016-09-02  9:16   ` Mika Kahola
@ 2016-09-07  0:13   ` Manasi Navare
  2016-09-07  7:33     ` Mika Kahola
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
  1 sibling, 2 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-07  0:13 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan

From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

This function cleans up clock recovery loop in link training compliant
tp Dp Spec 1.2. It tries the clock recovery 5 times for the same voltage
or until max voltage swing is reached and removes the additional non
compliant retries. This function now returns a boolean values based on
if clock recovery passed or failed.

v2:
* Rebased on top of new revision of vswing patch (Manasi Navare)

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dp_link_training.c | 56 ++++++++++++---------------
 1 file changed, 24 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index b1eee5b..fbdb2e4 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -125,12 +125,11 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
 }
 
 /* Enable corresponding port and start training pattern 1 */
-static void
+static bool
 intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 {
-	int i;
 	uint8_t voltage;
-	int voltage_tries, loop_tries;
+	int voltage_tries, max_vswing_tries;
 	uint8_t link_config[2];
 	uint8_t link_bw, rate_select;
 
@@ -146,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
 		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
 	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+
 	if (intel_dp->num_sink_rates)
 		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
 				  &rate_select, 1);
@@ -161,58 +161,50 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 				       DP_TRAINING_PATTERN_1 |
 				       DP_LINK_SCRAMBLING_DISABLE)) {
 		DRM_ERROR("failed to enable link training\n");
-		return;
+		return false;
 	}
 
-	voltage = 0xff;
-	voltage_tries = 0;
-	loop_tries = 0;
+	voltage_tries = 1;
+	max_vswing_tries = 0;
 	for (;;) {
 		uint8_t link_status[DP_LINK_STATUS_SIZE];
 
 		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+
 		if (!intel_dp_get_link_status(intel_dp, link_status)) {
 			DRM_ERROR("failed to get link status\n");
-			break;
+			return false;
 		}
 
 		if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
 			DRM_DEBUG_KMS("clock recovery OK\n");
-			break;
+			return true;
 		}
 
-		/* Check to see if we've tried the max voltage */
-		if (intel_dp_link_max_vswing_reached(intel_dp)) {
-			++loop_tries;
-			if (loop_tries == 5) {
-				DRM_ERROR("too many full retries, give up\n");
-				intel_dp_dump_link_status(link_status);
-				break;
-			}
-			intel_dp_reset_link_train(intel_dp,
-						  DP_TRAINING_PATTERN_1 |
-						  DP_LINK_SCRAMBLING_DISABLE);
-			voltage_tries = 0;
-			continue;
+		if (voltage_tries == 5 || max_vswing_tries == 1) {
+			DRM_DEBUG_KMS("Max. vswing reached or same voltage "
+				      "tried 5 times\n");
+			return false;
 		}
 
-		/* Check to see if we've tried the same voltage 5 times */
-		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-			++voltage_tries;
-			if (voltage_tries == 5) {
-				DRM_ERROR("too many voltage retries, give up\n");
-				break;
-			}
-		} else
-			voltage_tries = 0;
 		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
 		/* Update training set as requested by target */
 		intel_get_adjust_train(intel_dp, link_status);
 		if (!intel_dp_update_link_train(intel_dp)) {
 			DRM_ERROR("failed to update link training\n");
-			break;
+			return false;
 		}
+
+		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
+		    voltage)
+			++voltage_tries;
+		else
+			voltage_tries = 1;
+
+		if (intel_dp_link_max_vswing_reached(intel_dp))
+			++max_vswing_tries;
+
 	}
 }
 
-- 
1.9.1

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

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

* [PATCH v2 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-01 22:08 ` [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
                     ` (3 preceding siblings ...)
  2016-09-02 19:52   ` Pandiyan, Dhinakaran
@ 2016-09-07  0:13   ` Manasi Navare
  2016-09-07  9:47     ` Mika Kahola
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
  4 siblings, 2 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-07  0:13 UTC (permalink / raw)
  To: intel-gfx

According to the DisplayPort Spec, in case of Clock Recovery failure
the link training sequence should fall back to the lower link rate
followed by lower lane count until CR succeeds.
On CR success, the sequence proceeds with Channel EQ.
In case of Channel EQ failures, it should fallback to
lower link rate and lane count and start the CR phase again.

v2:
* Add a helper function to return index of requested link rate
into common_rates array
* Changed the link rate fallback loop to make use
of common_rates array (Mika Kahola)
* Changed INTEL_INFO to INTEL_GEN (David Weinehall)

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              | 125 +++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
 drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
 drivers/gpu/drm/i915/intel_drv.h              |   7 +-
 4 files changed, 145 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 67a6a0b..e38bf4b 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
 	}
 }
 
-static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
 				    int link_rate, uint32_t lane_count,
-				    struct intel_shared_dpll *pll,
-				    bool link_mst)
+				    struct intel_shared_dpll *pll)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum port port = intel_ddi_get_encoder_port(encoder);
 
 	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
-				 link_mst);
-	if (encoder->type == INTEL_OUTPUT_EDP)
-		intel_edp_panel_on(intel_dp);
+				 false);
+
+	intel_edp_panel_on(intel_dp);
 
 	intel_ddi_clk_select(encoder, pll);
 	intel_prepare_dp_ddi_buffers(encoder);
@@ -1657,6 +1656,29 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 		intel_dp_stop_link_train(intel_dp);
 }
 
+static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+				    int link_rate, uint32_t lane_count,
+				    struct intel_shared_dpll *pll,
+				    bool link_mst)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll_config tmp_pll_config;
+
+	/* Disable the PLL and obtain the PLL for Link Training
+	 * that starts with highest link rate and lane count.
+	 */
+	tmp_pll_config = pll->config;
+	pll->funcs.disable(dev_priv, pll);
+	pll->config.crtc_mask = 0;
+
+	/* If Link Training fails, send a uevent to generate a hotplug */
+	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst,
+				   false)))
+		drm_kms_helper_hotplug_event(encoder->base.dev);
+	pll->config = tmp_pll_config;
+}
+
 static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
 				      bool has_hdmi_sink,
 				      struct drm_display_mode *adjusted_mode,
@@ -1690,20 +1712,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	int type = intel_encoder->type;
 
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+	if (type == INTEL_OUTPUT_EDP)
+		intel_ddi_pre_enable_edp(intel_encoder,
+					crtc->config->port_clock,
+					crtc->config->lane_count,
+					crtc->config->shared_dpll);
+
+	if (type == INTEL_OUTPUT_DP)
 		intel_ddi_pre_enable_dp(intel_encoder,
 					crtc->config->port_clock,
 					crtc->config->lane_count,
 					crtc->config->shared_dpll,
 					intel_crtc_has_type(crtc->config,
 							    INTEL_OUTPUT_DP_MST));
-	}
-	if (type == INTEL_OUTPUT_HDMI) {
+
+	if (type == INTEL_OUTPUT_HDMI)
 		intel_ddi_pre_enable_hdmi(intel_encoder,
 					  crtc->config->has_hdmi_sink,
 					  &crtc->config->base.adjusted_mode,
 					  crtc->config->shared_dpll);
-	}
+
 }
 
 static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
@@ -2431,6 +2459,83 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 	return pll;
 }
 
+bool
+intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+		     uint8_t max_lane_count, bool link_mst, bool is_upfront)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct intel_encoder *encoder = connector->encoder;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	int link_rate, link_rate_index;
+	uint8_t lane_count;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	bool ret = false;
+
+	link_rate_index = intel_dp_link_rate_index(intel_dp, common_rates,
+						   max_link_rate);
+	if (link_rate_index < 0) {
+		DRM_ERROR("Invalid Link Rate\n");
+		return false;
+	}
+	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
+		for (link_rate = common_rates[link_rate_index];
+		     link_rate_index >= 0; link_rate_index --) {
+			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
+			if (pll == NULL) {
+				DRM_ERROR("Could not find DPLL for link "
+					  "training.\n");
+				return false;
+			}
+			tmp_pll_config = pll->config;
+			pll->funcs.enable(dev_priv, pll);
+
+			intel_dp_set_link_params(intel_dp, link_rate,
+						 lane_count, link_mst);
+
+			intel_ddi_clk_select(encoder, pll);
+			intel_prepare_dp_ddi_buffers(encoder);
+			intel_ddi_init_dp_buf_reg(encoder);
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+			ret = intel_dp_start_link_train(intel_dp);
+			if (ret)
+				break;
+
+			/* Disable port followed by PLL for next retry/clean up */
+			intel_ddi_post_disable(encoder, NULL, NULL);
+			pll->funcs.disable(dev_priv, pll);
+			pll->config = tmp_pll_config;
+		}
+		if (ret) {
+			DRM_DEBUG_KMS("Link Training successful at link rate: "
+				      "%d lane:%d\n", link_rate, lane_count);
+			break;
+		}
+	}
+	intel_dp_stop_link_train(intel_dp);
+
+	if (is_upfront) {
+		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d lanes:%d\n",
+			      ret ? "Passed" : "Failed",
+			      link_rate, lane_count);
+		/* Disable port followed by PLL for next retry/clean up */
+		intel_ddi_post_disable(encoder, NULL, NULL);
+		pll->funcs.disable(dev_priv, pll);
+		pll->config = tmp_pll_config;
+		if (ret) {
+			/* Save the upfront values */
+			intel_dp->max_lanes_upfront = lane_count;
+			intel_dp->max_link_rate_upfront = link_rate;
+		}
+	}
+
+	if (!lane_count)
+		DRM_ERROR("Link Training Failed\n");
+
+	return ret;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index dfdbe65..391e384 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	return rates[len - 1];
 }
 
+int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
+			     int link_rate)
+{
+	int common_len;
+	int index;
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	for (index = common_len - 1; index >= 0; index--) {
+		if (link_rate == common_rates[index])
+			return index;
+	}
+
+	return -1;
+}
+
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
 {
 	return rate_to_index(rate, intel_dp->sink_rates);
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 0fb845d..705dbd1 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 				DP_TRAINING_PATTERN_DISABLE);
 }
 
-void
+bool
 intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-	intel_dp_link_training_clock_recovery(intel_dp);
-	intel_dp_link_training_channel_equalization(intel_dp);
+	bool ret;
+
+	if (intel_dp_link_training_clock_recovery(intel_dp)) {
+		ret = intel_dp_link_training_channel_equalization(intel_dp);
+		if (ret)
+			return true;
+	}
+	return false;
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e5bc976..90e7b15 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1160,6 +1160,9 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
+bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+			  uint8_t max_lane_count, bool link_mst,
+			  bool is_upfront);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
@@ -1381,7 +1384,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
 			      int link_rate, uint8_t lane_count,
 			      bool link_mst);
-void intel_dp_start_link_train(struct intel_dp *intel_dp);
+bool intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 void intel_dp_encoder_reset(struct drm_encoder *encoder);
@@ -1403,6 +1406,8 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
 int intel_dp_max_link_rate(struct intel_dp *intel_dp);
+int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
+			     int link_rate);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
 void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
-- 
1.9.1

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

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

* [PATCH v12 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-01 22:08 ` [PATCH v11 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms) Manasi Navare
@ 2016-09-07  0:13   ` Manasi Navare
  2016-09-07 18:28     ` [PATCH v13 " Manasi Navare
  0 siblings, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-07  0:13 UTC (permalink / raw)
  To: intel-gfx

From: Durgadoss R <durgadoss.r@intel.com>

To support USB type C alternate DP mode, the display driver needs to
know the number of lanes required by the DP panel as well as number
of lanes that can be supported by the type-C cable. Sometimes, the
type-C cable may limit the bandwidth even if Panel can support
more lanes. To address these scenarios, the display driver will
start link training with max lanes, and if that fails, the driver
falls back to x2 lanes; and repeats this procedure for all
bandwidth/lane configurations.

* Since link training is done before modeset only the port
  (and not pipe/planes) and its associated PLLs are enabled.
* On DP hotplug: Directly start link training on the DP encoder.
* On Connected boot scenarios: When booted with an LFP and a DP,
  sometimes BIOS brings up DP. In these cases, we disable the
  crtc and then do upfront link training; and bring it back up.
* All local changes made for upfront link training are reset
  to their previous values once it is done; so that the
  subsequent modeset is not aware of these changes.

Changes since v11:
* Change the fallback link rate logic (Manasi)
Changes since v10:
* Use the ddi link train function that loops through all the link rates
and lane counts starting from the highest supported (Manasi)
* For upfront link training, set the upfront flag so that the link can
be disabled after caching upfront values (Manasi)
Changes since v9:
* Change the macros to use dev_priv in place of dev (David Weinehall)
Changes since v8:
* Reset upfront lane count and link rate values on HPD
for DP connector physical disconnect (Manasi)
Changes since v7:
* Move the upfront link training to intel_dp_mode_valid()
  to avoid a race condition with DP MST sideband comms. (Ville)
Changes since v6:
* Fix some initialization bugs on link_rate (Jim Bride)
* Use link_rate (and not link_bw) for upfront (Ville)
* Make intel_dp_upfront*() as a vfunc (Ander)
* The train_set_valid variable in intel_dp was removed due to
  issues in fast link training. So, to indicate the link train
  status, move the channel_eq inside intel_dp.
Changes since v5:
* Moved retry logic in upfront to intel_dp.c so that it
  can be used for all platforms.
Changes since v4:
* Removed usage of crtc_state in upfront link training;
  Hence no need to find free crtc to do upfront now.
* Re-enable crtc if it was disabled for upfront.
* Use separate variables to track max lane count
  and link rate found by upfront, without modifying
  the original DPCD read from panel.
Changes since v3:
* Fixed a return value on BXT check
* Reworked on top of bxt_ddi_pll_select split from Ander
* Renamed from ddi_upfront to bxt_upfront since the
  upfront logic includes BXT specific functions for now.
Changes since v2:
* Rebased on top of latest dpll_mgr.c code and
  latest HPD related clean ups.
* Corrected return values from upfront (Ander)
* Corrected atomic locking for upfront in intel_dp.c (Ville)
Changes since v1:
*  all pll related functions inside ddi.c

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              |   1 +
 drivers/gpu/drm/i915/intel_dp.c               | 376 +++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
 drivers/gpu/drm/i915/intel_drv.h              |  11 +
 4 files changed, 290 insertions(+), 99 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e38bf4b..b32f7ba 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2507,6 +2507,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 			pll->funcs.disable(dev_priv, pll);
 			pll->config = tmp_pll_config;
 		}
+
 		if (ret) {
 			DRM_DEBUG_KMS("Link Training successful at link rate: "
 				      "%d lane:%d\n", link_rate, lane_count);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 714fbe3..7794180 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	u8 source_max, sink_max;
+	u8 temp, source_max, sink_max;
 
 	source_max = intel_dig_port->max_lanes;
 	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
 
-	return min(source_max, sink_max);
+	temp = min(source_max, sink_max);
+
+	/*
+	 * Limit max lanes w.r.t to the max value found
+	 * using Upfront link training also.
+	 */
+	if (intel_dp->max_lanes_upfront)
+		return min(temp, intel_dp->max_lanes_upfront);
+	else
+		return temp;
 }
 
 /*
@@ -190,6 +199,229 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 	return (max_link_clock * max_lanes * 8) / 10;
 }
 
+static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
+				struct drm_modeset_acquire_ctx *ctx,
+				bool enable)
+{
+	int ret;
+	struct drm_atomic_state *state;
+	struct intel_crtc_state *crtc_state;
+	struct drm_device *dev = crtc->base.dev;
+	enum pipe pipe = crtc->pipe;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	crtc_state = intel_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		drm_atomic_state_free(state);
+		return ret;
+	}
+
+	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
+			enable ? "En" : "Dis",
+			pipe_name(pipe),
+			enable ? "after" : "before");
+
+	crtc_state->base.active = enable;
+	ret = drm_atomic_commit(state);
+	if (ret)
+		drm_atomic_state_free(state);
+
+	return ret;
+}
+
+static int
+intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
+{
+	if (intel_dp->num_sink_rates) {
+		*sink_rates = intel_dp->sink_rates;
+		return intel_dp->num_sink_rates;
+	}
+
+	*sink_rates = default_rates;
+
+	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
+}
+
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+
+	/* WaDisableHBR2:skl */
+	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
+		return false;
+
+	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
+	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
+		return true;
+	else
+		return false;
+}
+
+static int
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+	int size;
+
+	if (IS_BROXTON(dev_priv)) {
+		*source_rates = bxt_rates;
+		size = ARRAY_SIZE(bxt_rates);
+	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+		*source_rates = skl_rates;
+		size = ARRAY_SIZE(skl_rates);
+	} else {
+		*source_rates = default_rates;
+		size = ARRAY_SIZE(default_rates);
+	}
+
+	/* This depends on the fact that 5.4 is last value in the array */
+	if (!intel_dp_source_supports_hbr2(intel_dp))
+		size--;
+
+	return size;
+}
+
+static int intersect_rates(const int *source_rates, int source_len,
+			   const int *sink_rates, int sink_len,
+			   int *common_rates)
+{
+	int i = 0, j = 0, k = 0;
+
+	while (i < source_len && j < sink_len) {
+		if (source_rates[i] == sink_rates[j]) {
+			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+				return k;
+			common_rates[k] = source_rates[i];
+			++k;
+			++i;
+			++j;
+		} else if (source_rates[i] < sink_rates[j]) {
+			++i;
+		} else {
+			++j;
+		}
+	}
+	return k;
+}
+
+static int intel_dp_common_rates(struct intel_dp *intel_dp,
+				 int *common_rates)
+{
+	const int *source_rates, *sink_rates;
+	int source_len, sink_len;
+
+	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+
+	/* Cap sink rates w.r.t upfront values */
+	if (intel_dp->max_link_rate_upfront) {
+		int len = sink_len - 1;
+		while (len > 0 && sink_rates[len] >
+		       intel_dp->max_link_rate_upfront)
+			len--;
+		sink_len = len + 1;
+	}
+
+	source_len = intel_dp_source_rates(intel_dp, &source_rates);
+
+	return intersect_rates(source_rates, source_len,
+			       sink_rates, sink_len,
+			       common_rates);
+}
+
+static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct intel_encoder *intel_encoder = &intel_dig_port->base;
+	struct drm_device *dev = intel_encoder->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_modeset_acquire_ctx ctx;
+	struct intel_crtc *intel_crtc;
+	struct drm_crtc *crtc = NULL;
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	bool disable_dpll = false;
+	int ret;
+	bool done = false, has_mst = false;
+	uint8_t max_lanes;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	int common_len;
+	enum intel_display_power_domain power_domain;
+
+	power_domain = intel_display_port_power_domain(intel_encoder);
+	intel_display_power_get(dev_priv, power_domain);
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	max_lanes = intel_dp_max_lane_count(intel_dp);
+	if (WARN_ON(common_len <= 0))
+		return true;
+
+	drm_modeset_acquire_init(&ctx, 0);
+retry:
+	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
+	if (ret)
+		goto exit_fail;
+
+	if (intel_encoder->base.crtc) {
+		crtc = intel_encoder->base.crtc;
+
+		ret = drm_modeset_lock(&crtc->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		intel_crtc = to_intel_crtc(crtc);
+		pll = intel_crtc->config->shared_dpll;
+		disable_dpll = true;
+		has_mst = intel_crtc_has_type(intel_crtc->config,
+					      INTEL_OUTPUT_DP_MST);
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, false);
+		if (ret)
+			goto exit_fail;
+	}
+
+	mutex_lock(&dev_priv->dpll_lock);
+	if (disable_dpll) {
+		/* Clear the PLL config state */
+		tmp_pll_config = pll->config;
+		pll->config.crtc_mask = 0;
+	}
+
+	done = intel_dp->upfront_link_train(intel_dp,
+					    common_rates[common_len-1],
+					    max_lanes,
+					    has_mst,
+					    true);
+	if (disable_dpll)
+		pll->config = tmp_pll_config;
+
+	mutex_unlock(&dev_priv->dpll_lock);
+
+	if (crtc)
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, true);
+
+exit_fail:
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	intel_display_power_put(dev_priv, power_domain);
+	return done;
+}
+
 static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
@@ -211,6 +443,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
 		target_clock = fixed_mode->clock;
 	}
 
+	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
+		bool do_upfront_link_train;
+		/* Do not do upfront link train, if it is a compliance
+		 * request
+		 */
+		do_upfront_link_train = !intel_dp->upfront_done &&
+			(intel_dp->compliance_test_type !=
+			 DP_TEST_LINK_TRAINING);
+
+		if (do_upfront_link_train)
+			intel_dp->upfront_done = intel_dp_upfront_link_train(intel_dp);
+	}
+
 	max_link_clock = intel_dp_max_link_rate(intel_dp);
 	max_lanes = intel_dp_max_lane_count(intel_dp);
 
@@ -1256,60 +1501,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 	intel_dp->aux.transfer = intel_dp_aux_transfer;
 }
 
-static int
-intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
-{
-	if (intel_dp->num_sink_rates) {
-		*sink_rates = intel_dp->sink_rates;
-		return intel_dp->num_sink_rates;
-	}
-
-	*sink_rates = default_rates;
-
-	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
-}
-
-bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-
-	/* WaDisableHBR2:skl */
-	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
-		return false;
-
-	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
-	    (INTEL_INFO(dev)->gen >= 9))
-		return true;
-	else
-		return false;
-}
-
-static int
-intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-	int size;
-
-	if (IS_BROXTON(dev)) {
-		*source_rates = bxt_rates;
-		size = ARRAY_SIZE(bxt_rates);
-	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
-		*source_rates = skl_rates;
-		size = ARRAY_SIZE(skl_rates);
-	} else {
-		*source_rates = default_rates;
-		size = ARRAY_SIZE(default_rates);
-	}
-
-	/* This depends on the fact that 5.4 is last value in the array */
-	if (!intel_dp_source_supports_hbr2(intel_dp))
-		size--;
-
-	return size;
-}
-
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
 		   struct intel_crtc_state *pipe_config)
@@ -1343,42 +1534,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
 	}
 }
 
-static int intersect_rates(const int *source_rates, int source_len,
-			   const int *sink_rates, int sink_len,
-			   int *common_rates)
-{
-	int i = 0, j = 0, k = 0;
-
-	while (i < source_len && j < sink_len) {
-		if (source_rates[i] == sink_rates[j]) {
-			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
-				return k;
-			common_rates[k] = source_rates[i];
-			++k;
-			++i;
-			++j;
-		} else if (source_rates[i] < sink_rates[j]) {
-			++i;
-		} else {
-			++j;
-		}
-	}
-	return k;
-}
-
-static int intel_dp_common_rates(struct intel_dp *intel_dp,
-				 int *common_rates)
-{
-	const int *source_rates, *sink_rates;
-	int source_len, sink_len;
-
-	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-	source_len = intel_dp_source_rates(intel_dp, &source_rates);
-
-	return intersect_rates(source_rates, source_len,
-			       sink_rates, sink_len,
-			       common_rates);
-}
 
 static void snprintf_int_array(char *str, size_t len,
 			       const int *array, int nelem)
@@ -1436,6 +1591,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	int rates[DP_MAX_SUPPORTED_RATES] = {};
 	int len;
 
+	if (intel_dp->max_link_rate_upfront)
+		return intel_dp->max_link_rate_upfront;
+
 	len = intel_dp_common_rates(intel_dp, rates);
 	if (WARN_ON(len <= 0))
 		return 162000;
@@ -1488,7 +1646,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
-	int lane_count, clock;
+	int lane_count, clock = 0;
 	int min_lane_count = 1;
 	int max_lane_count = intel_dp_max_lane_count(intel_dp);
 	/* Conveniently, the link BW constants become indices with a shift...*/
@@ -1567,11 +1725,24 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	for (; bpp >= 6*3; bpp -= 2*3) {
 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
 						   bpp);
+		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
+			clock = max_clock;
+			lane_count = intel_dp->max_lanes_upfront;
+			link_clock = intel_dp->max_link_rate_upfront;
+			link_avail = intel_dp_max_data_rate(link_clock,
+							    lane_count);
+			mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+							   bpp);
+			if (mode_rate <= link_avail)
+				goto found;
+			else
+				continue;
+		}
+
 		for (clock = max_clock; clock >= max_clock; clock--) {
 			for (lane_count = max_lane_count;
 			     lane_count >= min_lane_count;
 			     lane_count >>= 1) {
-
 				link_clock = common_rates[clock];
 				link_avail = intel_dp_max_data_rate(link_clock,
 								    lane_count);
@@ -1600,7 +1771,6 @@ found:
 	}
 
 	pipe_config->lane_count = lane_count;
-
 	pipe_config->pipe_bpp = bpp;
 	pipe_config->port_clock = common_rates[clock];
 
@@ -4284,7 +4454,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	struct drm_device *dev = connector->dev;
 	enum drm_connector_status status;
 	enum intel_display_power_domain power_domain;
-	u8 sink_irq_vector = 0;
+	u8 sink_irq_vector;
 
 	power_domain = intel_display_port_aux_power_domain(intel_encoder);
 	intel_display_power_get(to_i915(dev), power_domain);
@@ -4377,9 +4547,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	}
 
 out:
-	if ((status != connector_status_connected) &&
-	    (intel_dp->is_mst == false))
+	if (status != connector_status_connected) {
 		intel_dp_unset_edid(intel_dp);
+		intel_dp->upfront_done = false;
+		intel_dp->max_lanes_upfront = 0;
+		intel_dp->max_link_rate_upfront = 0;
+	}
 
 	intel_display_power_put(to_i915(dev), power_domain);
 	return;
@@ -5623,6 +5796,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	if (type == DRM_MODE_CONNECTOR_eDP)
 		intel_encoder->type = INTEL_OUTPUT_EDP;
 
+	/* Initialize upfront link training vfunc for DP */
+	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
+		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
+		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+			intel_dp->upfront_link_train = intel_ddi_link_train;
+	}
+
 	/* eDP only on port B and/or C on vlv/chv */
 	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
 		    is_edp(intel_dp) && port != PORT_B && port != PORT_C))
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 705dbd1..c7434e2 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -300,7 +300,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 	intel_dp_set_idle_link_train(intel_dp);
 
 	return intel_dp->channel_eq_status;
-
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 90e7b15..a2bbf68 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -882,6 +882,12 @@ struct intel_dp {
 	enum hdmi_force_audio force_audio;
 	bool limited_color_range;
 	bool color_range_auto;
+
+	/* Upfront link train parameters */
+	int max_link_rate_upfront;
+	uint8_t max_lanes_upfront;
+	bool upfront_done;
+
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
 	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
@@ -939,6 +945,11 @@ struct intel_dp {
 	/* This is called before a link training is starterd */
 	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
 
+	/* For Upfront link training */
+	bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
+				   uint8_t lane_count, bool link_mst,
+				   bool is_upfront);
+
 	/* Displayport compliance testing */
 	unsigned long compliance_test_type;
 	unsigned long compliance_test_data;
-- 
1.9.1

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

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

* [PATCH v2 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST
  2016-09-01 22:08 ` [PATCH 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST Manasi Navare
@ 2016-09-07  0:13   ` Manasi Navare
  2016-09-07 10:53     ` Mika Kahola
  0 siblings, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-07  0:13 UTC (permalink / raw)
  To: intel-gfx

From: Jim Bride <jim.bride@linux.intel.com>

Add upfront link training to intel_dp_mst_mode_valid() so that we know
topology constraints before we validate the legality of modes to be
checked.
Call the function that loops through the link rates and lane counts
starting from highest supported link rate and lane count for training
the link in compliance with DP spec

v2:
* Rebased on new revision of link training patch (Manasi Navare)

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c     |  9 ++---
 drivers/gpu/drm/i915/intel_dp_mst.c | 74 +++++++++++++++++++++++++++----------
 drivers/gpu/drm/i915/intel_drv.h    |  3 ++
 3 files changed, 61 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 7794180..0c7674f 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -131,7 +131,7 @@ static void vlv_steal_power_sequencer(struct drm_device *dev,
 				      enum pipe pipe);
 static void intel_dp_unset_edid(struct intel_dp *intel_dp);
 
-static int
+int
 intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 {
 	int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
@@ -150,7 +150,7 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 	return max_link_bw;
 }
 
-static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
+u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	u8 temp, source_max, sink_max;
@@ -312,8 +312,7 @@ static int intersect_rates(const int *source_rates, int source_len,
 	return k;
 }
 
-static int intel_dp_common_rates(struct intel_dp *intel_dp,
-				 int *common_rates)
+int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates)
 {
 	const int *source_rates, *sink_rates;
 	int source_len, sink_len;
@@ -336,7 +335,7 @@ static int intel_dp_common_rates(struct intel_dp *intel_dp,
 			       common_rates);
 }
 
-static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
+bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct intel_encoder *intel_encoder = &intel_dig_port->base;
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 54a9d76..98d45a4 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -41,21 +41,30 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 	int bpp;
 	int lane_count, slots;
 	const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-	int mst_pbn;
+	int mst_pbn, common_len;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
 
 	pipe_config->dp_encoder_is_mst = true;
 	pipe_config->has_pch_encoder = false;
-	bpp = 24;
+
 	/*
-	 * for MST we always configure max link bw - the spec doesn't
-	 * seem to suggest we should do otherwise.
+	 * For MST we always configure for the maximum trainable link bw -
+	 * the spec doesn't seem to suggest we should do otherwise.  The
+	 * calls to intel_dp_max_lane_count() and intel_dp_common_rates()
+	 * both take successful upfront link training into account, and
+	 * return the DisplayPort max supported values in the event that
+	 * upfront link training was not done.
 	 */
-	lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
+	lane_count = intel_dp_max_lane_count(intel_dp);
 
 	pipe_config->lane_count = lane_count;
 
-	pipe_config->pipe_bpp = 24;
-	pipe_config->port_clock = intel_dp_max_link_rate(intel_dp);
+	pipe_config->pipe_bpp = bpp = 24;
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	pipe_config->port_clock = common_rates[common_len - 1];
+
+	DRM_DEBUG_KMS("DP MST link configured for %d lanes @ %d.\n",
+		      pipe_config->lane_count, pipe_config->port_clock);
 
 	state = pipe_config->base.state;
 
@@ -137,6 +146,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
 	enum port port = intel_dig_port->port;
 	struct intel_connector *connector =
 		to_intel_connector(conn_state->connector);
+	struct intel_shared_dpll *pll = pipe_config->shared_dpll;
+	struct intel_shared_dpll_config tmp_pll_config;
 	int ret;
 	uint32_t temp;
 	int slots;
@@ -150,21 +161,23 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder,
 	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
 
 	if (intel_dp->active_mst_links == 0) {
-		intel_ddi_clk_select(&intel_dig_port->base,
-				     pipe_config->shared_dpll);
-
-		intel_prepare_dp_ddi_buffers(&intel_dig_port->base);
-		intel_dp_set_link_params(intel_dp,
-					 pipe_config->port_clock,
-					 pipe_config->lane_count,
-					 true);
-
-		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
 
-		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+		/* Disable the PLL since we need to acquire the PLL
+		 * based on the link rate in the link training sequence
+		 */
+		tmp_pll_config = pll->config;
+		pll->funcs.disable(dev_priv, pll);
+		pll->config.crtc_mask = 0;
+
+		/* If Link Training fails, send a uevent to generate a
+		 *hotplug
+		 */
+		if (!(intel_ddi_link_train(intel_dp, pipe_config->port_clock,
+					   pipe_config->lane_count, true,
+					   false)))
+			drm_kms_helper_hotplug_event(encoder->base.dev);
+		pll->config = tmp_pll_config;
 
-		intel_dp_start_link_train(intel_dp);
-		intel_dp_stop_link_train(intel_dp);
 	}
 
 	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
@@ -336,6 +349,27 @@ intel_dp_mst_mode_valid(struct drm_connector *connector,
 			struct drm_display_mode *mode)
 {
 	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
+	struct intel_connector *intel_connector = to_intel_connector(connector);
+	struct intel_dp *intel_dp = intel_connector->mst_port;
+
+	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
+		bool do_upfront_link_train;
+
+		do_upfront_link_train = intel_dp->compliance_test_type !=
+			DP_TEST_LINK_TRAINING;
+		if (do_upfront_link_train) {
+			intel_dp->upfront_done =
+				intel_dp_upfront_link_train(intel_dp);
+			if (intel_dp->upfront_done) {
+				DRM_DEBUG_KMS("MST upfront trained at "
+					      "%d lanes @ %d.",
+					      intel_dp->max_lanes_upfront,
+					      intel_dp->max_link_rate_upfront);
+			} else
+				DRM_DEBUG_KMS("MST upfront link training "
+					      "failed.");
+		}
+	}
 
 	/* TODO - validate mode against available PBN for link */
 	if (mode->clock < 10000)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index a2bbf68..34af3e8 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1416,6 +1416,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
+u8 intel_dp_max_lane_count(struct intel_dp *intel_dp);
 int intel_dp_max_link_rate(struct intel_dp *intel_dp);
 int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
 			     int link_rate);
@@ -1448,6 +1449,8 @@ intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing);
 void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
 			   uint8_t *link_bw, uint8_t *rate_select);
 bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
+int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates);
+bool intel_dp_upfront_link_train(struct intel_dp *intel_dp);
 bool
 intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]);
 
-- 
1.9.1

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

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

* ✗ Fi.CI.BAT: warning for Enable upfront link training on DDI platforms (rev8)
  2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
                   ` (14 preceding siblings ...)
  2016-09-01 22:48 ` ✗ Fi.CI.BAT: failure for Enable upfront link training on DDI platforms (rev3) Patchwork
@ 2016-09-07  0:54 ` Patchwork
  15 siblings, 0 replies; 81+ messages in thread
From: Patchwork @ 2016-09-07  0:54 UTC (permalink / raw)
  To: Navare, Manasi D; +Cc: intel-gfx

== Series Details ==

Series: Enable upfront link training on DDI platforms (rev8)
URL   : https://patchwork.freedesktop.org/series/10821/
State : warning

== Summary ==

Series 10821v8 Enable upfront link training on DDI platforms
http://patchwork.freedesktop.org/api/1.0/series/10821/revisions/8/mbox/

Test kms_pipe_crc_basic:
        Subgroup bad-source:
                pass       -> DMESG-WARN (fi-hsw-4770k)
        Subgroup read-crc-pipe-b:
                pass       -> SKIP       (fi-hsw-4770r)
        Subgroup suspend-read-crc-pipe-a:
                pass       -> SKIP       (fi-hsw-4770k)

fi-bdw-5557u     total:252  pass:233  dwarn:2   dfail:1   fail:1   skip:15 
fi-bsw-n3050     total:252  pass:203  dwarn:1   dfail:1   fail:1   skip:46 
fi-byt-n2820     total:252  pass:206  dwarn:2   dfail:1   fail:2   skip:41 
fi-hsw-4770k     total:252  pass:224  dwarn:3   dfail:1   fail:1   skip:23 
fi-hsw-4770r     total:252  pass:221  dwarn:2   dfail:1   fail:1   skip:27 
fi-ivb-3520m     total:252  pass:217  dwarn:2   dfail:1   fail:1   skip:31 
fi-skl-6260u     total:252  pass:234  dwarn:2   dfail:1   fail:1   skip:14 
fi-skl-6700k     total:252  pass:219  dwarn:3   dfail:1   fail:1   skip:28 
fi-snb-2520m     total:252  pass:204  dwarn:2   dfail:1   fail:2   skip:43 
fi-snb-2600      total:252  pass:205  dwarn:2   dfail:1   fail:1   skip:43 

Results at /archive/results/CI_IGT_test/Patchwork_2477/

980cf7a5d9c420afbaf52a339a2005339f9f8319 drm-intel-nightly: 2016y-09m-06d-18h-01m-33s UTC integration manifest
b8c7c7b drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT
5e7a9cf drm/i915: Split hsw_get_dpll()
00eba02 drm/i915: Split skl_get_dpll()
0643769 drm/i915: Split bxt_ddi_pll_select()
b58acd4 drm/i915: Split intel_ddi_pre_enable() into DP and HDMI versions
15463d9 drm/i915: Remove ddi_pll_sel from intel_crtc_state
dc02fad drm/i915: Don't pass crtc_state to intel_dp_set_link_params()

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

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

* Re: [PATCH v2 8/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-07  0:13   ` [PATCH v2 8/14] " Manasi Navare
@ 2016-09-07  7:00     ` Mika Kahola
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
  1 sibling, 0 replies; 81+ messages in thread
From: Mika Kahola @ 2016-09-07  7:00 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> 
> Wrap the max. vswing check in a separate function.
> This makes the clock recovery phase of DP link training cleaner
> 
> v2:
> Fixed the Compiler warning (Mika Kahola)
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 17 +++++++++++++----
>  1 file changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 0deebed..b1eee5b 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -112,6 +112,18 @@ intel_dp_update_link_train(struct intel_dp
> *intel_dp)
>  	return ret == intel_dp->lane_count;
>  }
>  
> +static bool intel_dp_link_max_vswing_reached(struct intel_dp
> *intel_dp)
> +{
> +	int lane;
> +
> +	for (lane = 0; lane < intel_dp->lane_count; lane++)
> +		if (intel_dp->train_set[lane] &
> +		    (DP_TRAIN_MAX_SWING_REACHED == 0))
> +			return false;
It seems that the parenthesis a misplaced here. I think you meant 

	if ((intel_dp->train_set[lane] &
	     DP_TRAIN_MAX_SWING_REACHED) == 0)
 
 
> +
> +	return true;
> +}
> +
>  /* Enable corresponding port and start training pattern 1 */
>  static void
>  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> @@ -170,10 +182,7 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  		}
>  
>  		/* Check to see if we've tried the max voltage */
> -		for (i = 0; i < intel_dp->lane_count; i++)
> -			if ((intel_dp->train_set[i] &
> DP_TRAIN_MAX_SWING_REACHED) == 0)
> -				break;
> -		if (i == intel_dp->lane_count) {
> +		if (intel_dp_link_max_vswing_reached(intel_dp)) {
>  			++loop_tries;
>  			if (loop_tries == 5) {
>  				DRM_ERROR("too many full retries,
> give up\n");
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v2 9/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2
  2016-09-07  0:13   ` [PATCH v2 9/14] " Manasi Navare
@ 2016-09-07  7:33     ` Mika Kahola
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
  1 sibling, 0 replies; 81+ messages in thread
From: Mika Kahola @ 2016-09-07  7:33 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> 
> This function cleans up clock recovery loop in link training
> compliant
> tp Dp Spec 1.2. It tries the clock recovery 5 times for the same
> voltage
> or until max voltage swing is reached and removes the additional non
> compliant retries. This function now returns a boolean values based
> on
> if clock recovery passed or failed.
> 
> v2:
> * Rebased on top of new revision of vswing patch (Manasi Navare)
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 56 ++++++++++++-----
> ----------
>  1 file changed, 24 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index b1eee5b..fbdb2e4 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -125,12 +125,11 @@ static bool
> intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
>  }
>  
>  /* Enable corresponding port and start training pattern 1 */
> -static void
> +static bool
>  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>  {
> -	int i;
>  	uint8_t voltage;
> -	int voltage_tries, loop_tries;
> +	int voltage_tries, max_vswing_tries;
>  	uint8_t link_config[2];
>  	uint8_t link_bw, rate_select;
>  
> @@ -146,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
>  		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
>  	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET,
> link_config, 2);
> +
>  	if (intel_dp->num_sink_rates)
>  		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
>  				  &rate_select, 1);
> @@ -161,58 +161,50 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  				       DP_TRAINING_PATTERN_1 |
>  				       DP_LINK_SCRAMBLING_DISABLE))
> {
>  		DRM_ERROR("failed to enable link training\n");
> -		return;
> +		return false;
>  	}
>  
> -	voltage = 0xff;
> -	voltage_tries = 0;
> -	loop_tries = 0;
> +	voltage_tries = 1;
> +	max_vswing_tries = 0;
>  	for (;;) {
>  		uint8_t link_status[DP_LINK_STATUS_SIZE];
>  
>  		drm_dp_link_train_clock_recovery_delay(intel_dp-
> >dpcd);
> +
>  		if (!intel_dp_get_link_status(intel_dp,
> link_status)) {
>  			DRM_ERROR("failed to get link status\n");
> -			break;
> +			return false;
>  		}
>  
>  		if (drm_dp_clock_recovery_ok(link_status, intel_dp-
> >lane_count)) {
>  			DRM_DEBUG_KMS("clock recovery OK\n");
> -			break;
> +			return true;
>  		}
>  
> -		/* Check to see if we've tried the max voltage */
> -		if (intel_dp_link_max_vswing_reached(intel_dp)) {
> -			++loop_tries;
> -			if (loop_tries == 5) {
> -				DRM_ERROR("too many full retries,
> give up\n");
> -				intel_dp_dump_link_status(link_statu
> s);
> -				break;
> -			}
> -			intel_dp_reset_link_train(intel_dp,
> -						  DP_TRAINING_PATTER
> N_1 |
> -						  DP_LINK_SCRAMBLING
> _DISABLE);
> -			voltage_tries = 0;
> -			continue;
> +		if (voltage_tries == 5 || max_vswing_tries == 1) {
> +			DRM_DEBUG_KMS("Max. vswing reached or same
> voltage "
> +				      "tried 5 times\n");
> +			return false;
>  		}
I would split this debug message in two parts so we could separate
which one we actually hit. Did we try voltage for 5 times or did we
reach max vswing. This separation might be useful if or when we need to
debug this one.

>  
> -		/* Check to see if we've tried the same voltage 5
> times */
> -		if ((intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
> -			++voltage_tries;
> -			if (voltage_tries == 5) {
> -				DRM_ERROR("too many voltage retries,
> give up\n");
> -				break;
> -			}
> -		} else
> -			voltage_tries = 0;
>  		voltage = intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK;
>  
>  		/* Update training set as requested by target */
>  		intel_get_adjust_train(intel_dp, link_status);
>  		if (!intel_dp_update_link_train(intel_dp)) {
>  			DRM_ERROR("failed to update link
> training\n");
> -			break;
> +			return false;
>  		}
> +
> +		if ((intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK) ==
> +		    voltage)
> +			++voltage_tries;
> +		else
> +			voltage_tries = 1;
> +
> +		if (intel_dp_link_max_vswing_reached(intel_dp))
> +			++max_vswing_tries;
> +
>  	}
>  }
>  
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant
  2016-09-02 19:05     ` Pandiyan, Dhinakaran
@ 2016-09-07  7:50       ` Mika Kahola
  2016-09-13 16:09         ` Rodrigo Vivi
  0 siblings, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-07  7:50 UTC (permalink / raw)
  To: Pandiyan, Dhinakaran; +Cc: intel-gfx

Reviewed-by: Mika Kahola <mika.kahola@intel.com>

On Fri, 2016-09-02 at 22:05 +0300, Pandiyan, Dhinakaran wrote:
> On Fri, 2016-09-02 at 14:20 +0300, Mika Kahola wrote:
> > 
> > On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > > 
> > > Fix the number of tries in channel euqalization link training
> > > sequence
> > > according to DP 1.2 Spec. It returns a boolean depending on
> > > channel
> > > equalization pass or failure.
> > > 
> > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com
> > > >
> > > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/intel_dp_link_training.c | 57 ++++++++++---
> > > ----
> > > ----------
> > >  drivers/gpu/drm/i915/intel_drv.h              |  1 +
> > >  2 files changed, 22 insertions(+), 36 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > index 13a0341..07f0159 100644
> > > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > > @@ -240,12 +240,12 @@ static u32 intel_dp_training_pattern(struct
> > > intel_dp *intel_dp)
> > >  	return training_pattern;
> > >  }
> > >  
> > > -static void
> > > +static bool
> > >  intel_dp_link_training_channel_equalization(struct intel_dp
> > > *intel_dp)
> > >  {
> > > -	bool channel_eq = false;
> > > -	int tries, cr_tries;
> > > +	int tries;
> > >  	u32 training_pattern;
> > > +	uint8_t link_status[DP_LINK_STATUS_SIZE];
> > >  
> > >  	training_pattern = intel_dp_training_pattern(intel_dp);
> > >  
> > > @@ -254,20 +254,11 @@
> > > intel_dp_link_training_channel_equalization(struct intel_dp
> > > *intel_dp)
> > >  				     training_pattern |
> > >  				     DP_LINK_SCRAMBLING_DISABLE)
> > > ) {
> > >  		DRM_ERROR("failed to start channel
> > > equalization\n");
> > > -		return;
> > > +		return false;
> > >  	}
> > >  
> > > -	tries = 0;
> > > -	cr_tries = 0;
> > > -	channel_eq = false;
> > > -	for (;;) {
> > > -		uint8_t link_status[DP_LINK_STATUS_SIZE];
> > > -
> > > -		if (cr_tries > 5) {
> > > -			DRM_ERROR("failed to train DP,
> > > aborting\n");
> > > -			intel_dp_dump_link_status(link_status);
> > > -			break;
> > > -		}
> > > +	intel_dp->channel_eq_status = 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)) {
> > > @@ -278,44 +269,38 @@
> > > intel_dp_link_training_channel_equalization(struct intel_dp
> > > *intel_dp)
> > >  		/* Make sure clock is still ok */
> > >  		if (!drm_dp_clock_recovery_ok(link_status,
> > >  					      intel_dp-
> > > >lane_count)) 
> > > {
> > > -			intel_dp_link_training_clock_recovery(in
> > > tel_
> > > dp);
> > > -			intel_dp_set_link_train(intel_dp,
> > > -						training_pattern
> > > |
> > > -						DP_LINK_SCRAMBLI
> > > NG_D
> > > ISABLE);
> > > -			cr_tries++;
> > > -			continue;
> > > +			intel_dp_dump_link_status(link_status);
> > > +			DRM_DEBUG_KMS("Clock recovery check
> > > failed,
> > > cannot "
> > > +				      "continue channel
> > > equalization\n");
> > > +			break;
> > >  		}
> > This clock recovery check got me thinking. Do we really need to
> > check
> > if clock recovery is still ok within a loop? Could we move this
> > outside
> > the loop and return early if we have failed in clock recovery? One
> > idea
> > that I have in mind is that we wouldn't need to enter in channel
> > equalization if we have failed with clock recovery earlier.
> > 
> Looks like we do. This check helps us to break out of the loop for
> link
> rate reduction after adjusting drive setting. 
You're right we do that.
> 
> 
> > 
> > > 
> > >  
> > >  		if (drm_dp_channel_eq_ok(link_status,
> > >  					 intel_dp->lane_count))
> > > {
> > > -			channel_eq = true;
> > > +			intel_dp->channel_eq_status = true;
> > > +			DRM_DEBUG_KMS("Channel EQ done. DP
> > > Training
> > > "
> > > +				      "successful\n");
> > >  			break;
> > >  		}
> > >  
> > > -		/* Try 5 times, then try clock recovery if that
> > > fails */
> > > -		if (tries > 5) {
> > > -			intel_dp_link_training_clock_recovery(in
> > > tel_
> > > dp);
> > > -			intel_dp_set_link_train(intel_dp,
> > > -						training_pattern
> > > |
> > > -						DP_LINK_SCRAMBLI
> > > NG_D
> > > ISABLE);
> > > -			tries = 0;
> > > -			cr_tries++;
> > > -			continue;
> > > -		}
> > > -
> > >  		/* Update training set as requested by target */
> > >  		intel_get_adjust_train(intel_dp, link_status);
> > >  		if (!intel_dp_update_link_train(intel_dp)) {
> > >  			DRM_ERROR("failed to update link
> > > training\n");
> > >  			break;
> > >  		}
> > > -		++tries;
> > > +	}
> > > +
> > > +	/* Try 5 times, else fail and try at lower BW */
> > > +	if (tries == 5) {
> > > +		intel_dp_dump_link_status(link_status);
> > > +		DRM_DEBUG_KMS("Channel equalization failed 5
> > > times\n");
> > >  	}
> > >  
> > >  	intel_dp_set_idle_link_train(intel_dp);
> > >  
> > > -	if (channel_eq)
> > > -		DRM_DEBUG_KMS("Channel EQ done. DP Training
> > > successful\n");
> > > +	return intel_dp->channel_eq_status;
> > > +
> > >  }
> > >  
> > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > b/drivers/gpu/drm/i915/intel_drv.h
> > > index efcd80b..e5bc976 100644
> > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > @@ -878,6 +878,7 @@ struct intel_dp {
> > >  	bool link_mst;
> > >  	bool has_audio;
> > >  	bool detect_done;
> > > +	bool channel_eq_status;
> > >  	enum hdmi_force_audio force_audio;
> > >  	bool limited_color_range;
> > >  	bool color_range_auto;
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v2 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-07  0:13   ` [PATCH v2 " Manasi Navare
@ 2016-09-07  9:47     ` Mika Kahola
  2016-09-07 16:47       ` Jim Bride
  2016-09-07 16:48       ` Manasi Navare
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
  1 sibling, 2 replies; 81+ messages in thread
From: Mika Kahola @ 2016-09-07  9:47 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> According to the DisplayPort Spec, in case of Clock Recovery failure
> the link training sequence should fall back to the lower link rate
> followed by lower lane count until CR succeeds.
> On CR success, the sequence proceeds with Channel EQ.
> In case of Channel EQ failures, it should fallback to
> lower link rate and lane count and start the CR phase again.
> 
> v2:
> * Add a helper function to return index of requested link rate
> into common_rates array
> * Changed the link rate fallback loop to make use
> of common_rates array (Mika Kahola)
> * Changed INTEL_INFO to INTEL_GEN (David Weinehall)
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              | 125
> +++++++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>  drivers/gpu/drm/i915/intel_drv.h              |   7 +-
>  4 files changed, 145 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index 67a6a0b..e38bf4b 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct
> intel_encoder *encoder,
>  	}
>  }
>  
> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>  				    int link_rate, uint32_t
> lane_count,
> -				    struct intel_shared_dpll *pll,
> -				    bool link_mst)
> +				    struct intel_shared_dpll *pll)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
>  	enum port port = intel_ddi_get_encoder_port(encoder);
>  
>  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> -				 link_mst);
> -	if (encoder->type == INTEL_OUTPUT_EDP)
> -		intel_edp_panel_on(intel_dp);
> +				 false);
> +
> +	intel_edp_panel_on(intel_dp);
>  
>  	intel_ddi_clk_select(encoder, pll);
>  	intel_prepare_dp_ddi_buffers(encoder);
> @@ -1657,6 +1656,29 @@ static void intel_ddi_pre_enable_dp(struct
> intel_encoder *encoder,
>  		intel_dp_stop_link_train(intel_dp);
>  }
>  
> +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +				    int link_rate, uint32_t
> lane_count,
> +				    struct intel_shared_dpll *pll,
> +				    bool link_mst)
> +{
> +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
> +	struct intel_shared_dpll_config tmp_pll_config;
> +
> +	/* Disable the PLL and obtain the PLL for Link Training
> +	 * that starts with highest link rate and lane count.
> +	 */
> +	tmp_pll_config = pll->config;
> +	pll->funcs.disable(dev_priv, pll);
> +	pll->config.crtc_mask = 0;
> +
> +	/* If Link Training fails, send a uevent to generate a
> hotplug */
> +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> link_mst,
> +				   false)))
> +		drm_kms_helper_hotplug_event(encoder->base.dev);
> +	pll->config = tmp_pll_config;
> +}
> +
>  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>  				      bool has_hdmi_sink,
>  				      struct drm_display_mode
> *adjusted_mode,
> @@ -1690,20 +1712,26 @@ static void intel_ddi_pre_enable(struct
> intel_encoder *intel_encoder,
>  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>  	int type = intel_encoder->type;
>  
> -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> +	if (type == INTEL_OUTPUT_EDP)
> +		intel_ddi_pre_enable_edp(intel_encoder,
> +					crtc->config->port_clock,
> +					crtc->config->lane_count,
> +					crtc->config->shared_dpll);
> +
> +	if (type == INTEL_OUTPUT_DP)
>  		intel_ddi_pre_enable_dp(intel_encoder,
>  					crtc->config->port_clock,
>  					crtc->config->lane_count,
>  					crtc->config->shared_dpll,
>  					intel_crtc_has_type(crtc-
> >config,
>  							    INTEL_OU
> TPUT_DP_MST));
> -	}
> -	if (type == INTEL_OUTPUT_HDMI) {
> +
> +	if (type == INTEL_OUTPUT_HDMI)
>  		intel_ddi_pre_enable_hdmi(intel_encoder,
>  					  crtc->config-
> >has_hdmi_sink,
>  					  &crtc->config-
> >base.adjusted_mode,
>  					  crtc->config-
> >shared_dpll);
> -	}
> +
>  }
>  
>  static void intel_ddi_post_disable(struct intel_encoder
> *intel_encoder,
> @@ -2431,6 +2459,83 @@ intel_ddi_get_link_dpll(struct intel_dp
> *intel_dp, int clock)
>  	return pll;
>  }
>  
> +bool
> +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +		     uint8_t max_lane_count, bool link_mst, bool
> is_upfront)
> +{
> +	struct intel_connector *connector = intel_dp-
> >attached_connector;
> +	struct intel_encoder *encoder = connector->encoder;
> +	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
> +	struct intel_shared_dpll *pll;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	int link_rate, link_rate_index;
> +	uint8_t lane_count;
> +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> +	bool ret = false;
> +
> +	link_rate_index = intel_dp_link_rate_index(intel_dp,
> common_rates,
> +						   max_link_rate);
> +	if (link_rate_index < 0) {
> +		DRM_ERROR("Invalid Link Rate\n");
> +		return false;
> +	}
> +	for (lane_count = max_lane_count; lane_count > 0; lane_count
> >>= 1) {
> +		for (link_rate = common_rates[link_rate_index];
> +		     link_rate_index >= 0; link_rate_index --) {
> +			pll = intel_ddi_get_link_dpll(intel_dp,
> link_rate);
> +			if (pll == NULL) {
> +				DRM_ERROR("Could not find DPLL for
> link "
> +					  "training.\n");
> +				return false;
> +			}
> +			tmp_pll_config = pll->config;
> +			pll->funcs.enable(dev_priv, pll);
> +
> +			intel_dp_set_link_params(intel_dp,
> link_rate,
> +						 lane_count,
> link_mst);
> +
> +			intel_ddi_clk_select(encoder, pll);
> +			intel_prepare_dp_ddi_buffers(encoder);
> +			intel_ddi_init_dp_buf_reg(encoder);
> +			intel_dp_sink_dpms(intel_dp,
> DRM_MODE_DPMS_ON);
> +			ret = intel_dp_start_link_train(intel_dp);
> +			if (ret)
> +				break;
> +
> +			/* Disable port followed by PLL for next
> retry/clean up */
> +			intel_ddi_post_disable(encoder, NULL, NULL);
> +			pll->funcs.disable(dev_priv, pll);
> +			pll->config = tmp_pll_config;
> +		}
> +		if (ret) {
> +			DRM_DEBUG_KMS("Link Training successful at
> link rate: "
> +				      "%d lane:%d\n", link_rate,
> lane_count);
> +			break;
> +		}
> +	}
> +	intel_dp_stop_link_train(intel_dp);
> +
> +	if (is_upfront) {
> +		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d
> lanes:%d\n",
> +			      ret ? "Passed" : "Failed",
> +			      link_rate, lane_count);
> +		/* Disable port followed by PLL for next retry/clean
> up */
> +		intel_ddi_post_disable(encoder, NULL, NULL);
> +		pll->funcs.disable(dev_priv, pll);
> +		pll->config = tmp_pll_config;
In a case where link training was successful, I guess we could leave
the port on. Is there a reason why we should do otherwise?


> +		if (ret) {
> +			/* Save the upfront values */
> +			intel_dp->max_lanes_upfront = lane_count;
> +			intel_dp->max_link_rate_upfront = link_rate;
My compiler wasn't really a big fan of these new members in a intel_dp
struct so I these needs to be defined in intel_drv.h

drivers/gpu/drm/i915/intel_ddi.c: In function ‘intel_ddi_link_train’:
drivers/gpu/drm/i915/intel_ddi.c:2528:12: error: ‘struct intel_dp’ has
no member named ‘max_lanes_upfront’
    intel_dp->max_lanes_upfront = lane_count;
            ^
drivers/gpu/drm/i915/intel_ddi.c:2529:12: error: ‘struct intel_dp’ has
no member named ‘max_link_rate_upfront’

    intel_dp->max_link_rate_upfront = link_rate;
> +		}
> +	}
> +
> +	if (!lane_count)
> +		DRM_ERROR("Link Training Failed\n");
> +
> +	return ret;
> +}
> +
>  void intel_ddi_init(struct drm_device *dev, enum port port)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/intel_dp.c
> b/drivers/gpu/drm/i915/intel_dp.c
> index dfdbe65..391e384 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp
> *intel_dp)
>  	return rates[len - 1];
>  }
>  
> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> *common_rates,
> +			     int link_rate)
> +{
> +	int common_len;
> +	int index;
> +
> +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> +	for (index = common_len - 1; index >= 0; index--) {
> +		if (link_rate == common_rates[index])
> +			return index;
> +	}
> +
> +	return -1;
> +}
> +
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
>  {
>  	return rate_to_index(rate, intel_dp->sink_rates);
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 0fb845d..705dbd1 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp
> *intel_dp)
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
>  
> -void
> +bool
>  intel_dp_start_link_train(struct intel_dp *intel_dp)
>  {
> -	intel_dp_link_training_clock_recovery(intel_dp);
> -	intel_dp_link_training_channel_equalization(intel_dp);
> +	bool ret;
> +
> +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> +		ret =
> intel_dp_link_training_channel_equalization(intel_dp);
> +		if (ret)
> +			return true;
> +	}
> +	return false;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index e5bc976..90e7b15 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1160,6 +1160,9 @@ void intel_ddi_clock_get(struct intel_encoder
> *encoder,
>  			 struct intel_crtc_state *pipe_config);
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool
> state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> +bool intel_ddi_link_train(struct intel_dp *intel_dp, int
> max_link_rate,
> +			  uint8_t max_lane_count, bool link_mst,
> +			  bool is_upfront);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp
> *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
> @@ -1381,7 +1384,7 @@ bool intel_dp_init_connector(struct
> intel_digital_port *intel_dig_port,
>  void intel_dp_set_link_params(struct intel_dp *intel_dp,
>  			      int link_rate, uint8_t lane_count,
>  			      bool link_mst);
> -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> @@ -1403,6 +1406,8 @@ void intel_dp_add_properties(struct intel_dp
> *intel_dp, struct drm_connector *co
>  void intel_dp_mst_suspend(struct drm_device *dev);
>  void intel_dp_mst_resume(struct drm_device *dev);
>  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> *common_rates,
> +			     int link_rate);
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
>  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
>  void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v2 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST
  2016-09-07  0:13   ` [PATCH v2 " Manasi Navare
@ 2016-09-07 10:53     ` Mika Kahola
  2016-09-07 16:40       ` Jim Bride
  2016-09-08 11:50       ` Mika Kahola
  0 siblings, 2 replies; 81+ messages in thread
From: Mika Kahola @ 2016-09-07 10:53 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> From: Jim Bride <jim.bride@linux.intel.com>
> 
> Add upfront link training to intel_dp_mst_mode_valid() so that we
> know
> topology constraints before we validate the legality of modes to be
> checked.
> Call the function that loops through the link rates and lane counts
> starting from highest supported link rate and lane count for training
> the link in compliance with DP spec
> 
> v2:
> * Rebased on new revision of link training patch (Manasi Navare)
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp.c     |  9 ++---
>  drivers/gpu/drm/i915/intel_dp_mst.c | 74
> +++++++++++++++++++++++++++----------
>  drivers/gpu/drm/i915/intel_drv.h    |  3 ++
>  3 files changed, 61 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp.c
> b/drivers/gpu/drm/i915/intel_dp.c
> index 7794180..0c7674f 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -131,7 +131,7 @@ static void vlv_steal_power_sequencer(struct
> drm_device *dev,
>  				      enum pipe pipe);
>  static void intel_dp_unset_edid(struct intel_dp *intel_dp);
>  
> -static int
> +int
>  intel_dp_max_link_bw(struct intel_dp  *intel_dp)
>  {
>  	int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
> @@ -150,7 +150,7 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
>  	return max_link_bw;
>  }
>  
> -static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
> +u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
>  {
>  	struct intel_digital_port *intel_dig_port =
> dp_to_dig_port(intel_dp);
>  	u8 temp, source_max, sink_max;
> @@ -312,8 +312,7 @@ static int intersect_rates(const int
> *source_rates, int source_len,
>  	return k;
>  }
>  
> -static int intel_dp_common_rates(struct intel_dp *intel_dp,
> -				 int *common_rates)
> +int intel_dp_common_rates(struct intel_dp *intel_dp, int
> *common_rates)
>  {
>  	const int *source_rates, *sink_rates;
>  	int source_len, sink_len;
> @@ -336,7 +335,7 @@ static int intel_dp_common_rates(struct intel_dp
> *intel_dp,
>  			       common_rates);
>  }
>  
> -static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> +bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
>  {
>  	struct intel_digital_port *intel_dig_port =
> dp_to_dig_port(intel_dp);
>  	struct intel_encoder *intel_encoder = &intel_dig_port->base;
> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c
> b/drivers/gpu/drm/i915/intel_dp_mst.c
> index 54a9d76..98d45a4 100644
> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -41,21 +41,30 @@ static bool intel_dp_mst_compute_config(struct
> intel_encoder *encoder,
>  	int bpp;
>  	int lane_count, slots;
>  	const struct drm_display_mode *adjusted_mode = &pipe_config-
> >base.adjusted_mode;
> -	int mst_pbn;
> +	int mst_pbn, common_len;
> +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
>  
>  	pipe_config->dp_encoder_is_mst = true;
>  	pipe_config->has_pch_encoder = false;
> -	bpp = 24;
> +
>  	/*
> -	 * for MST we always configure max link bw - the spec
> doesn't
> -	 * seem to suggest we should do otherwise.
> +	 * For MST we always configure for the maximum trainable
> link bw -
> +	 * the spec doesn't seem to suggest we should do
> otherwise.  The
> +	 * calls to intel_dp_max_lane_count() and
> intel_dp_common_rates()
> +	 * both take successful upfront link training into account,
> and
> +	 * return the DisplayPort max supported values in the event
> that
> +	 * upfront link training was not done.
>  	 */
> -	lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
> +	lane_count = intel_dp_max_lane_count(intel_dp);
>  
>  	pipe_config->lane_count = lane_count;
>  
> -	pipe_config->pipe_bpp = 24;
> -	pipe_config->port_clock = intel_dp_max_link_rate(intel_dp);
> +	pipe_config->pipe_bpp = bpp = 24;
> +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> +	pipe_config->port_clock = common_rates[common_len - 1];
> +
> +	DRM_DEBUG_KMS("DP MST link configured for %d lanes @ %d.\n",
> +		      pipe_config->lane_count, pipe_config-
> >port_clock);
>  
>  	state = pipe_config->base.state;
>  
> @@ -137,6 +146,8 @@ static void intel_mst_pre_enable_dp(struct
> intel_encoder *encoder,
>  	enum port port = intel_dig_port->port;
>  	struct intel_connector *connector =
>  		to_intel_connector(conn_state->connector);
> +	struct intel_shared_dpll *pll = pipe_config->shared_dpll;
> +	struct intel_shared_dpll_config tmp_pll_config;
>  	int ret;
>  	uint32_t temp;
>  	int slots;
> @@ -150,21 +161,23 @@ static void intel_mst_pre_enable_dp(struct
> intel_encoder *encoder,
>  	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
>  
>  	if (intel_dp->active_mst_links == 0) {
> -		intel_ddi_clk_select(&intel_dig_port->base,
> -				     pipe_config->shared_dpll);
> -
> -		intel_prepare_dp_ddi_buffers(&intel_dig_port->base);
> -		intel_dp_set_link_params(intel_dp,
> -					 pipe_config->port_clock,
> -					 pipe_config->lane_count,
> -					 true);
> -
> -		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
>  
> -		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> +		/* Disable the PLL since we need to acquire the PLL
> +		 * based on the link rate in the link training
> sequence
> +		 */
> +		tmp_pll_config = pll->config;
> +		pll->funcs.disable(dev_priv, pll);
> +		pll->config.crtc_mask = 0;
> +
> +		/* If Link Training fails, send a uevent to generate
> a
> +		 *hotplug
> +		 */
> +		if (!(intel_ddi_link_train(intel_dp, pipe_config-
> >port_clock,
> +					   pipe_config->lane_count,
> true,
> +					   false)))
> +			drm_kms_helper_hotplug_event(encoder-
> >base.dev);
> +		pll->config = tmp_pll_config;
>  
> -		intel_dp_start_link_train(intel_dp);
> -		intel_dp_stop_link_train(intel_dp);
>  	}
>  
>  	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
> @@ -336,6 +349,27 @@ intel_dp_mst_mode_valid(struct drm_connector
> *connector,
>  			struct drm_display_mode *mode)
>  {
>  	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
> +	struct intel_connector *intel_connector =
> to_intel_connector(connector);
> +	struct intel_dp *intel_dp = intel_connector->mst_port;
> +
> +	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) 
> {
> +		bool do_upfront_link_train;
> +
> +		do_upfront_link_train = intel_dp-
> >compliance_test_type !=
> +			DP_TEST_LINK_TRAINING;
> +		if (do_upfront_link_train) {
> +			intel_dp->upfront_done =
> +				intel_dp_upfront_link_train(intel_dp
> );
> +			if (intel_dp->upfront_done) {
> +				DRM_DEBUG_KMS("MST upfront trained
> at "
> +					      "%d lanes @ %d.",
> +					      intel_dp-
> >max_lanes_upfront,
> +					      intel_dp-
> >max_link_rate_upfront);
> +			} else
> +				DRM_DEBUG_KMS("MST upfront link
> training "
> +					      "failed.");
Link training has failed and we have a blank screen. Should we throw an
error here? Maybe

	return MODE_ERROR;

> +		}
> +	}
>  
>  	/* TODO - validate mode against available PBN for link */
>  	if (mode->clock < 10000)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index a2bbf68..34af3e8 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1416,6 +1416,7 @@ void intel_edp_panel_off(struct intel_dp
> *intel_dp);
>  void intel_dp_add_properties(struct intel_dp *intel_dp, struct
> drm_connector *connector);
>  void intel_dp_mst_suspend(struct drm_device *dev);
>  void intel_dp_mst_resume(struct drm_device *dev);
> +u8 intel_dp_max_lane_count(struct intel_dp *intel_dp);
>  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
>  int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> *common_rates,
>  			     int link_rate);
> @@ -1448,6 +1449,8 @@ intel_dp_pre_emphasis_max(struct intel_dp
> *intel_dp, uint8_t voltage_swing);
>  void intel_dp_compute_rate(struct intel_dp *intel_dp, int
> port_clock,
>  			   uint8_t *link_bw, uint8_t *rate_select);
>  bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
> +int intel_dp_common_rates(struct intel_dp *intel_dp, int
> *common_rates);
> +bool intel_dp_upfront_link_train(struct intel_dp *intel_dp);
>  bool
>  intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t
> link_status[DP_LINK_STATUS_SIZE]);
>  
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v2 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST
  2016-09-07 10:53     ` Mika Kahola
@ 2016-09-07 16:40       ` Jim Bride
  2016-09-08 10:21         ` Mika Kahola
  2016-09-08 11:50       ` Mika Kahola
  1 sibling, 1 reply; 81+ messages in thread
From: Jim Bride @ 2016-09-07 16:40 UTC (permalink / raw)
  To: Mika Kahola; +Cc: intel-gfx

On Wed, Sep 07, 2016 at 01:53:31PM +0300, Mika Kahola wrote:
> On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> > From: Jim Bride <jim.bride@linux.intel.com>
> > 
> > Add upfront link training to intel_dp_mst_mode_valid() so that we
> > know
> > topology constraints before we validate the legality of modes to be
> > checked.
> > Call the function that loops through the link rates and lane counts
> > starting from highest supported link rate and lane count for training
> > the link in compliance with DP spec
> > 
> > v2:
> > * Rebased on new revision of link training patch (Manasi Navare)
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_dp.c     |  9 ++---
> >  drivers/gpu/drm/i915/intel_dp_mst.c | 74
> > +++++++++++++++++++++++++++----------
> >  drivers/gpu/drm/i915/intel_drv.h    |  3 ++
> >  3 files changed, 61 insertions(+), 25 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > b/drivers/gpu/drm/i915/intel_dp.c
> > index 7794180..0c7674f 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -131,7 +131,7 @@ static void vlv_steal_power_sequencer(struct
> > drm_device *dev,
> >  				      enum pipe pipe);
> >  static void intel_dp_unset_edid(struct intel_dp *intel_dp);
> >  
> > -static int
> > +int
> >  intel_dp_max_link_bw(struct intel_dp  *intel_dp)
> >  {
> >  	int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
> > @@ -150,7 +150,7 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
> >  	return max_link_bw;
> >  }
> >  
> > -static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
> > +u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
> >  {
> >  	struct intel_digital_port *intel_dig_port =
> > dp_to_dig_port(intel_dp);
> >  	u8 temp, source_max, sink_max;
> > @@ -312,8 +312,7 @@ static int intersect_rates(const int
> > *source_rates, int source_len,
> >  	return k;
> >  }
> >  
> > -static int intel_dp_common_rates(struct intel_dp *intel_dp,
> > -				 int *common_rates)
> > +int intel_dp_common_rates(struct intel_dp *intel_dp, int
> > *common_rates)
> >  {
> >  	const int *source_rates, *sink_rates;
> >  	int source_len, sink_len;
> > @@ -336,7 +335,7 @@ static int intel_dp_common_rates(struct intel_dp
> > *intel_dp,
> >  			       common_rates);
> >  }
> >  
> > -static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> > +bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> >  {
> >  	struct intel_digital_port *intel_dig_port =
> > dp_to_dig_port(intel_dp);
> >  	struct intel_encoder *intel_encoder = &intel_dig_port->base;
> > diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c
> > b/drivers/gpu/drm/i915/intel_dp_mst.c
> > index 54a9d76..98d45a4 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> > @@ -41,21 +41,30 @@ static bool intel_dp_mst_compute_config(struct
> > intel_encoder *encoder,
> >  	int bpp;
> >  	int lane_count, slots;
> >  	const struct drm_display_mode *adjusted_mode = &pipe_config-
> > >base.adjusted_mode;
> > -	int mst_pbn;
> > +	int mst_pbn, common_len;
> > +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> >  
> >  	pipe_config->dp_encoder_is_mst = true;
> >  	pipe_config->has_pch_encoder = false;
> > -	bpp = 24;
> > +
> >  	/*
> > -	 * for MST we always configure max link bw - the spec
> > doesn't
> > -	 * seem to suggest we should do otherwise.
> > +	 * For MST we always configure for the maximum trainable
> > link bw -
> > +	 * the spec doesn't seem to suggest we should do
> > otherwise.  The
> > +	 * calls to intel_dp_max_lane_count() and
> > intel_dp_common_rates()
> > +	 * both take successful upfront link training into account,
> > and
> > +	 * return the DisplayPort max supported values in the event
> > that
> > +	 * upfront link training was not done.
> >  	 */
> > -	lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
> > +	lane_count = intel_dp_max_lane_count(intel_dp);
> >  
> >  	pipe_config->lane_count = lane_count;
> >  
> > -	pipe_config->pipe_bpp = 24;
> > -	pipe_config->port_clock = intel_dp_max_link_rate(intel_dp);
> > +	pipe_config->pipe_bpp = bpp = 24;
> > +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> > +	pipe_config->port_clock = common_rates[common_len - 1];
> > +
> > +	DRM_DEBUG_KMS("DP MST link configured for %d lanes @ %d.\n",
> > +		      pipe_config->lane_count, pipe_config-
> > >port_clock);
> >  
> >  	state = pipe_config->base.state;
> >  
> > @@ -137,6 +146,8 @@ static void intel_mst_pre_enable_dp(struct
> > intel_encoder *encoder,
> >  	enum port port = intel_dig_port->port;
> >  	struct intel_connector *connector =
> >  		to_intel_connector(conn_state->connector);
> > +	struct intel_shared_dpll *pll = pipe_config->shared_dpll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> >  	int ret;
> >  	uint32_t temp;
> >  	int slots;
> > @@ -150,21 +161,23 @@ static void intel_mst_pre_enable_dp(struct
> > intel_encoder *encoder,
> >  	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
> >  
> >  	if (intel_dp->active_mst_links == 0) {
> > -		intel_ddi_clk_select(&intel_dig_port->base,
> > -				     pipe_config->shared_dpll);
> > -
> > -		intel_prepare_dp_ddi_buffers(&intel_dig_port->base);
> > -		intel_dp_set_link_params(intel_dp,
> > -					 pipe_config->port_clock,
> > -					 pipe_config->lane_count,
> > -					 true);
> > -
> > -		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
> >  
> > -		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> > +		/* Disable the PLL since we need to acquire the PLL
> > +		 * based on the link rate in the link training
> > sequence
> > +		 */
> > +		tmp_pll_config = pll->config;
> > +		pll->funcs.disable(dev_priv, pll);
> > +		pll->config.crtc_mask = 0;
> > +
> > +		/* If Link Training fails, send a uevent to generate
> > a
> > +		 *hotplug
> > +		 */
> > +		if (!(intel_ddi_link_train(intel_dp, pipe_config-
> > >port_clock,
> > +					   pipe_config->lane_count,
> > true,
> > +					   false)))
> > +			drm_kms_helper_hotplug_event(encoder-
> > >base.dev);
> > +		pll->config = tmp_pll_config;
> >  
> > -		intel_dp_start_link_train(intel_dp);
> > -		intel_dp_stop_link_train(intel_dp);
> >  	}
> >  
> >  	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
> > @@ -336,6 +349,27 @@ intel_dp_mst_mode_valid(struct drm_connector
> > *connector,
> >  			struct drm_display_mode *mode)
> >  {
> >  	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
> > +	struct intel_connector *intel_connector =
> > to_intel_connector(connector);
> > +	struct intel_dp *intel_dp = intel_connector->mst_port;
> > +
> > +	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) 
> > {
> > +		bool do_upfront_link_train;
> > +
> > +		do_upfront_link_train = intel_dp-
> > >compliance_test_type !=
> > +			DP_TEST_LINK_TRAINING;
> > +		if (do_upfront_link_train) {
> > +			intel_dp->upfront_done =
> > +				intel_dp_upfront_link_train(intel_dp
> > );
> > +			if (intel_dp->upfront_done) {
> > +				DRM_DEBUG_KMS("MST upfront trained
> > at "
> > +					      "%d lanes @ %d.",
> > +					      intel_dp-
> > >max_lanes_upfront,
> > +					      intel_dp-
> > >max_link_rate_upfront);
> > +			} else
> > +				DRM_DEBUG_KMS("MST upfront link
> > training "
> > +					      "failed.");
> Link training has failed and we have a blank screen. Should we throw an
> error here? Maybe
> 
> 	return MODE_ERROR;

This is only for upfront link training, which is helpful but not absolutely
required.  If this were a link training associated with a mode set I'd
agree.  As it is, I think a debug message is fine for this case.

Jim


> 
> > +		}
> > +	}
> >  
> >  	/* TODO - validate mode against available PBN for link */
> >  	if (mode->clock < 10000)
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index a2bbf68..34af3e8 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1416,6 +1416,7 @@ void intel_edp_panel_off(struct intel_dp
> > *intel_dp);
> >  void intel_dp_add_properties(struct intel_dp *intel_dp, struct
> > drm_connector *connector);
> >  void intel_dp_mst_suspend(struct drm_device *dev);
> >  void intel_dp_mst_resume(struct drm_device *dev);
> > +u8 intel_dp_max_lane_count(struct intel_dp *intel_dp);
> >  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> >  int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> > *common_rates,
> >  			     int link_rate);
> > @@ -1448,6 +1449,8 @@ intel_dp_pre_emphasis_max(struct intel_dp
> > *intel_dp, uint8_t voltage_swing);
> >  void intel_dp_compute_rate(struct intel_dp *intel_dp, int
> > port_clock,
> >  			   uint8_t *link_bw, uint8_t *rate_select);
> >  bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
> > +int intel_dp_common_rates(struct intel_dp *intel_dp, int
> > *common_rates);
> > +bool intel_dp_upfront_link_train(struct intel_dp *intel_dp);
> >  bool
> >  intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t
> > link_status[DP_LINK_STATUS_SIZE]);
> >  
> -- 
> Mika Kahola - Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v2 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-07  9:47     ` Mika Kahola
@ 2016-09-07 16:47       ` Jim Bride
  2016-09-07 16:48       ` Manasi Navare
  1 sibling, 0 replies; 81+ messages in thread
From: Jim Bride @ 2016-09-07 16:47 UTC (permalink / raw)
  To: Mika Kahola; +Cc: intel-gfx

On Wed, Sep 07, 2016 at 12:47:49PM +0300, Mika Kahola wrote:
> On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> > According to the DisplayPort Spec, in case of Clock Recovery failure
> > the link training sequence should fall back to the lower link rate
> > followed by lower lane count until CR succeeds.
> > On CR success, the sequence proceeds with Channel EQ.
> > In case of Channel EQ failures, it should fallback to
> > lower link rate and lane count and start the CR phase again.
> > 
> > v2:
> > * Add a helper function to return index of requested link rate
> > into common_rates array
> > * Changed the link rate fallback loop to make use
> > of common_rates array (Mika Kahola)
> > * Changed INTEL_INFO to INTEL_GEN (David Weinehall)
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c              | 125
> > +++++++++++++++++++++++---
> >  drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
> >  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
> >  drivers/gpu/drm/i915/intel_drv.h              |   7 +-
> >  4 files changed, 145 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > b/drivers/gpu/drm/i915/intel_ddi.c
> > index 67a6a0b..e38bf4b 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct
> > intel_encoder *encoder,
> >  	}
> >  }
> >  
> > -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
> >  				    int link_rate, uint32_t
> > lane_count,
> > -				    struct intel_shared_dpll *pll,
> > -				    bool link_mst)
> > +				    struct intel_shared_dpll *pll)
> >  {
> >  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> >  	enum port port = intel_ddi_get_encoder_port(encoder);
> >  
> >  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> > -				 link_mst);
> > -	if (encoder->type == INTEL_OUTPUT_EDP)
> > -		intel_edp_panel_on(intel_dp);
> > +				 false);
> > +
> > +	intel_edp_panel_on(intel_dp);
> >  
> >  	intel_ddi_clk_select(encoder, pll);
> >  	intel_prepare_dp_ddi_buffers(encoder);
> > @@ -1657,6 +1656,29 @@ static void intel_ddi_pre_enable_dp(struct
> > intel_encoder *encoder,
> >  		intel_dp_stop_link_train(intel_dp);
> >  }
> >  
> > +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +				    int link_rate, uint32_t
> > lane_count,
> > +				    struct intel_shared_dpll *pll,
> > +				    bool link_mst)
> > +{
> > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > +	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +
> > +	/* Disable the PLL and obtain the PLL for Link Training
> > +	 * that starts with highest link rate and lane count.
> > +	 */
> > +	tmp_pll_config = pll->config;
> > +	pll->funcs.disable(dev_priv, pll);
> > +	pll->config.crtc_mask = 0;
> > +
> > +	/* If Link Training fails, send a uevent to generate a
> > hotplug */
> > +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> > link_mst,
> > +				   false)))
> > +		drm_kms_helper_hotplug_event(encoder->base.dev);
> > +	pll->config = tmp_pll_config;
> > +}
> > +
> >  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
> >  				      bool has_hdmi_sink,
> >  				      struct drm_display_mode
> > *adjusted_mode,
> > @@ -1690,20 +1712,26 @@ static void intel_ddi_pre_enable(struct
> > intel_encoder *intel_encoder,
> >  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
> >  	int type = intel_encoder->type;
> >  
> > -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> > +	if (type == INTEL_OUTPUT_EDP)
> > +		intel_ddi_pre_enable_edp(intel_encoder,
> > +					crtc->config->port_clock,
> > +					crtc->config->lane_count,
> > +					crtc->config->shared_dpll);
> > +
> > +	if (type == INTEL_OUTPUT_DP)
> >  		intel_ddi_pre_enable_dp(intel_encoder,
> >  					crtc->config->port_clock,
> >  					crtc->config->lane_count,
> >  					crtc->config->shared_dpll,
> >  					intel_crtc_has_type(crtc-
> > >config,
> >  							    INTEL_OU
> > TPUT_DP_MST));
> > -	}
> > -	if (type == INTEL_OUTPUT_HDMI) {
> > +
> > +	if (type == INTEL_OUTPUT_HDMI)
> >  		intel_ddi_pre_enable_hdmi(intel_encoder,
> >  					  crtc->config-
> > >has_hdmi_sink,
> >  					  &crtc->config-
> > >base.adjusted_mode,
> >  					  crtc->config-
> > >shared_dpll);
> > -	}
> > +
> >  }
> >  
> >  static void intel_ddi_post_disable(struct intel_encoder
> > *intel_encoder,
> > @@ -2431,6 +2459,83 @@ intel_ddi_get_link_dpll(struct intel_dp
> > *intel_dp, int clock)
> >  	return pll;
> >  }
> >  
> > +bool
> > +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +		     uint8_t max_lane_count, bool link_mst, bool
> > is_upfront)
> > +{
> > +	struct intel_connector *connector = intel_dp-
> > >attached_connector;
> > +	struct intel_encoder *encoder = connector->encoder;
> > +	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> > +	struct intel_shared_dpll *pll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +	int link_rate, link_rate_index;
> > +	uint8_t lane_count;
> > +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> > +	bool ret = false;
> > +
> > +	link_rate_index = intel_dp_link_rate_index(intel_dp,
> > common_rates,
> > +						   max_link_rate);
> > +	if (link_rate_index < 0) {
> > +		DRM_ERROR("Invalid Link Rate\n");
> > +		return false;
> > +	}
> > +	for (lane_count = max_lane_count; lane_count > 0; lane_count
> > >>= 1) {
> > +		for (link_rate = common_rates[link_rate_index];
> > +		     link_rate_index >= 0; link_rate_index --) {
> > +			pll = intel_ddi_get_link_dpll(intel_dp,
> > link_rate);
> > +			if (pll == NULL) {
> > +				DRM_ERROR("Could not find DPLL for
> > link "
> > +					  "training.\n");
> > +				return false;
> > +			}
> > +			tmp_pll_config = pll->config;
> > +			pll->funcs.enable(dev_priv, pll);
> > +
> > +			intel_dp_set_link_params(intel_dp,
> > link_rate,
> > +						 lane_count,
> > link_mst);
> > +
> > +			intel_ddi_clk_select(encoder, pll);
> > +			intel_prepare_dp_ddi_buffers(encoder);
> > +			intel_ddi_init_dp_buf_reg(encoder);
> > +			intel_dp_sink_dpms(intel_dp,
> > DRM_MODE_DPMS_ON);
> > +			ret = intel_dp_start_link_train(intel_dp);
> > +			if (ret)
> > +				break;
> > +
> > +			/* Disable port followed by PLL for next
> > retry/clean up */
> > +			intel_ddi_post_disable(encoder, NULL, NULL);
> > +			pll->funcs.disable(dev_priv, pll);
> > +			pll->config = tmp_pll_config;
> > +		}
> > +		if (ret) {
> > +			DRM_DEBUG_KMS("Link Training successful at
> > link rate: "
> > +				      "%d lane:%d\n", link_rate,
> > lane_count);
> > +			break;
> > +		}
> > +	}
> > +	intel_dp_stop_link_train(intel_dp);
> > +
> > +	if (is_upfront) {
> > +		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d
> > lanes:%d\n",
> > +			      ret ? "Passed" : "Failed",
> > +			      link_rate, lane_count);
> > +		/* Disable port followed by PLL for next retry/clean
> > up */
> > +		intel_ddi_post_disable(encoder, NULL, NULL);
> > +		pll->funcs.disable(dev_priv, pll);
> > +		pll->config = tmp_pll_config;
> In a case where link training was successful, I guess we could leave
> the port on. Is there a reason why we should do otherwise?

Yes.  The whole idea with upfront is to have it be state neutral
with respect to the HW, so we try to undo any configuration
changes that we make as a part of upfront other than stowing
away the lane count and link bandwidth that we trained at.

Jim


> 
> > +		if (ret) {
> > +			/* Save the upfront values */
> > +			intel_dp->max_lanes_upfront = lane_count;
> > +			intel_dp->max_link_rate_upfront = link_rate;
> My compiler wasn't really a big fan of these new members in a intel_dp
> struct so I these needs to be defined in intel_drv.h
> 
> drivers/gpu/drm/i915/intel_ddi.c: In function ‘intel_ddi_link_train’:
> drivers/gpu/drm/i915/intel_ddi.c:2528:12: error: ‘struct intel_dp’ has
> no member named ‘max_lanes_upfront’
>     intel_dp->max_lanes_upfront = lane_count;
>             ^
> drivers/gpu/drm/i915/intel_ddi.c:2529:12: error: ‘struct intel_dp’ has
> no member named ‘max_link_rate_upfront’
> 
>     intel_dp->max_link_rate_upfront = link_rate;
> > +		}
> > +	}
> > +
> > +	if (!lane_count)
> > +		DRM_ERROR("Link Training Failed\n");
> > +
> > +	return ret;
> > +}
> > +
> >  void intel_ddi_init(struct drm_device *dev, enum port port)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > b/drivers/gpu/drm/i915/intel_dp.c
> > index dfdbe65..391e384 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp
> > *intel_dp)
> >  	return rates[len - 1];
> >  }
> >  
> > +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> > *common_rates,
> > +			     int link_rate)
> > +{
> > +	int common_len;
> > +	int index;
> > +
> > +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> > +	for (index = common_len - 1; index >= 0; index--) {
> > +		if (link_rate == common_rates[index])
> > +			return index;
> > +	}
> > +
> > +	return -1;
> > +}
> > +
> >  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
> >  {
> >  	return rate_to_index(rate, intel_dp->sink_rates);
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 0fb845d..705dbd1 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp
> > *intel_dp)
> >  				DP_TRAINING_PATTERN_DISABLE);
> >  }
> >  
> > -void
> > +bool
> >  intel_dp_start_link_train(struct intel_dp *intel_dp)
> >  {
> > -	intel_dp_link_training_clock_recovery(intel_dp);
> > -	intel_dp_link_training_channel_equalization(intel_dp);
> > +	bool ret;
> > +
> > +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> > +		ret =
> > intel_dp_link_training_channel_equalization(intel_dp);
> > +		if (ret)
> > +			return true;
> > +	}
> > +	return false;
> >  }
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index e5bc976..90e7b15 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1160,6 +1160,9 @@ void intel_ddi_clock_get(struct intel_encoder
> > *encoder,
> >  			 struct intel_crtc_state *pipe_config);
> >  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool
> > state);
> >  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> > +bool intel_ddi_link_train(struct intel_dp *intel_dp, int
> > max_link_rate,
> > +			  uint8_t max_lane_count, bool link_mst,
> > +			  bool is_upfront);
> >  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp
> > *intel_dp,
> >  						  int clock);
> >  unsigned int intel_fb_align_height(struct drm_device *dev,
> > @@ -1381,7 +1384,7 @@ bool intel_dp_init_connector(struct
> > intel_digital_port *intel_dig_port,
> >  void intel_dp_set_link_params(struct intel_dp *intel_dp,
> >  			      int link_rate, uint8_t lane_count,
> >  			      bool link_mst);
> > -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > @@ -1403,6 +1406,8 @@ void intel_dp_add_properties(struct intel_dp
> > *intel_dp, struct drm_connector *co
> >  void intel_dp_mst_suspend(struct drm_device *dev);
> >  void intel_dp_mst_resume(struct drm_device *dev);
> >  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> > +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> > *common_rates,
> > +			     int link_rate);
> >  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
> >  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
> >  void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
> -- 
> Mika Kahola - Intel OTC
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v2 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-07  9:47     ` Mika Kahola
  2016-09-07 16:47       ` Jim Bride
@ 2016-09-07 16:48       ` Manasi Navare
  1 sibling, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-07 16:48 UTC (permalink / raw)
  To: Mika Kahola; +Cc: intel-gfx

On Wed, Sep 07, 2016 at 12:47:49PM +0300, Mika Kahola wrote:
> On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> > According to the DisplayPort Spec, in case of Clock Recovery failure
> > the link training sequence should fall back to the lower link rate
> > followed by lower lane count until CR succeeds.
> > On CR success, the sequence proceeds with Channel EQ.
> > In case of Channel EQ failures, it should fallback to
> > lower link rate and lane count and start the CR phase again.
> > 
> > v2:
> > * Add a helper function to return index of requested link rate
> > into common_rates array
> > * Changed the link rate fallback loop to make use
> > of common_rates array (Mika Kahola)
> > * Changed INTEL_INFO to INTEL_GEN (David Weinehall)
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c              | 125
> > +++++++++++++++++++++++---
> >  drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
> >  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
> >  drivers/gpu/drm/i915/intel_drv.h              |   7 +-
> >  4 files changed, 145 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > b/drivers/gpu/drm/i915/intel_ddi.c
> > index 67a6a0b..e38bf4b 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct
> > intel_encoder *encoder,
> >  	}
> >  }
> >  
> > -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
> >  				    int link_rate, uint32_t
> > lane_count,
> > -				    struct intel_shared_dpll *pll,
> > -				    bool link_mst)
> > +				    struct intel_shared_dpll *pll)
> >  {
> >  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> >  	enum port port = intel_ddi_get_encoder_port(encoder);
> >  
> >  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> > -				 link_mst);
> > -	if (encoder->type == INTEL_OUTPUT_EDP)
> > -		intel_edp_panel_on(intel_dp);
> > +				 false);
> > +
> > +	intel_edp_panel_on(intel_dp);
> >  
> >  	intel_ddi_clk_select(encoder, pll);
> >  	intel_prepare_dp_ddi_buffers(encoder);
> > @@ -1657,6 +1656,29 @@ static void intel_ddi_pre_enable_dp(struct
> > intel_encoder *encoder,
> >  		intel_dp_stop_link_train(intel_dp);
> >  }
> >  
> > +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +				    int link_rate, uint32_t
> > lane_count,
> > +				    struct intel_shared_dpll *pll,
> > +				    bool link_mst)
> > +{
> > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > +	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +
> > +	/* Disable the PLL and obtain the PLL for Link Training
> > +	 * that starts with highest link rate and lane count.
> > +	 */
> > +	tmp_pll_config = pll->config;
> > +	pll->funcs.disable(dev_priv, pll);
> > +	pll->config.crtc_mask = 0;
> > +
> > +	/* If Link Training fails, send a uevent to generate a
> > hotplug */
> > +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> > link_mst,
> > +				   false)))
> > +		drm_kms_helper_hotplug_event(encoder->base.dev);
> > +	pll->config = tmp_pll_config;
> > +}
> > +
> >  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
> >  				      bool has_hdmi_sink,
> >  				      struct drm_display_mode
> > *adjusted_mode,
> > @@ -1690,20 +1712,26 @@ static void intel_ddi_pre_enable(struct
> > intel_encoder *intel_encoder,
> >  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
> >  	int type = intel_encoder->type;
> >  
> > -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> > +	if (type == INTEL_OUTPUT_EDP)
> > +		intel_ddi_pre_enable_edp(intel_encoder,
> > +					crtc->config->port_clock,
> > +					crtc->config->lane_count,
> > +					crtc->config->shared_dpll);
> > +
> > +	if (type == INTEL_OUTPUT_DP)
> >  		intel_ddi_pre_enable_dp(intel_encoder,
> >  					crtc->config->port_clock,
> >  					crtc->config->lane_count,
> >  					crtc->config->shared_dpll,
> >  					intel_crtc_has_type(crtc-
> > >config,
> >  							    INTEL_OU
> > TPUT_DP_MST));
> > -	}
> > -	if (type == INTEL_OUTPUT_HDMI) {
> > +
> > +	if (type == INTEL_OUTPUT_HDMI)
> >  		intel_ddi_pre_enable_hdmi(intel_encoder,
> >  					  crtc->config-
> > >has_hdmi_sink,
> >  					  &crtc->config-
> > >base.adjusted_mode,
> >  					  crtc->config-
> > >shared_dpll);
> > -	}
> > +
> >  }
> >  
> >  static void intel_ddi_post_disable(struct intel_encoder
> > *intel_encoder,
> > @@ -2431,6 +2459,83 @@ intel_ddi_get_link_dpll(struct intel_dp
> > *intel_dp, int clock)
> >  	return pll;
> >  }
> >  
> > +bool
> > +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +		     uint8_t max_lane_count, bool link_mst, bool
> > is_upfront)
> > +{
> > +	struct intel_connector *connector = intel_dp-
> > >attached_connector;
> > +	struct intel_encoder *encoder = connector->encoder;
> > +	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> > +	struct intel_shared_dpll *pll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +	int link_rate, link_rate_index;
> > +	uint8_t lane_count;
> > +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> > +	bool ret = false;
> > +
> > +	link_rate_index = intel_dp_link_rate_index(intel_dp,
> > common_rates,
> > +						   max_link_rate);
> > +	if (link_rate_index < 0) {
> > +		DRM_ERROR("Invalid Link Rate\n");
> > +		return false;
> > +	}
> > +	for (lane_count = max_lane_count; lane_count > 0; lane_count
> > >>= 1) {
> > +		for (link_rate = common_rates[link_rate_index];
> > +		     link_rate_index >= 0; link_rate_index --) {
> > +			pll = intel_ddi_get_link_dpll(intel_dp,
> > link_rate);
> > +			if (pll == NULL) {
> > +				DRM_ERROR("Could not find DPLL for
> > link "
> > +					  "training.\n");
> > +				return false;
> > +			}
> > +			tmp_pll_config = pll->config;
> > +			pll->funcs.enable(dev_priv, pll);
> > +
> > +			intel_dp_set_link_params(intel_dp,
> > link_rate,
> > +						 lane_count,
> > link_mst);
> > +
> > +			intel_ddi_clk_select(encoder, pll);
> > +			intel_prepare_dp_ddi_buffers(encoder);
> > +			intel_ddi_init_dp_buf_reg(encoder);
> > +			intel_dp_sink_dpms(intel_dp,
> > DRM_MODE_DPMS_ON);
> > +			ret = intel_dp_start_link_train(intel_dp);
> > +			if (ret)
> > +				break;
> > +
> > +			/* Disable port followed by PLL for next
> > retry/clean up */
> > +			intel_ddi_post_disable(encoder, NULL, NULL);
> > +			pll->funcs.disable(dev_priv, pll);
> > +			pll->config = tmp_pll_config;
> > +		}
> > +		if (ret) {
> > +			DRM_DEBUG_KMS("Link Training successful at
> > link rate: "
> > +				      "%d lane:%d\n", link_rate,
> > lane_count);
> > +			break;
> > +		}
> > +	}
> > +	intel_dp_stop_link_train(intel_dp);
> > +
> > +	if (is_upfront) {
> > +		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d
> > lanes:%d\n",
> > +			      ret ? "Passed" : "Failed",
> > +			      link_rate, lane_count);
> > +		/* Disable port followed by PLL for next retry/clean
> > up */
> > +		intel_ddi_post_disable(encoder, NULL, NULL);
> > +		pll->funcs.disable(dev_priv, pll);
> > +		pll->config = tmp_pll_config;
> In a case where link training was successful, I guess we could leave
> the port on. Is there a reason why we should do otherwise?
>

The port needs to be turned off and plls need to be disabled in case of upfront
since we dont want to change any HW state yet. Upfront training only happens
to cache the max lanes and lax link rate values and does not change any HW state.

 
> 
> > +		if (ret) {
> > +			/* Save the upfront values */
> > +			intel_dp->max_lanes_upfront = lane_count;
> > +			intel_dp->max_link_rate_upfront = link_rate;
> My compiler wasn't really a big fan of these new members in a intel_dp
> struct so I these needs to be defined in intel_drv.h
> 
> drivers/gpu/drm/i915/intel_ddi.c: In function ‘intel_ddi_link_train’:
> drivers/gpu/drm/i915/intel_ddi.c:2528:12: error: ‘struct intel_dp’ has
> no member named ‘max_lanes_upfront’
>     intel_dp->max_lanes_upfront = lane_count;
>             ^
> drivers/gpu/drm/i915/intel_ddi.c:2529:12: error: ‘struct intel_dp’ has
> no member named ‘max_link_rate_upfront’
>

This probably happened due to rebasing issue. Actually this entire if upfront part
should be added in the next patch that enables upfront link training. That is where 
these fields get defined inside the intel_dp structure.
I will correct this and submit a new revision.

Manasi
>     intel_dp->max_link_rate_upfront = link_rate;
> > +		}
> > +	}
> > +
> > +	if (!lane_count)
> > +		DRM_ERROR("Link Training Failed\n");
> > +
> > +	return ret;
> > +}
> > +
> >  void intel_ddi_init(struct drm_device *dev, enum port port)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > b/drivers/gpu/drm/i915/intel_dp.c
> > index dfdbe65..391e384 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp
> > *intel_dp)
> >  	return rates[len - 1];
> >  }
> >  
> > +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> > *common_rates,
> > +			     int link_rate)
> > +{
> > +	int common_len;
> > +	int index;
> > +
> > +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> > +	for (index = common_len - 1; index >= 0; index--) {
> > +		if (link_rate == common_rates[index])
> > +			return index;
> > +	}
> > +
> > +	return -1;
> > +}
> > +
> >  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
> >  {
> >  	return rate_to_index(rate, intel_dp->sink_rates);
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 0fb845d..705dbd1 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -309,9 +309,15 @@ void intel_dp_stop_link_train(struct intel_dp
> > *intel_dp)
> >  				DP_TRAINING_PATTERN_DISABLE);
> >  }
> >  
> > -void
> > +bool
> >  intel_dp_start_link_train(struct intel_dp *intel_dp)
> >  {
> > -	intel_dp_link_training_clock_recovery(intel_dp);
> > -	intel_dp_link_training_channel_equalization(intel_dp);
> > +	bool ret;
> > +
> > +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> > +		ret =
> > intel_dp_link_training_channel_equalization(intel_dp);
> > +		if (ret)
> > +			return true;
> > +	}
> > +	return false;
> >  }
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index e5bc976..90e7b15 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1160,6 +1160,9 @@ void intel_ddi_clock_get(struct intel_encoder
> > *encoder,
> >  			 struct intel_crtc_state *pipe_config);
> >  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool
> > state);
> >  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> > +bool intel_ddi_link_train(struct intel_dp *intel_dp, int
> > max_link_rate,
> > +			  uint8_t max_lane_count, bool link_mst,
> > +			  bool is_upfront);
> >  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp
> > *intel_dp,
> >  						  int clock);
> >  unsigned int intel_fb_align_height(struct drm_device *dev,
> > @@ -1381,7 +1384,7 @@ bool intel_dp_init_connector(struct
> > intel_digital_port *intel_dig_port,
> >  void intel_dp_set_link_params(struct intel_dp *intel_dp,
> >  			      int link_rate, uint8_t lane_count,
> >  			      bool link_mst);
> > -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > @@ -1403,6 +1406,8 @@ void intel_dp_add_properties(struct intel_dp
> > *intel_dp, struct drm_connector *co
> >  void intel_dp_mst_suspend(struct drm_device *dev);
> >  void intel_dp_mst_resume(struct drm_device *dev);
> >  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> > +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> > *common_rates,
> > +			     int link_rate);
> >  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
> >  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
> >  void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
> -- 
> Mika Kahola - Intel OTC
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH v3 8/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-07  0:13   ` [PATCH v2 8/14] " Manasi Navare
  2016-09-07  7:00     ` Mika Kahola
@ 2016-09-07 18:28     ` Manasi Navare
  2016-09-08  7:38       ` Mika Kahola
  1 sibling, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-07 18:28 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan

From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

Wrap the max. vswing check in a separate function.
This makes the clock recovery phase of DP link training cleaner

v3:
Fixed the paranthesis warning (Mika Kahola)
v2:
Fixed the Compiler warning (Mika Kahola)

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dp_link_training.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 0deebed..b9880cf 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -112,6 +112,18 @@ intel_dp_update_link_train(struct intel_dp *intel_dp)
 	return ret == intel_dp->lane_count;
 }
 
+static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
+{
+	int lane;
+
+	for (lane = 0; lane < intel_dp->lane_count; lane++)
+		if ((intel_dp->train_set[lane] &
+		     DP_TRAIN_MAX_SWING_REACHED) == 0)
+			return false;
+
+	return true;
+}
+
 /* Enable corresponding port and start training pattern 1 */
 static void
 intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
@@ -170,10 +182,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 		}
 
 		/* Check to see if we've tried the max voltage */
-		for (i = 0; i < intel_dp->lane_count; i++)
-			if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
-				break;
-		if (i == intel_dp->lane_count) {
+		if (intel_dp_link_max_vswing_reached(intel_dp)) {
 			++loop_tries;
 			if (loop_tries == 5) {
 				DRM_ERROR("too many full retries, give up\n");
-- 
1.9.1

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

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

* [PATCH v3 9/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2
  2016-09-07  0:13   ` [PATCH v2 9/14] " Manasi Navare
  2016-09-07  7:33     ` Mika Kahola
@ 2016-09-07 18:28     ` Manasi Navare
  2016-09-08  8:20       ` Mika Kahola
  1 sibling, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-07 18:28 UTC (permalink / raw)
  To: intel-gfx; +Cc: Dhinakaran Pandiyan

From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

This function cleans up clock recovery loop in link training compliant
tp Dp Spec 1.2. It tries the clock recovery 5 times for the same voltage
or until max voltage swing is reached and removes the additional non
compliant retries. This function now returns a boolean values based on
if clock recovery passed or failed.

v3:
* Better Debug prints in case of failures (Mika Kahola)
v2:
* Rebased on top of new revision of vswing patch (Manasi Navare)

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dp_link_training.c | 60 +++++++++++++--------------
 1 file changed, 28 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index b9880cf..80b9326 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -125,12 +125,11 @@ static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
 }
 
 /* Enable corresponding port and start training pattern 1 */
-static void
+static bool
 intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 {
-	int i;
 	uint8_t voltage;
-	int voltage_tries, loop_tries;
+	int voltage_tries, max_vswing_tries;
 	uint8_t link_config[2];
 	uint8_t link_bw, rate_select;
 
@@ -146,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
 		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
 	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
+
 	if (intel_dp->num_sink_rates)
 		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
 				  &rate_select, 1);
@@ -161,58 +161,54 @@ intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
 				       DP_TRAINING_PATTERN_1 |
 				       DP_LINK_SCRAMBLING_DISABLE)) {
 		DRM_ERROR("failed to enable link training\n");
-		return;
+		return false;
 	}
 
-	voltage = 0xff;
-	voltage_tries = 0;
-	loop_tries = 0;
+	voltage_tries = 1;
+	max_vswing_tries = 0;
 	for (;;) {
 		uint8_t link_status[DP_LINK_STATUS_SIZE];
 
 		drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
+
 		if (!intel_dp_get_link_status(intel_dp, link_status)) {
 			DRM_ERROR("failed to get link status\n");
-			break;
+			return false;
 		}
 
 		if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
 			DRM_DEBUG_KMS("clock recovery OK\n");
-			break;
+			return true;
 		}
 
-		/* Check to see if we've tried the max voltage */
-		if (intel_dp_link_max_vswing_reached(intel_dp)) {
-			++loop_tries;
-			if (loop_tries == 5) {
-				DRM_ERROR("too many full retries, give up\n");
-				intel_dp_dump_link_status(link_status);
-				break;
-			}
-			intel_dp_reset_link_train(intel_dp,
-						  DP_TRAINING_PATTERN_1 |
-						  DP_LINK_SCRAMBLING_DISABLE);
-			voltage_tries = 0;
-			continue;
+		if (voltage_tries == 5) {
+			DRM_DEBUG_KMS("Same voltage tried 5 times\n");
+			return false;
+		}
+
+		if (max_vswing_tries == 1) {
+			DRM_DEBUG_KMS("Max Voltage Swing reached\n");
+			return false;
 		}
 
-		/* Check to see if we've tried the same voltage 5 times */
-		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
-			++voltage_tries;
-			if (voltage_tries == 5) {
-				DRM_ERROR("too many voltage retries, give up\n");
-				break;
-			}
-		} else
-			voltage_tries = 0;
 		voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
 
 		/* Update training set as requested by target */
 		intel_get_adjust_train(intel_dp, link_status);
 		if (!intel_dp_update_link_train(intel_dp)) {
 			DRM_ERROR("failed to update link training\n");
-			break;
+			return false;
 		}
+
+		if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
+		    voltage)
+			++voltage_tries;
+		else
+			voltage_tries = 1;
+
+		if (intel_dp_link_max_vswing_reached(intel_dp))
+			++max_vswing_tries;
+
 	}
 }
 
-- 
1.9.1

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

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

* [PATCH v3 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-07  0:13   ` [PATCH v2 " Manasi Navare
  2016-09-07  9:47     ` Mika Kahola
@ 2016-09-07 18:28     ` Manasi Navare
  2016-09-08  0:30       ` [PATCH v4 " Manasi Navare
  1 sibling, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-07 18:28 UTC (permalink / raw)
  To: intel-gfx

According to the DisplayPort Spec, in case of Clock Recovery failure
the link training sequence should fall back to the lower link rate
followed by lower lane count until CR succeeds.
On CR success, the sequence proceeds with Channel EQ.
In case of Channel EQ failures, it should fallback to
lower link rate and lane count and start the CR phase again.

v3:
* Fixed some rebase issues (Mika Kahola)
v2:
* Add a helper function to return index of requested link rate
into common_rates array
* Changed the link rate fallback loop to make use
of common_rates array (Mika Kahola)
* Changed INTEL_INFO to INTEL_GEN (David Weinehall)

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
 drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
 drivers/gpu/drm/i915/intel_drv.h              |   6 +-
 4 files changed, 128 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 67a6a0b..da2b804 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
 	}
 }
 
-static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
 				    int link_rate, uint32_t lane_count,
-				    struct intel_shared_dpll *pll,
-				    bool link_mst)
+				    struct intel_shared_dpll *pll)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum port port = intel_ddi_get_encoder_port(encoder);
 
 	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
-				 link_mst);
-	if (encoder->type == INTEL_OUTPUT_EDP)
-		intel_edp_panel_on(intel_dp);
+				 false);
+
+	intel_edp_panel_on(intel_dp);
 
 	intel_ddi_clk_select(encoder, pll);
 	intel_prepare_dp_ddi_buffers(encoder);
@@ -1657,6 +1656,28 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 		intel_dp_stop_link_train(intel_dp);
 }
 
+static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+				    int link_rate, uint32_t lane_count,
+				    struct intel_shared_dpll *pll,
+				    bool link_mst)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll_config tmp_pll_config;
+
+	/* Disable the PLL and obtain the PLL for Link Training
+	 * that starts with highest link rate and lane count.
+	 */
+	tmp_pll_config = pll->config;
+	pll->funcs.disable(dev_priv, pll);
+	pll->config.crtc_mask = 0;
+
+	/* If Link Training fails, send a uevent to generate a hotplug */
+	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
+		drm_kms_helper_hotplug_event(encoder->base.dev);
+	pll->config = tmp_pll_config;
+}
+
 static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
 				      bool has_hdmi_sink,
 				      struct drm_display_mode *adjusted_mode,
@@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	int type = intel_encoder->type;
 
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+	if (type == INTEL_OUTPUT_EDP)
+		intel_ddi_pre_enable_edp(intel_encoder,
+					crtc->config->port_clock,
+					crtc->config->lane_count,
+					crtc->config->shared_dpll);
+
+	if (type == INTEL_OUTPUT_DP)
 		intel_ddi_pre_enable_dp(intel_encoder,
 					crtc->config->port_clock,
 					crtc->config->lane_count,
 					crtc->config->shared_dpll,
 					intel_crtc_has_type(crtc->config,
 							    INTEL_OUTPUT_DP_MST));
-	}
-	if (type == INTEL_OUTPUT_HDMI) {
+
+	if (type == INTEL_OUTPUT_HDMI)
 		intel_ddi_pre_enable_hdmi(intel_encoder,
 					  crtc->config->has_hdmi_sink,
 					  &crtc->config->base.adjusted_mode,
 					  crtc->config->shared_dpll);
-	}
+
 }
 
 static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
@@ -2431,6 +2458,68 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 	return pll;
 }
 
+bool
+intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+		     uint8_t max_lane_count, bool link_mst)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct intel_encoder *encoder = connector->encoder;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	int link_rate, link_rate_index;
+	uint8_t lane_count;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	bool ret = false;
+
+	link_rate_index = intel_dp_link_rate_index(intel_dp, common_rates,
+						   max_link_rate);
+	if (link_rate_index < 0) {
+		DRM_ERROR("Invalid Link Rate\n");
+		return false;
+	}
+	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
+		for (link_rate = common_rates[link_rate_index];
+		     link_rate_index >= 0; link_rate_index --) {
+			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
+			if (pll == NULL) {
+				DRM_ERROR("Could not find DPLL for link "
+					  "training.\n");
+				return false;
+			}
+			tmp_pll_config = pll->config;
+			pll->funcs.enable(dev_priv, pll);
+
+			intel_dp_set_link_params(intel_dp, link_rate,
+						 lane_count, link_mst);
+
+			intel_ddi_clk_select(encoder, pll);
+			intel_prepare_dp_ddi_buffers(encoder);
+			intel_ddi_init_dp_buf_reg(encoder);
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+			ret = intel_dp_start_link_train(intel_dp);
+			if (ret)
+				break;
+
+			/* Disable port followed by PLL for next retry/clean up */
+			intel_ddi_post_disable(encoder, NULL, NULL);
+			pll->funcs.disable(dev_priv, pll);
+			pll->config = tmp_pll_config;
+		}
+		if (ret) {
+			DRM_DEBUG_KMS("Link Training successful at link rate: "
+				      "%d lane:%d\n", link_rate, lane_count);
+			break;
+		}
+	}
+	intel_dp_stop_link_train(intel_dp);
+
+	if (!lane_count)
+		DRM_ERROR("Link Training Failed\n");
+
+	return ret;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index dfdbe65..391e384 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	return rates[len - 1];
 }
 
+int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
+			     int link_rate)
+{
+	int common_len;
+	int index;
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	for (index = common_len - 1; index >= 0; index--) {
+		if (link_rate == common_rates[index])
+			return index;
+	}
+
+	return -1;
+}
+
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
 {
 	return rate_to_index(rate, intel_dp->sink_rates);
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index c438b02..f1e08f0 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -313,9 +313,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 				DP_TRAINING_PATTERN_DISABLE);
 }
 
-void
+bool
 intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-	intel_dp_link_training_clock_recovery(intel_dp);
-	intel_dp_link_training_channel_equalization(intel_dp);
+	bool ret;
+
+	if (intel_dp_link_training_clock_recovery(intel_dp)) {
+		ret = intel_dp_link_training_channel_equalization(intel_dp);
+		if (ret)
+			return true;
+	}
+	return false;
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e5bc976..c571baf 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
+bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+			  uint8_t max_lane_count, bool link_mst);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
@@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
 			      int link_rate, uint8_t lane_count,
 			      bool link_mst);
-void intel_dp_start_link_train(struct intel_dp *intel_dp);
+bool intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 void intel_dp_encoder_reset(struct drm_encoder *encoder);
@@ -1403,6 +1405,8 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
 int intel_dp_max_link_rate(struct intel_dp *intel_dp);
+int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
+			     int link_rate);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
 void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
-- 
1.9.1

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

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

* [PATCH v13 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-07  0:13   ` [PATCH v12 " Manasi Navare
@ 2016-09-07 18:28     ` Manasi Navare
  2016-09-08 12:10       ` Mika Kahola
  2016-09-08 17:22       ` [PATCH v14 " Manasi Navare
  0 siblings, 2 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-07 18:28 UTC (permalink / raw)
  To: intel-gfx

From: Durgadoss R <durgadoss.r@intel.com>

To support USB type C alternate DP mode, the display driver needs to
know the number of lanes required by the DP panel as well as number
of lanes that can be supported by the type-C cable. Sometimes, the
type-C cable may limit the bandwidth even if Panel can support
more lanes. To address these scenarios, the display driver will
start link training with max lanes, and if that fails, the driver
falls back to x2 lanes; and repeats this procedure for all
bandwidth/lane configurations.

* Since link training is done before modeset only the port
  (and not pipe/planes) and its associated PLLs are enabled.
* On DP hotplug: Directly start link training on the DP encoder.
* On Connected boot scenarios: When booted with an LFP and a DP,
  sometimes BIOS brings up DP. In these cases, we disable the
  crtc and then do upfront link training; and bring it back up.
* All local changes made for upfront link training are reset
  to their previous values once it is done; so that the
  subsequent modeset is not aware of these changes.

Changes since v12:
* Fix Rebase issues (Mika Kahola)
Changes since v11:
* Change the fallback link rate logic (Manasi)
Changes since v10:
* Use the ddi link train function that loops through all the link rates
and lane counts starting from the highest supported (Manasi)
* For upfront link training, set the upfront flag so that the link can
be disabled after caching upfront values (Manasi)
Changes since v9:
* Change the macros to use dev_priv in place of dev (David Weinehall)
Changes since v8:
* Reset upfront lane count and link rate values on HPD
for DP connector physical disconnect (Manasi)
Changes since v7:
* Move the upfront link training to intel_dp_mode_valid()
  to avoid a race condition with DP MST sideband comms. (Ville)
Changes since v6:
* Fix some initialization bugs on link_rate (Jim Bride)
* Use link_rate (and not link_bw) for upfront (Ville)
* Make intel_dp_upfront*() as a vfunc (Ander)
* The train_set_valid variable in intel_dp was removed due to
  issues in fast link training. So, to indicate the link train
  status, move the channel_eq inside intel_dp.
Changes since v5:
* Moved retry logic in upfront to intel_dp.c so that it
  can be used for all platforms.
Changes since v4:
* Removed usage of crtc_state in upfront link training;
  Hence no need to find free crtc to do upfront now.
* Re-enable crtc if it was disabled for upfront.
* Use separate variables to track max lane count
  and link rate found by upfront, without modifying
  the original DPCD read from panel.
Changes since v3:
* Fixed a return value on BXT check
* Reworked on top of bxt_ddi_pll_select split from Ander
* Renamed from ddi_upfront to bxt_upfront since the
  upfront logic includes BXT specific functions for now.
Changes since v2:
* Rebased on top of latest dpll_mgr.c code and
  latest HPD related clean ups.
* Corrected return values from upfront (Ander)
* Corrected atomic locking for upfront in intel_dp.c (Ville)
Changes since v1:
*  all pll related functions inside ddi.c

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              |  21 +-
 drivers/gpu/drm/i915/intel_dp.c               | 376 +++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
 drivers/gpu/drm/i915/intel_drv.h              |  14 +-
 4 files changed, 310 insertions(+), 102 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index da2b804..b32f7ba 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 	pll->config.crtc_mask = 0;
 
 	/* If Link Training fails, send a uevent to generate a hotplug */
-	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
+	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst,
+				   false)))
 		drm_kms_helper_hotplug_event(encoder->base.dev);
 	pll->config = tmp_pll_config;
 }
@@ -2460,7 +2461,7 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 
 bool
 intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-		     uint8_t max_lane_count, bool link_mst)
+		     uint8_t max_lane_count, bool link_mst, bool is_upfront)
 {
 	struct intel_connector *connector = intel_dp->attached_connector;
 	struct intel_encoder *encoder = connector->encoder;
@@ -2506,6 +2507,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 			pll->funcs.disable(dev_priv, pll);
 			pll->config = tmp_pll_config;
 		}
+
 		if (ret) {
 			DRM_DEBUG_KMS("Link Training successful at link rate: "
 				      "%d lane:%d\n", link_rate, lane_count);
@@ -2514,6 +2516,21 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 	}
 	intel_dp_stop_link_train(intel_dp);
 
+	if (is_upfront) {
+		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d lanes:%d\n",
+			      ret ? "Passed" : "Failed",
+			      link_rate, lane_count);
+		/* Disable port followed by PLL for next retry/clean up */
+		intel_ddi_post_disable(encoder, NULL, NULL);
+		pll->funcs.disable(dev_priv, pll);
+		pll->config = tmp_pll_config;
+		if (ret) {
+			/* Save the upfront values */
+			intel_dp->max_lanes_upfront = lane_count;
+			intel_dp->max_link_rate_upfront = link_rate;
+		}
+	}
+
 	if (!lane_count)
 		DRM_ERROR("Link Training Failed\n");
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 714fbe3..7794180 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	u8 source_max, sink_max;
+	u8 temp, source_max, sink_max;
 
 	source_max = intel_dig_port->max_lanes;
 	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
 
-	return min(source_max, sink_max);
+	temp = min(source_max, sink_max);
+
+	/*
+	 * Limit max lanes w.r.t to the max value found
+	 * using Upfront link training also.
+	 */
+	if (intel_dp->max_lanes_upfront)
+		return min(temp, intel_dp->max_lanes_upfront);
+	else
+		return temp;
 }
 
 /*
@@ -190,6 +199,229 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 	return (max_link_clock * max_lanes * 8) / 10;
 }
 
+static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
+				struct drm_modeset_acquire_ctx *ctx,
+				bool enable)
+{
+	int ret;
+	struct drm_atomic_state *state;
+	struct intel_crtc_state *crtc_state;
+	struct drm_device *dev = crtc->base.dev;
+	enum pipe pipe = crtc->pipe;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	crtc_state = intel_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		drm_atomic_state_free(state);
+		return ret;
+	}
+
+	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
+			enable ? "En" : "Dis",
+			pipe_name(pipe),
+			enable ? "after" : "before");
+
+	crtc_state->base.active = enable;
+	ret = drm_atomic_commit(state);
+	if (ret)
+		drm_atomic_state_free(state);
+
+	return ret;
+}
+
+static int
+intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
+{
+	if (intel_dp->num_sink_rates) {
+		*sink_rates = intel_dp->sink_rates;
+		return intel_dp->num_sink_rates;
+	}
+
+	*sink_rates = default_rates;
+
+	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
+}
+
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+
+	/* WaDisableHBR2:skl */
+	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
+		return false;
+
+	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
+	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
+		return true;
+	else
+		return false;
+}
+
+static int
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+	int size;
+
+	if (IS_BROXTON(dev_priv)) {
+		*source_rates = bxt_rates;
+		size = ARRAY_SIZE(bxt_rates);
+	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+		*source_rates = skl_rates;
+		size = ARRAY_SIZE(skl_rates);
+	} else {
+		*source_rates = default_rates;
+		size = ARRAY_SIZE(default_rates);
+	}
+
+	/* This depends on the fact that 5.4 is last value in the array */
+	if (!intel_dp_source_supports_hbr2(intel_dp))
+		size--;
+
+	return size;
+}
+
+static int intersect_rates(const int *source_rates, int source_len,
+			   const int *sink_rates, int sink_len,
+			   int *common_rates)
+{
+	int i = 0, j = 0, k = 0;
+
+	while (i < source_len && j < sink_len) {
+		if (source_rates[i] == sink_rates[j]) {
+			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+				return k;
+			common_rates[k] = source_rates[i];
+			++k;
+			++i;
+			++j;
+		} else if (source_rates[i] < sink_rates[j]) {
+			++i;
+		} else {
+			++j;
+		}
+	}
+	return k;
+}
+
+static int intel_dp_common_rates(struct intel_dp *intel_dp,
+				 int *common_rates)
+{
+	const int *source_rates, *sink_rates;
+	int source_len, sink_len;
+
+	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+
+	/* Cap sink rates w.r.t upfront values */
+	if (intel_dp->max_link_rate_upfront) {
+		int len = sink_len - 1;
+		while (len > 0 && sink_rates[len] >
+		       intel_dp->max_link_rate_upfront)
+			len--;
+		sink_len = len + 1;
+	}
+
+	source_len = intel_dp_source_rates(intel_dp, &source_rates);
+
+	return intersect_rates(source_rates, source_len,
+			       sink_rates, sink_len,
+			       common_rates);
+}
+
+static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct intel_encoder *intel_encoder = &intel_dig_port->base;
+	struct drm_device *dev = intel_encoder->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_modeset_acquire_ctx ctx;
+	struct intel_crtc *intel_crtc;
+	struct drm_crtc *crtc = NULL;
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	bool disable_dpll = false;
+	int ret;
+	bool done = false, has_mst = false;
+	uint8_t max_lanes;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	int common_len;
+	enum intel_display_power_domain power_domain;
+
+	power_domain = intel_display_port_power_domain(intel_encoder);
+	intel_display_power_get(dev_priv, power_domain);
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	max_lanes = intel_dp_max_lane_count(intel_dp);
+	if (WARN_ON(common_len <= 0))
+		return true;
+
+	drm_modeset_acquire_init(&ctx, 0);
+retry:
+	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
+	if (ret)
+		goto exit_fail;
+
+	if (intel_encoder->base.crtc) {
+		crtc = intel_encoder->base.crtc;
+
+		ret = drm_modeset_lock(&crtc->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		intel_crtc = to_intel_crtc(crtc);
+		pll = intel_crtc->config->shared_dpll;
+		disable_dpll = true;
+		has_mst = intel_crtc_has_type(intel_crtc->config,
+					      INTEL_OUTPUT_DP_MST);
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, false);
+		if (ret)
+			goto exit_fail;
+	}
+
+	mutex_lock(&dev_priv->dpll_lock);
+	if (disable_dpll) {
+		/* Clear the PLL config state */
+		tmp_pll_config = pll->config;
+		pll->config.crtc_mask = 0;
+	}
+
+	done = intel_dp->upfront_link_train(intel_dp,
+					    common_rates[common_len-1],
+					    max_lanes,
+					    has_mst,
+					    true);
+	if (disable_dpll)
+		pll->config = tmp_pll_config;
+
+	mutex_unlock(&dev_priv->dpll_lock);
+
+	if (crtc)
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, true);
+
+exit_fail:
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	intel_display_power_put(dev_priv, power_domain);
+	return done;
+}
+
 static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
@@ -211,6 +443,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
 		target_clock = fixed_mode->clock;
 	}
 
+	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
+		bool do_upfront_link_train;
+		/* Do not do upfront link train, if it is a compliance
+		 * request
+		 */
+		do_upfront_link_train = !intel_dp->upfront_done &&
+			(intel_dp->compliance_test_type !=
+			 DP_TEST_LINK_TRAINING);
+
+		if (do_upfront_link_train)
+			intel_dp->upfront_done = intel_dp_upfront_link_train(intel_dp);
+	}
+
 	max_link_clock = intel_dp_max_link_rate(intel_dp);
 	max_lanes = intel_dp_max_lane_count(intel_dp);
 
@@ -1256,60 +1501,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 	intel_dp->aux.transfer = intel_dp_aux_transfer;
 }
 
-static int
-intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
-{
-	if (intel_dp->num_sink_rates) {
-		*sink_rates = intel_dp->sink_rates;
-		return intel_dp->num_sink_rates;
-	}
-
-	*sink_rates = default_rates;
-
-	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
-}
-
-bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-
-	/* WaDisableHBR2:skl */
-	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
-		return false;
-
-	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
-	    (INTEL_INFO(dev)->gen >= 9))
-		return true;
-	else
-		return false;
-}
-
-static int
-intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-	int size;
-
-	if (IS_BROXTON(dev)) {
-		*source_rates = bxt_rates;
-		size = ARRAY_SIZE(bxt_rates);
-	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
-		*source_rates = skl_rates;
-		size = ARRAY_SIZE(skl_rates);
-	} else {
-		*source_rates = default_rates;
-		size = ARRAY_SIZE(default_rates);
-	}
-
-	/* This depends on the fact that 5.4 is last value in the array */
-	if (!intel_dp_source_supports_hbr2(intel_dp))
-		size--;
-
-	return size;
-}
-
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
 		   struct intel_crtc_state *pipe_config)
@@ -1343,42 +1534,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
 	}
 }
 
-static int intersect_rates(const int *source_rates, int source_len,
-			   const int *sink_rates, int sink_len,
-			   int *common_rates)
-{
-	int i = 0, j = 0, k = 0;
-
-	while (i < source_len && j < sink_len) {
-		if (source_rates[i] == sink_rates[j]) {
-			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
-				return k;
-			common_rates[k] = source_rates[i];
-			++k;
-			++i;
-			++j;
-		} else if (source_rates[i] < sink_rates[j]) {
-			++i;
-		} else {
-			++j;
-		}
-	}
-	return k;
-}
-
-static int intel_dp_common_rates(struct intel_dp *intel_dp,
-				 int *common_rates)
-{
-	const int *source_rates, *sink_rates;
-	int source_len, sink_len;
-
-	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-	source_len = intel_dp_source_rates(intel_dp, &source_rates);
-
-	return intersect_rates(source_rates, source_len,
-			       sink_rates, sink_len,
-			       common_rates);
-}
 
 static void snprintf_int_array(char *str, size_t len,
 			       const int *array, int nelem)
@@ -1436,6 +1591,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	int rates[DP_MAX_SUPPORTED_RATES] = {};
 	int len;
 
+	if (intel_dp->max_link_rate_upfront)
+		return intel_dp->max_link_rate_upfront;
+
 	len = intel_dp_common_rates(intel_dp, rates);
 	if (WARN_ON(len <= 0))
 		return 162000;
@@ -1488,7 +1646,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
-	int lane_count, clock;
+	int lane_count, clock = 0;
 	int min_lane_count = 1;
 	int max_lane_count = intel_dp_max_lane_count(intel_dp);
 	/* Conveniently, the link BW constants become indices with a shift...*/
@@ -1567,11 +1725,24 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	for (; bpp >= 6*3; bpp -= 2*3) {
 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
 						   bpp);
+		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
+			clock = max_clock;
+			lane_count = intel_dp->max_lanes_upfront;
+			link_clock = intel_dp->max_link_rate_upfront;
+			link_avail = intel_dp_max_data_rate(link_clock,
+							    lane_count);
+			mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+							   bpp);
+			if (mode_rate <= link_avail)
+				goto found;
+			else
+				continue;
+		}
+
 		for (clock = max_clock; clock >= max_clock; clock--) {
 			for (lane_count = max_lane_count;
 			     lane_count >= min_lane_count;
 			     lane_count >>= 1) {
-
 				link_clock = common_rates[clock];
 				link_avail = intel_dp_max_data_rate(link_clock,
 								    lane_count);
@@ -1600,7 +1771,6 @@ found:
 	}
 
 	pipe_config->lane_count = lane_count;
-
 	pipe_config->pipe_bpp = bpp;
 	pipe_config->port_clock = common_rates[clock];
 
@@ -4284,7 +4454,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	struct drm_device *dev = connector->dev;
 	enum drm_connector_status status;
 	enum intel_display_power_domain power_domain;
-	u8 sink_irq_vector = 0;
+	u8 sink_irq_vector;
 
 	power_domain = intel_display_port_aux_power_domain(intel_encoder);
 	intel_display_power_get(to_i915(dev), power_domain);
@@ -4377,9 +4547,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	}
 
 out:
-	if ((status != connector_status_connected) &&
-	    (intel_dp->is_mst == false))
+	if (status != connector_status_connected) {
 		intel_dp_unset_edid(intel_dp);
+		intel_dp->upfront_done = false;
+		intel_dp->max_lanes_upfront = 0;
+		intel_dp->max_link_rate_upfront = 0;
+	}
 
 	intel_display_power_put(to_i915(dev), power_domain);
 	return;
@@ -5623,6 +5796,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	if (type == DRM_MODE_CONNECTOR_eDP)
 		intel_encoder->type = INTEL_OUTPUT_EDP;
 
+	/* Initialize upfront link training vfunc for DP */
+	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
+		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
+		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+			intel_dp->upfront_link_train = intel_ddi_link_train;
+	}
+
 	/* eDP only on port B and/or C on vlv/chv */
 	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
 		    is_edp(intel_dp) && port != PORT_B && port != PORT_C))
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index f1e08f0..b6f380b 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -304,7 +304,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 	intel_dp_set_idle_link_train(intel_dp);
 
 	return intel_dp->channel_eq_status;
-
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c571baf..a2bbf68 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -882,6 +882,12 @@ struct intel_dp {
 	enum hdmi_force_audio force_audio;
 	bool limited_color_range;
 	bool color_range_auto;
+
+	/* Upfront link train parameters */
+	int max_link_rate_upfront;
+	uint8_t max_lanes_upfront;
+	bool upfront_done;
+
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
 	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
@@ -939,6 +945,11 @@ struct intel_dp {
 	/* This is called before a link training is starterd */
 	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
 
+	/* For Upfront link training */
+	bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
+				   uint8_t lane_count, bool link_mst,
+				   bool is_upfront);
+
 	/* Displayport compliance testing */
 	unsigned long compliance_test_type;
 	unsigned long compliance_test_data;
@@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
 bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-			  uint8_t max_lane_count, bool link_mst);
+			  uint8_t max_lane_count, bool link_mst,
+			  bool is_upfront);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
-- 
1.9.1

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

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

* Re: [PATCH v3 07/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT
  2016-09-02 20:06   ` Pandiyan, Dhinakaran
@ 2016-09-07 22:08     ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-07 22:08 UTC (permalink / raw)
  To: Pandiyan, Dhinakaran; +Cc: intel-gfx

On Fri, Sep 02, 2016 at 01:06:32PM -0700, Pandiyan, Dhinakaran wrote:
> On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > From: Jim Bride <jim.bride@linux.intel.com>
> > 
> > Add the PLL selection code for HSW/BDW/BXT/SKL into a stand-alone function
> > in order to allow for the implementation of a platform neutral upfront
> > link training function.
> > 
> > v3:
> > * Add Hooks for all DDI platforms into this standalone function
> > 
> > v2:
> > * Change the macro to use dev_priv instead of dev (David Weinehall)
> > 
> > Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c      | 38 +++++++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/i915/intel_dpll_mgr.c | 38 +++++++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/i915/intel_dpll_mgr.h |  2 ++
> >  drivers/gpu/drm/i915/intel_drv.h      |  3 ++-
> >  4 files changed, 80 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index e4b875e..67a6a0b 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -2393,6 +2393,44 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
> >  	return connector;
> >  }
> >  
> > +struct intel_shared_dpll *
> > +intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
> > +{
> > +	struct intel_connector *connector = intel_dp->attached_connector;
> > +	struct intel_encoder *encoder = connector->encoder;
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> > +	struct intel_shared_dpll *pll = NULL;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +	enum intel_dpll_id dpll_id;
> > +
> > +	if (IS_BROXTON(dev_priv)) {
> > +		dpll_id =  (enum intel_dpll_id)dig_port->port;
> > +		/*
> > +		 * Select the required PLL. This works for platforms where
> > +		 * there is no shared DPLL.
> > +		 */
> > +		pll = &dev_priv->shared_dplls[dpll_id];
> > +		if (WARN_ON(pll->active_mask)) {
> > +
> > +			DRM_ERROR("Shared DPLL in use. active_mask:%x\n",
> > +				  pll->active_mask);
> > +			pll = NULL;
> > +		}
> > +		tmp_pll_config = pll->config;
> 
> NULL dereference when pll is in use? 

Yes I had given this comment in the internal review. So we moved this assignment out 
to the calling function, but left this here as well. I will remove this and resubmit.

Manasi
> 
> > +		if (!bxt_ddi_dp_set_dpll_hw_state(clock,
> > +						  &pll->config.hw_state)) {
> > +			DRM_ERROR("Could not setup DPLL\n");
> > +			pll->config = tmp_pll_config;
> > +		}
> > +	} else if (IS_SKYLAKE(dev_priv)) {
> > +		pll = skl_find_link_pll(dev_priv, clock);
> > +	} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
> > +		pll = hsw_ddi_dp_get_dpll(encoder, clock);
> > +	}
> > +	return pll;
> > +}
> > +
> >  void intel_ddi_init(struct drm_device *dev, enum port port)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > index 9a1da98..4b067ac 100644
> > --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > @@ -24,6 +24,44 @@
> >  #include "intel_drv.h"
> >  
> >  struct intel_shared_dpll *
> > +skl_find_link_pll(struct drm_i915_private *dev_priv, int clock)
> > +{
> > +	struct intel_shared_dpll *pll = NULL;
> > +	struct intel_dpll_hw_state dpll_hw_state;
> > +	enum intel_dpll_id i;
> > +	bool found = false;
> > +
> > +	if (!skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
> > +		return pll;
> > +
> > +	for (i = DPLL_ID_SKL_DPLL1; i <= DPLL_ID_SKL_DPLL3; i++) {
> > +		pll = &dev_priv->shared_dplls[i];
> > +
> > +		/* Only want to check enabled timings first */
> > +		if (pll->config.crtc_mask == 0)
> > +			continue;
> > +
> > +		if (memcmp(&dpll_hw_state, &pll->config.hw_state,
> > +			   sizeof(pll->config.hw_state)) == 0) {
> > +			found = true;
> > +			break;
> > +		}
> > +	}
> > +
> > +	/* Ok no matching timings, maybe there's a free one? */
> > +	for (i = DPLL_ID_SKL_DPLL1;
> > +	     ((found == false) && (i <= DPLL_ID_SKL_DPLL3)); i++) {
> > +		pll = &dev_priv->shared_dplls[i];
> > +		if (pll->config.crtc_mask == 0) {
> > +			pll->config.hw_state = dpll_hw_state;
> > +			break;
> > +		}
> > +	}
> > +
> > +	return pll;
> > +}
> > +
> > +struct intel_shared_dpll *
> >  intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
> >  			    enum intel_dpll_id id)
> >  {
> > diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> > index aed7408..f438535 100644
> > --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
> > +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> > @@ -168,6 +168,8 @@ bool bxt_ddi_dp_set_dpll_hw_state(int clock,
> >  /* SKL dpll related functions */
> >  bool skl_ddi_dp_set_dpll_hw_state(int clock,
> >  				  struct intel_dpll_hw_state *dpll_hw_state);
> > +struct intel_shared_dpll *skl_find_link_pll(struct drm_i915_private *dev_priv,
> > +					    int clock);
> >  
> > 
> >  /* HSW dpll related functions */
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index 529fa7b..efcd80b 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1159,7 +1159,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
> >  			 struct intel_crtc_state *pipe_config);
> >  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
> >  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> > -
> > +struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
> > +						  int clock);
> >  unsigned int intel_fb_align_height(struct drm_device *dev,
> >  				   unsigned int height,
> >  				   uint32_t pixel_format,
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH v4 7/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT
  2016-09-01 22:08 ` [PATCH v3 07/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT Manasi Navare
  2016-09-02 20:06   ` Pandiyan, Dhinakaran
@ 2016-09-07 22:47   ` Manasi Navare
  1 sibling, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-07 22:47 UTC (permalink / raw)
  To: intel-gfx; +Cc: dhinakaran.pandiyan

From: Jim Bride <jim.bride@linux.intel.com>

Add the PLL selection code for HSW/BDW/BXT/SKL into a stand-alone function
in order to allow for the implementation of a platform neutral upfront
link training function.

v4:
* Removed dereferencing NULL pointer in  case of failure (Dhinakaran Pandiyan)
v3:
* Add Hooks for all DDI platforms into this standalone function

v2:
* Change the macro to use dev_priv instead of dev (David Weinehall)

Reviewed-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c      | 39 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 38 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_dpll_mgr.h |  2 ++
 drivers/gpu/drm/i915/intel_drv.h      |  3 ++-
 4 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e4b875e..25e7973 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2393,6 +2393,45 @@ intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
 	return connector;
 }
 
+struct intel_shared_dpll *
+intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct intel_encoder *encoder = connector->encoder;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct intel_shared_dpll *pll = NULL;
+	struct intel_shared_dpll_config tmp_pll_config;
+	enum intel_dpll_id dpll_id;
+
+	if (IS_BROXTON(dev_priv)) {
+		dpll_id =  (enum intel_dpll_id)dig_port->port;
+		/*
+		 * Select the required PLL. This works for platforms where
+		 * there is no shared DPLL.
+		 */
+		pll = &dev_priv->shared_dplls[dpll_id];
+		if (WARN_ON(pll->active_mask)) {
+
+			DRM_ERROR("Shared DPLL in use. active_mask:%x\n",
+				  pll->active_mask);
+			return NULL;
+		}
+		tmp_pll_config = pll->config;
+		if (!bxt_ddi_dp_set_dpll_hw_state(clock,
+						  &pll->config.hw_state)) {
+			DRM_ERROR("Could not setup DPLL\n");
+			pll->config = tmp_pll_config;
+			return NULL;
+		}
+	} else if (IS_SKYLAKE(dev_priv)) {
+		pll = skl_find_link_pll(dev_priv, clock);
+	} else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
+		pll = hsw_ddi_dp_get_dpll(encoder, clock);
+	}
+	return pll;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index 9a1da98..4b067ac 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -24,6 +24,44 @@
 #include "intel_drv.h"
 
 struct intel_shared_dpll *
+skl_find_link_pll(struct drm_i915_private *dev_priv, int clock)
+{
+	struct intel_shared_dpll *pll = NULL;
+	struct intel_dpll_hw_state dpll_hw_state;
+	enum intel_dpll_id i;
+	bool found = false;
+
+	if (!skl_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state))
+		return pll;
+
+	for (i = DPLL_ID_SKL_DPLL1; i <= DPLL_ID_SKL_DPLL3; i++) {
+		pll = &dev_priv->shared_dplls[i];
+
+		/* Only want to check enabled timings first */
+		if (pll->config.crtc_mask == 0)
+			continue;
+
+		if (memcmp(&dpll_hw_state, &pll->config.hw_state,
+			   sizeof(pll->config.hw_state)) == 0) {
+			found = true;
+			break;
+		}
+	}
+
+	/* Ok no matching timings, maybe there's a free one? */
+	for (i = DPLL_ID_SKL_DPLL1;
+	     ((found == false) && (i <= DPLL_ID_SKL_DPLL3)); i++) {
+		pll = &dev_priv->shared_dplls[i];
+		if (pll->config.crtc_mask == 0) {
+			pll->config.hw_state = dpll_hw_state;
+			break;
+		}
+	}
+
+	return pll;
+}
+
+struct intel_shared_dpll *
 intel_get_shared_dpll_by_id(struct drm_i915_private *dev_priv,
 			    enum intel_dpll_id id)
 {
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
index aed7408..f438535 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
@@ -168,6 +168,8 @@ bool bxt_ddi_dp_set_dpll_hw_state(int clock,
 /* SKL dpll related functions */
 bool skl_ddi_dp_set_dpll_hw_state(int clock,
 				  struct intel_dpll_hw_state *dpll_hw_state);
+struct intel_shared_dpll *skl_find_link_pll(struct drm_i915_private *dev_priv,
+					    int clock);
 
 
 /* HSW dpll related functions */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 7868d5c..996c804 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1159,7 +1159,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
-
+struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
+						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
 				   unsigned int height,
 				   uint32_t pixel_format,
-- 
1.9.1

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

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

* [PATCH v4 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
@ 2016-09-08  0:30       ` Manasi Navare
  2016-09-08  9:32         ` Mika Kahola
                           ` (3 more replies)
  0 siblings, 4 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-08  0:30 UTC (permalink / raw)
  To: intel-gfx

According to the DisplayPort Spec, in case of Clock Recovery failure
the link training sequence should fall back to the lower link rate
followed by lower lane count until CR succeeds.
On CR success, the sequence proceeds with Channel EQ.
In case of Channel EQ failures, it should fallback to
lower link rate and lane count and start the CR phase again.

v4:
* Fixed the link rate fallback loop (Manasi Navare)
v3:
* Fixed some rebase issues (Mika Kahola)
v2:
* Add a helper function to return index of requested link rate
into common_rates array
* Changed the link rate fallback loop to make use
of common_rates array (Mika Kahola)
* Changed INTEL_INFO to INTEL_GEN (David Weinehall)

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
 drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
 drivers/gpu/drm/i915/intel_drv.h              |   6 +-
 4 files changed, 128 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 25e7973..1278daa 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
 	}
 }
 
-static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
 				    int link_rate, uint32_t lane_count,
-				    struct intel_shared_dpll *pll,
-				    bool link_mst)
+				    struct intel_shared_dpll *pll)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum port port = intel_ddi_get_encoder_port(encoder);
 
 	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
-				 link_mst);
-	if (encoder->type == INTEL_OUTPUT_EDP)
-		intel_edp_panel_on(intel_dp);
+				 false);
+
+	intel_edp_panel_on(intel_dp);
 
 	intel_ddi_clk_select(encoder, pll);
 	intel_prepare_dp_ddi_buffers(encoder);
@@ -1657,6 +1656,28 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 		intel_dp_stop_link_train(intel_dp);
 }
 
+static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+				    int link_rate, uint32_t lane_count,
+				    struct intel_shared_dpll *pll,
+				    bool link_mst)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll_config tmp_pll_config;
+
+	/* Disable the PLL and obtain the PLL for Link Training
+	 * that starts with highest link rate and lane count.
+	 */
+	tmp_pll_config = pll->config;
+	pll->funcs.disable(dev_priv, pll);
+	pll->config.crtc_mask = 0;
+
+	/* If Link Training fails, send a uevent to generate a hotplug */
+	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
+		drm_kms_helper_hotplug_event(encoder->base.dev);
+	pll->config = tmp_pll_config;
+}
+
 static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
 				      bool has_hdmi_sink,
 				      struct drm_display_mode *adjusted_mode,
@@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	int type = intel_encoder->type;
 
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+	if (type == INTEL_OUTPUT_EDP)
+		intel_ddi_pre_enable_edp(intel_encoder,
+					crtc->config->port_clock,
+					crtc->config->lane_count,
+					crtc->config->shared_dpll);
+
+	if (type == INTEL_OUTPUT_DP)
 		intel_ddi_pre_enable_dp(intel_encoder,
 					crtc->config->port_clock,
 					crtc->config->lane_count,
 					crtc->config->shared_dpll,
 					intel_crtc_has_type(crtc->config,
 							    INTEL_OUTPUT_DP_MST));
-	}
-	if (type == INTEL_OUTPUT_HDMI) {
+
+	if (type == INTEL_OUTPUT_HDMI)
 		intel_ddi_pre_enable_hdmi(intel_encoder,
 					  crtc->config->has_hdmi_sink,
 					  &crtc->config->base.adjusted_mode,
 					  crtc->config->shared_dpll);
-	}
+
 }
 
 static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
@@ -2432,6 +2459,68 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 	return pll;
 }
 
+bool
+intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+		     uint8_t max_lane_count, bool link_mst)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct intel_encoder *encoder = connector->encoder;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	int link_rate, link_rate_index;
+	uint8_t lane_count;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	bool ret = false;
+
+	link_rate_index = intel_dp_link_rate_index(intel_dp, common_rates,
+						   max_link_rate);
+	if (link_rate_index < 0) {
+		DRM_ERROR("Invalid Link Rate\n");
+		return false;
+	}
+	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
+		for (; link_rate_index >= 0; link_rate_index --) {
+			link_rate = common_rates[link_rate_index];
+			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
+			if (pll == NULL) {
+				DRM_ERROR("Could not find DPLL for link "
+					  "training.\n");
+				return false;
+			}
+			tmp_pll_config = pll->config;
+			pll->funcs.enable(dev_priv, pll);
+
+			intel_dp_set_link_params(intel_dp, link_rate,
+						 lane_count, link_mst);
+
+			intel_ddi_clk_select(encoder, pll);
+			intel_prepare_dp_ddi_buffers(encoder);
+			intel_ddi_init_dp_buf_reg(encoder);
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+			ret = intel_dp_start_link_train(intel_dp);
+			if (ret)
+				break;
+
+			/* Disable port followed by PLL for next retry/clean up */
+			intel_ddi_post_disable(encoder, NULL, NULL);
+			pll->funcs.disable(dev_priv, pll);
+			pll->config = tmp_pll_config;
+		}
+		if (ret) {
+			DRM_DEBUG_KMS("Link Training successful at link rate: "
+				      "%d lane:%d\n", link_rate, lane_count);
+			break;
+		}
+	}
+	intel_dp_stop_link_train(intel_dp);
+
+	if (!lane_count)
+		DRM_ERROR("Link Training Failed\n");
+
+	return ret;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 75ac62f..1378116 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	return rates[len - 1];
 }
 
+int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
+			     int link_rate)
+{
+	int common_len;
+	int index;
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	for (index = common_len - 1; index >= 0; index--) {
+		if (link_rate == common_rates[index])
+			return index;
+	}
+
+	return -1;
+}
+
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
 {
 	return rate_to_index(rate, intel_dp->sink_rates);
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index c438b02..f1e08f0 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -313,9 +313,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 				DP_TRAINING_PATTERN_DISABLE);
 }
 
-void
+bool
 intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-	intel_dp_link_training_clock_recovery(intel_dp);
-	intel_dp_link_training_channel_equalization(intel_dp);
+	bool ret;
+
+	if (intel_dp_link_training_clock_recovery(intel_dp)) {
+		ret = intel_dp_link_training_channel_equalization(intel_dp);
+		if (ret)
+			return true;
+	}
+	return false;
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ca51e1a..5b97a7d4 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
+bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+			  uint8_t max_lane_count, bool link_mst);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
@@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
 			      int link_rate, uint8_t lane_count,
 			      bool link_mst);
-void intel_dp_start_link_train(struct intel_dp *intel_dp);
+bool intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 void intel_dp_encoder_reset(struct drm_encoder *encoder);
@@ -1403,6 +1405,8 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
 int intel_dp_max_link_rate(struct intel_dp *intel_dp);
+int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
+			     int link_rate);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
 void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
-- 
1.9.1

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

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

* Re: [PATCH v3 8/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
@ 2016-09-08  7:38       ` Mika Kahola
  2016-09-13 11:44         ` Jani Nikula
  0 siblings, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-08  7:38 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

This compiler warning is fixed with the next patch of the series.

drivers/gpu/drm/i915/intel_dp_link_training.c: In function
‘intel_dp_link_training_clock_recovery’:
drivers/gpu/drm/i915/intel_dp_link_training.c:131:6: warning: unused
variable ‘i’ [-Wunused-variable]

Therefore,

Reviewed-by: Mika Kahola <mika.kahola@intel.com>

On Wed, 2016-09-07 at 11:28 -0700, Manasi Navare wrote:
> From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> 
> Wrap the max. vswing check in a separate function.
> This makes the clock recovery phase of DP link training cleaner
> 
> v3:
> Fixed the paranthesis warning (Mika Kahola)
> v2:
> Fixed the Compiler warning (Mika Kahola)
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 17 +++++++++++++----
>  1 file changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 0deebed..b9880cf 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -112,6 +112,18 @@ intel_dp_update_link_train(struct intel_dp
> *intel_dp)
>  	return ret == intel_dp->lane_count;
>  }
>  
> +static bool intel_dp_link_max_vswing_reached(struct intel_dp
> *intel_dp)
> +{
> +	int lane;
> +
> +	for (lane = 0; lane < intel_dp->lane_count; lane++)
> +		if ((intel_dp->train_set[lane] &
> +		     DP_TRAIN_MAX_SWING_REACHED) == 0)
> +			return false;
> +
> +	return true;
> +}
> +
>  /* Enable corresponding port and start training pattern 1 */
>  static void
>  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> @@ -170,10 +182,7 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  		}
>  
>  		/* Check to see if we've tried the max voltage */
> -		for (i = 0; i < intel_dp->lane_count; i++)
> -			if ((intel_dp->train_set[i] &
> DP_TRAIN_MAX_SWING_REACHED) == 0)
> -				break;
> -		if (i == intel_dp->lane_count) {
> +		if (intel_dp_link_max_vswing_reached(intel_dp)) {
>  			++loop_tries;
>  			if (loop_tries == 5) {
>  				DRM_ERROR("too many full retries,
> give up\n");
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v3 9/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2
  2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
@ 2016-09-08  8:20       ` Mika Kahola
  0 siblings, 0 replies; 81+ messages in thread
From: Mika Kahola @ 2016-09-08  8:20 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

Reviewed-by: Mika Kahola <mika.kahola@intel.com>

On Wed, 2016-09-07 at 11:28 -0700, Manasi Navare wrote:
> From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> 
> This function cleans up clock recovery loop in link training
> compliant
> tp Dp Spec 1.2. It tries the clock recovery 5 times for the same
> voltage
> or until max voltage swing is reached and removes the additional non
> compliant retries. This function now returns a boolean values based
> on
> if clock recovery passed or failed.
> 
> v3:
> * Better Debug prints in case of failures (Mika Kahola)
> v2:
> * Rebased on top of new revision of vswing patch (Manasi Navare)
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 60 +++++++++++++--
> ------------
>  1 file changed, 28 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index b9880cf..80b9326 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -125,12 +125,11 @@ static bool
> intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
>  }
>  
>  /* Enable corresponding port and start training pattern 1 */
> -static void
> +static bool
>  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>  {
> -	int i;
>  	uint8_t voltage;
> -	int voltage_tries, loop_tries;
> +	int voltage_tries, max_vswing_tries;
>  	uint8_t link_config[2];
>  	uint8_t link_bw, rate_select;
>  
> @@ -146,6 +145,7 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  	if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
>  		link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
>  	drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET,
> link_config, 2);
> +
>  	if (intel_dp->num_sink_rates)
>  		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
>  				  &rate_select, 1);
> @@ -161,58 +161,54 @@ intel_dp_link_training_clock_recovery(struct
> intel_dp *intel_dp)
>  				       DP_TRAINING_PATTERN_1 |
>  				       DP_LINK_SCRAMBLING_DISABLE))
> {
>  		DRM_ERROR("failed to enable link training\n");
> -		return;
> +		return false;
>  	}
>  
> -	voltage = 0xff;
> -	voltage_tries = 0;
> -	loop_tries = 0;
> +	voltage_tries = 1;
> +	max_vswing_tries = 0;
>  	for (;;) {
>  		uint8_t link_status[DP_LINK_STATUS_SIZE];
>  
>  		drm_dp_link_train_clock_recovery_delay(intel_dp-
> >dpcd);
> +
>  		if (!intel_dp_get_link_status(intel_dp,
> link_status)) {
>  			DRM_ERROR("failed to get link status\n");
> -			break;
> +			return false;
>  		}
>  
>  		if (drm_dp_clock_recovery_ok(link_status, intel_dp-
> >lane_count)) {
>  			DRM_DEBUG_KMS("clock recovery OK\n");
> -			break;
> +			return true;
>  		}
>  
> -		/* Check to see if we've tried the max voltage */
> -		if (intel_dp_link_max_vswing_reached(intel_dp)) {
> -			++loop_tries;
> -			if (loop_tries == 5) {
> -				DRM_ERROR("too many full retries,
> give up\n");
> -				intel_dp_dump_link_status(link_statu
> s);
> -				break;
> -			}
> -			intel_dp_reset_link_train(intel_dp,
> -						  DP_TRAINING_PATTER
> N_1 |
> -						  DP_LINK_SCRAMBLING
> _DISABLE);
> -			voltage_tries = 0;
> -			continue;
> +		if (voltage_tries == 5) {
> +			DRM_DEBUG_KMS("Same voltage tried 5
> times\n");
> +			return false;
> +		}
> +
> +		if (max_vswing_tries == 1) {
> +			DRM_DEBUG_KMS("Max Voltage Swing
> reached\n");
> +			return false;
>  		}
>  
> -		/* Check to see if we've tried the same voltage 5
> times */
> -		if ((intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
> -			++voltage_tries;
> -			if (voltage_tries == 5) {
> -				DRM_ERROR("too many voltage retries,
> give up\n");
> -				break;
> -			}
> -		} else
> -			voltage_tries = 0;
>  		voltage = intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK;
>  
>  		/* Update training set as requested by target */
>  		intel_get_adjust_train(intel_dp, link_status);
>  		if (!intel_dp_update_link_train(intel_dp)) {
>  			DRM_ERROR("failed to update link
> training\n");
> -			break;
> +			return false;
>  		}
> +
> +		if ((intel_dp->train_set[0] &
> DP_TRAIN_VOLTAGE_SWING_MASK) ==
> +		    voltage)
> +			++voltage_tries;
> +		else
> +			voltage_tries = 1;
> +
> +		if (intel_dp_link_max_vswing_reached(intel_dp))
> +			++max_vswing_tries;
> +
>  	}
>  }
>  
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v4 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-08  0:30       ` [PATCH v4 " Manasi Navare
@ 2016-09-08  9:32         ` Mika Kahola
  2016-09-09  1:05         ` Rodrigo Vivi
                           ` (2 subsequent siblings)
  3 siblings, 0 replies; 81+ messages in thread
From: Mika Kahola @ 2016-09-08  9:32 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

Reviewed-by: Mika Kahola <mika.kahola@intel.com>

On Wed, 2016-09-07 at 17:30 -0700, Manasi Navare wrote:
> According to the DisplayPort Spec, in case of Clock Recovery failure
> the link training sequence should fall back to the lower link rate
> followed by lower lane count until CR succeeds.
> On CR success, the sequence proceeds with Channel EQ.
> In case of Channel EQ failures, it should fallback to
> lower link rate and lane count and start the CR phase again.
> 
> v4:
> * Fixed the link rate fallback loop (Manasi Navare)
> v3:
> * Fixed some rebase issues (Mika Kahola)
> v2:
> * Add a helper function to return index of requested link rate
> into common_rates array
> * Changed the link rate fallback loop to make use
> of common_rates array (Mika Kahola)
> * Changed INTEL_INFO to INTEL_GEN (David Weinehall)
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              | 109
> +++++++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>  drivers/gpu/drm/i915/intel_drv.h              |   6 +-
>  4 files changed, 128 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index 25e7973..1278daa 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct
> intel_encoder *encoder,
>  	}
>  }
>  
> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>  				    int link_rate, uint32_t
> lane_count,
> -				    struct intel_shared_dpll *pll,
> -				    bool link_mst)
> +				    struct intel_shared_dpll *pll)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
>  	enum port port = intel_ddi_get_encoder_port(encoder);
>  
>  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> -				 link_mst);
> -	if (encoder->type == INTEL_OUTPUT_EDP)
> -		intel_edp_panel_on(intel_dp);
> +				 false);
> +
> +	intel_edp_panel_on(intel_dp);
>  
>  	intel_ddi_clk_select(encoder, pll);
>  	intel_prepare_dp_ddi_buffers(encoder);
> @@ -1657,6 +1656,28 @@ static void intel_ddi_pre_enable_dp(struct
> intel_encoder *encoder,
>  		intel_dp_stop_link_train(intel_dp);
>  }
>  
> +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +				    int link_rate, uint32_t
> lane_count,
> +				    struct intel_shared_dpll *pll,
> +				    bool link_mst)
> +{
> +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
> +	struct intel_shared_dpll_config tmp_pll_config;
> +
> +	/* Disable the PLL and obtain the PLL for Link Training
> +	 * that starts with highest link rate and lane count.
> +	 */
> +	tmp_pll_config = pll->config;
> +	pll->funcs.disable(dev_priv, pll);
> +	pll->config.crtc_mask = 0;
> +
> +	/* If Link Training fails, send a uevent to generate a
> hotplug */
> +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> link_mst)))
> +		drm_kms_helper_hotplug_event(encoder->base.dev);
> +	pll->config = tmp_pll_config;
> +}
> +
>  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>  				      bool has_hdmi_sink,
>  				      struct drm_display_mode
> *adjusted_mode,
> @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct
> intel_encoder *intel_encoder,
>  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>  	int type = intel_encoder->type;
>  
> -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> +	if (type == INTEL_OUTPUT_EDP)
> +		intel_ddi_pre_enable_edp(intel_encoder,
> +					crtc->config->port_clock,
> +					crtc->config->lane_count,
> +					crtc->config->shared_dpll);
> +
> +	if (type == INTEL_OUTPUT_DP)
>  		intel_ddi_pre_enable_dp(intel_encoder,
>  					crtc->config->port_clock,
>  					crtc->config->lane_count,
>  					crtc->config->shared_dpll,
>  					intel_crtc_has_type(crtc-
> >config,
>  							    INTEL_OU
> TPUT_DP_MST));
> -	}
> -	if (type == INTEL_OUTPUT_HDMI) {
> +
> +	if (type == INTEL_OUTPUT_HDMI)
>  		intel_ddi_pre_enable_hdmi(intel_encoder,
>  					  crtc->config-
> >has_hdmi_sink,
>  					  &crtc->config-
> >base.adjusted_mode,
>  					  crtc->config-
> >shared_dpll);
> -	}
> +
>  }
>  
>  static void intel_ddi_post_disable(struct intel_encoder
> *intel_encoder,
> @@ -2432,6 +2459,68 @@ intel_ddi_get_link_dpll(struct intel_dp
> *intel_dp, int clock)
>  	return pll;
>  }
>  
> +bool
> +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +		     uint8_t max_lane_count, bool link_mst)
> +{
> +	struct intel_connector *connector = intel_dp-
> >attached_connector;
> +	struct intel_encoder *encoder = connector->encoder;
> +	struct drm_i915_private *dev_priv = to_i915(encoder-
> >base.dev);
> +	struct intel_shared_dpll *pll;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	int link_rate, link_rate_index;
> +	uint8_t lane_count;
> +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> +	bool ret = false;
> +
> +	link_rate_index = intel_dp_link_rate_index(intel_dp,
> common_rates,
> +						   max_link_rate);
> +	if (link_rate_index < 0) {
> +		DRM_ERROR("Invalid Link Rate\n");
> +		return false;
> +	}
> +	for (lane_count = max_lane_count; lane_count > 0; lane_count
> >>= 1) {
> +		for (; link_rate_index >= 0; link_rate_index --) {
> +			link_rate = common_rates[link_rate_index];
> +			pll = intel_ddi_get_link_dpll(intel_dp,
> link_rate);
> +			if (pll == NULL) {
> +				DRM_ERROR("Could not find DPLL for
> link "
> +					  "training.\n");
> +				return false;
> +			}
> +			tmp_pll_config = pll->config;
> +			pll->funcs.enable(dev_priv, pll);
> +
> +			intel_dp_set_link_params(intel_dp,
> link_rate,
> +						 lane_count,
> link_mst);
> +
> +			intel_ddi_clk_select(encoder, pll);
> +			intel_prepare_dp_ddi_buffers(encoder);
> +			intel_ddi_init_dp_buf_reg(encoder);
> +			intel_dp_sink_dpms(intel_dp,
> DRM_MODE_DPMS_ON);
> +			ret = intel_dp_start_link_train(intel_dp);
> +			if (ret)
> +				break;
> +
> +			/* Disable port followed by PLL for next
> retry/clean up */
> +			intel_ddi_post_disable(encoder, NULL, NULL);
> +			pll->funcs.disable(dev_priv, pll);
> +			pll->config = tmp_pll_config;
> +		}
> +		if (ret) {
> +			DRM_DEBUG_KMS("Link Training successful at
> link rate: "
> +				      "%d lane:%d\n", link_rate,
> lane_count);
> +			break;
> +		}
> +	}
> +	intel_dp_stop_link_train(intel_dp);
> +
> +	if (!lane_count)
> +		DRM_ERROR("Link Training Failed\n");
> +
> +	return ret;
> +}
> +
>  void intel_ddi_init(struct drm_device *dev, enum port port)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/intel_dp.c
> b/drivers/gpu/drm/i915/intel_dp.c
> index 75ac62f..1378116 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp
> *intel_dp)
>  	return rates[len - 1];
>  }
>  
> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> *common_rates,
> +			     int link_rate)
> +{
> +	int common_len;
> +	int index;
> +
> +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> +	for (index = common_len - 1; index >= 0; index--) {
> +		if (link_rate == common_rates[index])
> +			return index;
> +	}
> +
> +	return -1;
> +}
> +
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
>  {
>  	return rate_to_index(rate, intel_dp->sink_rates);
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index c438b02..f1e08f0 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -313,9 +313,15 @@ void intel_dp_stop_link_train(struct intel_dp
> *intel_dp)
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
>  
> -void
> +bool
>  intel_dp_start_link_train(struct intel_dp *intel_dp)
>  {
> -	intel_dp_link_training_clock_recovery(intel_dp);
> -	intel_dp_link_training_channel_equalization(intel_dp);
> +	bool ret;
> +
> +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> +		ret =
> intel_dp_link_training_channel_equalization(intel_dp);
> +		if (ret)
> +			return true;
> +	}
> +	return false;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index ca51e1a..5b97a7d4 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder
> *encoder,
>  			 struct intel_crtc_state *pipe_config);
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool
> state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> +bool intel_ddi_link_train(struct intel_dp *intel_dp, int
> max_link_rate,
> +			  uint8_t max_lane_count, bool link_mst);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp
> *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
> @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct
> intel_digital_port *intel_dig_port,
>  void intel_dp_set_link_params(struct intel_dp *intel_dp,
>  			      int link_rate, uint8_t lane_count,
>  			      bool link_mst);
> -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> @@ -1403,6 +1405,8 @@ void intel_dp_add_properties(struct intel_dp
> *intel_dp, struct drm_connector *co
>  void intel_dp_mst_suspend(struct drm_device *dev);
>  void intel_dp_mst_resume(struct drm_device *dev);
>  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> *common_rates,
> +			     int link_rate);
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
>  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
>  void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v2 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST
  2016-09-07 16:40       ` Jim Bride
@ 2016-09-08 10:21         ` Mika Kahola
  0 siblings, 0 replies; 81+ messages in thread
From: Mika Kahola @ 2016-09-08 10:21 UTC (permalink / raw)
  To: Jim Bride; +Cc: intel-gfx

On Wed, 2016-09-07 at 09:40 -0700, Jim Bride wrote:
> On Wed, Sep 07, 2016 at 01:53:31PM +0300, Mika Kahola wrote:
> > 
> > On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> > > 
> > > From: Jim Bride <jim.bride@linux.intel.com>
> > > 
> > > Add upfront link training to intel_dp_mst_mode_valid() so that we
> > > know
> > > topology constraints before we validate the legality of modes to
> > > be
> > > checked.
> > > Call the function that loops through the link rates and lane
> > > counts
> > > starting from highest supported link rate and lane count for
> > > training
> > > the link in compliance with DP spec
> > > 
> > > v2:
> > > * Rebased on new revision of link training patch (Manasi Navare)
> > > 
> > > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > > Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/intel_dp.c     |  9 ++---
> > >  drivers/gpu/drm/i915/intel_dp_mst.c | 74
> > > +++++++++++++++++++++++++++----------
> > >  drivers/gpu/drm/i915/intel_drv.h    |  3 ++
> > >  3 files changed, 61 insertions(+), 25 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > > b/drivers/gpu/drm/i915/intel_dp.c
> > > index 7794180..0c7674f 100644
> > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > @@ -131,7 +131,7 @@ static void vlv_steal_power_sequencer(struct
> > > drm_device *dev,
> > >  				      enum pipe pipe);
> > >  static void intel_dp_unset_edid(struct intel_dp *intel_dp);
> > >  
> > > -static int
> > > +int
> > >  intel_dp_max_link_bw(struct intel_dp  *intel_dp)
> > >  {
> > >  	int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
> > > @@ -150,7 +150,7 @@ intel_dp_max_link_bw(struct
> > > intel_dp  *intel_dp)
> > >  	return max_link_bw;
> > >  }
> > >  
> > > -static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
> > > +u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
> > >  {
> > >  	struct intel_digital_port *intel_dig_port =
> > > dp_to_dig_port(intel_dp);
> > >  	u8 temp, source_max, sink_max;
> > > @@ -312,8 +312,7 @@ static int intersect_rates(const int
> > > *source_rates, int source_len,
> > >  	return k;
> > >  }
> > >  
> > > -static int intel_dp_common_rates(struct intel_dp *intel_dp,
> > > -				 int *common_rates)
> > > +int intel_dp_common_rates(struct intel_dp *intel_dp, int
> > > *common_rates)
> > >  {
> > >  	const int *source_rates, *sink_rates;
> > >  	int source_len, sink_len;
> > > @@ -336,7 +335,7 @@ static int intel_dp_common_rates(struct
> > > intel_dp
> > > *intel_dp,
> > >  			       common_rates);
> > >  }
> > >  
> > > -static bool intel_dp_upfront_link_train(struct intel_dp
> > > *intel_dp)
> > > +bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> > >  {
> > >  	struct intel_digital_port *intel_dig_port =
> > > dp_to_dig_port(intel_dp);
> > >  	struct intel_encoder *intel_encoder = &intel_dig_port-
> > > >base;
> > > diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c
> > > b/drivers/gpu/drm/i915/intel_dp_mst.c
> > > index 54a9d76..98d45a4 100644
> > > --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> > > +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> > > @@ -41,21 +41,30 @@ static bool
> > > intel_dp_mst_compute_config(struct
> > > intel_encoder *encoder,
> > >  	int bpp;
> > >  	int lane_count, slots;
> > >  	const struct drm_display_mode *adjusted_mode =
> > > &pipe_config-
> > > > 
> > > > base.adjusted_mode;
> > > -	int mst_pbn;
> > > +	int mst_pbn, common_len;
> > > +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> > >  
> > >  	pipe_config->dp_encoder_is_mst = true;
> > >  	pipe_config->has_pch_encoder = false;
> > > -	bpp = 24;
> > > +
> > >  	/*
> > > -	 * for MST we always configure max link bw - the spec
> > > doesn't
> > > -	 * seem to suggest we should do otherwise.
> > > +	 * For MST we always configure for the maximum trainable
> > > link bw -
> > > +	 * the spec doesn't seem to suggest we should do
> > > otherwise.  The
> > > +	 * calls to intel_dp_max_lane_count() and
> > > intel_dp_common_rates()
> > > +	 * both take successful upfront link training into
> > > account,
> > > and
> > > +	 * return the DisplayPort max supported values in the
> > > event
> > > that
> > > +	 * upfront link training was not done.
> > >  	 */
> > > -	lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
> > > +	lane_count = intel_dp_max_lane_count(intel_dp);
> > >  
> > >  	pipe_config->lane_count = lane_count;
> > >  
> > > -	pipe_config->pipe_bpp = 24;
> > > -	pipe_config->port_clock =
> > > intel_dp_max_link_rate(intel_dp);
> > > +	pipe_config->pipe_bpp = bpp = 24;
> > > +	common_len = intel_dp_common_rates(intel_dp,
> > > common_rates);
> > > +	pipe_config->port_clock = common_rates[common_len - 1];
> > > +
> > > +	DRM_DEBUG_KMS("DP MST link configured for %d lanes @
> > > %d.\n",
> > > +		      pipe_config->lane_count, pipe_config-
> > > > 
> > > > port_clock);
> > >  
> > >  	state = pipe_config->base.state;
> > >  
> > > @@ -137,6 +146,8 @@ static void intel_mst_pre_enable_dp(struct
> > > intel_encoder *encoder,
> > >  	enum port port = intel_dig_port->port;
> > >  	struct intel_connector *connector =
> > >  		to_intel_connector(conn_state->connector);
> > > +	struct intel_shared_dpll *pll = pipe_config-
> > > >shared_dpll;
> > > +	struct intel_shared_dpll_config tmp_pll_config;
> > >  	int ret;
> > >  	uint32_t temp;
> > >  	int slots;
> > > @@ -150,21 +161,23 @@ static void intel_mst_pre_enable_dp(struct
> > > intel_encoder *encoder,
> > >  	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
> > >  
> > >  	if (intel_dp->active_mst_links == 0) {
> > > -		intel_ddi_clk_select(&intel_dig_port->base,
> > > -				     pipe_config->shared_dpll);
> > > -
> > > -		intel_prepare_dp_ddi_buffers(&intel_dig_port-
> > > >base);
> > > -		intel_dp_set_link_params(intel_dp,
> > > -					 pipe_config-
> > > >port_clock,
> > > -					 pipe_config-
> > > >lane_count,
> > > -					 true);
> > > -
> > > -		intel_ddi_init_dp_buf_reg(&intel_dig_port-
> > > >base);
> > >  
> > > -		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> > > +		/* Disable the PLL since we need to acquire the
> > > PLL
> > > +		 * based on the link rate in the link training
> > > sequence
> > > +		 */
> > > +		tmp_pll_config = pll->config;
> > > +		pll->funcs.disable(dev_priv, pll);
> > > +		pll->config.crtc_mask = 0;
> > > +
> > > +		/* If Link Training fails, send a uevent to
> > > generate
> > > a
> > > +		 *hotplug
> > > +		 */
> > > +		if (!(intel_ddi_link_train(intel_dp,
> > > pipe_config-
> > > > 
> > > > port_clock,
> > > +					   pipe_config-
> > > >lane_count,
> > > true,
> > > +					   false)))
> > > +			drm_kms_helper_hotplug_event(encoder-
> > > > 
> > > > base.dev);
> > > +		pll->config = tmp_pll_config;
> > >  
> > > -		intel_dp_start_link_train(intel_dp);
> > > -		intel_dp_stop_link_train(intel_dp);
> > >  	}
> > >  
> > >  	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
> > > @@ -336,6 +349,27 @@ intel_dp_mst_mode_valid(struct drm_connector
> > > *connector,
> > >  			struct drm_display_mode *mode)
> > >  {
> > >  	int max_dotclk = to_i915(connector->dev)-
> > > >max_dotclk_freq;
> > > +	struct intel_connector *intel_connector =
> > > to_intel_connector(connector);
> > > +	struct intel_dp *intel_dp = intel_connector->mst_port;
> > > +
> > > +	if (intel_dp->upfront_link_train && !intel_dp-
> > > >upfront_done) 
> > > {
> > > +		bool do_upfront_link_train;
> > > +
> > > +		do_upfront_link_train = intel_dp-
> > > > 
> > > > compliance_test_type !=
> > > +			DP_TEST_LINK_TRAINING;
> > > +		if (do_upfront_link_train) {
> > > +			intel_dp->upfront_done =
> > > +				intel_dp_upfront_link_train(inte
> > > l_dp
> > > );
> > > +			if (intel_dp->upfront_done) {
> > > +				DRM_DEBUG_KMS("MST upfront
> > > trained
> > > at "
> > > +					      "%d lanes @ %d.",
> > > +					      intel_dp-
> > > > 
> > > > max_lanes_upfront,
> > > +					      intel_dp-
> > > > 
> > > > max_link_rate_upfront);
> > > +			} else
> > > +				DRM_DEBUG_KMS("MST upfront link
> > > training "
> > > +					      "failed.");
> > Link training has failed and we have a blank screen. Should we
> > throw an
> > error here? Maybe
> > 
> > 	return MODE_ERROR;
> This is only for upfront link training, which is helpful but not
> absolutely
> required.  If this were a link training associated with a mode set
> I'd
> agree.  As it is, I think a debug message is fine for this case.
> 
> Jim
Ok, so at this point we are not associated with any mode so I think
debug message is just fine here.

> 
> 
> > 
> > 
> > > 
> > > +		}
> > > +	}
> > >  
> > >  	/* TODO - validate mode against available PBN for link
> > > */
> > >  	if (mode->clock < 10000)
> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > b/drivers/gpu/drm/i915/intel_drv.h
> > > index a2bbf68..34af3e8 100644
> > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > @@ -1416,6 +1416,7 @@ void intel_edp_panel_off(struct intel_dp
> > > *intel_dp);
> > >  void intel_dp_add_properties(struct intel_dp *intel_dp, struct
> > > drm_connector *connector);
> > >  void intel_dp_mst_suspend(struct drm_device *dev);
> > >  void intel_dp_mst_resume(struct drm_device *dev);
> > > +u8 intel_dp_max_lane_count(struct intel_dp *intel_dp);
> > >  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> > >  int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> > > *common_rates,
> > >  			     int link_rate);
> > > @@ -1448,6 +1449,8 @@ intel_dp_pre_emphasis_max(struct intel_dp
> > > *intel_dp, uint8_t voltage_swing);
> > >  void intel_dp_compute_rate(struct intel_dp *intel_dp, int
> > > port_clock,
> > >  			   uint8_t *link_bw, uint8_t
> > > *rate_select);
> > >  bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
> > > +int intel_dp_common_rates(struct intel_dp *intel_dp, int
> > > *common_rates);
> > > +bool intel_dp_upfront_link_train(struct intel_dp *intel_dp);
> > >  bool
> > >  intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t
> > > link_status[DP_LINK_STATUS_SIZE]);
> > >  
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v2 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST
  2016-09-07 10:53     ` Mika Kahola
  2016-09-07 16:40       ` Jim Bride
@ 2016-09-08 11:50       ` Mika Kahola
  1 sibling, 0 replies; 81+ messages in thread
From: Mika Kahola @ 2016-09-08 11:50 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

Reviewed-by: Mika Kahola <mika.kahola@intel.com>

On Wed, 2016-09-07 at 13:53 +0300, Mika Kahola wrote:
> On Tue, 2016-09-06 at 17:13 -0700, Manasi Navare wrote:
> > 
> > From: Jim Bride <jim.bride@linux.intel.com>
> > 
> > Add upfront link training to intel_dp_mst_mode_valid() so that we
> > know
> > topology constraints before we validate the legality of modes to be
> > checked.
> > Call the function that loops through the link rates and lane counts
> > starting from highest supported link rate and lane count for
> > training
> > the link in compliance with DP spec
> > 
> > v2:
> > * Rebased on new revision of link training patch (Manasi Navare)
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_dp.c     |  9 ++---
> >  drivers/gpu/drm/i915/intel_dp_mst.c | 74
> > +++++++++++++++++++++++++++----------
> >  drivers/gpu/drm/i915/intel_drv.h    |  3 ++
> >  3 files changed, 61 insertions(+), 25 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > b/drivers/gpu/drm/i915/intel_dp.c
> > index 7794180..0c7674f 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -131,7 +131,7 @@ static void vlv_steal_power_sequencer(struct
> > drm_device *dev,
> >  				      enum pipe pipe);
> >  static void intel_dp_unset_edid(struct intel_dp *intel_dp);
> >  
> > -static int
> > +int
> >  intel_dp_max_link_bw(struct intel_dp  *intel_dp)
> >  {
> >  	int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
> > @@ -150,7 +150,7 @@ intel_dp_max_link_bw(struct
> > intel_dp  *intel_dp)
> >  	return max_link_bw;
> >  }
> >  
> > -static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
> > +u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
> >  {
> >  	struct intel_digital_port *intel_dig_port =
> > dp_to_dig_port(intel_dp);
> >  	u8 temp, source_max, sink_max;
> > @@ -312,8 +312,7 @@ static int intersect_rates(const int
> > *source_rates, int source_len,
> >  	return k;
> >  }
> >  
> > -static int intel_dp_common_rates(struct intel_dp *intel_dp,
> > -				 int *common_rates)
> > +int intel_dp_common_rates(struct intel_dp *intel_dp, int
> > *common_rates)
> >  {
> >  	const int *source_rates, *sink_rates;
> >  	int source_len, sink_len;
> > @@ -336,7 +335,7 @@ static int intel_dp_common_rates(struct
> > intel_dp
> > *intel_dp,
> >  			       common_rates);
> >  }
> >  
> > -static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> > +bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> >  {
> >  	struct intel_digital_port *intel_dig_port =
> > dp_to_dig_port(intel_dp);
> >  	struct intel_encoder *intel_encoder = &intel_dig_port-
> > >base;
> > diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c
> > b/drivers/gpu/drm/i915/intel_dp_mst.c
> > index 54a9d76..98d45a4 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> > @@ -41,21 +41,30 @@ static bool intel_dp_mst_compute_config(struct
> > intel_encoder *encoder,
> >  	int bpp;
> >  	int lane_count, slots;
> >  	const struct drm_display_mode *adjusted_mode =
> > &pipe_config-
> > > 
> > > base.adjusted_mode;
> > -	int mst_pbn;
> > +	int mst_pbn, common_len;
> > +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> >  
> >  	pipe_config->dp_encoder_is_mst = true;
> >  	pipe_config->has_pch_encoder = false;
> > -	bpp = 24;
> > +
> >  	/*
> > -	 * for MST we always configure max link bw - the spec
> > doesn't
> > -	 * seem to suggest we should do otherwise.
> > +	 * For MST we always configure for the maximum trainable
> > link bw -
> > +	 * the spec doesn't seem to suggest we should do
> > otherwise.  The
> > +	 * calls to intel_dp_max_lane_count() and
> > intel_dp_common_rates()
> > +	 * both take successful upfront link training into
> > account,
> > and
> > +	 * return the DisplayPort max supported values in the
> > event
> > that
> > +	 * upfront link training was not done.
> >  	 */
> > -	lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
> > +	lane_count = intel_dp_max_lane_count(intel_dp);
> >  
> >  	pipe_config->lane_count = lane_count;
> >  
> > -	pipe_config->pipe_bpp = 24;
> > -	pipe_config->port_clock =
> > intel_dp_max_link_rate(intel_dp);
> > +	pipe_config->pipe_bpp = bpp = 24;
> > +	common_len = intel_dp_common_rates(intel_dp,
> > common_rates);
> > +	pipe_config->port_clock = common_rates[common_len - 1];
> > +
> > +	DRM_DEBUG_KMS("DP MST link configured for %d lanes @
> > %d.\n",
> > +		      pipe_config->lane_count, pipe_config-
> > > 
> > > port_clock);
> >  
> >  	state = pipe_config->base.state;
> >  
> > @@ -137,6 +146,8 @@ static void intel_mst_pre_enable_dp(struct
> > intel_encoder *encoder,
> >  	enum port port = intel_dig_port->port;
> >  	struct intel_connector *connector =
> >  		to_intel_connector(conn_state->connector);
> > +	struct intel_shared_dpll *pll = pipe_config->shared_dpll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> >  	int ret;
> >  	uint32_t temp;
> >  	int slots;
> > @@ -150,21 +161,23 @@ static void intel_mst_pre_enable_dp(struct
> > intel_encoder *encoder,
> >  	DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links);
> >  
> >  	if (intel_dp->active_mst_links == 0) {
> > -		intel_ddi_clk_select(&intel_dig_port->base,
> > -				     pipe_config->shared_dpll);
> > -
> > -		intel_prepare_dp_ddi_buffers(&intel_dig_port-
> > >base);
> > -		intel_dp_set_link_params(intel_dp,
> > -					 pipe_config->port_clock,
> > -					 pipe_config->lane_count,
> > -					 true);
> > -
> > -		intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
> >  
> > -		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> > +		/* Disable the PLL since we need to acquire the
> > PLL
> > +		 * based on the link rate in the link training
> > sequence
> > +		 */
> > +		tmp_pll_config = pll->config;
> > +		pll->funcs.disable(dev_priv, pll);
> > +		pll->config.crtc_mask = 0;
> > +
> > +		/* If Link Training fails, send a uevent to
> > generate
> > a
> > +		 *hotplug
> > +		 */
> > +		if (!(intel_ddi_link_train(intel_dp, pipe_config-
> > > 
> > > port_clock,
> > +					   pipe_config-
> > >lane_count,
> > true,
> > +					   false)))
> > +			drm_kms_helper_hotplug_event(encoder-
> > > 
> > > base.dev);
> > +		pll->config = tmp_pll_config;
> >  
> > -		intel_dp_start_link_train(intel_dp);
> > -		intel_dp_stop_link_train(intel_dp);
> >  	}
> >  
> >  	ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
> > @@ -336,6 +349,27 @@ intel_dp_mst_mode_valid(struct drm_connector
> > *connector,
> >  			struct drm_display_mode *mode)
> >  {
> >  	int max_dotclk = to_i915(connector->dev)->max_dotclk_freq;
> > +	struct intel_connector *intel_connector =
> > to_intel_connector(connector);
> > +	struct intel_dp *intel_dp = intel_connector->mst_port;
> > +
> > +	if (intel_dp->upfront_link_train && !intel_dp-
> > >upfront_done) 
> > {
> > +		bool do_upfront_link_train;
> > +
> > +		do_upfront_link_train = intel_dp-
> > > 
> > > compliance_test_type !=
> > +			DP_TEST_LINK_TRAINING;
> > +		if (do_upfront_link_train) {
> > +			intel_dp->upfront_done =
> > +				intel_dp_upfront_link_train(intel_
> > dp
> > );
> > +			if (intel_dp->upfront_done) {
> > +				DRM_DEBUG_KMS("MST upfront trained
> > at "
> > +					      "%d lanes @ %d.",
> > +					      intel_dp-
> > > 
> > > max_lanes_upfront,
> > +					      intel_dp-
> > > 
> > > max_link_rate_upfront);
> > +			} else
> > +				DRM_DEBUG_KMS("MST upfront link
> > training "
> > +					      "failed.");
> Link training has failed and we have a blank screen. Should we throw
> an
> error here? Maybe
> 
> 	return MODE_ERROR;
> 
> > 
> > +		}
> > +	}
> >  
> >  	/* TODO - validate mode against available PBN for link */
> >  	if (mode->clock < 10000)
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index a2bbf68..34af3e8 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1416,6 +1416,7 @@ void intel_edp_panel_off(struct intel_dp
> > *intel_dp);
> >  void intel_dp_add_properties(struct intel_dp *intel_dp, struct
> > drm_connector *connector);
> >  void intel_dp_mst_suspend(struct drm_device *dev);
> >  void intel_dp_mst_resume(struct drm_device *dev);
> > +u8 intel_dp_max_lane_count(struct intel_dp *intel_dp);
> >  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> >  int intel_dp_link_rate_index(struct intel_dp *intel_dp, int
> > *common_rates,
> >  			     int link_rate);
> > @@ -1448,6 +1449,8 @@ intel_dp_pre_emphasis_max(struct intel_dp
> > *intel_dp, uint8_t voltage_swing);
> >  void intel_dp_compute_rate(struct intel_dp *intel_dp, int
> > port_clock,
> >  			   uint8_t *link_bw, uint8_t
> > *rate_select);
> >  bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
> > +int intel_dp_common_rates(struct intel_dp *intel_dp, int
> > *common_rates);
> > +bool intel_dp_upfront_link_train(struct intel_dp *intel_dp);
> >  bool
> >  intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t
> > link_status[DP_LINK_STATUS_SIZE]);
> >  
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH v13 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-07 18:28     ` [PATCH v13 " Manasi Navare
@ 2016-09-08 12:10       ` Mika Kahola
  2016-09-08 15:06         ` Manasi Navare
  2016-09-08 17:22       ` [PATCH v14 " Manasi Navare
  1 sibling, 1 reply; 81+ messages in thread
From: Mika Kahola @ 2016-09-08 12:10 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

On Wed, 2016-09-07 at 11:28 -0700, Manasi Navare wrote:
> From: Durgadoss R <durgadoss.r@intel.com>
> 
> To support USB type C alternate DP mode, the display driver needs to
> know the number of lanes required by the DP panel as well as number
> of lanes that can be supported by the type-C cable. Sometimes, the
> type-C cable may limit the bandwidth even if Panel can support
> more lanes. To address these scenarios, the display driver will
> start link training with max lanes, and if that fails, the driver
> falls back to x2 lanes; and repeats this procedure for all
> bandwidth/lane configurations.
> 
> * Since link training is done before modeset only the port
>   (and not pipe/planes) and its associated PLLs are enabled.
> * On DP hotplug: Directly start link training on the DP encoder.
> * On Connected boot scenarios: When booted with an LFP and a DP,
>   sometimes BIOS brings up DP. In these cases, we disable the
>   crtc and then do upfront link training; and bring it back up.
> * All local changes made for upfront link training are reset
>   to their previous values once it is done; so that the
>   subsequent modeset is not aware of these changes.
> 
> Changes since v12:
> * Fix Rebase issues (Mika Kahola)
> Changes since v11:
> * Change the fallback link rate logic (Manasi)
> Changes since v10:
> * Use the ddi link train function that loops through all the link
> rates
> and lane counts starting from the highest supported (Manasi)
> * For upfront link training, set the upfront flag so that the link
> can
> be disabled after caching upfront values (Manasi)
> Changes since v9:
> * Change the macros to use dev_priv in place of dev (David Weinehall)
> Changes since v8:
> * Reset upfront lane count and link rate values on HPD
> for DP connector physical disconnect (Manasi)
> Changes since v7:
> * Move the upfront link training to intel_dp_mode_valid()
>   to avoid a race condition with DP MST sideband comms. (Ville)
> Changes since v6:
> * Fix some initialization bugs on link_rate (Jim Bride)
> * Use link_rate (and not link_bw) for upfront (Ville)
> * Make intel_dp_upfront*() as a vfunc (Ander)
> * The train_set_valid variable in intel_dp was removed due to
>   issues in fast link training. So, to indicate the link train
>   status, move the channel_eq inside intel_dp.
> Changes since v5:
> * Moved retry logic in upfront to intel_dp.c so that it
>   can be used for all platforms.
> Changes since v4:
> * Removed usage of crtc_state in upfront link training;
>   Hence no need to find free crtc to do upfront now.
> * Re-enable crtc if it was disabled for upfront.
> * Use separate variables to track max lane count
>   and link rate found by upfront, without modifying
>   the original DPCD read from panel.
> Changes since v3:
> * Fixed a return value on BXT check
> * Reworked on top of bxt_ddi_pll_select split from Ander
> * Renamed from ddi_upfront to bxt_upfront since the
>   upfront logic includes BXT specific functions for now.
> Changes since v2:
> * Rebased on top of latest dpll_mgr.c code and
>   latest HPD related clean ups.
> * Corrected return values from upfront (Ander)
> * Corrected atomic locking for upfront in intel_dp.c (Ville)
> Changes since v1:
> *  all pll related functions inside ddi.c
> 
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              |  21 +-
>  drivers/gpu/drm/i915/intel_dp.c               | 376
> +++++++++++++++++++-------
>  drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
>  drivers/gpu/drm/i915/intel_drv.h              |  14 +-
>  4 files changed, 310 insertions(+), 102 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index da2b804..b32f7ba 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct
> intel_encoder *encoder,
>  	pll->config.crtc_mask = 0;
>  
>  	/* If Link Training fails, send a uevent to generate a
> hotplug */
> -	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> link_mst)))
> +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> link_mst,
> +				   false)))
>  		drm_kms_helper_hotplug_event(encoder->base.dev);
>  	pll->config = tmp_pll_config;
>  }
> @@ -2460,7 +2461,7 @@ intel_ddi_get_link_dpll(struct intel_dp
> *intel_dp, int clock)
>  
>  bool
>  intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> -		     uint8_t max_lane_count, bool link_mst)
> +		     uint8_t max_lane_count, bool link_mst, bool
> is_upfront)
>  {
>  	struct intel_connector *connector = intel_dp-
> >attached_connector;
>  	struct intel_encoder *encoder = connector->encoder;
> @@ -2506,6 +2507,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp,
> int max_link_rate,
>  			pll->funcs.disable(dev_priv, pll);
>  			pll->config = tmp_pll_config;
>  		}
> +
>  		if (ret) {
>  			DRM_DEBUG_KMS("Link Training successful at
> link rate: "
>  				      "%d lane:%d\n", link_rate,
> lane_count);
> @@ -2514,6 +2516,21 @@ intel_ddi_link_train(struct intel_dp
> *intel_dp, int max_link_rate,
>  	}
>  	intel_dp_stop_link_train(intel_dp);
>  
> +	if (is_upfront) {
> +		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d
> lanes:%d\n",
> +			      ret ? "Passed" : "Failed",
> +			      link_rate, lane_count);
> +		/* Disable port followed by PLL for next retry/clean
> up */
> +		intel_ddi_post_disable(encoder, NULL, NULL);
> +		pll->funcs.disable(dev_priv, pll);
> +		pll->config = tmp_pll_config;
> +		if (ret) {
> +			/* Save the upfront values */
> +			intel_dp->max_lanes_upfront = lane_count;
> +			intel_dp->max_link_rate_upfront = link_rate;
> +		}
> +	}
> +
>  	if (!lane_count)
>  		DRM_ERROR("Link Training Failed\n");
>  
> diff --git a/drivers/gpu/drm/i915/intel_dp.c
> b/drivers/gpu/drm/i915/intel_dp.c
> index 714fbe3..7794180 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct
> intel_dp  *intel_dp)
>  static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
>  {
>  	struct intel_digital_port *intel_dig_port =
> dp_to_dig_port(intel_dp);
> -	u8 source_max, sink_max;
> +	u8 temp, source_max, sink_max;
>  
>  	source_max = intel_dig_port->max_lanes;
>  	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
>  
> -	return min(source_max, sink_max);
> +	temp = min(source_max, sink_max);
> +
> +	/*
> +	 * Limit max lanes w.r.t to the max value found
> +	 * using Upfront link training also.
> +	 */
> +	if (intel_dp->max_lanes_upfront)
> +		return min(temp, intel_dp->max_lanes_upfront);
> +	else
> +		return temp;
>  }
>  
>  /*
> @@ -190,6 +199,229 @@ intel_dp_max_data_rate(int max_link_clock, int
> max_lanes)
>  	return (max_link_clock * max_lanes * 8) / 10;
>  }
>  
> +static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
> +				struct drm_modeset_acquire_ctx *ctx,
> +				bool enable)
Indentation seems a bit off.

> +{
> +	int ret;
> +	struct drm_atomic_state *state;
> +	struct intel_crtc_state *crtc_state;
> +	struct drm_device *dev = crtc->base.dev;
> +	enum pipe pipe = crtc->pipe;
> +
> +	state = drm_atomic_state_alloc(dev);
> +	if (!state)
> +		return -ENOMEM;
> +
> +	state->acquire_ctx = ctx;
> +
> +	crtc_state = intel_atomic_get_crtc_state(state, crtc);
> +	if (IS_ERR(crtc_state)) {
> +		ret = PTR_ERR(crtc_state);
> +		drm_atomic_state_free(state);
> +		return ret;
> +	}
> +
> +	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
> +			enable ? "En" : "Dis",
> +			pipe_name(pipe),
> +			enable ? "after" : "before");
> +
> +	crtc_state->base.active = enable;
> +	ret = drm_atomic_commit(state);
> +	if (ret)
> +		drm_atomic_state_free(state);
> +
> +	return ret;
> +}
> +
> +static int
> +intel_dp_sink_rates(struct intel_dp *intel_dp, const int
> **sink_rates)
> +{
> +	if (intel_dp->num_sink_rates) {
> +		*sink_rates = intel_dp->sink_rates;
> +		return intel_dp->num_sink_rates;
> +	}
> +
> +	*sink_rates = default_rates;
> +
> +	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
> +}
> +
> +bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
> +{
> +	struct intel_digital_port *dig_port =
> dp_to_dig_port(intel_dp);
> +	struct drm_i915_private *dev_priv = to_i915(dig_port-
> >base.base.dev);
> +
> +	/* WaDisableHBR2:skl */
> +	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
> +		return false;
> +
> +	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
> +	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
> +		return true;
> +	else
> +		return false;
> +}
> +
> +static int
> +intel_dp_source_rates(struct intel_dp *intel_dp, const int
> **source_rates)
> +{
> +	struct intel_digital_port *dig_port =
> dp_to_dig_port(intel_dp);
> +	struct drm_i915_private *dev_priv = to_i915(dig_port-
> >base.base.dev);
> +	int size;
> +
> +	if (IS_BROXTON(dev_priv)) {
> +		*source_rates = bxt_rates;
> +		size = ARRAY_SIZE(bxt_rates);
> +	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
> +		*source_rates = skl_rates;
> +		size = ARRAY_SIZE(skl_rates);
> +	} else {
> +		*source_rates = default_rates;
> +		size = ARRAY_SIZE(default_rates);
> +	}
> +
> +	/* This depends on the fact that 5.4 is last value in the
> array */
> +	if (!intel_dp_source_supports_hbr2(intel_dp))
> +		size--;
> +
> +	return size;
> +}
> +
> +static int intersect_rates(const int *source_rates, int source_len,
> +			   const int *sink_rates, int sink_len,
> +			   int *common_rates)
> +{
> +	int i = 0, j = 0, k = 0;
> +
> +	while (i < source_len && j < sink_len) {
> +		if (source_rates[i] == sink_rates[j]) {
> +			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
> +				return k;
> +			common_rates[k] = source_rates[i];
> +			++k;
> +			++i;
> +			++j;
> +		} else if (source_rates[i] < sink_rates[j]) {
> +			++i;
> +		} else {
> +			++j;
> +		}
> +	}
> +	return k;
> +}
> +
> +static int intel_dp_common_rates(struct intel_dp *intel_dp,
> +				 int *common_rates)
> +{
> +	const int *source_rates, *sink_rates;
> +	int source_len, sink_len;
> +
> +	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> +
> +	/* Cap sink rates w.r.t upfront values */
> +	if (intel_dp->max_link_rate_upfront) {
> +		int len = sink_len - 1;
> +		while (len > 0 && sink_rates[len] >
> +		       intel_dp->max_link_rate_upfront)
> +			len--;
> +		sink_len = len + 1;
> +	}
> +
> +	source_len = intel_dp_source_rates(intel_dp, &source_rates);
> +
> +	return intersect_rates(source_rates, source_len,
> +			       sink_rates, sink_len,
> +			       common_rates);
> +}
> +
> +static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> +{
> +	struct intel_digital_port *intel_dig_port =
> dp_to_dig_port(intel_dp);
> +	struct intel_encoder *intel_encoder = &intel_dig_port->base;
> +	struct drm_device *dev = intel_encoder->base.dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_mode_config *config = &dev->mode_config;
> +	struct drm_modeset_acquire_ctx ctx;
> +	struct intel_crtc *intel_crtc;
> +	struct drm_crtc *crtc = NULL;
> +	struct intel_shared_dpll *pll;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	bool disable_dpll = false;
> +	int ret;
> +	bool done = false, has_mst = false;
> +	uint8_t max_lanes;
> +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> +	int common_len;
> +	enum intel_display_power_domain power_domain;
> +
> +	power_domain =
> intel_display_port_power_domain(intel_encoder);
> +	intel_display_power_get(dev_priv, power_domain);
> +
> +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> +	max_lanes = intel_dp_max_lane_count(intel_dp);
> +	if (WARN_ON(common_len <= 0))
> +		return true;
> +
> +	drm_modeset_acquire_init(&ctx, 0);
> +retry:
> +	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
> +	if (ret)
> +		goto exit_fail;
> +
> +	if (intel_encoder->base.crtc) {
> +		crtc = intel_encoder->base.crtc;
> +
> +		ret = drm_modeset_lock(&crtc->mutex, &ctx);
> +		if (ret)
> +			goto exit_fail;
> +
> +		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
> +		if (ret)
> +			goto exit_fail;
> +
> +		intel_crtc = to_intel_crtc(crtc);
> +		pll = intel_crtc->config->shared_dpll;
> +		disable_dpll = true;
> +		has_mst = intel_crtc_has_type(intel_crtc->config,
> +					      INTEL_OUTPUT_DP_MST);
> +		ret = intel_dp_upfront_crtc_disable(intel_crtc,
> &ctx, false);
> +		if (ret)
> +			goto exit_fail;
> +	}
> +
> +	mutex_lock(&dev_priv->dpll_lock);
> +	if (disable_dpll) {
> +		/* Clear the PLL config state */
> +		tmp_pll_config = pll->config;
> +		pll->config.crtc_mask = 0;
> +	}
> +
> +	done = intel_dp->upfront_link_train(intel_dp,
> +					    common_rates[common_len-
> 1],
> +					    max_lanes,
> +					    has_mst,
> +					    true);
> +	if (disable_dpll)
> +		pll->config = tmp_pll_config;
> +
> +	mutex_unlock(&dev_priv->dpll_lock);
> +
> +	if (crtc)
> +		ret = intel_dp_upfront_crtc_disable(intel_crtc,
> &ctx, true);
> +
> +exit_fail:
> +	if (ret == -EDEADLK) {
> +		drm_modeset_backoff(&ctx);
> +		goto retry;
> +	}
> +	drm_modeset_drop_locks(&ctx);
> +	drm_modeset_acquire_fini(&ctx);
> +	intel_display_power_put(dev_priv, power_domain);
> +	return done;
> +}
> +
>  static enum drm_mode_status
>  intel_dp_mode_valid(struct drm_connector *connector,
>  		    struct drm_display_mode *mode)
> @@ -211,6 +443,19 @@ intel_dp_mode_valid(struct drm_connector
> *connector,
>  		target_clock = fixed_mode->clock;
>  	}
>  
> +	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) 
> {
> +		bool do_upfront_link_train;
> +		/* Do not do upfront link train, if it is a
> compliance
> +		 * request
> +		 */
> +		do_upfront_link_train = !intel_dp->upfront_done &&
> +			(intel_dp->compliance_test_type !=
> +			 DP_TEST_LINK_TRAINING);
> +
> +		if (do_upfront_link_train)
> +			intel_dp->upfront_done =
> intel_dp_upfront_link_train(intel_dp);
> +	}
> +
>  	max_link_clock = intel_dp_max_link_rate(intel_dp);
>  	max_lanes = intel_dp_max_lane_count(intel_dp);
>  
> @@ -1256,60 +1501,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp,
> struct intel_connector *connector)
>  	intel_dp->aux.transfer = intel_dp_aux_transfer;
>  }
>  
> -static int
> -intel_dp_sink_rates(struct intel_dp *intel_dp, const int
> **sink_rates)
> -{
> -	if (intel_dp->num_sink_rates) {
> -		*sink_rates = intel_dp->sink_rates;
> -		return intel_dp->num_sink_rates;
> -	}
> -
> -	*sink_rates = default_rates;
> -
> -	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
> -}
> -
> -bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
> -{
> -	struct intel_digital_port *dig_port =
> dp_to_dig_port(intel_dp);
> -	struct drm_device *dev = dig_port->base.base.dev;
> -
> -	/* WaDisableHBR2:skl */
> -	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
> -		return false;
> -
> -	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) ||
> IS_BROADWELL(dev) ||
> -	    (INTEL_INFO(dev)->gen >= 9))
> -		return true;
> -	else
> -		return false;
> -}
> -
> -static int
> -intel_dp_source_rates(struct intel_dp *intel_dp, const int
> **source_rates)
> -{
> -	struct intel_digital_port *dig_port =
> dp_to_dig_port(intel_dp);
> -	struct drm_device *dev = dig_port->base.base.dev;
> -	int size;
> -
> -	if (IS_BROXTON(dev)) {
> -		*source_rates = bxt_rates;
> -		size = ARRAY_SIZE(bxt_rates);
> -	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
> -		*source_rates = skl_rates;
> -		size = ARRAY_SIZE(skl_rates);
> -	} else {
> -		*source_rates = default_rates;
> -		size = ARRAY_SIZE(default_rates);
> -	}
> -
> -	/* This depends on the fact that 5.4 is last value in the
> array */
> -	if (!intel_dp_source_supports_hbr2(intel_dp))
> -		size--;
> -
> -	return size;
> -}
> -
>  static void
>  intel_dp_set_clock(struct intel_encoder *encoder,
>  		   struct intel_crtc_state *pipe_config)
> @@ -1343,42 +1534,6 @@ intel_dp_set_clock(struct intel_encoder
> *encoder,
>  	}
>  }
>  
> -static int intersect_rates(const int *source_rates, int source_len,
> -			   const int *sink_rates, int sink_len,
> -			   int *common_rates)
> -{
> -	int i = 0, j = 0, k = 0;
> -
> -	while (i < source_len && j < sink_len) {
> -		if (source_rates[i] == sink_rates[j]) {
> -			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
> -				return k;
> -			common_rates[k] = source_rates[i];
> -			++k;
> -			++i;
> -			++j;
> -		} else if (source_rates[i] < sink_rates[j]) {
> -			++i;
> -		} else {
> -			++j;
> -		}
> -	}
> -	return k;
> -}
> -
> -static int intel_dp_common_rates(struct intel_dp *intel_dp,
> -				 int *common_rates)
> -{
> -	const int *source_rates, *sink_rates;
> -	int source_len, sink_len;
> -
> -	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> -	source_len = intel_dp_source_rates(intel_dp, &source_rates);
> -
> -	return intersect_rates(source_rates, source_len,
> -			       sink_rates, sink_len,
> -			       common_rates);
> -}
>  
>  static void snprintf_int_array(char *str, size_t len,
>  			       const int *array, int nelem)
> @@ -1436,6 +1591,9 @@ intel_dp_max_link_rate(struct intel_dp
> *intel_dp)
>  	int rates[DP_MAX_SUPPORTED_RATES] = {};
>  	int len;
>  
> +	if (intel_dp->max_link_rate_upfront)
> +		return intel_dp->max_link_rate_upfront;
> +
>  	len = intel_dp_common_rates(intel_dp, rates);
>  	if (WARN_ON(len <= 0))
>  		return 162000;
> @@ -1488,7 +1646,7 @@ intel_dp_compute_config(struct intel_encoder
> *encoder,
>  	enum port port = dp_to_dig_port(intel_dp)->port;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config-
> >base.crtc);
>  	struct intel_connector *intel_connector = intel_dp-
> >attached_connector;
> -	int lane_count, clock;
> +	int lane_count, clock = 0;
>  	int min_lane_count = 1;
>  	int max_lane_count = intel_dp_max_lane_count(intel_dp);
>  	/* Conveniently, the link BW constants become indices with a
> shift...*/
> @@ -1567,11 +1725,24 @@ intel_dp_compute_config(struct intel_encoder
> *encoder,
>  	for (; bpp >= 6*3; bpp -= 2*3) {
>  		mode_rate = intel_dp_link_required(adjusted_mode-
> >crtc_clock,
>  						   bpp);
> +		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
> +			clock = max_clock;
> +			lane_count = intel_dp->max_lanes_upfront;
> +			link_clock = intel_dp-
> >max_link_rate_upfront;
> +			link_avail =
> intel_dp_max_data_rate(link_clock,
> +							    lane_cou
> nt);
> +			mode_rate =
> intel_dp_link_required(adjusted_mode->crtc_clock,
> +							   bpp);
> +			if (mode_rate <= link_avail)
> +				goto found;
> +			else
> +				continue;
> +		}
> +
>  		for (clock = max_clock; clock >= max_clock; clock--)
> {
>  			for (lane_count = max_lane_count;
>  			     lane_count >= min_lane_count;
>  			     lane_count >>= 1) {
> -
>  				link_clock = common_rates[clock];
>  				link_avail =
> intel_dp_max_data_rate(link_clock,
>  								    
> lane_count);
> @@ -1600,7 +1771,6 @@ found:
>  	}
>  
>  	pipe_config->lane_count = lane_count;
> -
>  	pipe_config->pipe_bpp = bpp;
>  	pipe_config->port_clock = common_rates[clock];
>  
> @@ -4284,7 +4454,7 @@ intel_dp_long_pulse(struct intel_connector
> *intel_connector)
>  	struct drm_device *dev = connector->dev;
>  	enum drm_connector_status status;
>  	enum intel_display_power_domain power_domain;
> -	u8 sink_irq_vector = 0;
> +	u8 sink_irq_vector;
>  
>  	power_domain =
> intel_display_port_aux_power_domain(intel_encoder);
>  	intel_display_power_get(to_i915(dev), power_domain);
> @@ -4377,9 +4547,12 @@ intel_dp_long_pulse(struct intel_connector
> *intel_connector)
>  	}
>  
>  out:
> -	if ((status != connector_status_connected) &&
> -	    (intel_dp->is_mst == false))
> +	if (status != connector_status_connected) {
>  		intel_dp_unset_edid(intel_dp);
> +		intel_dp->upfront_done = false;
> +		intel_dp->max_lanes_upfront = 0;
> +		intel_dp->max_link_rate_upfront = 0;
> +	}
>  
>  	intel_display_power_put(to_i915(dev), power_domain);
>  	return;
> @@ -5623,6 +5796,13 @@ intel_dp_init_connector(struct
> intel_digital_port *intel_dig_port,
>  	if (type == DRM_MODE_CONNECTOR_eDP)
>  		intel_encoder->type = INTEL_OUTPUT_EDP;
>  
> +	/* Initialize upfront link training vfunc for DP */
> +	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
> +		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
> +		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> +			intel_dp->upfront_link_train =
> intel_ddi_link_train;
> +	}
> +
>  	/* eDP only on port B and/or C on vlv/chv */
>  	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
>  		    is_edp(intel_dp) && port != PORT_B && port !=
> PORT_C))
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index f1e08f0..b6f380b 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -304,7 +304,6 @@
> intel_dp_link_training_channel_equalization(struct intel_dp
> *intel_dp)
>  	intel_dp_set_idle_link_train(intel_dp);
>  
>  	return intel_dp->channel_eq_status;
> -
>  }
>  
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index c571baf..a2bbf68 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -882,6 +882,12 @@ struct intel_dp {
>  	enum hdmi_force_audio force_audio;
>  	bool limited_color_range;
>  	bool color_range_auto;
> +
> +	/* Upfront link train parameters */
> +	int max_link_rate_upfront;
> +	uint8_t max_lanes_upfront;
> +	bool upfront_done;
> +
>  	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
>  	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
>  	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
> @@ -939,6 +945,11 @@ struct intel_dp {
>  	/* This is called before a link training is starterd */
>  	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
>  
> +	/* For Upfront link training */
> +	bool (*upfront_link_train)(struct intel_dp *intel_dp, int
> clock,
> +				   uint8_t lane_count, bool
> link_mst,
> +				   bool is_upfront);
> +
>  	/* Displayport compliance testing */
>  	unsigned long compliance_test_type;
>  	unsigned long compliance_test_data;
> @@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder
> *encoder,
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool
> state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
>  bool intel_ddi_link_train(struct intel_dp *intel_dp, int
> max_link_rate,
> -			  uint8_t max_lane_count, bool link_mst);
> +			  uint8_t max_lane_count, bool link_mst,
> +			  bool is_upfront);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp
> *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
-- 
Mika Kahola - Intel OTC

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

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

* Re: [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config
  2016-09-02 13:08   ` Mika Kahola
@ 2016-09-08 14:47     ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-08 14:47 UTC (permalink / raw)
  To: Mika Kahola; +Cc: intel-gfx

On Fri, Sep 02, 2016 at 04:08:27PM +0300, Mika Kahola wrote:
> On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
> > While configuring the pipe during modeset, it should loop
> > starting from max clock and max lane count reducing the
> > lane count and clock in each iteration until the requested mode
> > rate is less than or equal to available link BW.
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_dp.c | 9 ++++-----
> >  1 file changed, 4 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > b/drivers/gpu/drm/i915/intel_dp.c
> > index dfdbe65..e094b25 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -1552,11 +1552,10 @@ intel_dp_compute_config(struct intel_encoder
> > *encoder,
> >  	for (; bpp >= 6*3; bpp -= 2*3) {
> >  		mode_rate = intel_dp_link_required(adjusted_mode-
> > >crtc_clock,
> >  						   bpp);
> > -
> > -		for (clock = min_clock; clock <= max_clock; clock++)
> > {
> > -			for (lane_count = min_lane_count;
> > -				lane_count <= max_lane_count;
> > -				lane_count <<= 1) {
> > +		for (clock = max_clock; clock >= max_clock; clock--)
> The clock should be higher than or equal to min_clock.

Thanks for the review. Yes that is a mistake. I will fix this in the loop.


> > {
> > +			for (lane_count = max_lane_count;
> > +			     lane_count >= min_lane_count;
> > +			     lane_count >>= 1) {
> >  
> >  				link_clock = common_rates[clock];
> >  				link_avail =
> > intel_dp_max_data_rate(link_clock,
> -- 
> Mika Kahola - Intel OTC
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v13 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-08 12:10       ` Mika Kahola
@ 2016-09-08 15:06         ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-08 15:06 UTC (permalink / raw)
  To: Mika Kahola; +Cc: intel-gfx

On Thu, Sep 08, 2016 at 03:10:43PM +0300, Mika Kahola wrote:
> On Wed, 2016-09-07 at 11:28 -0700, Manasi Navare wrote:
> > From: Durgadoss R <durgadoss.r@intel.com>
> > 
> > To support USB type C alternate DP mode, the display driver needs to
> > know the number of lanes required by the DP panel as well as number
> > of lanes that can be supported by the type-C cable. Sometimes, the
> > type-C cable may limit the bandwidth even if Panel can support
> > more lanes. To address these scenarios, the display driver will
> > start link training with max lanes, and if that fails, the driver
> > falls back to x2 lanes; and repeats this procedure for all
> > bandwidth/lane configurations.
> > 
> > * Since link training is done before modeset only the port
> >   (and not pipe/planes) and its associated PLLs are enabled.
> > * On DP hotplug: Directly start link training on the DP encoder.
> > * On Connected boot scenarios: When booted with an LFP and a DP,
> >   sometimes BIOS brings up DP. In these cases, we disable the
> >   crtc and then do upfront link training; and bring it back up.
> > * All local changes made for upfront link training are reset
> >   to their previous values once it is done; so that the
> >   subsequent modeset is not aware of these changes.
> > 
> > Changes since v12:
> > * Fix Rebase issues (Mika Kahola)
> > Changes since v11:
> > * Change the fallback link rate logic (Manasi)
> > Changes since v10:
> > * Use the ddi link train function that loops through all the link
> > rates
> > and lane counts starting from the highest supported (Manasi)
> > * For upfront link training, set the upfront flag so that the link
> > can
> > be disabled after caching upfront values (Manasi)
> > Changes since v9:
> > * Change the macros to use dev_priv in place of dev (David Weinehall)
> > Changes since v8:
> > * Reset upfront lane count and link rate values on HPD
> > for DP connector physical disconnect (Manasi)
> > Changes since v7:
> > * Move the upfront link training to intel_dp_mode_valid()
> >   to avoid a race condition with DP MST sideband comms. (Ville)
> > Changes since v6:
> > * Fix some initialization bugs on link_rate (Jim Bride)
> > * Use link_rate (and not link_bw) for upfront (Ville)
> > * Make intel_dp_upfront*() as a vfunc (Ander)
> > * The train_set_valid variable in intel_dp was removed due to
> >   issues in fast link training. So, to indicate the link train
> >   status, move the channel_eq inside intel_dp.
> > Changes since v5:
> > * Moved retry logic in upfront to intel_dp.c so that it
> >   can be used for all platforms.
> > Changes since v4:
> > * Removed usage of crtc_state in upfront link training;
> >   Hence no need to find free crtc to do upfront now.
> > * Re-enable crtc if it was disabled for upfront.
> > * Use separate variables to track max lane count
> >   and link rate found by upfront, without modifying
> >   the original DPCD read from panel.
> > Changes since v3:
> > * Fixed a return value on BXT check
> > * Reworked on top of bxt_ddi_pll_select split from Ander
> > * Renamed from ddi_upfront to bxt_upfront since the
> >   upfront logic includes BXT specific functions for now.
> > Changes since v2:
> > * Rebased on top of latest dpll_mgr.c code and
> >   latest HPD related clean ups.
> > * Corrected return values from upfront (Ander)
> > * Corrected atomic locking for upfront in intel_dp.c (Ville)
> > Changes since v1:
> > *  all pll related functions inside ddi.c
> > 
> > Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> > Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c              |  21 +-
> >  drivers/gpu/drm/i915/intel_dp.c               | 376
> > +++++++++++++++++++-------
> >  drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
> >  drivers/gpu/drm/i915/intel_drv.h              |  14 +-
> >  4 files changed, 310 insertions(+), 102 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > b/drivers/gpu/drm/i915/intel_ddi.c
> > index da2b804..b32f7ba 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct
> > intel_encoder *encoder,
> >  	pll->config.crtc_mask = 0;
> >  
> >  	/* If Link Training fails, send a uevent to generate a
> > hotplug */
> > -	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> > link_mst)))
> > +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count,
> > link_mst,
> > +				   false)))
> >  		drm_kms_helper_hotplug_event(encoder->base.dev);
> >  	pll->config = tmp_pll_config;
> >  }
> > @@ -2460,7 +2461,7 @@ intel_ddi_get_link_dpll(struct intel_dp
> > *intel_dp, int clock)
> >  
> >  bool
> >  intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > -		     uint8_t max_lane_count, bool link_mst)
> > +		     uint8_t max_lane_count, bool link_mst, bool
> > is_upfront)
> >  {
> >  	struct intel_connector *connector = intel_dp-
> > >attached_connector;
> >  	struct intel_encoder *encoder = connector->encoder;
> > @@ -2506,6 +2507,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp,
> > int max_link_rate,
> >  			pll->funcs.disable(dev_priv, pll);
> >  			pll->config = tmp_pll_config;
> >  		}
> > +
> >  		if (ret) {
> >  			DRM_DEBUG_KMS("Link Training successful at
> > link rate: "
> >  				      "%d lane:%d\n", link_rate,
> > lane_count);
> > @@ -2514,6 +2516,21 @@ intel_ddi_link_train(struct intel_dp
> > *intel_dp, int max_link_rate,
> >  	}
> >  	intel_dp_stop_link_train(intel_dp);
> >  
> > +	if (is_upfront) {
> > +		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d
> > lanes:%d\n",
> > +			      ret ? "Passed" : "Failed",
> > +			      link_rate, lane_count);
> > +		/* Disable port followed by PLL for next retry/clean
> > up */
> > +		intel_ddi_post_disable(encoder, NULL, NULL);
> > +		pll->funcs.disable(dev_priv, pll);
> > +		pll->config = tmp_pll_config;
> > +		if (ret) {
> > +			/* Save the upfront values */
> > +			intel_dp->max_lanes_upfront = lane_count;
> > +			intel_dp->max_link_rate_upfront = link_rate;
> > +		}
> > +	}
> > +
> >  	if (!lane_count)
> >  		DRM_ERROR("Link Training Failed\n");
> >  
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > b/drivers/gpu/drm/i915/intel_dp.c
> > index 714fbe3..7794180 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct
> > intel_dp  *intel_dp)
> >  static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
> >  {
> >  	struct intel_digital_port *intel_dig_port =
> > dp_to_dig_port(intel_dp);
> > -	u8 source_max, sink_max;
> > +	u8 temp, source_max, sink_max;
> >  
> >  	source_max = intel_dig_port->max_lanes;
> >  	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
> >  
> > -	return min(source_max, sink_max);
> > +	temp = min(source_max, sink_max);
> > +
> > +	/*
> > +	 * Limit max lanes w.r.t to the max value found
> > +	 * using Upfront link training also.
> > +	 */
> > +	if (intel_dp->max_lanes_upfront)
> > +		return min(temp, intel_dp->max_lanes_upfront);
> > +	else
> > +		return temp;
> >  }
> >  
> >  /*
> > @@ -190,6 +199,229 @@ intel_dp_max_data_rate(int max_link_clock, int
> > max_lanes)
> >  	return (max_link_clock * max_lanes * 8) / 10;
> >  }
> >  
> > +static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
> > +				struct drm_modeset_acquire_ctx *ctx,
> > +				bool enable)
> Indentation seems a bit off.
>

Yep, will fix that and resubmit.

 
> > +{
> > +	int ret;
> > +	struct drm_atomic_state *state;
> > +	struct intel_crtc_state *crtc_state;
> > +	struct drm_device *dev = crtc->base.dev;
> > +	enum pipe pipe = crtc->pipe;
> > +
> > +	state = drm_atomic_state_alloc(dev);
> > +	if (!state)
> > +		return -ENOMEM;
> > +
> > +	state->acquire_ctx = ctx;
> > +
> > +	crtc_state = intel_atomic_get_crtc_state(state, crtc);
> > +	if (IS_ERR(crtc_state)) {
> > +		ret = PTR_ERR(crtc_state);
> > +		drm_atomic_state_free(state);
> > +		return ret;
> > +	}
> > +
> > +	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
> > +			enable ? "En" : "Dis",
> > +			pipe_name(pipe),
> > +			enable ? "after" : "before");
> > +
> > +	crtc_state->base.active = enable;
> > +	ret = drm_atomic_commit(state);
> > +	if (ret)
> > +		drm_atomic_state_free(state);
> > +
> > +	return ret;
> > +}
> > +
> > +static int
> > +intel_dp_sink_rates(struct intel_dp *intel_dp, const int
> > **sink_rates)
> > +{
> > +	if (intel_dp->num_sink_rates) {
> > +		*sink_rates = intel_dp->sink_rates;
> > +		return intel_dp->num_sink_rates;
> > +	}
> > +
> > +	*sink_rates = default_rates;
> > +
> > +	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
> > +}
> > +
> > +bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
> > +{
> > +	struct intel_digital_port *dig_port =
> > dp_to_dig_port(intel_dp);
> > +	struct drm_i915_private *dev_priv = to_i915(dig_port-
> > >base.base.dev);
> > +
> > +	/* WaDisableHBR2:skl */
> > +	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
> > +		return false;
> > +
> > +	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
> > +	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
> > +		return true;
> > +	else
> > +		return false;
> > +}
> > +
> > +static int
> > +intel_dp_source_rates(struct intel_dp *intel_dp, const int
> > **source_rates)
> > +{
> > +	struct intel_digital_port *dig_port =
> > dp_to_dig_port(intel_dp);
> > +	struct drm_i915_private *dev_priv = to_i915(dig_port-
> > >base.base.dev);
> > +	int size;
> > +
> > +	if (IS_BROXTON(dev_priv)) {
> > +		*source_rates = bxt_rates;
> > +		size = ARRAY_SIZE(bxt_rates);
> > +	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
> > +		*source_rates = skl_rates;
> > +		size = ARRAY_SIZE(skl_rates);
> > +	} else {
> > +		*source_rates = default_rates;
> > +		size = ARRAY_SIZE(default_rates);
> > +	}
> > +
> > +	/* This depends on the fact that 5.4 is last value in the
> > array */
> > +	if (!intel_dp_source_supports_hbr2(intel_dp))
> > +		size--;
> > +
> > +	return size;
> > +}
> > +
> > +static int intersect_rates(const int *source_rates, int source_len,
> > +			   const int *sink_rates, int sink_len,
> > +			   int *common_rates)
> > +{
> > +	int i = 0, j = 0, k = 0;
> > +
> > +	while (i < source_len && j < sink_len) {
> > +		if (source_rates[i] == sink_rates[j]) {
> > +			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
> > +				return k;
> > +			common_rates[k] = source_rates[i];
> > +			++k;
> > +			++i;
> > +			++j;
> > +		} else if (source_rates[i] < sink_rates[j]) {
> > +			++i;
> > +		} else {
> > +			++j;
> > +		}
> > +	}
> > +	return k;
> > +}
> > +
> > +static int intel_dp_common_rates(struct intel_dp *intel_dp,
> > +				 int *common_rates)
> > +{
> > +	const int *source_rates, *sink_rates;
> > +	int source_len, sink_len;
> > +
> > +	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> > +
> > +	/* Cap sink rates w.r.t upfront values */
> > +	if (intel_dp->max_link_rate_upfront) {
> > +		int len = sink_len - 1;
> > +		while (len > 0 && sink_rates[len] >
> > +		       intel_dp->max_link_rate_upfront)
> > +			len--;
> > +		sink_len = len + 1;
> > +	}
> > +
> > +	source_len = intel_dp_source_rates(intel_dp, &source_rates);
> > +
> > +	return intersect_rates(source_rates, source_len,
> > +			       sink_rates, sink_len,
> > +			       common_rates);
> > +}
> > +
> > +static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> > +{
> > +	struct intel_digital_port *intel_dig_port =
> > dp_to_dig_port(intel_dp);
> > +	struct intel_encoder *intel_encoder = &intel_dig_port->base;
> > +	struct drm_device *dev = intel_encoder->base.dev;
> > +	struct drm_i915_private *dev_priv = to_i915(dev);
> > +	struct drm_mode_config *config = &dev->mode_config;
> > +	struct drm_modeset_acquire_ctx ctx;
> > +	struct intel_crtc *intel_crtc;
> > +	struct drm_crtc *crtc = NULL;
> > +	struct intel_shared_dpll *pll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +	bool disable_dpll = false;
> > +	int ret;
> > +	bool done = false, has_mst = false;
> > +	uint8_t max_lanes;
> > +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> > +	int common_len;
> > +	enum intel_display_power_domain power_domain;
> > +
> > +	power_domain =
> > intel_display_port_power_domain(intel_encoder);
> > +	intel_display_power_get(dev_priv, power_domain);
> > +
> > +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> > +	max_lanes = intel_dp_max_lane_count(intel_dp);
> > +	if (WARN_ON(common_len <= 0))
> > +		return true;
> > +
> > +	drm_modeset_acquire_init(&ctx, 0);
> > +retry:
> > +	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
> > +	if (ret)
> > +		goto exit_fail;
> > +
> > +	if (intel_encoder->base.crtc) {
> > +		crtc = intel_encoder->base.crtc;
> > +
> > +		ret = drm_modeset_lock(&crtc->mutex, &ctx);
> > +		if (ret)
> > +			goto exit_fail;
> > +
> > +		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
> > +		if (ret)
> > +			goto exit_fail;
> > +
> > +		intel_crtc = to_intel_crtc(crtc);
> > +		pll = intel_crtc->config->shared_dpll;
> > +		disable_dpll = true;
> > +		has_mst = intel_crtc_has_type(intel_crtc->config,
> > +					      INTEL_OUTPUT_DP_MST);
> > +		ret = intel_dp_upfront_crtc_disable(intel_crtc,
> > &ctx, false);
> > +		if (ret)
> > +			goto exit_fail;
> > +	}
> > +
> > +	mutex_lock(&dev_priv->dpll_lock);
> > +	if (disable_dpll) {
> > +		/* Clear the PLL config state */
> > +		tmp_pll_config = pll->config;
> > +		pll->config.crtc_mask = 0;
> > +	}
> > +
> > +	done = intel_dp->upfront_link_train(intel_dp,
> > +					    common_rates[common_len-
> > 1],
> > +					    max_lanes,
> > +					    has_mst,
> > +					    true);
> > +	if (disable_dpll)
> > +		pll->config = tmp_pll_config;
> > +
> > +	mutex_unlock(&dev_priv->dpll_lock);
> > +
> > +	if (crtc)
> > +		ret = intel_dp_upfront_crtc_disable(intel_crtc,
> > &ctx, true);
> > +
> > +exit_fail:
> > +	if (ret == -EDEADLK) {
> > +		drm_modeset_backoff(&ctx);
> > +		goto retry;
> > +	}
> > +	drm_modeset_drop_locks(&ctx);
> > +	drm_modeset_acquire_fini(&ctx);
> > +	intel_display_power_put(dev_priv, power_domain);
> > +	return done;
> > +}
> > +
> >  static enum drm_mode_status
> >  intel_dp_mode_valid(struct drm_connector *connector,
> >  		    struct drm_display_mode *mode)
> > @@ -211,6 +443,19 @@ intel_dp_mode_valid(struct drm_connector
> > *connector,
> >  		target_clock = fixed_mode->clock;
> >  	}
> >  
> > +	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) 
> > {
> > +		bool do_upfront_link_train;
> > +		/* Do not do upfront link train, if it is a
> > compliance
> > +		 * request
> > +		 */
> > +		do_upfront_link_train = !intel_dp->upfront_done &&
> > +			(intel_dp->compliance_test_type !=
> > +			 DP_TEST_LINK_TRAINING);
> > +
> > +		if (do_upfront_link_train)
> > +			intel_dp->upfront_done =
> > intel_dp_upfront_link_train(intel_dp);
> > +	}
> > +
> >  	max_link_clock = intel_dp_max_link_rate(intel_dp);
> >  	max_lanes = intel_dp_max_lane_count(intel_dp);
> >  
> > @@ -1256,60 +1501,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp,
> > struct intel_connector *connector)
> >  	intel_dp->aux.transfer = intel_dp_aux_transfer;
> >  }
> >  
> > -static int
> > -intel_dp_sink_rates(struct intel_dp *intel_dp, const int
> > **sink_rates)
> > -{
> > -	if (intel_dp->num_sink_rates) {
> > -		*sink_rates = intel_dp->sink_rates;
> > -		return intel_dp->num_sink_rates;
> > -	}
> > -
> > -	*sink_rates = default_rates;
> > -
> > -	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
> > -}
> > -
> > -bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
> > -{
> > -	struct intel_digital_port *dig_port =
> > dp_to_dig_port(intel_dp);
> > -	struct drm_device *dev = dig_port->base.base.dev;
> > -
> > -	/* WaDisableHBR2:skl */
> > -	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
> > -		return false;
> > -
> > -	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) ||
> > IS_BROADWELL(dev) ||
> > -	    (INTEL_INFO(dev)->gen >= 9))
> > -		return true;
> > -	else
> > -		return false;
> > -}
> > -
> > -static int
> > -intel_dp_source_rates(struct intel_dp *intel_dp, const int
> > **source_rates)
> > -{
> > -	struct intel_digital_port *dig_port =
> > dp_to_dig_port(intel_dp);
> > -	struct drm_device *dev = dig_port->base.base.dev;
> > -	int size;
> > -
> > -	if (IS_BROXTON(dev)) {
> > -		*source_rates = bxt_rates;
> > -		size = ARRAY_SIZE(bxt_rates);
> > -	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
> > -		*source_rates = skl_rates;
> > -		size = ARRAY_SIZE(skl_rates);
> > -	} else {
> > -		*source_rates = default_rates;
> > -		size = ARRAY_SIZE(default_rates);
> > -	}
> > -
> > -	/* This depends on the fact that 5.4 is last value in the
> > array */
> > -	if (!intel_dp_source_supports_hbr2(intel_dp))
> > -		size--;
> > -
> > -	return size;
> > -}
> > -
> >  static void
> >  intel_dp_set_clock(struct intel_encoder *encoder,
> >  		   struct intel_crtc_state *pipe_config)
> > @@ -1343,42 +1534,6 @@ intel_dp_set_clock(struct intel_encoder
> > *encoder,
> >  	}
> >  }
> >  
> > -static int intersect_rates(const int *source_rates, int source_len,
> > -			   const int *sink_rates, int sink_len,
> > -			   int *common_rates)
> > -{
> > -	int i = 0, j = 0, k = 0;
> > -
> > -	while (i < source_len && j < sink_len) {
> > -		if (source_rates[i] == sink_rates[j]) {
> > -			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
> > -				return k;
> > -			common_rates[k] = source_rates[i];
> > -			++k;
> > -			++i;
> > -			++j;
> > -		} else if (source_rates[i] < sink_rates[j]) {
> > -			++i;
> > -		} else {
> > -			++j;
> > -		}
> > -	}
> > -	return k;
> > -}
> > -
> > -static int intel_dp_common_rates(struct intel_dp *intel_dp,
> > -				 int *common_rates)
> > -{
> > -	const int *source_rates, *sink_rates;
> > -	int source_len, sink_len;
> > -
> > -	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> > -	source_len = intel_dp_source_rates(intel_dp, &source_rates);
> > -
> > -	return intersect_rates(source_rates, source_len,
> > -			       sink_rates, sink_len,
> > -			       common_rates);
> > -}
> >  
> >  static void snprintf_int_array(char *str, size_t len,
> >  			       const int *array, int nelem)
> > @@ -1436,6 +1591,9 @@ intel_dp_max_link_rate(struct intel_dp
> > *intel_dp)
> >  	int rates[DP_MAX_SUPPORTED_RATES] = {};
> >  	int len;
> >  
> > +	if (intel_dp->max_link_rate_upfront)
> > +		return intel_dp->max_link_rate_upfront;
> > +
> >  	len = intel_dp_common_rates(intel_dp, rates);
> >  	if (WARN_ON(len <= 0))
> >  		return 162000;
> > @@ -1488,7 +1646,7 @@ intel_dp_compute_config(struct intel_encoder
> > *encoder,
> >  	enum port port = dp_to_dig_port(intel_dp)->port;
> >  	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config-
> > >base.crtc);
> >  	struct intel_connector *intel_connector = intel_dp-
> > >attached_connector;
> > -	int lane_count, clock;
> > +	int lane_count, clock = 0;
> >  	int min_lane_count = 1;
> >  	int max_lane_count = intel_dp_max_lane_count(intel_dp);
> >  	/* Conveniently, the link BW constants become indices with a
> > shift...*/
> > @@ -1567,11 +1725,24 @@ intel_dp_compute_config(struct intel_encoder
> > *encoder,
> >  	for (; bpp >= 6*3; bpp -= 2*3) {
> >  		mode_rate = intel_dp_link_required(adjusted_mode-
> > >crtc_clock,
> >  						   bpp);
> > +		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
> > +			clock = max_clock;
> > +			lane_count = intel_dp->max_lanes_upfront;
> > +			link_clock = intel_dp-
> > >max_link_rate_upfront;
> > +			link_avail =
> > intel_dp_max_data_rate(link_clock,
> > +							    lane_cou
> > nt);
> > +			mode_rate =
> > intel_dp_link_required(adjusted_mode->crtc_clock,
> > +							   bpp);
> > +			if (mode_rate <= link_avail)
> > +				goto found;
> > +			else
> > +				continue;
> > +		}
> > +
> >  		for (clock = max_clock; clock >= max_clock; clock--)
> > {
> >  			for (lane_count = max_lane_count;
> >  			     lane_count >= min_lane_count;
> >  			     lane_count >>= 1) {
> > -
> >  				link_clock = common_rates[clock];
> >  				link_avail =
> > intel_dp_max_data_rate(link_clock,
> >  								    
> > lane_count);
> > @@ -1600,7 +1771,6 @@ found:
> >  	}
> >  
> >  	pipe_config->lane_count = lane_count;
> > -
> >  	pipe_config->pipe_bpp = bpp;
> >  	pipe_config->port_clock = common_rates[clock];
> >  
> > @@ -4284,7 +4454,7 @@ intel_dp_long_pulse(struct intel_connector
> > *intel_connector)
> >  	struct drm_device *dev = connector->dev;
> >  	enum drm_connector_status status;
> >  	enum intel_display_power_domain power_domain;
> > -	u8 sink_irq_vector = 0;
> > +	u8 sink_irq_vector;
> >  
> >  	power_domain =
> > intel_display_port_aux_power_domain(intel_encoder);
> >  	intel_display_power_get(to_i915(dev), power_domain);
> > @@ -4377,9 +4547,12 @@ intel_dp_long_pulse(struct intel_connector
> > *intel_connector)
> >  	}
> >  
> >  out:
> > -	if ((status != connector_status_connected) &&
> > -	    (intel_dp->is_mst == false))
> > +	if (status != connector_status_connected) {
> >  		intel_dp_unset_edid(intel_dp);
> > +		intel_dp->upfront_done = false;
> > +		intel_dp->max_lanes_upfront = 0;
> > +		intel_dp->max_link_rate_upfront = 0;
> > +	}
> >  
> >  	intel_display_power_put(to_i915(dev), power_domain);
> >  	return;
> > @@ -5623,6 +5796,13 @@ intel_dp_init_connector(struct
> > intel_digital_port *intel_dig_port,
> >  	if (type == DRM_MODE_CONNECTOR_eDP)
> >  		intel_encoder->type = INTEL_OUTPUT_EDP;
> >  
> > +	/* Initialize upfront link training vfunc for DP */
> > +	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
> > +		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
> > +		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> > +			intel_dp->upfront_link_train =
> > intel_ddi_link_train;
> > +	}
> > +
> >  	/* eDP only on port B and/or C on vlv/chv */
> >  	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
> >  		    is_edp(intel_dp) && port != PORT_B && port !=
> > PORT_C))
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index f1e08f0..b6f380b 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -304,7 +304,6 @@
> > intel_dp_link_training_channel_equalization(struct intel_dp
> > *intel_dp)
> >  	intel_dp_set_idle_link_train(intel_dp);
> >  
> >  	return intel_dp->channel_eq_status;
> > -
> >  }
> >  
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index c571baf..a2bbf68 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -882,6 +882,12 @@ struct intel_dp {
> >  	enum hdmi_force_audio force_audio;
> >  	bool limited_color_range;
> >  	bool color_range_auto;
> > +
> > +	/* Upfront link train parameters */
> > +	int max_link_rate_upfront;
> > +	uint8_t max_lanes_upfront;
> > +	bool upfront_done;
> > +
> >  	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
> >  	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
> >  	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
> > @@ -939,6 +945,11 @@ struct intel_dp {
> >  	/* This is called before a link training is starterd */
> >  	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
> >  
> > +	/* For Upfront link training */
> > +	bool (*upfront_link_train)(struct intel_dp *intel_dp, int
> > clock,
> > +				   uint8_t lane_count, bool
> > link_mst,
> > +				   bool is_upfront);
> > +
> >  	/* Displayport compliance testing */
> >  	unsigned long compliance_test_type;
> >  	unsigned long compliance_test_data;
> > @@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder
> > *encoder,
> >  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool
> > state);
> >  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> >  bool intel_ddi_link_train(struct intel_dp *intel_dp, int
> > max_link_rate,
> > -			  uint8_t max_lane_count, bool link_mst);
> > +			  uint8_t max_lane_count, bool link_mst,
> > +			  bool is_upfront);
> >  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp
> > *intel_dp,
> >  						  int clock);
> >  unsigned int intel_fb_align_height(struct drm_device *dev,
> -- 
> Mika Kahola - Intel OTC
> 
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH v14 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-07 18:28     ` [PATCH v13 " Manasi Navare
  2016-09-08 12:10       ` Mika Kahola
@ 2016-09-08 17:22       ` Manasi Navare
  2016-09-08 20:02         ` [PATCH v15 " Manasi Navare
  2016-09-09  7:31         ` [PATCH v14 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms) Jani Nikula
  1 sibling, 2 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-08 17:22 UTC (permalink / raw)
  To: intel-gfx

From: Durgadoss R <durgadoss.r@intel.com>

To support USB type C alternate DP mode, the display driver needs to
know the number of lanes required by the DP panel as well as number
of lanes that can be supported by the type-C cable. Sometimes, the
type-C cable may limit the bandwidth even if Panel can support
more lanes. To address these scenarios, the display driver will
start link training with max lanes, and if that fails, the driver
falls back to x2 lanes; and repeats this procedure for all
bandwidth/lane configurations.

* Since link training is done before modeset only the port
  (and not pipe/planes) and its associated PLLs are enabled.
* On DP hotplug: Directly start link training on the DP encoder.
* On Connected boot scenarios: When booted with an LFP and a DP,
  sometimes BIOS brings up DP. In these cases, we disable the
  crtc and then do upfront link training; and bring it back up.
* All local changes made for upfront link training are reset
  to their previous values once it is done; so that the
  subsequent modeset is not aware of these changes.

Changes since v13:
* Fix some indentation issues (Mika Kahola)
Changes since v12:
* Fix Rebase issues (Mika Kahola)
Changes since v11:
* Change the fallback link rate logic (Manasi)
Changes since v10:
* Use the ddi link train function that loops through all the link rates
and lane counts starting from the highest supported (Manasi)
* For upfront link training, set the upfront flag so that the link can
be disabled after caching upfront values (Manasi)
Changes since v9:
* Change the macros to use dev_priv in place of dev (David Weinehall)
Changes since v8:
* Reset upfront lane count and link rate values on HPD
for DP connector physical disconnect (Manasi)
Changes since v7:
* Move the upfront link training to intel_dp_mode_valid()
  to avoid a race condition with DP MST sideband comms. (Ville)
Changes since v6:
* Fix some initialization bugs on link_rate (Jim Bride)
* Use link_rate (and not link_bw) for upfront (Ville)
* Make intel_dp_upfront*() as a vfunc (Ander)
* The train_set_valid variable in intel_dp was removed due to
  issues in fast link training. So, to indicate the link train
  status, move the channel_eq inside intel_dp.
Changes since v5:
* Moved retry logic in upfront to intel_dp.c so that it
  can be used for all platforms.
Changes since v4:
* Removed usage of crtc_state in upfront link training;
  Hence no need to find free crtc to do upfront now.
* Re-enable crtc if it was disabled for upfront.
* Use separate variables to track max lane count
  and link rate found by upfront, without modifying
  the original DPCD read from panel.
Changes since v3:
* Fixed a return value on BXT check
* Reworked on top of bxt_ddi_pll_select split from Ander
* Renamed from ddi_upfront to bxt_upfront since the
  upfront logic includes BXT specific functions for now.
Changes since v2:
* Rebased on top of latest dpll_mgr.c code and
  latest HPD related clean ups.
* Corrected return values from upfront (Ander)
* Corrected atomic locking for upfront in intel_dp.c (Ville)
Changes since v1:
*  all pll related functions inside ddi.c

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              |  21 +-
 drivers/gpu/drm/i915/intel_dp.c               | 377 +++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
 drivers/gpu/drm/i915/intel_drv.h              |  14 +-
 4 files changed, 311 insertions(+), 102 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 1278daa..797c3bb 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 	pll->config.crtc_mask = 0;
 
 	/* If Link Training fails, send a uevent to generate a hotplug */
-	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
+	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst,
+				   false)))
 		drm_kms_helper_hotplug_event(encoder->base.dev);
 	pll->config = tmp_pll_config;
 }
@@ -2461,7 +2462,7 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 
 bool
 intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-		     uint8_t max_lane_count, bool link_mst)
+		     uint8_t max_lane_count, bool link_mst, bool is_upfront)
 {
 	struct intel_connector *connector = intel_dp->attached_connector;
 	struct intel_encoder *encoder = connector->encoder;
@@ -2507,6 +2508,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 			pll->funcs.disable(dev_priv, pll);
 			pll->config = tmp_pll_config;
 		}
+
 		if (ret) {
 			DRM_DEBUG_KMS("Link Training successful at link rate: "
 				      "%d lane:%d\n", link_rate, lane_count);
@@ -2515,6 +2517,21 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 	}
 	intel_dp_stop_link_train(intel_dp);
 
+	if (is_upfront) {
+		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d lanes:%d\n",
+			      ret ? "Passed" : "Failed",
+			      link_rate, lane_count);
+		/* Disable port followed by PLL for next retry/clean up */
+		intel_ddi_post_disable(encoder, NULL, NULL);
+		pll->funcs.disable(dev_priv, pll);
+		pll->config = tmp_pll_config;
+		if (ret) {
+			/* Save the upfront values */
+			intel_dp->max_lanes_upfront = lane_count;
+			intel_dp->max_link_rate_upfront = link_rate;
+		}
+	}
+
 	if (!lane_count)
 		DRM_ERROR("Link Training Failed\n");
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 853e97d..3d76968 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	u8 source_max, sink_max;
+	u8 temp, source_max, sink_max;
 
 	source_max = intel_dig_port->max_lanes;
 	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
 
-	return min(source_max, sink_max);
+	temp = min(source_max, sink_max);
+
+	/*
+	 * Limit max lanes w.r.t to the max value found
+	 * using Upfront link training also.
+	 */
+	if (intel_dp->max_lanes_upfront)
+		return min(temp, intel_dp->max_lanes_upfront);
+	else
+		return temp;
 }
 
 /*
@@ -190,6 +199,230 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 	return (max_link_clock * max_lanes * 8) / 10;
 }
 
+static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
+					 struct drm_modeset_acquire_ctx *ctx,
+					 bool enable)
+{
+	int ret;
+	struct drm_atomic_state *state;
+	struct intel_crtc_state *crtc_state;
+	struct drm_device *dev = crtc->base.dev;
+	enum pipe pipe = crtc->pipe;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	crtc_state = intel_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		drm_atomic_state_free(state);
+		return ret;
+	}
+
+	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
+			enable ? "En" : "Dis",
+			pipe_name(pipe),
+			enable ? "after" : "before");
+
+	crtc_state->base.active = enable;
+	ret = drm_atomic_commit(state);
+	if (ret)
+		drm_atomic_state_free(state);
+
+	return ret;
+}
+
+static int
+intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
+{
+	if (intel_dp->num_sink_rates) {
+		*sink_rates = intel_dp->sink_rates;
+		return intel_dp->num_sink_rates;
+	}
+
+	*sink_rates = default_rates;
+
+	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
+}
+
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+
+	/* WaDisableHBR2:skl */
+	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
+		return false;
+
+	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
+	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
+		return true;
+	else
+		return false;
+}
+
+static int
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+	int size;
+
+	if (IS_BROXTON(dev_priv)) {
+		*source_rates = bxt_rates;
+		size = ARRAY_SIZE(bxt_rates);
+	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+		*source_rates = skl_rates;
+		size = ARRAY_SIZE(skl_rates);
+	} else {
+		*source_rates = default_rates;
+		size = ARRAY_SIZE(default_rates);
+	}
+
+	/* This depends on the fact that 5.4 is last value in the array */
+	if (!intel_dp_source_supports_hbr2(intel_dp))
+		size--;
+
+	return size;
+}
+
+static int intersect_rates(const int *source_rates, int source_len,
+			   const int *sink_rates, int sink_len,
+			   int *common_rates)
+{
+	int i = 0, j = 0, k = 0;
+
+	while (i < source_len && j < sink_len) {
+		if (source_rates[i] == sink_rates[j]) {
+			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+				return k;
+			common_rates[k] = source_rates[i];
+			++k;
+			++i;
+			++j;
+		} else if (source_rates[i] < sink_rates[j]) {
+			++i;
+		} else {
+			++j;
+		}
+	}
+	return k;
+}
+
+static int intel_dp_common_rates(struct intel_dp *intel_dp,
+				 int *common_rates)
+{
+	const int *source_rates, *sink_rates;
+	int source_len, sink_len;
+
+	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+
+	/* Cap sink rates w.r.t upfront values */
+	if (intel_dp->max_link_rate_upfront) {
+		int len = sink_len - 1;
+
+		while (len > 0 && sink_rates[len] >
+		       intel_dp->max_link_rate_upfront)
+			len--;
+		sink_len = len + 1;
+	}
+
+	source_len = intel_dp_source_rates(intel_dp, &source_rates);
+
+	return intersect_rates(source_rates, source_len,
+			       sink_rates, sink_len,
+			       common_rates);
+}
+
+static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct intel_encoder *intel_encoder = &intel_dig_port->base;
+	struct drm_device *dev = intel_encoder->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_modeset_acquire_ctx ctx;
+	struct intel_crtc *intel_crtc;
+	struct drm_crtc *crtc = NULL;
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	bool disable_dpll = false;
+	int ret;
+	bool done = false, has_mst = false;
+	uint8_t max_lanes;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	int common_len;
+	enum intel_display_power_domain power_domain;
+
+	power_domain = intel_display_port_power_domain(intel_encoder);
+	intel_display_power_get(dev_priv, power_domain);
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	max_lanes = intel_dp_max_lane_count(intel_dp);
+	if (WARN_ON(common_len <= 0))
+		return true;
+
+	drm_modeset_acquire_init(&ctx, 0);
+retry:
+	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
+	if (ret)
+		goto exit_fail;
+
+	if (intel_encoder->base.crtc) {
+		crtc = intel_encoder->base.crtc;
+
+		ret = drm_modeset_lock(&crtc->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		intel_crtc = to_intel_crtc(crtc);
+		pll = intel_crtc->config->shared_dpll;
+		disable_dpll = true;
+		has_mst = intel_crtc_has_type(intel_crtc->config,
+					      INTEL_OUTPUT_DP_MST);
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, false);
+		if (ret)
+			goto exit_fail;
+	}
+
+	mutex_lock(&dev_priv->dpll_lock);
+	if (disable_dpll) {
+		/* Clear the PLL config state */
+		tmp_pll_config = pll->config;
+		pll->config.crtc_mask = 0;
+	}
+
+	done = intel_dp->upfront_link_train(intel_dp,
+					    common_rates[common_len-1],
+					    max_lanes,
+					    has_mst,
+					    true);
+	if (disable_dpll)
+		pll->config = tmp_pll_config;
+
+	mutex_unlock(&dev_priv->dpll_lock);
+
+	if (crtc)
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, true);
+
+exit_fail:
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	intel_display_power_put(dev_priv, power_domain);
+	return done;
+}
+
 static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
@@ -211,6 +444,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
 		target_clock = fixed_mode->clock;
 	}
 
+	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
+		bool do_upfront_link_train;
+		/* Do not do upfront link train, if it is a compliance
+		 * request
+		 */
+		do_upfront_link_train = !intel_dp->upfront_done &&
+			(intel_dp->compliance_test_type !=
+			 DP_TEST_LINK_TRAINING);
+
+		if (do_upfront_link_train)
+			intel_dp->upfront_done = intel_dp_upfront_link_train(intel_dp);
+	}
+
 	max_link_clock = intel_dp_max_link_rate(intel_dp);
 	max_lanes = intel_dp_max_lane_count(intel_dp);
 
@@ -1256,60 +1502,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 	intel_dp->aux.transfer = intel_dp_aux_transfer;
 }
 
-static int
-intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
-{
-	if (intel_dp->num_sink_rates) {
-		*sink_rates = intel_dp->sink_rates;
-		return intel_dp->num_sink_rates;
-	}
-
-	*sink_rates = default_rates;
-
-	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
-}
-
-bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-
-	/* WaDisableHBR2:skl */
-	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
-		return false;
-
-	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
-	    (INTEL_INFO(dev)->gen >= 9))
-		return true;
-	else
-		return false;
-}
-
-static int
-intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-	int size;
-
-	if (IS_BROXTON(dev)) {
-		*source_rates = bxt_rates;
-		size = ARRAY_SIZE(bxt_rates);
-	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
-		*source_rates = skl_rates;
-		size = ARRAY_SIZE(skl_rates);
-	} else {
-		*source_rates = default_rates;
-		size = ARRAY_SIZE(default_rates);
-	}
-
-	/* This depends on the fact that 5.4 is last value in the array */
-	if (!intel_dp_source_supports_hbr2(intel_dp))
-		size--;
-
-	return size;
-}
-
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
 		   struct intel_crtc_state *pipe_config)
@@ -1343,42 +1535,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
 	}
 }
 
-static int intersect_rates(const int *source_rates, int source_len,
-			   const int *sink_rates, int sink_len,
-			   int *common_rates)
-{
-	int i = 0, j = 0, k = 0;
-
-	while (i < source_len && j < sink_len) {
-		if (source_rates[i] == sink_rates[j]) {
-			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
-				return k;
-			common_rates[k] = source_rates[i];
-			++k;
-			++i;
-			++j;
-		} else if (source_rates[i] < sink_rates[j]) {
-			++i;
-		} else {
-			++j;
-		}
-	}
-	return k;
-}
-
-static int intel_dp_common_rates(struct intel_dp *intel_dp,
-				 int *common_rates)
-{
-	const int *source_rates, *sink_rates;
-	int source_len, sink_len;
-
-	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-	source_len = intel_dp_source_rates(intel_dp, &source_rates);
-
-	return intersect_rates(source_rates, source_len,
-			       sink_rates, sink_len,
-			       common_rates);
-}
 
 static void snprintf_int_array(char *str, size_t len,
 			       const int *array, int nelem)
@@ -1436,6 +1592,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	int rates[DP_MAX_SUPPORTED_RATES] = {};
 	int len;
 
+	if (intel_dp->max_link_rate_upfront)
+		return intel_dp->max_link_rate_upfront;
+
 	len = intel_dp_common_rates(intel_dp, rates);
 	if (WARN_ON(len <= 0))
 		return 162000;
@@ -1488,7 +1647,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
-	int lane_count, clock;
+	int lane_count, clock = 0;
 	int min_lane_count = 1;
 	int max_lane_count = intel_dp_max_lane_count(intel_dp);
 	/* Conveniently, the link BW constants become indices with a shift...*/
@@ -1567,11 +1726,24 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	for (; bpp >= 6*3; bpp -= 2*3) {
 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
 						   bpp);
+		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
+			clock = max_clock;
+			lane_count = intel_dp->max_lanes_upfront;
+			link_clock = intel_dp->max_link_rate_upfront;
+			link_avail = intel_dp_max_data_rate(link_clock,
+							    lane_count);
+			mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+							   bpp);
+			if (mode_rate <= link_avail)
+				goto found;
+			else
+				continue;
+		}
+
 		for (clock = max_clock; clock >= max_clock; clock--) {
 			for (lane_count = max_lane_count;
 			     lane_count >= min_lane_count;
 			     lane_count >>= 1) {
-
 				link_clock = common_rates[clock];
 				link_avail = intel_dp_max_data_rate(link_clock,
 								    lane_count);
@@ -1600,7 +1772,6 @@ found:
 	}
 
 	pipe_config->lane_count = lane_count;
-
 	pipe_config->pipe_bpp = bpp;
 	pipe_config->port_clock = common_rates[clock];
 
@@ -4284,7 +4455,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	struct drm_device *dev = connector->dev;
 	enum drm_connector_status status;
 	enum intel_display_power_domain power_domain;
-	u8 sink_irq_vector = 0;
+	u8 sink_irq_vector;
 
 	power_domain = intel_display_port_aux_power_domain(intel_encoder);
 	intel_display_power_get(to_i915(dev), power_domain);
@@ -4377,9 +4548,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	}
 
 out:
-	if ((status != connector_status_connected) &&
-	    (intel_dp->is_mst == false))
+	if (status != connector_status_connected) {
 		intel_dp_unset_edid(intel_dp);
+		intel_dp->upfront_done = false;
+		intel_dp->max_lanes_upfront = 0;
+		intel_dp->max_link_rate_upfront = 0;
+	}
 
 	intel_display_power_put(to_i915(dev), power_domain);
 	return;
@@ -5623,6 +5797,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	if (type == DRM_MODE_CONNECTOR_eDP)
 		intel_encoder->type = INTEL_OUTPUT_EDP;
 
+	/* Initialize upfront link training vfunc for DP */
+	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
+		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
+		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+			intel_dp->upfront_link_train = intel_ddi_link_train;
+	}
+
 	/* eDP only on port B and/or C on vlv/chv */
 	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
 		    is_edp(intel_dp) && port != PORT_B && port != PORT_C))
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index f1e08f0..b6f380b 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -304,7 +304,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 	intel_dp_set_idle_link_train(intel_dp);
 
 	return intel_dp->channel_eq_status;
-
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5b97a7d4..e5ab375 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -882,6 +882,12 @@ struct intel_dp {
 	enum hdmi_force_audio force_audio;
 	bool limited_color_range;
 	bool color_range_auto;
+
+	/* Upfront link train parameters */
+	int max_link_rate_upfront;
+	uint8_t max_lanes_upfront;
+	bool upfront_done;
+
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
 	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
@@ -939,6 +945,11 @@ struct intel_dp {
 	/* This is called before a link training is starterd */
 	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
 
+	/* For Upfront link training */
+	bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
+				   uint8_t lane_count, bool link_mst,
+				   bool is_upfront);
+
 	/* Displayport compliance testing */
 	unsigned long compliance_test_type;
 	unsigned long compliance_test_data;
@@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
 bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-			  uint8_t max_lane_count, bool link_mst);
+			  uint8_t max_lane_count, bool link_mst,
+			  bool is_upfront);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
-- 
1.9.1

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

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

* [PATCH v2 12/14] drm/i915: Remove the link rate and lane count loop in compute config
  2016-09-01 22:08 ` [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config Manasi Navare
  2016-09-02 13:08   ` Mika Kahola
  2016-09-02 20:24   ` Pandiyan, Dhinakaran
@ 2016-09-08 20:02   ` Manasi Navare
  2016-09-13  1:14     ` Pandiyan, Dhinakaran
  2 siblings, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-08 20:02 UTC (permalink / raw)
  To: intel-gfx

While configuring the pipe during modeset, it should use
max clock and max lane count and reduce the bpp until
the requested mode rate is less than or equal to
available link BW.
This is required to pass DP Compliance.

v2:
* Removed the loop since we use max values of clock
and lane count (Dhinakaran Pandiyan)

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1378116..60c8857 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1567,20 +1567,14 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	for (; bpp >= 6*3; bpp -= 2*3) {
 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
 						   bpp);
-
-		for (clock = min_clock; clock <= max_clock; clock++) {
-			for (lane_count = min_lane_count;
-				lane_count <= max_lane_count;
-				lane_count <<= 1) {
-
-				link_clock = common_rates[clock];
-				link_avail = intel_dp_max_data_rate(link_clock,
-								    lane_count);
-
-				if (mode_rate <= link_avail) {
-					goto found;
-				}
-			}
+		clock = max_clock;
+		lane_count = max_lane_count;
+		link_clock = common_rates[clock];
+		link_avail = intel_dp_max_data_rate(link_clock,
+						    lane_count);
+
+		if (mode_rate <= link_avail) {
+			goto found;
 		}
 	}
 
-- 
1.9.1

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

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

* [PATCH v15 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-08 17:22       ` [PATCH v14 " Manasi Navare
@ 2016-09-08 20:02         ` Manasi Navare
  2016-09-09  7:34           ` Jani Nikula
                             ` (2 more replies)
  2016-09-09  7:31         ` [PATCH v14 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms) Jani Nikula
  1 sibling, 3 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-08 20:02 UTC (permalink / raw)
  To: intel-gfx

From: Durgadoss R <durgadoss.r@intel.com>

To support USB type C alternate DP mode, the display driver needs to
know the number of lanes required by the DP panel as well as number
of lanes that can be supported by the type-C cable. Sometimes, the
type-C cable may limit the bandwidth even if Panel can support
more lanes. To address these scenarios, the display driver will
start link training with max lanes, and if that fails, the driver
falls back to x2 lanes; and repeats this procedure for all
bandwidth/lane configurations.

* Since link training is done before modeset only the port
  (and not pipe/planes) and its associated PLLs are enabled.
* On DP hotplug: Directly start link training on the DP encoder.
* On Connected boot scenarios: When booted with an LFP and a DP,
  sometimes BIOS brings up DP. In these cases, we disable the
  crtc and then do upfront link training; and bring it back up.
* All local changes made for upfront link training are reset
  to their previous values once it is done; so that the
  subsequent modeset is not aware of these changes.

Changes since v14:
* Rebased on new revision of compute config patch (Manasi)
Changes since v13:
* Fix some indentation issues (Mika Kahola)
Changes since v12:
* Fix Rebase issues (Mika Kahola)
Changes since v11:
* Change the fallback link rate logic (Manasi)
Changes since v10:
* Use the ddi link train function that loops through all the link rates
and lane counts starting from the highest supported (Manasi)
* For upfront link training, set the upfront flag so that the link can
be disabled after caching upfront values (Manasi)
Changes since v9:
* Change the macros to use dev_priv in place of dev (David Weinehall)
Changes since v8:
* Reset upfront lane count and link rate values on HPD
for DP connector physical disconnect (Manasi)
Changes since v7:
* Move the upfront link training to intel_dp_mode_valid()
  to avoid a race condition with DP MST sideband comms. (Ville)
Changes since v6:
* Fix some initialization bugs on link_rate (Jim Bride)
* Use link_rate (and not link_bw) for upfront (Ville)
* Make intel_dp_upfront*() as a vfunc (Ander)
* The train_set_valid variable in intel_dp was removed due to
  issues in fast link training. So, to indicate the link train
  status, move the channel_eq inside intel_dp.
Changes since v5:
* Moved retry logic in upfront to intel_dp.c so that it
  can be used for all platforms.
Changes since v4:
* Removed usage of crtc_state in upfront link training;
  Hence no need to find free crtc to do upfront now.
* Re-enable crtc if it was disabled for upfront.
* Use separate variables to track max lane count
  and link rate found by upfront, without modifying
  the original DPCD read from panel.
Changes since v3:
* Fixed a return value on BXT check
* Reworked on top of bxt_ddi_pll_select split from Ander
* Renamed from ddi_upfront to bxt_upfront since the
  upfront logic includes BXT specific functions for now.
Changes since v2:
* Rebased on top of latest dpll_mgr.c code and
  latest HPD related clean ups.
* Corrected return values from upfront (Ander)
* Corrected atomic locking for upfront in intel_dp.c (Ville)
Changes since v1:
*  all pll related functions inside ddi.c

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              |  21 +-
 drivers/gpu/drm/i915/intel_dp.c               | 377 +++++++++++++++++++-------
 drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
 drivers/gpu/drm/i915/intel_drv.h              |  14 +-
 4 files changed, 312 insertions(+), 101 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 1278daa..797c3bb 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 	pll->config.crtc_mask = 0;
 
 	/* If Link Training fails, send a uevent to generate a hotplug */
-	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
+	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst,
+				   false)))
 		drm_kms_helper_hotplug_event(encoder->base.dev);
 	pll->config = tmp_pll_config;
 }
@@ -2461,7 +2462,7 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 
 bool
 intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-		     uint8_t max_lane_count, bool link_mst)
+		     uint8_t max_lane_count, bool link_mst, bool is_upfront)
 {
 	struct intel_connector *connector = intel_dp->attached_connector;
 	struct intel_encoder *encoder = connector->encoder;
@@ -2507,6 +2508,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 			pll->funcs.disable(dev_priv, pll);
 			pll->config = tmp_pll_config;
 		}
+
 		if (ret) {
 			DRM_DEBUG_KMS("Link Training successful at link rate: "
 				      "%d lane:%d\n", link_rate, lane_count);
@@ -2515,6 +2517,21 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 	}
 	intel_dp_stop_link_train(intel_dp);
 
+	if (is_upfront) {
+		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d lanes:%d\n",
+			      ret ? "Passed" : "Failed",
+			      link_rate, lane_count);
+		/* Disable port followed by PLL for next retry/clean up */
+		intel_ddi_post_disable(encoder, NULL, NULL);
+		pll->funcs.disable(dev_priv, pll);
+		pll->config = tmp_pll_config;
+		if (ret) {
+			/* Save the upfront values */
+			intel_dp->max_lanes_upfront = lane_count;
+			intel_dp->max_link_rate_upfront = link_rate;
+		}
+	}
+
 	if (!lane_count)
 		DRM_ERROR("Link Training Failed\n");
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 60c8857..7adf093 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	u8 source_max, sink_max;
+	u8 temp, source_max, sink_max;
 
 	source_max = intel_dig_port->max_lanes;
 	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
 
-	return min(source_max, sink_max);
+	temp = min(source_max, sink_max);
+
+	/*
+	 * Limit max lanes w.r.t to the max value found
+	 * using Upfront link training also.
+	 */
+	if (intel_dp->max_lanes_upfront)
+		return min(temp, intel_dp->max_lanes_upfront);
+	else
+		return temp;
 }
 
 /*
@@ -190,6 +199,230 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 	return (max_link_clock * max_lanes * 8) / 10;
 }
 
+static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
+					 struct drm_modeset_acquire_ctx *ctx,
+					 bool enable)
+{
+	int ret;
+	struct drm_atomic_state *state;
+	struct intel_crtc_state *crtc_state;
+	struct drm_device *dev = crtc->base.dev;
+	enum pipe pipe = crtc->pipe;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	crtc_state = intel_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		drm_atomic_state_free(state);
+		return ret;
+	}
+
+	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
+			enable ? "En" : "Dis",
+			pipe_name(pipe),
+			enable ? "after" : "before");
+
+	crtc_state->base.active = enable;
+	ret = drm_atomic_commit(state);
+	if (ret)
+		drm_atomic_state_free(state);
+
+	return ret;
+}
+
+static int
+intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
+{
+	if (intel_dp->num_sink_rates) {
+		*sink_rates = intel_dp->sink_rates;
+		return intel_dp->num_sink_rates;
+	}
+
+	*sink_rates = default_rates;
+
+	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
+}
+
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+
+	/* WaDisableHBR2:skl */
+	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
+		return false;
+
+	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
+	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
+		return true;
+	else
+		return false;
+}
+
+static int
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+	int size;
+
+	if (IS_BROXTON(dev_priv)) {
+		*source_rates = bxt_rates;
+		size = ARRAY_SIZE(bxt_rates);
+	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+		*source_rates = skl_rates;
+		size = ARRAY_SIZE(skl_rates);
+	} else {
+		*source_rates = default_rates;
+		size = ARRAY_SIZE(default_rates);
+	}
+
+	/* This depends on the fact that 5.4 is last value in the array */
+	if (!intel_dp_source_supports_hbr2(intel_dp))
+		size--;
+
+	return size;
+}
+
+static int intersect_rates(const int *source_rates, int source_len,
+			   const int *sink_rates, int sink_len,
+			   int *common_rates)
+{
+	int i = 0, j = 0, k = 0;
+
+	while (i < source_len && j < sink_len) {
+		if (source_rates[i] == sink_rates[j]) {
+			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+				return k;
+			common_rates[k] = source_rates[i];
+			++k;
+			++i;
+			++j;
+		} else if (source_rates[i] < sink_rates[j]) {
+			++i;
+		} else {
+			++j;
+		}
+	}
+	return k;
+}
+
+static int intel_dp_common_rates(struct intel_dp *intel_dp,
+				 int *common_rates)
+{
+	const int *source_rates, *sink_rates;
+	int source_len, sink_len;
+
+	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+
+	/* Cap sink rates w.r.t upfront values */
+	if (intel_dp->max_link_rate_upfront) {
+		int len = sink_len - 1;
+
+		while (len > 0 && sink_rates[len] >
+		       intel_dp->max_link_rate_upfront)
+			len--;
+		sink_len = len + 1;
+	}
+
+	source_len = intel_dp_source_rates(intel_dp, &source_rates);
+
+	return intersect_rates(source_rates, source_len,
+			       sink_rates, sink_len,
+			       common_rates);
+}
+
+static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct intel_encoder *intel_encoder = &intel_dig_port->base;
+	struct drm_device *dev = intel_encoder->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_modeset_acquire_ctx ctx;
+	struct intel_crtc *intel_crtc;
+	struct drm_crtc *crtc = NULL;
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	bool disable_dpll = false;
+	int ret;
+	bool done = false, has_mst = false;
+	uint8_t max_lanes;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	int common_len;
+	enum intel_display_power_domain power_domain;
+
+	power_domain = intel_display_port_power_domain(intel_encoder);
+	intel_display_power_get(dev_priv, power_domain);
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	max_lanes = intel_dp_max_lane_count(intel_dp);
+	if (WARN_ON(common_len <= 0))
+		return true;
+
+	drm_modeset_acquire_init(&ctx, 0);
+retry:
+	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
+	if (ret)
+		goto exit_fail;
+
+	if (intel_encoder->base.crtc) {
+		crtc = intel_encoder->base.crtc;
+
+		ret = drm_modeset_lock(&crtc->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		intel_crtc = to_intel_crtc(crtc);
+		pll = intel_crtc->config->shared_dpll;
+		disable_dpll = true;
+		has_mst = intel_crtc_has_type(intel_crtc->config,
+					      INTEL_OUTPUT_DP_MST);
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, false);
+		if (ret)
+			goto exit_fail;
+	}
+
+	mutex_lock(&dev_priv->dpll_lock);
+	if (disable_dpll) {
+		/* Clear the PLL config state */
+		tmp_pll_config = pll->config;
+		pll->config.crtc_mask = 0;
+	}
+
+	done = intel_dp->upfront_link_train(intel_dp,
+					    common_rates[common_len-1],
+					    max_lanes,
+					    has_mst,
+					    true);
+	if (disable_dpll)
+		pll->config = tmp_pll_config;
+
+	mutex_unlock(&dev_priv->dpll_lock);
+
+	if (crtc)
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, true);
+
+exit_fail:
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	intel_display_power_put(dev_priv, power_domain);
+	return done;
+}
+
 static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
@@ -211,6 +444,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
 		target_clock = fixed_mode->clock;
 	}
 
+	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
+		bool do_upfront_link_train;
+		/* Do not do upfront link train, if it is a compliance
+		 * request
+		 */
+		do_upfront_link_train = !intel_dp->upfront_done &&
+			(intel_dp->compliance_test_type !=
+			 DP_TEST_LINK_TRAINING);
+
+		if (do_upfront_link_train)
+			intel_dp->upfront_done = intel_dp_upfront_link_train(intel_dp);
+	}
+
 	max_link_clock = intel_dp_max_link_rate(intel_dp);
 	max_lanes = intel_dp_max_lane_count(intel_dp);
 
@@ -1256,60 +1502,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 	intel_dp->aux.transfer = intel_dp_aux_transfer;
 }
 
-static int
-intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
-{
-	if (intel_dp->num_sink_rates) {
-		*sink_rates = intel_dp->sink_rates;
-		return intel_dp->num_sink_rates;
-	}
-
-	*sink_rates = default_rates;
-
-	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
-}
-
-bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-
-	/* WaDisableHBR2:skl */
-	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
-		return false;
-
-	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
-	    (INTEL_INFO(dev)->gen >= 9))
-		return true;
-	else
-		return false;
-}
-
-static int
-intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-	int size;
-
-	if (IS_BROXTON(dev)) {
-		*source_rates = bxt_rates;
-		size = ARRAY_SIZE(bxt_rates);
-	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
-		*source_rates = skl_rates;
-		size = ARRAY_SIZE(skl_rates);
-	} else {
-		*source_rates = default_rates;
-		size = ARRAY_SIZE(default_rates);
-	}
-
-	/* This depends on the fact that 5.4 is last value in the array */
-	if (!intel_dp_source_supports_hbr2(intel_dp))
-		size--;
-
-	return size;
-}
-
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
 		   struct intel_crtc_state *pipe_config)
@@ -1343,42 +1535,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
 	}
 }
 
-static int intersect_rates(const int *source_rates, int source_len,
-			   const int *sink_rates, int sink_len,
-			   int *common_rates)
-{
-	int i = 0, j = 0, k = 0;
-
-	while (i < source_len && j < sink_len) {
-		if (source_rates[i] == sink_rates[j]) {
-			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
-				return k;
-			common_rates[k] = source_rates[i];
-			++k;
-			++i;
-			++j;
-		} else if (source_rates[i] < sink_rates[j]) {
-			++i;
-		} else {
-			++j;
-		}
-	}
-	return k;
-}
-
-static int intel_dp_common_rates(struct intel_dp *intel_dp,
-				 int *common_rates)
-{
-	const int *source_rates, *sink_rates;
-	int source_len, sink_len;
-
-	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-	source_len = intel_dp_source_rates(intel_dp, &source_rates);
-
-	return intersect_rates(source_rates, source_len,
-			       sink_rates, sink_len,
-			       common_rates);
-}
 
 static void snprintf_int_array(char *str, size_t len,
 			       const int *array, int nelem)
@@ -1436,6 +1592,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	int rates[DP_MAX_SUPPORTED_RATES] = {};
 	int len;
 
+	if (intel_dp->max_link_rate_upfront)
+		return intel_dp->max_link_rate_upfront;
+
 	len = intel_dp_common_rates(intel_dp, rates);
 	if (WARN_ON(len <= 0))
 		return 162000;
@@ -1488,7 +1647,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
-	int lane_count, clock;
+	int lane_count, clock = 0;
 	int min_lane_count = 1;
 	int max_lane_count = intel_dp_max_lane_count(intel_dp);
 	/* Conveniently, the link BW constants become indices with a shift...*/
@@ -1567,6 +1726,21 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	for (; bpp >= 6*3; bpp -= 2*3) {
 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
 						   bpp);
+
+		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
+			clock = max_clock;
+			lane_count = intel_dp->max_lanes_upfront;
+			link_clock = intel_dp->max_link_rate_upfront;
+			link_avail = intel_dp_max_data_rate(link_clock,
+							    lane_count);
+			mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+							   bpp);
+			if (mode_rate <= link_avail)
+				goto found;
+			else
+				continue;
+		}
+
 		clock = max_clock;
 		lane_count = max_lane_count;
 		link_clock = common_rates[clock];
@@ -1595,7 +1769,6 @@ found:
 	}
 
 	pipe_config->lane_count = lane_count;
-
 	pipe_config->pipe_bpp = bpp;
 	pipe_config->port_clock = common_rates[clock];
 
@@ -4279,7 +4452,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	struct drm_device *dev = connector->dev;
 	enum drm_connector_status status;
 	enum intel_display_power_domain power_domain;
-	u8 sink_irq_vector = 0;
+	u8 sink_irq_vector;
 
 	power_domain = intel_display_port_aux_power_domain(intel_encoder);
 	intel_display_power_get(to_i915(dev), power_domain);
@@ -4372,9 +4545,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	}
 
 out:
-	if ((status != connector_status_connected) &&
-	    (intel_dp->is_mst == false))
+	if (status != connector_status_connected) {
 		intel_dp_unset_edid(intel_dp);
+		intel_dp->upfront_done = false;
+		intel_dp->max_lanes_upfront = 0;
+		intel_dp->max_link_rate_upfront = 0;
+	}
 
 	intel_display_power_put(to_i915(dev), power_domain);
 	return;
@@ -5618,6 +5794,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	if (type == DRM_MODE_CONNECTOR_eDP)
 		intel_encoder->type = INTEL_OUTPUT_EDP;
 
+	/* Initialize upfront link training vfunc for DP */
+	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
+		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
+		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+			intel_dp->upfront_link_train = intel_ddi_link_train;
+	}
+
 	/* eDP only on port B and/or C on vlv/chv */
 	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
 		    is_edp(intel_dp) && port != PORT_B && port != PORT_C))
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index f1e08f0..b6f380b 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -304,7 +304,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 	intel_dp_set_idle_link_train(intel_dp);
 
 	return intel_dp->channel_eq_status;
-
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5b97a7d4..e5ab375 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -882,6 +882,12 @@ struct intel_dp {
 	enum hdmi_force_audio force_audio;
 	bool limited_color_range;
 	bool color_range_auto;
+
+	/* Upfront link train parameters */
+	int max_link_rate_upfront;
+	uint8_t max_lanes_upfront;
+	bool upfront_done;
+
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
 	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
@@ -939,6 +945,11 @@ struct intel_dp {
 	/* This is called before a link training is starterd */
 	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
 
+	/* For Upfront link training */
+	bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
+				   uint8_t lane_count, bool link_mst,
+				   bool is_upfront);
+
 	/* Displayport compliance testing */
 	unsigned long compliance_test_type;
 	unsigned long compliance_test_data;
@@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
 bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-			  uint8_t max_lane_count, bool link_mst);
+			  uint8_t max_lane_count, bool link_mst,
+			  bool is_upfront);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
-- 
1.9.1

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

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

* Re: [PATCH v4 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-08  0:30       ` [PATCH v4 " Manasi Navare
  2016-09-08  9:32         ` Mika Kahola
@ 2016-09-09  1:05         ` Rodrigo Vivi
  2016-09-09  7:11           ` Jani Nikula
  2016-09-09  7:11         ` Jani Nikula
  2016-09-09 23:29         ` [PATCH v5 " Manasi Navare
  3 siblings, 1 reply; 81+ messages in thread
From: Rodrigo Vivi @ 2016-09-09  1:05 UTC (permalink / raw)
  To: Manasi Navare, Jani Nikula; +Cc: intel-gfx

On Wed, Sep 7, 2016 at 5:30 PM, Manasi Navare <manasi.d.navare@intel.com> wrote:
> According to the DisplayPort Spec, in case of Clock Recovery failure
> the link training sequence should fall back to the lower link rate
> followed by lower lane count until CR succeeds.
> On CR success, the sequence proceeds with Channel EQ.
> In case of Channel EQ failures, it should fallback to
> lower link rate and lane count and start the CR phase again.
>
> v4:
> * Fixed the link rate fallback loop (Manasi Navare)
> v3:
> * Fixed some rebase issues (Mika Kahola)
> v2:
> * Add a helper function to return index of requested link rate
> into common_rates array
> * Changed the link rate fallback loop to make use
> of common_rates array (Mika Kahola)
> * Changed INTEL_INFO to INTEL_GEN (David Weinehall)
>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>  drivers/gpu/drm/i915/intel_drv.h              |   6 +-
>  4 files changed, 128 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 25e7973..1278daa 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
>         }
>  }
>
> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>                                     int link_rate, uint32_t lane_count,
> -                                   struct intel_shared_dpll *pll,
> -                                   bool link_mst)
> +                                   struct intel_shared_dpll *pll)
>  {
>         struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>         struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>         enum port port = intel_ddi_get_encoder_port(encoder);
>
>         intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> -                                link_mst);
> -       if (encoder->type == INTEL_OUTPUT_EDP)
> -               intel_edp_panel_on(intel_dp);
> +                                false);
> +
> +       intel_edp_panel_on(intel_dp);
>
>         intel_ddi_clk_select(encoder, pll);
>         intel_prepare_dp_ddi_buffers(encoder);
> @@ -1657,6 +1656,28 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
>                 intel_dp_stop_link_train(intel_dp);
>  }
>
> +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +                                   int link_rate, uint32_t lane_count,
> +                                   struct intel_shared_dpll *pll,
> +                                   bool link_mst)
> +{
> +       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +       struct intel_shared_dpll_config tmp_pll_config;
> +
> +       /* Disable the PLL and obtain the PLL for Link Training
> +        * that starts with highest link rate and lane count.
> +        */
> +       tmp_pll_config = pll->config;
> +       pll->funcs.disable(dev_priv, pll);
> +       pll->config.crtc_mask = 0;
> +
> +       /* If Link Training fails, send a uevent to generate a hotplug */
> +       if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
> +               drm_kms_helper_hotplug_event(encoder->base.dev);
> +       pll->config = tmp_pll_config;
> +}
> +
>  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>                                       bool has_hdmi_sink,
>                                       struct drm_display_mode *adjusted_mode,
> @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
>         struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>         int type = intel_encoder->type;
>
> -       if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> +       if (type == INTEL_OUTPUT_EDP)
> +               intel_ddi_pre_enable_edp(intel_encoder,
> +                                       crtc->config->port_clock,
> +                                       crtc->config->lane_count,
> +                                       crtc->config->shared_dpll);
> +
> +       if (type == INTEL_OUTPUT_DP)
>                 intel_ddi_pre_enable_dp(intel_encoder,
>                                         crtc->config->port_clock,
>                                         crtc->config->lane_count,
>                                         crtc->config->shared_dpll,
>                                         intel_crtc_has_type(crtc->config,
>                                                             INTEL_OUTPUT_DP_MST));
> -       }
> -       if (type == INTEL_OUTPUT_HDMI) {
> +
> +       if (type == INTEL_OUTPUT_HDMI)
>                 intel_ddi_pre_enable_hdmi(intel_encoder,
>                                           crtc->config->has_hdmi_sink,
>                                           &crtc->config->base.adjusted_mode,
>                                           crtc->config->shared_dpll);
> -       }
> +
>  }
>
>  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
> @@ -2432,6 +2459,68 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
>         return pll;
>  }
>
> +bool
> +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +                    uint8_t max_lane_count, bool link_mst)
> +{
> +       struct intel_connector *connector = intel_dp->attached_connector;
> +       struct intel_encoder *encoder = connector->encoder;
> +       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +       struct intel_shared_dpll *pll;
> +       struct intel_shared_dpll_config tmp_pll_config;
> +       int link_rate, link_rate_index;
> +       uint8_t lane_count;
> +       int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> +       bool ret = false;
> +
> +       link_rate_index = intel_dp_link_rate_index(intel_dp, common_rates,
> +                                                  max_link_rate);
> +       if (link_rate_index < 0) {
> +               DRM_ERROR("Invalid Link Rate\n");
> +               return false;
> +       }
> +       for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
> +               for (; link_rate_index >= 0; link_rate_index --) {

ERROR: space prohibited before that '--' (ctx:WxB)
#148: FILE: drivers/gpu/drm/i915/intel_ddi.c:2483:
+ for (; link_rate_index >= 0; link_rate_index --) {
                                              ^
> +                       link_rate = common_rates[link_rate_index];
> +                       pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
> +                       if (pll == NULL) {
> +                               DRM_ERROR("Could not find DPLL for link "
> +                                         "training.\n");

The most common way in our code is to not split the comment and go over 80 cols.

checkpatch complains either ways anyway:

WARNING: quoted string split across lines
#153: FILE: drivers/gpu/drm/i915/intel_ddi.c:2488:
+ DRM_ERROR("Could not find DPLL for link "
+  "training.\n");

Not sure what our maintainer prefer. Jani?


> +                               return false;
> +                       }
> +                       tmp_pll_config = pll->config;
> +                       pll->funcs.enable(dev_priv, pll);
> +
> +                       intel_dp_set_link_params(intel_dp, link_rate,
> +                                                lane_count, link_mst);
> +
> +                       intel_ddi_clk_select(encoder, pll);
> +                       intel_prepare_dp_ddi_buffers(encoder);
> +                       intel_ddi_init_dp_buf_reg(encoder);
> +                       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> +                       ret = intel_dp_start_link_train(intel_dp);
> +                       if (ret)
> +                               break;
> +
> +                       /* Disable port followed by PLL for next retry/clean up */

And here it goes over 80 cols the most common is to

/*
 * Disable...
 * ...clean up
*/

> +                       intel_ddi_post_disable(encoder, NULL, NULL);
> +                       pll->funcs.disable(dev_priv, pll);
> +                       pll->config = tmp_pll_config;
> +               }
> +               if (ret) {
> +                       DRM_DEBUG_KMS("Link Training successful at link rate: "
> +                                     "%d lane:%d\n", link_rate, lane_count);

also here and in 2 other places in
drm-i915-Make-DP-link-training-channel-equalization-.patch

Thanks,
Rodrigo.

> +                       break;
> +               }
> +       }
> +       intel_dp_stop_link_train(intel_dp);
> +
> +       if (!lane_count)
> +               DRM_ERROR("Link Training Failed\n");
> +
> +       return ret;
> +}
> +
>  void intel_ddi_init(struct drm_device *dev, enum port port)
>  {
>         struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 75ac62f..1378116 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
>         return rates[len - 1];
>  }
>
> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
> +                            int link_rate)
> +{
> +       int common_len;
> +       int index;
> +
> +       common_len = intel_dp_common_rates(intel_dp, common_rates);
> +       for (index = common_len - 1; index >= 0; index--) {
> +               if (link_rate == common_rates[index])
> +                       return index;
> +       }
> +
> +       return -1;
> +}
> +
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
>  {
>         return rate_to_index(rate, intel_dp->sink_rates);
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index c438b02..f1e08f0 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -313,9 +313,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>                                 DP_TRAINING_PATTERN_DISABLE);
>  }
>
> -void
> +bool
>  intel_dp_start_link_train(struct intel_dp *intel_dp)
>  {
> -       intel_dp_link_training_clock_recovery(intel_dp);
> -       intel_dp_link_training_channel_equalization(intel_dp);
> +       bool ret;
> +
> +       if (intel_dp_link_training_clock_recovery(intel_dp)) {
> +               ret = intel_dp_link_training_channel_equalization(intel_dp);
> +               if (ret)
> +                       return true;
> +       }
> +       return false;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index ca51e1a..5b97a7d4 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>                          struct intel_crtc_state *pipe_config);
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> +bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +                         uint8_t max_lane_count, bool link_mst);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
>                                                   int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
> @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>  void intel_dp_set_link_params(struct intel_dp *intel_dp,
>                               int link_rate, uint8_t lane_count,
>                               bool link_mst);
> -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> @@ -1403,6 +1405,8 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co
>  void intel_dp_mst_suspend(struct drm_device *dev);
>  void intel_dp_mst_resume(struct drm_device *dev);
>  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
> +                            int link_rate);
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
>  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
>  void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
> --
> 1.9.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v4 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-08  0:30       ` [PATCH v4 " Manasi Navare
  2016-09-08  9:32         ` Mika Kahola
  2016-09-09  1:05         ` Rodrigo Vivi
@ 2016-09-09  7:11         ` Jani Nikula
  2016-09-09 17:13           ` Manasi Navare
  2016-09-09 23:29         ` [PATCH v5 " Manasi Navare
  3 siblings, 1 reply; 81+ messages in thread
From: Jani Nikula @ 2016-09-09  7:11 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

On Thu, 08 Sep 2016, Manasi Navare <manasi.d.navare@intel.com> wrote:
> According to the DisplayPort Spec, in case of Clock Recovery failure
> the link training sequence should fall back to the lower link rate
> followed by lower lane count until CR succeeds.
> On CR success, the sequence proceeds with Channel EQ.
> In case of Channel EQ failures, it should fallback to
> lower link rate and lane count and start the CR phase again.
>
> v4:
> * Fixed the link rate fallback loop (Manasi Navare)
> v3:
> * Fixed some rebase issues (Mika Kahola)
> v2:
> * Add a helper function to return index of requested link rate
> into common_rates array
> * Changed the link rate fallback loop to make use
> of common_rates array (Mika Kahola)
> * Changed INTEL_INFO to INTEL_GEN (David Weinehall)
>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
>  drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>  drivers/gpu/drm/i915/intel_drv.h              |   6 +-
>  4 files changed, 128 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 25e7973..1278daa 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
>  	}
>  }
>  
> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>  				    int link_rate, uint32_t lane_count,
> -				    struct intel_shared_dpll *pll,
> -				    bool link_mst)
> +				    struct intel_shared_dpll *pll)
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>  	enum port port = intel_ddi_get_encoder_port(encoder);
>  
>  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> -				 link_mst);
> -	if (encoder->type == INTEL_OUTPUT_EDP)
> -		intel_edp_panel_on(intel_dp);
> +				 false);
> +
> +	intel_edp_panel_on(intel_dp);
>  
>  	intel_ddi_clk_select(encoder, pll);
>  	intel_prepare_dp_ddi_buffers(encoder);
> @@ -1657,6 +1656,28 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
>  		intel_dp_stop_link_train(intel_dp);
>  }
>  
> +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> +				    int link_rate, uint32_t lane_count,
> +				    struct intel_shared_dpll *pll,
> +				    bool link_mst)
> +{
> +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_shared_dpll_config tmp_pll_config;
> +
> +	/* Disable the PLL and obtain the PLL for Link Training
> +	 * that starts with highest link rate and lane count.
> +	 */
> +	tmp_pll_config = pll->config;
> +	pll->funcs.disable(dev_priv, pll);
> +	pll->config.crtc_mask = 0;
> +
> +	/* If Link Training fails, send a uevent to generate a hotplug */
> +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))

Redundant parens.

> +		drm_kms_helper_hotplug_event(encoder->base.dev);
> +	pll->config = tmp_pll_config;
> +}
> +
>  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>  				      bool has_hdmi_sink,
>  				      struct drm_display_mode *adjusted_mode,
> @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
>  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>  	int type = intel_encoder->type;
>  
> -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> +	if (type == INTEL_OUTPUT_EDP)
> +		intel_ddi_pre_enable_edp(intel_encoder,
> +					crtc->config->port_clock,
> +					crtc->config->lane_count,
> +					crtc->config->shared_dpll);
> +
> +	if (type == INTEL_OUTPUT_DP)
>  		intel_ddi_pre_enable_dp(intel_encoder,
>  					crtc->config->port_clock,
>  					crtc->config->lane_count,
>  					crtc->config->shared_dpll,
>  					intel_crtc_has_type(crtc->config,
>  							    INTEL_OUTPUT_DP_MST));
> -	}
> -	if (type == INTEL_OUTPUT_HDMI) {
> +
> +	if (type == INTEL_OUTPUT_HDMI)
>  		intel_ddi_pre_enable_hdmi(intel_encoder,
>  					  crtc->config->has_hdmi_sink,
>  					  &crtc->config->base.adjusted_mode,
>  					  crtc->config->shared_dpll);
> -	}
> +
>  }
>  
>  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
> @@ -2432,6 +2459,68 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
>  	return pll;
>  }
>  
> +bool
> +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +		     uint8_t max_lane_count, bool link_mst)
> +{
> +	struct intel_connector *connector = intel_dp->attached_connector;
> +	struct intel_encoder *encoder = connector->encoder;
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_shared_dpll *pll;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	int link_rate, link_rate_index;
> +	uint8_t lane_count;
> +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> +	bool ret = false;
> +
> +	link_rate_index = intel_dp_link_rate_index(intel_dp, common_rates,
> +						   max_link_rate);
> +	if (link_rate_index < 0) {
> +		DRM_ERROR("Invalid Link Rate\n");
> +		return false;
> +	}
> +	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
> +		for (; link_rate_index >= 0; link_rate_index --) {

Once you've reached link_rate_index < 0 here, you won't try lower lane
counts anymore and the nested loop is useless, i.e. you never reset
link_rate_index back.

> +			link_rate = common_rates[link_rate_index];
> +			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
> +			if (pll == NULL) {
> +				DRM_ERROR("Could not find DPLL for link "
> +					  "training.\n");
> +				return false;
> +			}
> +			tmp_pll_config = pll->config;
> +			pll->funcs.enable(dev_priv, pll);
> +
> +			intel_dp_set_link_params(intel_dp, link_rate,
> +						 lane_count, link_mst);
> +
> +			intel_ddi_clk_select(encoder, pll);
> +			intel_prepare_dp_ddi_buffers(encoder);
> +			intel_ddi_init_dp_buf_reg(encoder);
> +			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> +			ret = intel_dp_start_link_train(intel_dp);
> +			if (ret)
> +				break;
> +
> +			/* Disable port followed by PLL for next retry/clean up */
> +			intel_ddi_post_disable(encoder, NULL, NULL);
> +			pll->funcs.disable(dev_priv, pll);
> +			pll->config = tmp_pll_config;
> +		}
> +		if (ret) {
> +			DRM_DEBUG_KMS("Link Training successful at link rate: "
> +				      "%d lane:%d\n", link_rate, lane_count);
> +			break;
> +		}
> +	}
> +	intel_dp_stop_link_train(intel_dp);
> +
> +	if (!lane_count)
> +		DRM_ERROR("Link Training Failed\n");
> +
> +	return ret;
> +}
> +
>  void intel_ddi_init(struct drm_device *dev, enum port port)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 75ac62f..1378116 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
>  	return rates[len - 1];
>  }
>  
> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
> +			     int link_rate)
> +{
> +	int common_len;
> +	int index;
> +
> +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> +	for (index = common_len - 1; index >= 0; index--) {
> +		if (link_rate == common_rates[index])
> +			return index;
> +	}

I think it's always easier to have the paradigm for loop, and do the
math using the length and index, like this:

	common_len = intel_dp_common_rates(intel_dp, common_rates);
        for (i = 0; i < common_len; i++)
        	if (link_rate == common_rates[common_len - i - 1])
                	return i;

> +
> +	return -1;
> +}
> +
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
>  {
>  	return rate_to_index(rate, intel_dp->sink_rates);
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index c438b02..f1e08f0 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -313,9 +313,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
>  
> -void
> +bool
>  intel_dp_start_link_train(struct intel_dp *intel_dp)
>  {
> -	intel_dp_link_training_clock_recovery(intel_dp);
> -	intel_dp_link_training_channel_equalization(intel_dp);
> +	bool ret;
> +
> +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> +		ret = intel_dp_link_training_channel_equalization(intel_dp);
> +		if (ret)
> +			return true;
> +	}

Prefer early returns instead of adding more indentation.

> +	return false;
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index ca51e1a..5b97a7d4 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>  			 struct intel_crtc_state *pipe_config);
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> +bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> +			  uint8_t max_lane_count, bool link_mst);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
> @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>  void intel_dp_set_link_params(struct intel_dp *intel_dp,
>  			      int link_rate, uint8_t lane_count,
>  			      bool link_mst);
> -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> @@ -1403,6 +1405,8 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co
>  void intel_dp_mst_suspend(struct drm_device *dev);
>  void intel_dp_mst_resume(struct drm_device *dev);
>  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
> +			     int link_rate);
>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
>  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
>  void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v4 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-09  1:05         ` Rodrigo Vivi
@ 2016-09-09  7:11           ` Jani Nikula
  0 siblings, 0 replies; 81+ messages in thread
From: Jani Nikula @ 2016-09-09  7:11 UTC (permalink / raw)
  To: Rodrigo Vivi, Manasi Navare; +Cc: intel-gfx

On Fri, 09 Sep 2016, Rodrigo Vivi <rodrigo.vivi@gmail.com> wrote:
> On Wed, Sep 7, 2016 at 5:30 PM, Manasi Navare <manasi.d.navare@intel.com> wrote:
>> According to the DisplayPort Spec, in case of Clock Recovery failure
>> the link training sequence should fall back to the lower link rate
>> followed by lower lane count until CR succeeds.
>> On CR success, the sequence proceeds with Channel EQ.
>> In case of Channel EQ failures, it should fallback to
>> lower link rate and lane count and start the CR phase again.
>>
>> v4:
>> * Fixed the link rate fallback loop (Manasi Navare)
>> v3:
>> * Fixed some rebase issues (Mika Kahola)
>> v2:
>> * Add a helper function to return index of requested link rate
>> into common_rates array
>> * Changed the link rate fallback loop to make use
>> of common_rates array (Mika Kahola)
>> * Changed INTEL_INFO to INTEL_GEN (David Weinehall)
>>
>> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
>> ---
>>  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
>>  drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
>>  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
>>  drivers/gpu/drm/i915/intel_drv.h              |   6 +-
>>  4 files changed, 128 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
>> index 25e7973..1278daa 100644
>> --- a/drivers/gpu/drm/i915/intel_ddi.c
>> +++ b/drivers/gpu/drm/i915/intel_ddi.c
>> @@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
>>         }
>>  }
>>
>> -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
>> +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
>>                                     int link_rate, uint32_t lane_count,
>> -                                   struct intel_shared_dpll *pll,
>> -                                   bool link_mst)
>> +                                   struct intel_shared_dpll *pll)
>>  {
>>         struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>>         struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>>         enum port port = intel_ddi_get_encoder_port(encoder);
>>
>>         intel_dp_set_link_params(intel_dp, link_rate, lane_count,
>> -                                link_mst);
>> -       if (encoder->type == INTEL_OUTPUT_EDP)
>> -               intel_edp_panel_on(intel_dp);
>> +                                false);
>> +
>> +       intel_edp_panel_on(intel_dp);
>>
>>         intel_ddi_clk_select(encoder, pll);
>>         intel_prepare_dp_ddi_buffers(encoder);
>> @@ -1657,6 +1656,28 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
>>                 intel_dp_stop_link_train(intel_dp);
>>  }
>>
>> +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
>> +                                   int link_rate, uint32_t lane_count,
>> +                                   struct intel_shared_dpll *pll,
>> +                                   bool link_mst)
>> +{
>> +       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>> +       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>> +       struct intel_shared_dpll_config tmp_pll_config;
>> +
>> +       /* Disable the PLL and obtain the PLL for Link Training
>> +        * that starts with highest link rate and lane count.
>> +        */
>> +       tmp_pll_config = pll->config;
>> +       pll->funcs.disable(dev_priv, pll);
>> +       pll->config.crtc_mask = 0;
>> +
>> +       /* If Link Training fails, send a uevent to generate a hotplug */
>> +       if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
>> +               drm_kms_helper_hotplug_event(encoder->base.dev);
>> +       pll->config = tmp_pll_config;
>> +}
>> +
>>  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
>>                                       bool has_hdmi_sink,
>>                                       struct drm_display_mode *adjusted_mode,
>> @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
>>         struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>>         int type = intel_encoder->type;
>>
>> -       if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
>> +       if (type == INTEL_OUTPUT_EDP)
>> +               intel_ddi_pre_enable_edp(intel_encoder,
>> +                                       crtc->config->port_clock,
>> +                                       crtc->config->lane_count,
>> +                                       crtc->config->shared_dpll);
>> +
>> +       if (type == INTEL_OUTPUT_DP)
>>                 intel_ddi_pre_enable_dp(intel_encoder,
>>                                         crtc->config->port_clock,
>>                                         crtc->config->lane_count,
>>                                         crtc->config->shared_dpll,
>>                                         intel_crtc_has_type(crtc->config,
>>                                                             INTEL_OUTPUT_DP_MST));
>> -       }
>> -       if (type == INTEL_OUTPUT_HDMI) {
>> +
>> +       if (type == INTEL_OUTPUT_HDMI)
>>                 intel_ddi_pre_enable_hdmi(intel_encoder,
>>                                           crtc->config->has_hdmi_sink,
>>                                           &crtc->config->base.adjusted_mode,
>>                                           crtc->config->shared_dpll);
>> -       }
>> +
>>  }
>>
>>  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
>> @@ -2432,6 +2459,68 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
>>         return pll;
>>  }
>>
>> +bool
>> +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
>> +                    uint8_t max_lane_count, bool link_mst)
>> +{
>> +       struct intel_connector *connector = intel_dp->attached_connector;
>> +       struct intel_encoder *encoder = connector->encoder;
>> +       struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
>> +       struct intel_shared_dpll *pll;
>> +       struct intel_shared_dpll_config tmp_pll_config;
>> +       int link_rate, link_rate_index;
>> +       uint8_t lane_count;
>> +       int common_rates[DP_MAX_SUPPORTED_RATES] = {};
>> +       bool ret = false;
>> +
>> +       link_rate_index = intel_dp_link_rate_index(intel_dp, common_rates,
>> +                                                  max_link_rate);
>> +       if (link_rate_index < 0) {
>> +               DRM_ERROR("Invalid Link Rate\n");
>> +               return false;
>> +       }
>> +       for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
>> +               for (; link_rate_index >= 0; link_rate_index --) {
>
> ERROR: space prohibited before that '--' (ctx:WxB)
> #148: FILE: drivers/gpu/drm/i915/intel_ddi.c:2483:
> + for (; link_rate_index >= 0; link_rate_index --) {
>                                               ^
>> +                       link_rate = common_rates[link_rate_index];
>> +                       pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
>> +                       if (pll == NULL) {
>> +                               DRM_ERROR("Could not find DPLL for link "
>> +                                         "training.\n");
>
> The most common way in our code is to not split the comment and go over 80 cols.
>
> checkpatch complains either ways anyway:
>
> WARNING: quoted string split across lines
> #153: FILE: drivers/gpu/drm/i915/intel_ddi.c:2488:
> + DRM_ERROR("Could not find DPLL for link "
> +  "training.\n");
>
> Not sure what our maintainer prefer. Jani?

In this case, I'd prefer rigorous review of the functional aspects of
the changes.

>
>
>> +                               return false;
>> +                       }
>> +                       tmp_pll_config = pll->config;
>> +                       pll->funcs.enable(dev_priv, pll);
>> +
>> +                       intel_dp_set_link_params(intel_dp, link_rate,
>> +                                                lane_count, link_mst);
>> +
>> +                       intel_ddi_clk_select(encoder, pll);
>> +                       intel_prepare_dp_ddi_buffers(encoder);
>> +                       intel_ddi_init_dp_buf_reg(encoder);
>> +                       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
>> +                       ret = intel_dp_start_link_train(intel_dp);
>> +                       if (ret)
>> +                               break;
>> +
>> +                       /* Disable port followed by PLL for next retry/clean up */
>
> And here it goes over 80 cols the most common is to
>
> /*
>  * Disable...
>  * ...clean up
> */
>
>> +                       intel_ddi_post_disable(encoder, NULL, NULL);
>> +                       pll->funcs.disable(dev_priv, pll);
>> +                       pll->config = tmp_pll_config;
>> +               }
>> +               if (ret) {
>> +                       DRM_DEBUG_KMS("Link Training successful at link rate: "
>> +                                     "%d lane:%d\n", link_rate, lane_count);
>
> also here and in 2 other places in
> drm-i915-Make-DP-link-training-channel-equalization-.patch
>
> Thanks,
> Rodrigo.
>
>> +                       break;
>> +               }
>> +       }
>> +       intel_dp_stop_link_train(intel_dp);
>> +
>> +       if (!lane_count)
>> +               DRM_ERROR("Link Training Failed\n");
>> +
>> +       return ret;
>> +}
>> +
>>  void intel_ddi_init(struct drm_device *dev, enum port port)
>>  {
>>         struct drm_i915_private *dev_priv = to_i915(dev);
>> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>> index 75ac62f..1378116 100644
>> --- a/drivers/gpu/drm/i915/intel_dp.c
>> +++ b/drivers/gpu/drm/i915/intel_dp.c
>> @@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
>>         return rates[len - 1];
>>  }
>>
>> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
>> +                            int link_rate)
>> +{
>> +       int common_len;
>> +       int index;
>> +
>> +       common_len = intel_dp_common_rates(intel_dp, common_rates);
>> +       for (index = common_len - 1; index >= 0; index--) {
>> +               if (link_rate == common_rates[index])
>> +                       return index;
>> +       }
>> +
>> +       return -1;
>> +}
>> +
>>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
>>  {
>>         return rate_to_index(rate, intel_dp->sink_rates);
>> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
>> index c438b02..f1e08f0 100644
>> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
>> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
>> @@ -313,9 +313,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>>                                 DP_TRAINING_PATTERN_DISABLE);
>>  }
>>
>> -void
>> +bool
>>  intel_dp_start_link_train(struct intel_dp *intel_dp)
>>  {
>> -       intel_dp_link_training_clock_recovery(intel_dp);
>> -       intel_dp_link_training_channel_equalization(intel_dp);
>> +       bool ret;
>> +
>> +       if (intel_dp_link_training_clock_recovery(intel_dp)) {
>> +               ret = intel_dp_link_training_channel_equalization(intel_dp);
>> +               if (ret)
>> +                       return true;
>> +       }
>> +       return false;
>>  }
>> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
>> index ca51e1a..5b97a7d4 100644
>> --- a/drivers/gpu/drm/i915/intel_drv.h
>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>> @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>>                          struct intel_crtc_state *pipe_config);
>>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
>> +bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
>> +                         uint8_t max_lane_count, bool link_mst);
>>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
>>                                                   int clock);
>>  unsigned int intel_fb_align_height(struct drm_device *dev,
>> @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>>  void intel_dp_set_link_params(struct intel_dp *intel_dp,
>>                               int link_rate, uint8_t lane_count,
>>                               bool link_mst);
>> -void intel_dp_start_link_train(struct intel_dp *intel_dp);
>> +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
>>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
>>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>>  void intel_dp_encoder_reset(struct drm_encoder *encoder);
>> @@ -1403,6 +1405,8 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co
>>  void intel_dp_mst_suspend(struct drm_device *dev);
>>  void intel_dp_mst_resume(struct drm_device *dev);
>>  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
>> +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
>> +                            int link_rate);
>>  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
>>  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
>>  void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
>> --
>> 1.9.1
>>
>> _______________________________________________
>> Intel-gfx mailing list
>> Intel-gfx@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/intel-gfx

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v14 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-08 17:22       ` [PATCH v14 " Manasi Navare
  2016-09-08 20:02         ` [PATCH v15 " Manasi Navare
@ 2016-09-09  7:31         ` Jani Nikula
  1 sibling, 0 replies; 81+ messages in thread
From: Jani Nikula @ 2016-09-09  7:31 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

On Thu, 08 Sep 2016, Manasi Navare <manasi.d.navare@intel.com> wrote:
> From: Durgadoss R <durgadoss.r@intel.com>
>
> To support USB type C alternate DP mode, the display driver needs to
> know the number of lanes required by the DP panel as well as number
> of lanes that can be supported by the type-C cable. Sometimes, the
> type-C cable may limit the bandwidth even if Panel can support
> more lanes. To address these scenarios, the display driver will
> start link training with max lanes, and if that fails, the driver
> falls back to x2 lanes; and repeats this procedure for all
> bandwidth/lane configurations.

Please do not combine non-functional code movement with real
changes. They must be separated.

BR,
Jani.


>
> * Since link training is done before modeset only the port
>   (and not pipe/planes) and its associated PLLs are enabled.
> * On DP hotplug: Directly start link training on the DP encoder.
> * On Connected boot scenarios: When booted with an LFP and a DP,
>   sometimes BIOS brings up DP. In these cases, we disable the
>   crtc and then do upfront link training; and bring it back up.
> * All local changes made for upfront link training are reset
>   to their previous values once it is done; so that the
>   subsequent modeset is not aware of these changes.
>
> Changes since v13:
> * Fix some indentation issues (Mika Kahola)
> Changes since v12:
> * Fix Rebase issues (Mika Kahola)
> Changes since v11:
> * Change the fallback link rate logic (Manasi)
> Changes since v10:
> * Use the ddi link train function that loops through all the link rates
> and lane counts starting from the highest supported (Manasi)
> * For upfront link training, set the upfront flag so that the link can
> be disabled after caching upfront values (Manasi)
> Changes since v9:
> * Change the macros to use dev_priv in place of dev (David Weinehall)
> Changes since v8:
> * Reset upfront lane count and link rate values on HPD
> for DP connector physical disconnect (Manasi)
> Changes since v7:
> * Move the upfront link training to intel_dp_mode_valid()
>   to avoid a race condition with DP MST sideband comms. (Ville)
> Changes since v6:
> * Fix some initialization bugs on link_rate (Jim Bride)
> * Use link_rate (and not link_bw) for upfront (Ville)
> * Make intel_dp_upfront*() as a vfunc (Ander)
> * The train_set_valid variable in intel_dp was removed due to
>   issues in fast link training. So, to indicate the link train
>   status, move the channel_eq inside intel_dp.
> Changes since v5:
> * Moved retry logic in upfront to intel_dp.c so that it
>   can be used for all platforms.
> Changes since v4:
> * Removed usage of crtc_state in upfront link training;
>   Hence no need to find free crtc to do upfront now.
> * Re-enable crtc if it was disabled for upfront.
> * Use separate variables to track max lane count
>   and link rate found by upfront, without modifying
>   the original DPCD read from panel.
> Changes since v3:
> * Fixed a return value on BXT check
> * Reworked on top of bxt_ddi_pll_select split from Ander
> * Renamed from ddi_upfront to bxt_upfront since the
>   upfront logic includes BXT specific functions for now.
> Changes since v2:
> * Rebased on top of latest dpll_mgr.c code and
>   latest HPD related clean ups.
> * Corrected return values from upfront (Ander)
> * Corrected atomic locking for upfront in intel_dp.c (Ville)
> Changes since v1:
> *  all pll related functions inside ddi.c
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              |  21 +-
>  drivers/gpu/drm/i915/intel_dp.c               | 377 +++++++++++++++++++-------
>  drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
>  drivers/gpu/drm/i915/intel_drv.h              |  14 +-
>  4 files changed, 311 insertions(+), 102 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 1278daa..797c3bb 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
>  	pll->config.crtc_mask = 0;
>  
>  	/* If Link Training fails, send a uevent to generate a hotplug */
> -	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
> +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst,
> +				   false)))
>  		drm_kms_helper_hotplug_event(encoder->base.dev);
>  	pll->config = tmp_pll_config;
>  }
> @@ -2461,7 +2462,7 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
>  
>  bool
>  intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> -		     uint8_t max_lane_count, bool link_mst)
> +		     uint8_t max_lane_count, bool link_mst, bool is_upfront)
>  {
>  	struct intel_connector *connector = intel_dp->attached_connector;
>  	struct intel_encoder *encoder = connector->encoder;
> @@ -2507,6 +2508,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
>  			pll->funcs.disable(dev_priv, pll);
>  			pll->config = tmp_pll_config;
>  		}
> +
>  		if (ret) {
>  			DRM_DEBUG_KMS("Link Training successful at link rate: "
>  				      "%d lane:%d\n", link_rate, lane_count);
> @@ -2515,6 +2517,21 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
>  	}
>  	intel_dp_stop_link_train(intel_dp);
>  
> +	if (is_upfront) {
> +		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d lanes:%d\n",
> +			      ret ? "Passed" : "Failed",
> +			      link_rate, lane_count);
> +		/* Disable port followed by PLL for next retry/clean up */
> +		intel_ddi_post_disable(encoder, NULL, NULL);
> +		pll->funcs.disable(dev_priv, pll);
> +		pll->config = tmp_pll_config;
> +		if (ret) {
> +			/* Save the upfront values */
> +			intel_dp->max_lanes_upfront = lane_count;
> +			intel_dp->max_link_rate_upfront = link_rate;
> +		}
> +	}
> +
>  	if (!lane_count)
>  		DRM_ERROR("Link Training Failed\n");
>  
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 853e97d..3d76968 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
>  static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
>  {
>  	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> -	u8 source_max, sink_max;
> +	u8 temp, source_max, sink_max;
>  
>  	source_max = intel_dig_port->max_lanes;
>  	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
>  
> -	return min(source_max, sink_max);
> +	temp = min(source_max, sink_max);
> +
> +	/*
> +	 * Limit max lanes w.r.t to the max value found
> +	 * using Upfront link training also.
> +	 */
> +	if (intel_dp->max_lanes_upfront)
> +		return min(temp, intel_dp->max_lanes_upfront);
> +	else
> +		return temp;
>  }
>  
>  /*
> @@ -190,6 +199,230 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
>  	return (max_link_clock * max_lanes * 8) / 10;
>  }
>  
> +static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
> +					 struct drm_modeset_acquire_ctx *ctx,
> +					 bool enable)
> +{
> +	int ret;
> +	struct drm_atomic_state *state;
> +	struct intel_crtc_state *crtc_state;
> +	struct drm_device *dev = crtc->base.dev;
> +	enum pipe pipe = crtc->pipe;
> +
> +	state = drm_atomic_state_alloc(dev);
> +	if (!state)
> +		return -ENOMEM;
> +
> +	state->acquire_ctx = ctx;
> +
> +	crtc_state = intel_atomic_get_crtc_state(state, crtc);
> +	if (IS_ERR(crtc_state)) {
> +		ret = PTR_ERR(crtc_state);
> +		drm_atomic_state_free(state);
> +		return ret;
> +	}
> +
> +	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
> +			enable ? "En" : "Dis",
> +			pipe_name(pipe),
> +			enable ? "after" : "before");
> +
> +	crtc_state->base.active = enable;
> +	ret = drm_atomic_commit(state);
> +	if (ret)
> +		drm_atomic_state_free(state);
> +
> +	return ret;
> +}
> +
> +static int
> +intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
> +{
> +	if (intel_dp->num_sink_rates) {
> +		*sink_rates = intel_dp->sink_rates;
> +		return intel_dp->num_sink_rates;
> +	}
> +
> +	*sink_rates = default_rates;
> +
> +	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
> +}
> +
> +bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
> +{
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
> +
> +	/* WaDisableHBR2:skl */
> +	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
> +		return false;
> +
> +	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
> +	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
> +		return true;
> +	else
> +		return false;
> +}
> +
> +static int
> +intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
> +{
> +	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
> +	int size;
> +
> +	if (IS_BROXTON(dev_priv)) {
> +		*source_rates = bxt_rates;
> +		size = ARRAY_SIZE(bxt_rates);
> +	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
> +		*source_rates = skl_rates;
> +		size = ARRAY_SIZE(skl_rates);
> +	} else {
> +		*source_rates = default_rates;
> +		size = ARRAY_SIZE(default_rates);
> +	}
> +
> +	/* This depends on the fact that 5.4 is last value in the array */
> +	if (!intel_dp_source_supports_hbr2(intel_dp))
> +		size--;
> +
> +	return size;
> +}
> +
> +static int intersect_rates(const int *source_rates, int source_len,
> +			   const int *sink_rates, int sink_len,
> +			   int *common_rates)
> +{
> +	int i = 0, j = 0, k = 0;
> +
> +	while (i < source_len && j < sink_len) {
> +		if (source_rates[i] == sink_rates[j]) {
> +			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
> +				return k;
> +			common_rates[k] = source_rates[i];
> +			++k;
> +			++i;
> +			++j;
> +		} else if (source_rates[i] < sink_rates[j]) {
> +			++i;
> +		} else {
> +			++j;
> +		}
> +	}
> +	return k;
> +}
> +
> +static int intel_dp_common_rates(struct intel_dp *intel_dp,
> +				 int *common_rates)
> +{
> +	const int *source_rates, *sink_rates;
> +	int source_len, sink_len;
> +
> +	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> +
> +	/* Cap sink rates w.r.t upfront values */
> +	if (intel_dp->max_link_rate_upfront) {
> +		int len = sink_len - 1;
> +
> +		while (len > 0 && sink_rates[len] >
> +		       intel_dp->max_link_rate_upfront)
> +			len--;
> +		sink_len = len + 1;
> +	}
> +
> +	source_len = intel_dp_source_rates(intel_dp, &source_rates);
> +
> +	return intersect_rates(source_rates, source_len,
> +			       sink_rates, sink_len,
> +			       common_rates);
> +}
> +
> +static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> +{
> +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +	struct intel_encoder *intel_encoder = &intel_dig_port->base;
> +	struct drm_device *dev = intel_encoder->base.dev;
> +	struct drm_i915_private *dev_priv = to_i915(dev);
> +	struct drm_mode_config *config = &dev->mode_config;
> +	struct drm_modeset_acquire_ctx ctx;
> +	struct intel_crtc *intel_crtc;
> +	struct drm_crtc *crtc = NULL;
> +	struct intel_shared_dpll *pll;
> +	struct intel_shared_dpll_config tmp_pll_config;
> +	bool disable_dpll = false;
> +	int ret;
> +	bool done = false, has_mst = false;
> +	uint8_t max_lanes;
> +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> +	int common_len;
> +	enum intel_display_power_domain power_domain;
> +
> +	power_domain = intel_display_port_power_domain(intel_encoder);
> +	intel_display_power_get(dev_priv, power_domain);
> +
> +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> +	max_lanes = intel_dp_max_lane_count(intel_dp);
> +	if (WARN_ON(common_len <= 0))
> +		return true;
> +
> +	drm_modeset_acquire_init(&ctx, 0);
> +retry:
> +	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
> +	if (ret)
> +		goto exit_fail;
> +
> +	if (intel_encoder->base.crtc) {
> +		crtc = intel_encoder->base.crtc;
> +
> +		ret = drm_modeset_lock(&crtc->mutex, &ctx);
> +		if (ret)
> +			goto exit_fail;
> +
> +		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
> +		if (ret)
> +			goto exit_fail;
> +
> +		intel_crtc = to_intel_crtc(crtc);
> +		pll = intel_crtc->config->shared_dpll;
> +		disable_dpll = true;
> +		has_mst = intel_crtc_has_type(intel_crtc->config,
> +					      INTEL_OUTPUT_DP_MST);
> +		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, false);
> +		if (ret)
> +			goto exit_fail;
> +	}
> +
> +	mutex_lock(&dev_priv->dpll_lock);
> +	if (disable_dpll) {
> +		/* Clear the PLL config state */
> +		tmp_pll_config = pll->config;
> +		pll->config.crtc_mask = 0;
> +	}
> +
> +	done = intel_dp->upfront_link_train(intel_dp,
> +					    common_rates[common_len-1],
> +					    max_lanes,
> +					    has_mst,
> +					    true);
> +	if (disable_dpll)
> +		pll->config = tmp_pll_config;
> +
> +	mutex_unlock(&dev_priv->dpll_lock);
> +
> +	if (crtc)
> +		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, true);
> +
> +exit_fail:
> +	if (ret == -EDEADLK) {
> +		drm_modeset_backoff(&ctx);
> +		goto retry;
> +	}
> +	drm_modeset_drop_locks(&ctx);
> +	drm_modeset_acquire_fini(&ctx);
> +	intel_display_power_put(dev_priv, power_domain);
> +	return done;
> +}
> +
>  static enum drm_mode_status
>  intel_dp_mode_valid(struct drm_connector *connector,
>  		    struct drm_display_mode *mode)
> @@ -211,6 +444,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
>  		target_clock = fixed_mode->clock;
>  	}
>  
> +	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
> +		bool do_upfront_link_train;
> +		/* Do not do upfront link train, if it is a compliance
> +		 * request
> +		 */
> +		do_upfront_link_train = !intel_dp->upfront_done &&
> +			(intel_dp->compliance_test_type !=
> +			 DP_TEST_LINK_TRAINING);
> +
> +		if (do_upfront_link_train)
> +			intel_dp->upfront_done = intel_dp_upfront_link_train(intel_dp);
> +	}
> +
>  	max_link_clock = intel_dp_max_link_rate(intel_dp);
>  	max_lanes = intel_dp_max_lane_count(intel_dp);
>  
> @@ -1256,60 +1502,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
>  	intel_dp->aux.transfer = intel_dp_aux_transfer;
>  }
>  
> -static int
> -intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
> -{
> -	if (intel_dp->num_sink_rates) {
> -		*sink_rates = intel_dp->sink_rates;
> -		return intel_dp->num_sink_rates;
> -	}
> -
> -	*sink_rates = default_rates;
> -
> -	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
> -}
> -
> -bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
> -{
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	struct drm_device *dev = dig_port->base.base.dev;
> -
> -	/* WaDisableHBR2:skl */
> -	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
> -		return false;
> -
> -	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
> -	    (INTEL_INFO(dev)->gen >= 9))
> -		return true;
> -	else
> -		return false;
> -}
> -
> -static int
> -intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
> -{
> -	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -	struct drm_device *dev = dig_port->base.base.dev;
> -	int size;
> -
> -	if (IS_BROXTON(dev)) {
> -		*source_rates = bxt_rates;
> -		size = ARRAY_SIZE(bxt_rates);
> -	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
> -		*source_rates = skl_rates;
> -		size = ARRAY_SIZE(skl_rates);
> -	} else {
> -		*source_rates = default_rates;
> -		size = ARRAY_SIZE(default_rates);
> -	}
> -
> -	/* This depends on the fact that 5.4 is last value in the array */
> -	if (!intel_dp_source_supports_hbr2(intel_dp))
> -		size--;
> -
> -	return size;
> -}
> -
>  static void
>  intel_dp_set_clock(struct intel_encoder *encoder,
>  		   struct intel_crtc_state *pipe_config)
> @@ -1343,42 +1535,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
>  	}
>  }
>  
> -static int intersect_rates(const int *source_rates, int source_len,
> -			   const int *sink_rates, int sink_len,
> -			   int *common_rates)
> -{
> -	int i = 0, j = 0, k = 0;
> -
> -	while (i < source_len && j < sink_len) {
> -		if (source_rates[i] == sink_rates[j]) {
> -			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
> -				return k;
> -			common_rates[k] = source_rates[i];
> -			++k;
> -			++i;
> -			++j;
> -		} else if (source_rates[i] < sink_rates[j]) {
> -			++i;
> -		} else {
> -			++j;
> -		}
> -	}
> -	return k;
> -}
> -
> -static int intel_dp_common_rates(struct intel_dp *intel_dp,
> -				 int *common_rates)
> -{
> -	const int *source_rates, *sink_rates;
> -	int source_len, sink_len;
> -
> -	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> -	source_len = intel_dp_source_rates(intel_dp, &source_rates);
> -
> -	return intersect_rates(source_rates, source_len,
> -			       sink_rates, sink_len,
> -			       common_rates);
> -}
>  
>  static void snprintf_int_array(char *str, size_t len,
>  			       const int *array, int nelem)
> @@ -1436,6 +1592,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
>  	int rates[DP_MAX_SUPPORTED_RATES] = {};
>  	int len;
>  
> +	if (intel_dp->max_link_rate_upfront)
> +		return intel_dp->max_link_rate_upfront;
> +
>  	len = intel_dp_common_rates(intel_dp, rates);
>  	if (WARN_ON(len <= 0))
>  		return 162000;
> @@ -1488,7 +1647,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  	enum port port = dp_to_dig_port(intel_dp)->port;
>  	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
>  	struct intel_connector *intel_connector = intel_dp->attached_connector;
> -	int lane_count, clock;
> +	int lane_count, clock = 0;
>  	int min_lane_count = 1;
>  	int max_lane_count = intel_dp_max_lane_count(intel_dp);
>  	/* Conveniently, the link BW constants become indices with a shift...*/
> @@ -1567,11 +1726,24 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  	for (; bpp >= 6*3; bpp -= 2*3) {
>  		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
>  						   bpp);
> +		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
> +			clock = max_clock;
> +			lane_count = intel_dp->max_lanes_upfront;
> +			link_clock = intel_dp->max_link_rate_upfront;
> +			link_avail = intel_dp_max_data_rate(link_clock,
> +							    lane_count);
> +			mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
> +							   bpp);
> +			if (mode_rate <= link_avail)
> +				goto found;
> +			else
> +				continue;
> +		}
> +
>  		for (clock = max_clock; clock >= max_clock; clock--) {
>  			for (lane_count = max_lane_count;
>  			     lane_count >= min_lane_count;
>  			     lane_count >>= 1) {
> -
>  				link_clock = common_rates[clock];
>  				link_avail = intel_dp_max_data_rate(link_clock,
>  								    lane_count);
> @@ -1600,7 +1772,6 @@ found:
>  	}
>  
>  	pipe_config->lane_count = lane_count;
> -
>  	pipe_config->pipe_bpp = bpp;
>  	pipe_config->port_clock = common_rates[clock];
>  
> @@ -4284,7 +4455,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
>  	struct drm_device *dev = connector->dev;
>  	enum drm_connector_status status;
>  	enum intel_display_power_domain power_domain;
> -	u8 sink_irq_vector = 0;
> +	u8 sink_irq_vector;
>  
>  	power_domain = intel_display_port_aux_power_domain(intel_encoder);
>  	intel_display_power_get(to_i915(dev), power_domain);
> @@ -4377,9 +4548,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
>  	}
>  
>  out:
> -	if ((status != connector_status_connected) &&
> -	    (intel_dp->is_mst == false))
> +	if (status != connector_status_connected) {
>  		intel_dp_unset_edid(intel_dp);
> +		intel_dp->upfront_done = false;
> +		intel_dp->max_lanes_upfront = 0;
> +		intel_dp->max_link_rate_upfront = 0;
> +	}
>  
>  	intel_display_power_put(to_i915(dev), power_domain);
>  	return;
> @@ -5623,6 +5797,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>  	if (type == DRM_MODE_CONNECTOR_eDP)
>  		intel_encoder->type = INTEL_OUTPUT_EDP;
>  
> +	/* Initialize upfront link training vfunc for DP */
> +	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
> +		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
> +		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
> +			intel_dp->upfront_link_train = intel_ddi_link_train;
> +	}
> +
>  	/* eDP only on port B and/or C on vlv/chv */
>  	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
>  		    is_edp(intel_dp) && port != PORT_B && port != PORT_C))
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index f1e08f0..b6f380b 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -304,7 +304,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  	intel_dp_set_idle_link_train(intel_dp);
>  
>  	return intel_dp->channel_eq_status;
> -
>  }
>  
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 5b97a7d4..e5ab375 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -882,6 +882,12 @@ struct intel_dp {
>  	enum hdmi_force_audio force_audio;
>  	bool limited_color_range;
>  	bool color_range_auto;
> +
> +	/* Upfront link train parameters */
> +	int max_link_rate_upfront;
> +	uint8_t max_lanes_upfront;
> +	bool upfront_done;
> +
>  	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
>  	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
>  	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
> @@ -939,6 +945,11 @@ struct intel_dp {
>  	/* This is called before a link training is starterd */
>  	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
>  
> +	/* For Upfront link training */
> +	bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
> +				   uint8_t lane_count, bool link_mst,
> +				   bool is_upfront);
> +
>  	/* Displayport compliance testing */
>  	unsigned long compliance_test_type;
>  	unsigned long compliance_test_data;
> @@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
>  bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> -			  uint8_t max_lane_count, bool link_mst);
> +			  uint8_t max_lane_count, bool link_mst,
> +			  bool is_upfront);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v15 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms)
  2016-09-08 20:02         ` [PATCH v15 " Manasi Navare
@ 2016-09-09  7:34           ` Jani Nikula
  2016-09-09 23:29           ` [PATCH 13-1/14] drm/i915: Change the placement of some static functions in intel_dp.c Manasi Navare
  2016-09-09 23:29           ` [PATCH v16 13-2/14] drm/i915/dp: Enable Upfront link training on HSW/BDW/SKL/BXT Manasi Navare
  2 siblings, 0 replies; 81+ messages in thread
From: Jani Nikula @ 2016-09-09  7:34 UTC (permalink / raw)
  To: Manasi Navare, intel-gfx

On Thu, 08 Sep 2016, Manasi Navare <manasi.d.navare@intel.com> wrote:
> From: Durgadoss R <durgadoss.r@intel.com>
>
> To support USB type C alternate DP mode, the display driver needs to
> know the number of lanes required by the DP panel as well as number
> of lanes that can be supported by the type-C cable. Sometimes, the
> type-C cable may limit the bandwidth even if Panel can support
> more lanes. To address these scenarios, the display driver will
> start link training with max lanes, and if that fails, the driver
> falls back to x2 lanes; and repeats this procedure for all
> bandwidth/lane configurations.
>
> * Since link training is done before modeset only the port
>   (and not pipe/planes) and its associated PLLs are enabled.
> * On DP hotplug: Directly start link training on the DP encoder.
> * On Connected boot scenarios: When booted with an LFP and a DP,
>   sometimes BIOS brings up DP. In these cases, we disable the
>   crtc and then do upfront link training; and bring it back up.
> * All local changes made for upfront link training are reset
>   to their previous values once it is done; so that the
>   subsequent modeset is not aware of these changes.

As I said for a previous version, this needs to be split to functional
and non-functional parts.

> @@ -5618,6 +5794,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>  	if (type == DRM_MODE_CONNECTOR_eDP)
>  		intel_encoder->type = INTEL_OUTPUT_EDP;
>  
> +	/* Initialize upfront link training vfunc for DP */
> +	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
> +		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
> +		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))

What's this based on? What happened to Kabylake?

> +			intel_dp->upfront_link_train = intel_ddi_link_train;
> +	}
> +
>  	/* eDP only on port B and/or C on vlv/chv */
>  	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
>  		    is_edp(intel_dp) && port != PORT_B && port != PORT_C))
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index f1e08f0..b6f380b 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -304,7 +304,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  	intel_dp_set_idle_link_train(intel_dp);
>  
>  	return intel_dp->channel_eq_status;
> -
>  }
>  
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 5b97a7d4..e5ab375 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -882,6 +882,12 @@ struct intel_dp {
>  	enum hdmi_force_audio force_audio;
>  	bool limited_color_range;
>  	bool color_range_auto;
> +
> +	/* Upfront link train parameters */
> +	int max_link_rate_upfront;
> +	uint8_t max_lanes_upfront;
> +	bool upfront_done;
> +
>  	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
>  	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
>  	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
> @@ -939,6 +945,11 @@ struct intel_dp {
>  	/* This is called before a link training is starterd */
>  	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
>  
> +	/* For Upfront link training */
> +	bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
> +				   uint8_t lane_count, bool link_mst,
> +				   bool is_upfront);
> +
>  	/* Displayport compliance testing */
>  	unsigned long compliance_test_type;
>  	unsigned long compliance_test_data;
> @@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
>  bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> -			  uint8_t max_lane_count, bool link_mst);
> +			  uint8_t max_lane_count, bool link_mst,
> +			  bool is_upfront);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
>  						  int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v4 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-09  7:11         ` Jani Nikula
@ 2016-09-09 17:13           ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-09 17:13 UTC (permalink / raw)
  To: Jani Nikula; +Cc: intel-gfx

On Fri, Sep 09, 2016 at 10:11:06AM +0300, Jani Nikula wrote:
> On Thu, 08 Sep 2016, Manasi Navare <manasi.d.navare@intel.com> wrote:
> > According to the DisplayPort Spec, in case of Clock Recovery failure
> > the link training sequence should fall back to the lower link rate
> > followed by lower lane count until CR succeeds.
> > On CR success, the sequence proceeds with Channel EQ.
> > In case of Channel EQ failures, it should fallback to
> > lower link rate and lane count and start the CR phase again.
> >
> > v4:
> > * Fixed the link rate fallback loop (Manasi Navare)
> > v3:
> > * Fixed some rebase issues (Mika Kahola)
> > v2:
> > * Add a helper function to return index of requested link rate
> > into common_rates array
> > * Changed the link rate fallback loop to make use
> > of common_rates array (Mika Kahola)
> > * Changed INTEL_INFO to INTEL_GEN (David Weinehall)
> >
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c              | 109 +++++++++++++++++++++++---
> >  drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
> >  drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
> >  drivers/gpu/drm/i915/intel_drv.h              |   6 +-
> >  4 files changed, 128 insertions(+), 14 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> > index 25e7973..1278daa 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
> >  	}
> >  }
> >  
> > -static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
> >  				    int link_rate, uint32_t lane_count,
> > -				    struct intel_shared_dpll *pll,
> > -				    bool link_mst)
> > +				    struct intel_shared_dpll *pll)
> >  {
> >  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> >  	enum port port = intel_ddi_get_encoder_port(encoder);
> >  
> >  	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
> > -				 link_mst);
> > -	if (encoder->type == INTEL_OUTPUT_EDP)
> > -		intel_edp_panel_on(intel_dp);
> > +				 false);
> > +
> > +	intel_edp_panel_on(intel_dp);
> >  
> >  	intel_ddi_clk_select(encoder, pll);
> >  	intel_prepare_dp_ddi_buffers(encoder);
> > @@ -1657,6 +1656,28 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> >  		intel_dp_stop_link_train(intel_dp);
> >  }
> >  
> > +static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > +				    int link_rate, uint32_t lane_count,
> > +				    struct intel_shared_dpll *pll,
> > +				    bool link_mst)
> > +{
> > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +
> > +	/* Disable the PLL and obtain the PLL for Link Training
> > +	 * that starts with highest link rate and lane count.
> > +	 */
> > +	tmp_pll_config = pll->config;
> > +	pll->funcs.disable(dev_priv, pll);
> > +	pll->config.crtc_mask = 0;
> > +
> > +	/* If Link Training fails, send a uevent to generate a hotplug */
> > +	if (!(intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst)))
> 
> Redundant parens.
> 
> > +		drm_kms_helper_hotplug_event(encoder->base.dev);
> > +	pll->config = tmp_pll_config;
> > +}
> > +
> >  static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
> >  				      bool has_hdmi_sink,
> >  				      struct drm_display_mode *adjusted_mode,
> > @@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
> >  	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
> >  	int type = intel_encoder->type;
> >  
> > -	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
> > +	if (type == INTEL_OUTPUT_EDP)
> > +		intel_ddi_pre_enable_edp(intel_encoder,
> > +					crtc->config->port_clock,
> > +					crtc->config->lane_count,
> > +					crtc->config->shared_dpll);
> > +
> > +	if (type == INTEL_OUTPUT_DP)
> >  		intel_ddi_pre_enable_dp(intel_encoder,
> >  					crtc->config->port_clock,
> >  					crtc->config->lane_count,
> >  					crtc->config->shared_dpll,
> >  					intel_crtc_has_type(crtc->config,
> >  							    INTEL_OUTPUT_DP_MST));
> > -	}
> > -	if (type == INTEL_OUTPUT_HDMI) {
> > +
> > +	if (type == INTEL_OUTPUT_HDMI)
> >  		intel_ddi_pre_enable_hdmi(intel_encoder,
> >  					  crtc->config->has_hdmi_sink,
> >  					  &crtc->config->base.adjusted_mode,
> >  					  crtc->config->shared_dpll);
> > -	}
> > +
> >  }
> >  
> >  static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
> > @@ -2432,6 +2459,68 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
> >  	return pll;
> >  }
> >  
> > +bool
> > +intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +		     uint8_t max_lane_count, bool link_mst)
> > +{
> > +	struct intel_connector *connector = intel_dp->attached_connector;
> > +	struct intel_encoder *encoder = connector->encoder;
> > +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > +	struct intel_shared_dpll *pll;
> > +	struct intel_shared_dpll_config tmp_pll_config;
> > +	int link_rate, link_rate_index;
> > +	uint8_t lane_count;
> > +	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> > +	bool ret = false;
> > +
> > +	link_rate_index = intel_dp_link_rate_index(intel_dp, common_rates,
> > +						   max_link_rate);
> > +	if (link_rate_index < 0) {
> > +		DRM_ERROR("Invalid Link Rate\n");
> > +		return false;
> > +	}
> > +	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
> > +		for (; link_rate_index >= 0; link_rate_index --) {
> 
> Once you've reached link_rate_index < 0 here, you won't try lower lane
> counts anymore and the nested loop is useless, i.e. you never reset
> link_rate_index back.
>

Thanks for the review comments.
Yes this reseting of link rate index got lost when the logic was changed to use
common rates. I will make the necessary changes.  


> > +			link_rate = common_rates[link_rate_index];
> > +			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
> > +			if (pll == NULL) {
> > +				DRM_ERROR("Could not find DPLL for link "
> > +					  "training.\n");
> > +				return false;
> > +			}
> > +			tmp_pll_config = pll->config;
> > +			pll->funcs.enable(dev_priv, pll);
> > +
> > +			intel_dp_set_link_params(intel_dp, link_rate,
> > +						 lane_count, link_mst);
> > +
> > +			intel_ddi_clk_select(encoder, pll);
> > +			intel_prepare_dp_ddi_buffers(encoder);
> > +			intel_ddi_init_dp_buf_reg(encoder);
> > +			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
> > +			ret = intel_dp_start_link_train(intel_dp);
> > +			if (ret)
> > +				break;
> > +
> > +			/* Disable port followed by PLL for next retry/clean up */
> > +			intel_ddi_post_disable(encoder, NULL, NULL);
> > +			pll->funcs.disable(dev_priv, pll);
> > +			pll->config = tmp_pll_config;
> > +		}
> > +		if (ret) {
> > +			DRM_DEBUG_KMS("Link Training successful at link rate: "
> > +				      "%d lane:%d\n", link_rate, lane_count);
> > +			break;
> > +		}
> > +	}
> > +	intel_dp_stop_link_train(intel_dp);
> > +
> > +	if (!lane_count)
> > +		DRM_ERROR("Link Training Failed\n");
> > +
> > +	return ret;
> > +}
> > +
> >  void intel_ddi_init(struct drm_device *dev, enum port port)
> >  {
> >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > index 75ac62f..1378116 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
> >  	return rates[len - 1];
> >  }
> >  
> > +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
> > +			     int link_rate)
> > +{
> > +	int common_len;
> > +	int index;
> > +
> > +	common_len = intel_dp_common_rates(intel_dp, common_rates);
> > +	for (index = common_len - 1; index >= 0; index--) {
> > +		if (link_rate == common_rates[index])
> > +			return index;
> > +	}
> 
> I think it's always easier to have the paradigm for loop, and do the
> math using the length and index, like this:
> 
> 	common_len = intel_dp_common_rates(intel_dp, common_rates);
>         for (i = 0; i < common_len; i++)
>         	if (link_rate == common_rates[common_len - i - 1])
>                 	return i;
>

Ok agreed I will change the loop to just common_len and do math using index and length.
But we need to start comparing from the highest index since we will be starting the 
link training at highest link rate so lesser iterations if we start comparing from
the highest index.

Manasi
 
> > +
> > +	return -1;
> > +}
> > +
> >  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
> >  {
> >  	return rate_to_index(rate, intel_dp->sink_rates);
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index c438b02..f1e08f0 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -313,9 +313,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> >  				DP_TRAINING_PATTERN_DISABLE);
> >  }
> >  
> > -void
> > +bool
> >  intel_dp_start_link_train(struct intel_dp *intel_dp)
> >  {
> > -	intel_dp_link_training_clock_recovery(intel_dp);
> > -	intel_dp_link_training_channel_equalization(intel_dp);
> > +	bool ret;
> > +
> > +	if (intel_dp_link_training_clock_recovery(intel_dp)) {
> > +		ret = intel_dp_link_training_channel_equalization(intel_dp);
> > +		if (ret)
> > +			return true;
> > +	}
> 
> Prefer early returns instead of adding more indentation.
> 
> > +	return false;
> >  }
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index ca51e1a..5b97a7d4 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
> >  			 struct intel_crtc_state *pipe_config);
> >  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
> >  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
> > +bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> > +			  uint8_t max_lane_count, bool link_mst);
> >  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
> >  						  int clock);
> >  unsigned int intel_fb_align_height(struct drm_device *dev,
> > @@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
> >  void intel_dp_set_link_params(struct intel_dp *intel_dp,
> >  			      int link_rate, uint8_t lane_count,
> >  			      bool link_mst);
> > -void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > +bool intel_dp_start_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > @@ -1403,6 +1405,8 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co
> >  void intel_dp_mst_suspend(struct drm_device *dev);
> >  void intel_dp_mst_resume(struct drm_device *dev);
> >  int intel_dp_max_link_rate(struct intel_dp *intel_dp);
> > +int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
> > +			     int link_rate);
> >  int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
> >  void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
> >  void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
> 
> -- 
> Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH v5 11/14] drm/i915: Fallback to lower link rate and lane count during link training
  2016-09-08  0:30       ` [PATCH v4 " Manasi Navare
                           ` (2 preceding siblings ...)
  2016-09-09  7:11         ` Jani Nikula
@ 2016-09-09 23:29         ` Manasi Navare
  3 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-09 23:29 UTC (permalink / raw)
  To: intel-gfx

According to the DisplayPort Spec, in case of Clock Recovery failure
the link training sequence should fall back to the lower link rate
followed by lower lane count until CR succeeds.
On CR success, the sequence proceeds with Channel EQ.
In case of Channel EQ failures, it should fallback to
lower link rate and lane count and start the CR phase again.

v5:
* Reset the link rate index to the max link rate index
before lowering the lane count (Jani Nikula)
* Use the paradigm for loop in intel_dp_link_rate_index
v4:
* Fixed the link rate fallback loop (Manasi Navare)
v3:
* Fixed some rebase issues (Mika Kahola)
v2:
* Add a helper function to return index of requested link rate
into common_rates array
* Changed the link rate fallback loop to make use
of common_rates array (Mika Kahola)
* Changed INTEL_INFO to INTEL_GEN (David Weinehall)

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              | 112 +++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_dp.c               |  15 ++++
 drivers/gpu/drm/i915/intel_dp_link_training.c |  12 ++-
 drivers/gpu/drm/i915/intel_drv.h              |   6 +-
 4 files changed, 131 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 67a6a0b..2c13d0c 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1634,19 +1634,18 @@ void intel_ddi_clk_select(struct intel_encoder *encoder,
 	}
 }
 
-static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+static void intel_ddi_pre_enable_edp(struct intel_encoder *encoder,
 				    int link_rate, uint32_t lane_count,
-				    struct intel_shared_dpll *pll,
-				    bool link_mst)
+				    struct intel_shared_dpll *pll)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
 	enum port port = intel_ddi_get_encoder_port(encoder);
 
 	intel_dp_set_link_params(intel_dp, link_rate, lane_count,
-				 link_mst);
-	if (encoder->type == INTEL_OUTPUT_EDP)
-		intel_edp_panel_on(intel_dp);
+				 false);
+
+	intel_edp_panel_on(intel_dp);
 
 	intel_ddi_clk_select(encoder, pll);
 	intel_prepare_dp_ddi_buffers(encoder);
@@ -1657,6 +1656,28 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 		intel_dp_stop_link_train(intel_dp);
 }
 
+static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
+				    int link_rate, uint32_t lane_count,
+				    struct intel_shared_dpll *pll,
+				    bool link_mst)
+{
+	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll_config tmp_pll_config;
+
+	/* Disable the PLL and obtain the PLL for Link Training
+	 * that starts with highest link rate and lane count.
+	 */
+	tmp_pll_config = pll->config;
+	pll->funcs.disable(dev_priv, pll);
+	pll->config.crtc_mask = 0;
+
+	/* If Link Training fails, send a uevent to generate a hotplug */
+	if (!intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst))
+		drm_kms_helper_hotplug_event(encoder->base.dev);
+	pll->config = tmp_pll_config;
+}
+
 static void intel_ddi_pre_enable_hdmi(struct intel_encoder *encoder,
 				      bool has_hdmi_sink,
 				      struct drm_display_mode *adjusted_mode,
@@ -1690,20 +1711,26 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder,
 	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	int type = intel_encoder->type;
 
-	if (type == INTEL_OUTPUT_DP || type == INTEL_OUTPUT_EDP) {
+	if (type == INTEL_OUTPUT_EDP)
+		intel_ddi_pre_enable_edp(intel_encoder,
+					crtc->config->port_clock,
+					crtc->config->lane_count,
+					crtc->config->shared_dpll);
+
+	if (type == INTEL_OUTPUT_DP)
 		intel_ddi_pre_enable_dp(intel_encoder,
 					crtc->config->port_clock,
 					crtc->config->lane_count,
 					crtc->config->shared_dpll,
 					intel_crtc_has_type(crtc->config,
 							    INTEL_OUTPUT_DP_MST));
-	}
-	if (type == INTEL_OUTPUT_HDMI) {
+
+	if (type == INTEL_OUTPUT_HDMI)
 		intel_ddi_pre_enable_hdmi(intel_encoder,
 					  crtc->config->has_hdmi_sink,
 					  &crtc->config->base.adjusted_mode,
 					  crtc->config->shared_dpll);
-	}
+
 }
 
 static void intel_ddi_post_disable(struct intel_encoder *intel_encoder,
@@ -2431,6 +2458,71 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 	return pll;
 }
 
+bool
+intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+		     uint8_t max_lane_count, bool link_mst)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct intel_encoder *encoder = connector->encoder;
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	int link_rate, max_link_rate_index, link_rate_index;
+	uint8_t lane_count;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	bool ret = false;
+
+	max_link_rate_index = intel_dp_link_rate_index(intel_dp, common_rates,
+						   max_link_rate);
+	if (max_link_rate_index < 0) {
+		DRM_ERROR("Invalid Link Rate\n");
+		return false;
+	}
+	for (lane_count = max_lane_count; lane_count > 0; lane_count >>= 1) {
+		for (link_rate_index = max_link_rate_index;
+		     link_rate_index >= 0; link_rate_index--) {
+			link_rate = common_rates[link_rate_index];
+			pll = intel_ddi_get_link_dpll(intel_dp, link_rate);
+			if (pll == NULL) {
+				DRM_ERROR("Could not find DPLL for link "
+					  "training.\n");
+				return false;
+			}
+			tmp_pll_config = pll->config;
+			pll->funcs.enable(dev_priv, pll);
+
+			intel_dp_set_link_params(intel_dp, link_rate,
+						 lane_count, link_mst);
+
+			intel_ddi_clk_select(encoder, pll);
+			intel_prepare_dp_ddi_buffers(encoder);
+			intel_ddi_init_dp_buf_reg(encoder);
+			intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+			ret = intel_dp_start_link_train(intel_dp);
+			if (ret)
+				break;
+
+			/* Disable port followed by PLL for next
+			 *retry/clean up
+			 */
+			intel_ddi_post_disable(encoder, NULL, NULL);
+			pll->funcs.disable(dev_priv, pll);
+			pll->config = tmp_pll_config;
+		}
+		if (ret) {
+			DRM_DEBUG_KMS("Link Training successful at link rate: "
+				      "%d lane:%d\n", link_rate, lane_count);
+			break;
+		}
+	}
+	intel_dp_stop_link_train(intel_dp);
+
+	if (!lane_count)
+		DRM_ERROR("Link Training Failed\n");
+
+	return ret;
+}
+
 void intel_ddi_init(struct drm_device *dev, enum port port)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 75ac62f..bb9df1e 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1443,6 +1443,21 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	return rates[len - 1];
 }
 
+int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
+			     int link_rate)
+{
+	int common_len;
+	int index;
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	for (index = 0; index < common_len; index++) {
+		if (link_rate == common_rates[common_len - index - 1])
+			return common_len - index - 1;
+	}
+
+	return -1;
+}
+
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
 {
 	return rate_to_index(rate, intel_dp->sink_rates);
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index c438b02..f1e08f0 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -313,9 +313,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 				DP_TRAINING_PATTERN_DISABLE);
 }
 
-void
+bool
 intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
-	intel_dp_link_training_clock_recovery(intel_dp);
-	intel_dp_link_training_channel_equalization(intel_dp);
+	bool ret;
+
+	if (intel_dp_link_training_clock_recovery(intel_dp)) {
+		ret = intel_dp_link_training_channel_equalization(intel_dp);
+		if (ret)
+			return true;
+	}
+	return false;
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ca51e1a..5b97a7d4 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1160,6 +1160,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 			 struct intel_crtc_state *pipe_config);
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
+bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
+			  uint8_t max_lane_count, bool link_mst);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
@@ -1381,7 +1383,7 @@ bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 void intel_dp_set_link_params(struct intel_dp *intel_dp,
 			      int link_rate, uint8_t lane_count,
 			      bool link_mst);
-void intel_dp_start_link_train(struct intel_dp *intel_dp);
+bool intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 void intel_dp_encoder_reset(struct drm_encoder *encoder);
@@ -1403,6 +1405,8 @@ void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *co
 void intel_dp_mst_suspend(struct drm_device *dev);
 void intel_dp_mst_resume(struct drm_device *dev);
 int intel_dp_max_link_rate(struct intel_dp *intel_dp);
+int intel_dp_link_rate_index(struct intel_dp *intel_dp, int *common_rates,
+			     int link_rate);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
 void intel_power_sequencer_reset(struct drm_i915_private *dev_priv);
-- 
1.9.1

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

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

* [PATCH 13-1/14] drm/i915: Change the placement of some static functions in intel_dp.c
  2016-09-08 20:02         ` [PATCH v15 " Manasi Navare
  2016-09-09  7:34           ` Jani Nikula
@ 2016-09-09 23:29           ` Manasi Navare
  2016-09-12 23:21             ` Rodrigo Vivi
  2016-09-09 23:29           ` [PATCH v16 13-2/14] drm/i915/dp: Enable Upfront link training on HSW/BDW/SKL/BXT Manasi Navare
  2 siblings, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-09 23:29 UTC (permalink / raw)
  To: intel-gfx

These static helper functions are required to be used within upfront
link training related functions so they need to be placed at the top
of the file.

Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c | 182 ++++++++++++++++++++--------------------
 1 file changed, 91 insertions(+), 91 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 75350b2..429ecf8 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -190,6 +190,97 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 	return (max_link_clock * max_lanes * 8) / 10;
 }
 
+static int
+intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
+{
+	if (intel_dp->num_sink_rates) {
+		*sink_rates = intel_dp->sink_rates;
+		return intel_dp->num_sink_rates;
+	}
+
+	*sink_rates = default_rates;
+
+	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
+}
+
+bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+
+	/* WaDisableHBR2:skl */
+	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
+		return false;
+
+	if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
+	    IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
+		return true;
+	else
+		return false;
+}
+
+static int
+intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
+	int size;
+
+	if (IS_BROXTON(dev_priv)) {
+		*source_rates = bxt_rates;
+		size = ARRAY_SIZE(bxt_rates);
+	} else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
+		*source_rates = skl_rates;
+		size = ARRAY_SIZE(skl_rates);
+	} else {
+		*source_rates = default_rates;
+		size = ARRAY_SIZE(default_rates);
+	}
+
+	/* This depends on the fact that 5.4 is last value in the array */
+	if (!intel_dp_source_supports_hbr2(intel_dp))
+		size--;
+
+	return size;
+}
+
+static int intersect_rates(const int *source_rates, int source_len,
+			   const int *sink_rates, int sink_len,
+			   int *common_rates)
+{
+	int i = 0, j = 0, k = 0;
+
+	while (i < source_len && j < sink_len) {
+		if (source_rates[i] == sink_rates[j]) {
+			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
+				return k;
+			common_rates[k] = source_rates[i];
+			++k;
+			++i;
+			++j;
+		} else if (source_rates[i] < sink_rates[j]) {
+			++i;
+		} else {
+			++j;
+		}
+	}
+	return k;
+}
+
+static int intel_dp_common_rates(struct intel_dp *intel_dp,
+				 int *common_rates)
+{
+	const int *source_rates, *sink_rates;
+	int source_len, sink_len;
+
+	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+	source_len = intel_dp_source_rates(intel_dp, &source_rates);
+
+	return intersect_rates(source_rates, source_len,
+			       sink_rates, sink_len,
+			       common_rates);
+}
+
 static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
@@ -1256,60 +1347,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
 	intel_dp->aux.transfer = intel_dp_aux_transfer;
 }
 
-static int
-intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
-{
-	if (intel_dp->num_sink_rates) {
-		*sink_rates = intel_dp->sink_rates;
-		return intel_dp->num_sink_rates;
-	}
-
-	*sink_rates = default_rates;
-
-	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
-}
-
-bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-
-	/* WaDisableHBR2:skl */
-	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
-		return false;
-
-	if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
-	    (INTEL_INFO(dev)->gen >= 9))
-		return true;
-	else
-		return false;
-}
-
-static int
-intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct drm_device *dev = dig_port->base.base.dev;
-	int size;
-
-	if (IS_BROXTON(dev)) {
-		*source_rates = bxt_rates;
-		size = ARRAY_SIZE(bxt_rates);
-	} else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
-		*source_rates = skl_rates;
-		size = ARRAY_SIZE(skl_rates);
-	} else {
-		*source_rates = default_rates;
-		size = ARRAY_SIZE(default_rates);
-	}
-
-	/* This depends on the fact that 5.4 is last value in the array */
-	if (!intel_dp_source_supports_hbr2(intel_dp))
-		size--;
-
-	return size;
-}
-
 static void
 intel_dp_set_clock(struct intel_encoder *encoder,
 		   struct intel_crtc_state *pipe_config)
@@ -1343,43 +1380,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
 	}
 }
 
-static int intersect_rates(const int *source_rates, int source_len,
-			   const int *sink_rates, int sink_len,
-			   int *common_rates)
-{
-	int i = 0, j = 0, k = 0;
-
-	while (i < source_len && j < sink_len) {
-		if (source_rates[i] == sink_rates[j]) {
-			if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
-				return k;
-			common_rates[k] = source_rates[i];
-			++k;
-			++i;
-			++j;
-		} else if (source_rates[i] < sink_rates[j]) {
-			++i;
-		} else {
-			++j;
-		}
-	}
-	return k;
-}
-
-static int intel_dp_common_rates(struct intel_dp *intel_dp,
-				 int *common_rates)
-{
-	const int *source_rates, *sink_rates;
-	int source_len, sink_len;
-
-	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
-	source_len = intel_dp_source_rates(intel_dp, &source_rates);
-
-	return intersect_rates(source_rates, source_len,
-			       sink_rates, sink_len,
-			       common_rates);
-}
-
 static void snprintf_int_array(char *str, size_t len,
 			       const int *array, int nelem)
 {
-- 
1.9.1

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

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

* [PATCH v16 13-2/14] drm/i915/dp: Enable Upfront link training on HSW/BDW/SKL/BXT
  2016-09-08 20:02         ` [PATCH v15 " Manasi Navare
  2016-09-09  7:34           ` Jani Nikula
  2016-09-09 23:29           ` [PATCH 13-1/14] drm/i915: Change the placement of some static functions in intel_dp.c Manasi Navare
@ 2016-09-09 23:29           ` Manasi Navare
  2016-09-13  0:22             ` Rodrigo Vivi
  2 siblings, 1 reply; 81+ messages in thread
From: Manasi Navare @ 2016-09-09 23:29 UTC (permalink / raw)
  To: intel-gfx

To support USB type C alternate DP mode, the display driver needs to
know the number of lanes required by the DP panel as well as number
of lanes that can be supported by the type-C cable. Sometimes, the
type-C cable may limit the bandwidth even if Panel can support
more lanes. To address these scenarios we need to train the link before
modeset. This upfront link training caches the values of max link rate
and max lane count that get used later during modeset. Upfront link
training does not change any HW state, the link is disabled and PLL
values are reset to previous values after upfront link tarining so
that subsequent modeset is not aware of these changes.

This patch is based on prior work done by
R,Durgadoss <durgadoss.r@intel.com>

Changes since v15:
* Split this patch into two patches - one with functional
changes to enable upfront and other with moving the existing
functions around so that they can be used for upfront (Jani Nikula)
* Cleaned up the commit message

Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              |  21 ++-
 drivers/gpu/drm/i915/intel_dp.c               | 196 +++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
 drivers/gpu/drm/i915/intel_drv.h              |  14 +-
 4 files changed, 221 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 2c13d0c..2eee5b5 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
 	pll->config.crtc_mask = 0;
 
 	/* If Link Training fails, send a uevent to generate a hotplug */
-	if (!intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst))
+	if (!intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst,
+				  false))
 		drm_kms_helper_hotplug_event(encoder->base.dev);
 	pll->config = tmp_pll_config;
 }
@@ -2460,7 +2461,7 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
 
 bool
 intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-		     uint8_t max_lane_count, bool link_mst)
+		     uint8_t max_lane_count, bool link_mst, bool is_upfront)
 {
 	struct intel_connector *connector = intel_dp->attached_connector;
 	struct intel_encoder *encoder = connector->encoder;
@@ -2509,6 +2510,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 			pll->funcs.disable(dev_priv, pll);
 			pll->config = tmp_pll_config;
 		}
+
 		if (ret) {
 			DRM_DEBUG_KMS("Link Training successful at link rate: "
 				      "%d lane:%d\n", link_rate, lane_count);
@@ -2517,6 +2519,21 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
 	}
 	intel_dp_stop_link_train(intel_dp);
 
+	if (is_upfront) {
+		DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d lanes:%d\n",
+			      ret ? "Passed" : "Failed",
+			      link_rate, lane_count);
+		/* Disable port followed by PLL for next retry/clean up */
+		intel_ddi_post_disable(encoder, NULL, NULL);
+		pll->funcs.disable(dev_priv, pll);
+		pll->config = tmp_pll_config;
+		if (ret) {
+			/* Save the upfront values */
+			intel_dp->max_lanes_upfront = lane_count;
+			intel_dp->max_link_rate_upfront = link_rate;
+		}
+	}
+
 	if (!lane_count)
 		DRM_ERROR("Link Training Failed\n");
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 429ecf8..18c663d 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
 static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
-	u8 source_max, sink_max;
+	u8 temp, source_max, sink_max;
 
 	source_max = intel_dig_port->max_lanes;
 	sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
 
-	return min(source_max, sink_max);
+	temp = min(source_max, sink_max);
+
+	/*
+	 * Limit max lanes w.r.t to the max value found
+	 * using Upfront link training also.
+	 */
+	if (intel_dp->max_lanes_upfront)
+		return min(temp, intel_dp->max_lanes_upfront);
+	else
+		return temp;
 }
 
 /*
@@ -190,6 +199,42 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
 	return (max_link_clock * max_lanes * 8) / 10;
 }
 
+static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
+					 struct drm_modeset_acquire_ctx *ctx,
+					 bool enable)
+{
+	int ret;
+	struct drm_atomic_state *state;
+	struct intel_crtc_state *crtc_state;
+	struct drm_device *dev = crtc->base.dev;
+	enum pipe pipe = crtc->pipe;
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	crtc_state = intel_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		drm_atomic_state_free(state);
+		return ret;
+	}
+
+	DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
+			enable ? "En" : "Dis",
+			pipe_name(pipe),
+			enable ? "after" : "before");
+
+	crtc_state->base.active = enable;
+	ret = drm_atomic_commit(state);
+	if (ret)
+		drm_atomic_state_free(state);
+
+	return ret;
+}
+
 static int
 intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
 {
@@ -274,6 +319,17 @@ static int intel_dp_common_rates(struct intel_dp *intel_dp,
 	int source_len, sink_len;
 
 	sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
+
+	/* Cap sink rates w.r.t upfront values */
+	if (intel_dp->max_link_rate_upfront) {
+		int len = sink_len - 1;
+
+		while (len > 0 && sink_rates[len] >
+		       intel_dp->max_link_rate_upfront)
+			len--;
+		sink_len = len + 1;
+	}
+
 	source_len = intel_dp_source_rates(intel_dp, &source_rates);
 
 	return intersect_rates(source_rates, source_len,
@@ -281,6 +337,92 @@ static int intel_dp_common_rates(struct intel_dp *intel_dp,
 			       common_rates);
 }
 
+static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+	struct intel_encoder *intel_encoder = &intel_dig_port->base;
+	struct drm_device *dev = intel_encoder->base.dev;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_mode_config *config = &dev->mode_config;
+	struct drm_modeset_acquire_ctx ctx;
+	struct intel_crtc *intel_crtc;
+	struct drm_crtc *crtc = NULL;
+	struct intel_shared_dpll *pll;
+	struct intel_shared_dpll_config tmp_pll_config;
+	bool disable_dpll = false;
+	int ret;
+	bool done = false, has_mst = false;
+	uint8_t max_lanes;
+	int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+	int common_len;
+	enum intel_display_power_domain power_domain;
+
+	power_domain = intel_display_port_power_domain(intel_encoder);
+	intel_display_power_get(dev_priv, power_domain);
+
+	common_len = intel_dp_common_rates(intel_dp, common_rates);
+	max_lanes = intel_dp_max_lane_count(intel_dp);
+	if (WARN_ON(common_len <= 0))
+		return true;
+
+	drm_modeset_acquire_init(&ctx, 0);
+retry:
+	ret = drm_modeset_lock(&config->connection_mutex, &ctx);
+	if (ret)
+		goto exit_fail;
+
+	if (intel_encoder->base.crtc) {
+		crtc = intel_encoder->base.crtc;
+
+		ret = drm_modeset_lock(&crtc->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
+		if (ret)
+			goto exit_fail;
+
+		intel_crtc = to_intel_crtc(crtc);
+		pll = intel_crtc->config->shared_dpll;
+		disable_dpll = true;
+		has_mst = intel_crtc_has_type(intel_crtc->config,
+					      INTEL_OUTPUT_DP_MST);
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, false);
+		if (ret)
+			goto exit_fail;
+	}
+
+	mutex_lock(&dev_priv->dpll_lock);
+	if (disable_dpll) {
+		/* Clear the PLL config state */
+		tmp_pll_config = pll->config;
+		pll->config.crtc_mask = 0;
+	}
+
+	done = intel_dp->upfront_link_train(intel_dp,
+					    common_rates[common_len-1],
+					    max_lanes,
+					    has_mst,
+					    true);
+	if (disable_dpll)
+		pll->config = tmp_pll_config;
+
+	mutex_unlock(&dev_priv->dpll_lock);
+
+	if (crtc)
+		ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, true);
+
+exit_fail:
+	if (ret == -EDEADLK) {
+		drm_modeset_backoff(&ctx);
+		goto retry;
+	}
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	intel_display_power_put(dev_priv, power_domain);
+	return done;
+}
+
 static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
 		    struct drm_display_mode *mode)
@@ -302,6 +444,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
 		target_clock = fixed_mode->clock;
 	}
 
+	if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
+		bool do_upfront_link_train;
+		/* Do not do upfront link train, if it is a compliance
+		 * request
+		 */
+		do_upfront_link_train = !intel_dp->upfront_done &&
+			(intel_dp->compliance_test_type !=
+			 DP_TEST_LINK_TRAINING);
+
+		if (do_upfront_link_train)
+			intel_dp->upfront_done = intel_dp_upfront_link_train(intel_dp);
+	}
+
 	max_link_clock = intel_dp_max_link_rate(intel_dp);
 	max_lanes = intel_dp_max_lane_count(intel_dp);
 
@@ -1436,6 +1591,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	int rates[DP_MAX_SUPPORTED_RATES] = {};
 	int len;
 
+	if (intel_dp->max_link_rate_upfront)
+		return intel_dp->max_link_rate_upfront;
+
 	len = intel_dp_common_rates(intel_dp, rates);
 	if (WARN_ON(len <= 0))
 		return 162000;
@@ -1488,7 +1646,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
 	struct intel_connector *intel_connector = intel_dp->attached_connector;
-	int lane_count, clock;
+	int lane_count, clock = 0;
 	int min_lane_count = 1;
 	int max_lane_count = intel_dp_max_lane_count(intel_dp);
 	/* Conveniently, the link BW constants become indices with a shift...*/
@@ -1567,6 +1725,21 @@ intel_dp_compute_config(struct intel_encoder *encoder,
 	for (; bpp >= 6*3; bpp -= 2*3) {
 		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
 						   bpp);
+
+		if (!is_edp(intel_dp) && intel_dp->upfront_done) {
+			clock = max_clock;
+			lane_count = intel_dp->max_lanes_upfront;
+			link_clock = intel_dp->max_link_rate_upfront;
+			link_avail = intel_dp_max_data_rate(link_clock,
+							    lane_count);
+			mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
+							   bpp);
+			if (mode_rate <= link_avail)
+				goto found;
+			else
+				continue;
+		}
+
 		clock = max_clock;
 		lane_count = max_lane_count;
 		link_clock = common_rates[clock];
@@ -1595,7 +1768,6 @@ found:
 	}
 
 	pipe_config->lane_count = lane_count;
-
 	pipe_config->pipe_bpp = bpp;
 	pipe_config->port_clock = common_rates[clock];
 
@@ -4279,7 +4451,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	struct drm_device *dev = connector->dev;
 	enum drm_connector_status status;
 	enum intel_display_power_domain power_domain;
-	u8 sink_irq_vector = 0;
+	u8 sink_irq_vector;
 
 	power_domain = intel_display_port_aux_power_domain(intel_encoder);
 	intel_display_power_get(to_i915(dev), power_domain);
@@ -4372,9 +4544,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 	}
 
 out:
-	if ((status != connector_status_connected) &&
-	    (intel_dp->is_mst == false))
+	if (status != connector_status_connected) {
 		intel_dp_unset_edid(intel_dp);
+		intel_dp->upfront_done = false;
+		intel_dp->max_lanes_upfront = 0;
+		intel_dp->max_link_rate_upfront = 0;
+	}
 
 	intel_display_power_put(to_i915(dev), power_domain);
 	return;
@@ -5618,6 +5793,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
 	if (type == DRM_MODE_CONNECTOR_eDP)
 		intel_encoder->type = INTEL_OUTPUT_EDP;
 
+	/* Initialize upfront link training vfunc for DP */
+	if (intel_encoder->type != INTEL_OUTPUT_EDP) {
+		if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
+		    IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
+			intel_dp->upfront_link_train = intel_ddi_link_train;
+	}
+
 	/* eDP only on port B and/or C on vlv/chv */
 	if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
 		    is_edp(intel_dp) && port != PORT_B && port != PORT_C))
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index f1e08f0..b6f380b 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -304,7 +304,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 	intel_dp_set_idle_link_train(intel_dp);
 
 	return intel_dp->channel_eq_status;
-
 }
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5b97a7d4..e5ab375 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -882,6 +882,12 @@ struct intel_dp {
 	enum hdmi_force_audio force_audio;
 	bool limited_color_range;
 	bool color_range_auto;
+
+	/* Upfront link train parameters */
+	int max_link_rate_upfront;
+	uint8_t max_lanes_upfront;
+	bool upfront_done;
+
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
 	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
 	uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
@@ -939,6 +945,11 @@ struct intel_dp {
 	/* This is called before a link training is starterd */
 	void (*prepare_link_retrain)(struct intel_dp *intel_dp);
 
+	/* For Upfront link training */
+	bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
+				   uint8_t lane_count, bool link_mst,
+				   bool is_upfront);
+
 	/* Displayport compliance testing */
 	unsigned long compliance_test_type;
 	unsigned long compliance_test_data;
@@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
 void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
 uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
 bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
-			  uint8_t max_lane_count, bool link_mst);
+			  uint8_t max_lane_count, bool link_mst,
+			  bool is_upfront);
 struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
 						  int clock);
 unsigned int intel_fb_align_height(struct drm_device *dev,
-- 
1.9.1

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

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

* Re: [PATCH 13-1/14] drm/i915: Change the placement of some static functions in intel_dp.c
  2016-09-09 23:29           ` [PATCH 13-1/14] drm/i915: Change the placement of some static functions in intel_dp.c Manasi Navare
@ 2016-09-12 23:21             ` Rodrigo Vivi
  0 siblings, 0 replies; 81+ messages in thread
From: Rodrigo Vivi @ 2016-09-12 23:21 UTC (permalink / raw)
  To: Manasi Navare; +Cc: intel-gfx

On Fri, Sep 9, 2016 at 4:29 PM, Manasi Navare <manasi.d.navare@intel.com> wrote:
> These static helper functions are required to be used within upfront
> link training related functions so they need to be placed at the top
> of the file.
>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp.c | 182 ++++++++++++++++++++--------------------
>  1 file changed, 91 insertions(+), 91 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 75350b2..429ecf8 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -190,6 +190,97 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
>         return (max_link_clock * max_lanes * 8) / 10;
>  }
>
> +static int
> +intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
> +{
> +       if (intel_dp->num_sink_rates) {
> +               *sink_rates = intel_dp->sink_rates;
> +               return intel_dp->num_sink_rates;
> +       }
> +
> +       *sink_rates = default_rates;
> +
> +       return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
> +}
> +
> +bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)

This is declared at intel_drv.h so it doesn't need a re-position.

> +{
> +       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
> +
> +       /* WaDisableHBR2:skl */
> +       if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0))
> +               return false;
> +
> +       if ((IS_HASWELL(dev_priv) && !IS_HSW_ULX(dev_priv)) ||
> +           IS_BROADWELL(dev_priv) || (INTEL_GEN(dev_priv) >= 9))
> +               return true;
> +       else
> +               return false;
> +}
> +
> +static int
> +intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
> +{
> +       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> +       struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev);
> +       int size;
> +
> +       if (IS_BROXTON(dev_priv)) {
> +               *source_rates = bxt_rates;
> +               size = ARRAY_SIZE(bxt_rates);
> +       } else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) {
> +               *source_rates = skl_rates;
> +               size = ARRAY_SIZE(skl_rates);
> +       } else {
> +               *source_rates = default_rates;
> +               size = ARRAY_SIZE(default_rates);
> +       }
> +
> +       /* This depends on the fact that 5.4 is last value in the array */
> +       if (!intel_dp_source_supports_hbr2(intel_dp))
> +               size--;
> +
> +       return size;
> +}
> +
> +static int intersect_rates(const int *source_rates, int source_len,
> +                          const int *sink_rates, int sink_len,
> +                          int *common_rates)
> +{
> +       int i = 0, j = 0, k = 0;
> +
> +       while (i < source_len && j < sink_len) {
> +               if (source_rates[i] == sink_rates[j]) {
> +                       if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
> +                               return k;
> +                       common_rates[k] = source_rates[i];
> +                       ++k;
> +                       ++i;
> +                       ++j;
> +               } else if (source_rates[i] < sink_rates[j]) {
> +                       ++i;
> +               } else {
> +                       ++j;
> +               }
> +       }
> +       return k;
> +}
> +
> +static int intel_dp_common_rates(struct intel_dp *intel_dp,
> +                                int *common_rates)
> +{
> +       const int *source_rates, *sink_rates;
> +       int source_len, sink_len;
> +
> +       sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> +       source_len = intel_dp_source_rates(intel_dp, &source_rates);
> +
> +       return intersect_rates(source_rates, source_len,
> +                              sink_rates, sink_len,
> +                              common_rates);
> +}
> +
>  static enum drm_mode_status
>  intel_dp_mode_valid(struct drm_connector *connector,
>                     struct drm_display_mode *mode)
> @@ -1256,60 +1347,6 @@ intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
>         intel_dp->aux.transfer = intel_dp_aux_transfer;
>  }
>
> -static int
> -intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
> -{
> -       if (intel_dp->num_sink_rates) {
> -               *sink_rates = intel_dp->sink_rates;
> -               return intel_dp->num_sink_rates;
> -       }
> -
> -       *sink_rates = default_rates;
> -
> -       return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
> -}
> -
> -bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp)
> -{
> -       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -       struct drm_device *dev = dig_port->base.base.dev;
> -
> -       /* WaDisableHBR2:skl */
> -       if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
> -               return false;
> -
> -       if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) ||
> -           (INTEL_INFO(dev)->gen >= 9))
> -               return true;
> -       else
> -               return false;
> -}
> -
> -static int
> -intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates)
> -{
> -       struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
> -       struct drm_device *dev = dig_port->base.base.dev;
> -       int size;
> -
> -       if (IS_BROXTON(dev)) {
> -               *source_rates = bxt_rates;
> -               size = ARRAY_SIZE(bxt_rates);
> -       } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
> -               *source_rates = skl_rates;
> -               size = ARRAY_SIZE(skl_rates);
> -       } else {
> -               *source_rates = default_rates;
> -               size = ARRAY_SIZE(default_rates);
> -       }
> -
> -       /* This depends on the fact that 5.4 is last value in the array */
> -       if (!intel_dp_source_supports_hbr2(intel_dp))
> -               size--;
> -
> -       return size;
> -}
> -
>  static void
>  intel_dp_set_clock(struct intel_encoder *encoder,
>                    struct intel_crtc_state *pipe_config)
> @@ -1343,43 +1380,6 @@ intel_dp_set_clock(struct intel_encoder *encoder,
>         }
>  }
>
> -static int intersect_rates(const int *source_rates, int source_len,
> -                          const int *sink_rates, int sink_len,
> -                          int *common_rates)
> -{
> -       int i = 0, j = 0, k = 0;
> -
> -       while (i < source_len && j < sink_len) {
> -               if (source_rates[i] == sink_rates[j]) {
> -                       if (WARN_ON(k >= DP_MAX_SUPPORTED_RATES))
> -                               return k;
> -                       common_rates[k] = source_rates[i];
> -                       ++k;
> -                       ++i;
> -                       ++j;
> -               } else if (source_rates[i] < sink_rates[j]) {
> -                       ++i;
> -               } else {
> -                       ++j;
> -               }
> -       }
> -       return k;
> -}
> -
> -static int intel_dp_common_rates(struct intel_dp *intel_dp,
> -                                int *common_rates)
> -{
> -       const int *source_rates, *sink_rates;
> -       int source_len, sink_len;
> -
> -       sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> -       source_len = intel_dp_source_rates(intel_dp, &source_rates);
> -
> -       return intersect_rates(source_rates, source_len,
> -                              sink_rates, sink_len,
> -                              common_rates);
> -}
> -
>  static void snprintf_int_array(char *str, size_t len,
>                                const int *array, int nelem)
>  {
> --
> 1.9.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v16 13-2/14] drm/i915/dp: Enable Upfront link training on HSW/BDW/SKL/BXT
  2016-09-09 23:29           ` [PATCH v16 13-2/14] drm/i915/dp: Enable Upfront link training on HSW/BDW/SKL/BXT Manasi Navare
@ 2016-09-13  0:22             ` Rodrigo Vivi
  0 siblings, 0 replies; 81+ messages in thread
From: Rodrigo Vivi @ 2016-09-13  0:22 UTC (permalink / raw)
  To: Manasi Navare; +Cc: intel-gfx

On Fri, Sep 9, 2016 at 4:29 PM, Manasi Navare <manasi.d.navare@intel.com> wrote:
> To support USB type C alternate DP mode, the display driver needs to
> know the number of lanes required by the DP panel as well as number
> of lanes that can be supported by the type-C cable. Sometimes, the
> type-C cable may limit the bandwidth even if Panel can support
> more lanes. To address these scenarios we need to train the link before
> modeset. This upfront link training caches the values of max link rate
> and max lane count that get used later during modeset. Upfront link
> training does not change any HW state, the link is disabled and PLL
> values are reset to previous values after upfront link tarining so
> that subsequent modeset is not aware of these changes.
>
> This patch is based on prior work done by
> R,Durgadoss <durgadoss.r@intel.com>
>
> Changes since v15:
> * Split this patch into two patches - one with functional
> changes to enable upfront and other with moving the existing
> functions around so that they can be used for upfront (Jani Nikula)
> * Cleaned up the commit message
>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> Signed-off-by: Jim Bride <jim.bride@linux.intel.com>
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              |  21 ++-
>  drivers/gpu/drm/i915/intel_dp.c               | 196 +++++++++++++++++++++++++-
>  drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
>  drivers/gpu/drm/i915/intel_drv.h              |  14 +-
>  4 files changed, 221 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 2c13d0c..2eee5b5 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -1673,7 +1673,8 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
>         pll->config.crtc_mask = 0;
>
>         /* If Link Training fails, send a uevent to generate a hotplug */
> -       if (!intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst))
> +       if (!intel_ddi_link_train(intel_dp, link_rate, lane_count, link_mst,
> +                                 false))
>                 drm_kms_helper_hotplug_event(encoder->base.dev);
>         pll->config = tmp_pll_config;
>  }
> @@ -2460,7 +2461,7 @@ intel_ddi_get_link_dpll(struct intel_dp *intel_dp, int clock)
>
>  bool
>  intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> -                    uint8_t max_lane_count, bool link_mst)
> +                    uint8_t max_lane_count, bool link_mst, bool is_upfront)
>  {
>         struct intel_connector *connector = intel_dp->attached_connector;
>         struct intel_encoder *encoder = connector->encoder;
> @@ -2509,6 +2510,7 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
>                         pll->funcs.disable(dev_priv, pll);
>                         pll->config = tmp_pll_config;
>                 }
> +
>                 if (ret) {
>                         DRM_DEBUG_KMS("Link Training successful at link rate: "
>                                       "%d lane:%d\n", link_rate, lane_count);
> @@ -2517,6 +2519,21 @@ intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
>         }
>         intel_dp_stop_link_train(intel_dp);
>
> +       if (is_upfront) {
> +               DRM_DEBUG_KMS("Upfront link train %s: link_clock:%d lanes:%d\n",
> +                             ret ? "Passed" : "Failed",
> +                             link_rate, lane_count);
> +               /* Disable port followed by PLL for next retry/clean up */
> +               intel_ddi_post_disable(encoder, NULL, NULL);
> +               pll->funcs.disable(dev_priv, pll);
> +               pll->config = tmp_pll_config;
> +               if (ret) {
> +                       /* Save the upfront values */
> +                       intel_dp->max_lanes_upfront = lane_count;
> +                       intel_dp->max_link_rate_upfront = link_rate;
> +               }
> +       }
> +
>         if (!lane_count)
>                 DRM_ERROR("Link Training Failed\n");
>
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 429ecf8..18c663d 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -153,12 +153,21 @@ intel_dp_max_link_bw(struct intel_dp  *intel_dp)
>  static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
>  {
>         struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> -       u8 source_max, sink_max;
> +       u8 temp, source_max, sink_max;
>
>         source_max = intel_dig_port->max_lanes;
>         sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
>
> -       return min(source_max, sink_max);
> +       temp = min(source_max, sink_max);
> +
> +       /*
> +        * Limit max lanes w.r.t to the max value found
> +        * using Upfront link training also.
> +        */
> +       if (intel_dp->max_lanes_upfront)
> +               return min(temp, intel_dp->max_lanes_upfront);
> +       else
> +               return temp;
>  }
>
>  /*
> @@ -190,6 +199,42 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
>         return (max_link_clock * max_lanes * 8) / 10;
>  }
>
> +static int intel_dp_upfront_crtc_disable(struct intel_crtc *crtc,
> +                                        struct drm_modeset_acquire_ctx *ctx,
> +                                        bool enable)
> +{
> +       int ret;
> +       struct drm_atomic_state *state;
> +       struct intel_crtc_state *crtc_state;
> +       struct drm_device *dev = crtc->base.dev;
> +       enum pipe pipe = crtc->pipe;
> +
> +       state = drm_atomic_state_alloc(dev);
> +       if (!state)
> +               return -ENOMEM;
> +
> +       state->acquire_ctx = ctx;
> +
> +       crtc_state = intel_atomic_get_crtc_state(state, crtc);
> +       if (IS_ERR(crtc_state)) {
> +               ret = PTR_ERR(crtc_state);
> +               drm_atomic_state_free(state);
> +               return ret;
> +       }
> +
> +       DRM_DEBUG_KMS("%sabling crtc %c %s upfront link train\n",
> +                       enable ? "En" : "Dis",
> +                       pipe_name(pipe),
> +                       enable ? "after" : "before");
> +
> +       crtc_state->base.active = enable;
> +       ret = drm_atomic_commit(state);
> +       if (ret)
> +               drm_atomic_state_free(state);
> +
> +       return ret;
> +}
> +
>  static int
>  intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
>  {
> @@ -274,6 +319,17 @@ static int intel_dp_common_rates(struct intel_dp *intel_dp,
>         int source_len, sink_len;
>
>         sink_len = intel_dp_sink_rates(intel_dp, &sink_rates);
> +
> +       /* Cap sink rates w.r.t upfront values */
> +       if (intel_dp->max_link_rate_upfront) {
> +               int len = sink_len - 1;
> +
> +               while (len > 0 && sink_rates[len] >
> +                      intel_dp->max_link_rate_upfront)
> +                       len--;
> +               sink_len = len + 1;
> +       }
> +
>         source_len = intel_dp_source_rates(intel_dp, &source_rates);
>
>         return intersect_rates(source_rates, source_len,
> @@ -281,6 +337,92 @@ static int intel_dp_common_rates(struct intel_dp *intel_dp,
>                                common_rates);
>  }
>
> +static bool intel_dp_upfront_link_train(struct intel_dp *intel_dp)
> +{
> +       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> +       struct intel_encoder *intel_encoder = &intel_dig_port->base;
> +       struct drm_device *dev = intel_encoder->base.dev;
> +       struct drm_i915_private *dev_priv = to_i915(dev);
> +       struct drm_mode_config *config = &dev->mode_config;
> +       struct drm_modeset_acquire_ctx ctx;
> +       struct intel_crtc *intel_crtc;
> +       struct drm_crtc *crtc = NULL;
> +       struct intel_shared_dpll *pll;
> +       struct intel_shared_dpll_config tmp_pll_config;
> +       bool disable_dpll = false;
> +       int ret;
> +       bool done = false, has_mst = false;
> +       uint8_t max_lanes;
> +       int common_rates[DP_MAX_SUPPORTED_RATES] = {};
> +       int common_len;
> +       enum intel_display_power_domain power_domain;
> +
> +       power_domain = intel_display_port_power_domain(intel_encoder);
> +       intel_display_power_get(dev_priv, power_domain);
> +
> +       common_len = intel_dp_common_rates(intel_dp, common_rates);
> +       max_lanes = intel_dp_max_lane_count(intel_dp);
> +       if (WARN_ON(common_len <= 0))
> +               return true;
> +
> +       drm_modeset_acquire_init(&ctx, 0);
> +retry:
> +       ret = drm_modeset_lock(&config->connection_mutex, &ctx);
> +       if (ret)
> +               goto exit_fail;
> +
> +       if (intel_encoder->base.crtc) {
> +               crtc = intel_encoder->base.crtc;
> +
> +               ret = drm_modeset_lock(&crtc->mutex, &ctx);
> +               if (ret)
> +                       goto exit_fail;
> +
> +               ret = drm_modeset_lock(&crtc->primary->mutex, &ctx);
> +               if (ret)
> +                       goto exit_fail;
> +
> +               intel_crtc = to_intel_crtc(crtc);
> +               pll = intel_crtc->config->shared_dpll;
> +               disable_dpll = true;
> +               has_mst = intel_crtc_has_type(intel_crtc->config,
> +                                             INTEL_OUTPUT_DP_MST);
> +               ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, false);
> +               if (ret)
> +                       goto exit_fail;
> +       }
> +
> +       mutex_lock(&dev_priv->dpll_lock);
> +       if (disable_dpll) {
> +               /* Clear the PLL config state */
> +               tmp_pll_config = pll->config;
> +               pll->config.crtc_mask = 0;
> +       }
> +
> +       done = intel_dp->upfront_link_train(intel_dp,
> +                                           common_rates[common_len-1],
> +                                           max_lanes,
> +                                           has_mst,
> +                                           true);
> +       if (disable_dpll)
> +               pll->config = tmp_pll_config;
> +
> +       mutex_unlock(&dev_priv->dpll_lock);
> +
> +       if (crtc)
> +               ret = intel_dp_upfront_crtc_disable(intel_crtc, &ctx, true);
> +
> +exit_fail:
> +       if (ret == -EDEADLK) {
> +               drm_modeset_backoff(&ctx);
> +               goto retry;
> +       }
> +       drm_modeset_drop_locks(&ctx);
> +       drm_modeset_acquire_fini(&ctx);
> +       intel_display_power_put(dev_priv, power_domain);
> +       return done;
> +}
> +
>  static enum drm_mode_status
>  intel_dp_mode_valid(struct drm_connector *connector,
>                     struct drm_display_mode *mode)
> @@ -302,6 +444,19 @@ intel_dp_mode_valid(struct drm_connector *connector,
>                 target_clock = fixed_mode->clock;
>         }
>
> +       if (intel_dp->upfront_link_train && !intel_dp->upfront_done) {
> +               bool do_upfront_link_train;
> +               /* Do not do upfront link train, if it is a compliance
> +                * request
> +                */
> +               do_upfront_link_train = !intel_dp->upfront_done &&
> +                       (intel_dp->compliance_test_type !=
> +                        DP_TEST_LINK_TRAINING);
> +
> +               if (do_upfront_link_train)
> +                       intel_dp->upfront_done = intel_dp_upfront_link_train(intel_dp);
> +       }
> +
>         max_link_clock = intel_dp_max_link_rate(intel_dp);
>         max_lanes = intel_dp_max_lane_count(intel_dp);
>
> @@ -1436,6 +1591,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
>         int rates[DP_MAX_SUPPORTED_RATES] = {};
>         int len;
>
> +       if (intel_dp->max_link_rate_upfront)
> +               return intel_dp->max_link_rate_upfront;
> +
>         len = intel_dp_common_rates(intel_dp, rates);
>         if (WARN_ON(len <= 0))
>                 return 162000;
> @@ -1488,7 +1646,7 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>         enum port port = dp_to_dig_port(intel_dp)->port;
>         struct intel_crtc *intel_crtc = to_intel_crtc(pipe_config->base.crtc);
>         struct intel_connector *intel_connector = intel_dp->attached_connector;
> -       int lane_count, clock;
> +       int lane_count, clock = 0;

minor, but I believe you don't need this.

>         int min_lane_count = 1;
>         int max_lane_count = intel_dp_max_lane_count(intel_dp);
>         /* Conveniently, the link BW constants become indices with a shift...*/
> @@ -1567,6 +1725,21 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>         for (; bpp >= 6*3; bpp -= 2*3) {
>                 mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
>                                                    bpp);
> +
> +               if (!is_edp(intel_dp) && intel_dp->upfront_done) {
> +                       clock = max_clock;
> +                       lane_count = intel_dp->max_lanes_upfront;
> +                       link_clock = intel_dp->max_link_rate_upfront;
> +                       link_avail = intel_dp_max_data_rate(link_clock,
> +                                                           lane_count);
> +                       mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
> +                                                          bpp);
> +                       if (mode_rate <= link_avail)
> +                               goto found;
> +                       else
> +                               continue;
> +               }
> +
>                 clock = max_clock;
>                 lane_count = max_lane_count;
>                 link_clock = common_rates[clock];
> @@ -1595,7 +1768,6 @@ found:
>         }
>
>         pipe_config->lane_count = lane_count;
> -
>         pipe_config->pipe_bpp = bpp;
>         pipe_config->port_clock = common_rates[clock];
>
> @@ -4279,7 +4451,7 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
>         struct drm_device *dev = connector->dev;
>         enum drm_connector_status status;
>         enum intel_display_power_domain power_domain;
> -       u8 sink_irq_vector = 0;
> +       u8 sink_irq_vector;

out of context... Why do you need this on this patch?
or separated patch?

>
>         power_domain = intel_display_port_aux_power_domain(intel_encoder);
>         intel_display_power_get(to_i915(dev), power_domain);
> @@ -4372,9 +4544,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
>         }
>
>  out:
> -       if ((status != connector_status_connected) &&
> -           (intel_dp->is_mst == false))

This should be in a separated patch I believe. There is no explanation
why you don't need this for MST

> +       if (status != connector_status_connected) {
>                 intel_dp_unset_edid(intel_dp);
> +               intel_dp->upfront_done = false;
> +               intel_dp->max_lanes_upfront = 0;
> +               intel_dp->max_link_rate_upfront = 0;
> +       }
>
>         intel_display_power_put(to_i915(dev), power_domain);
>         return;
> @@ -5618,6 +5793,13 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
>         if (type == DRM_MODE_CONNECTOR_eDP)
>                 intel_encoder->type = INTEL_OUTPUT_EDP;
>
> +       /* Initialize upfront link training vfunc for DP */
> +       if (intel_encoder->type != INTEL_OUTPUT_EDP) {
> +               if (IS_BROXTON(dev_priv) || IS_SKYLAKE(dev_priv) ||
> +                   IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))

This should be HAS_DDI(dev_priv), otherwise we have the risk to forget
a platform, like we are leaving Kabylake behind.

> +                       intel_dp->upfront_link_train = intel_ddi_link_train;
> +       }
> +
>         /* eDP only on port B and/or C on vlv/chv */
>         if (WARN_ON((IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) &&
>                     is_edp(intel_dp) && port != PORT_B && port != PORT_C))
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index f1e08f0..b6f380b 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -304,7 +304,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>         intel_dp_set_idle_link_train(intel_dp);
>
>         return intel_dp->channel_eq_status;
> -
>  }
>
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 5b97a7d4..e5ab375 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -882,6 +882,12 @@ struct intel_dp {
>         enum hdmi_force_audio force_audio;
>         bool limited_color_range;
>         bool color_range_auto;
> +
> +       /* Upfront link train parameters */
> +       int max_link_rate_upfront;
> +       uint8_t max_lanes_upfront;
> +       bool upfront_done;
> +
>         uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
>         uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
>         uint8_t downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
> @@ -939,6 +945,11 @@ struct intel_dp {
>         /* This is called before a link training is starterd */
>         void (*prepare_link_retrain)(struct intel_dp *intel_dp);
>
> +       /* For Upfront link training */
> +       bool (*upfront_link_train)(struct intel_dp *intel_dp, int clock,
> +                                  uint8_t lane_count, bool link_mst,
> +                                  bool is_upfront);
> +
>         /* Displayport compliance testing */
>         unsigned long compliance_test_type;
>         unsigned long compliance_test_data;
> @@ -1161,7 +1172,8 @@ void intel_ddi_clock_get(struct intel_encoder *encoder,
>  void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
>  uint32_t ddi_signal_levels(struct intel_dp *intel_dp);
>  bool intel_ddi_link_train(struct intel_dp *intel_dp, int max_link_rate,
> -                         uint8_t max_lane_count, bool link_mst);
> +                         uint8_t max_lane_count, bool link_mst,
> +                         bool is_upfront);
>  struct intel_shared_dpll *intel_ddi_get_link_dpll(struct intel_dp *intel_dp,
>                                                   int clock);
>  unsigned int intel_fb_align_height(struct drm_device *dev,
> --
> 1.9.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v2 12/14] drm/i915: Remove the link rate and lane count loop in compute config
  2016-09-08 20:02   ` [PATCH v2 12/14] drm/i915: Remove the link rate and lane count loop in compute config Manasi Navare
@ 2016-09-13  1:14     ` Pandiyan, Dhinakaran
  2016-09-14  1:05       ` Manasi Navare
  0 siblings, 1 reply; 81+ messages in thread
From: Pandiyan, Dhinakaran @ 2016-09-13  1:14 UTC (permalink / raw)
  To: Navare, Manasi D; +Cc: intel-gfx

On Thu, 2016-09-08 at 13:02 -0700, Manasi Navare wrote:
> While configuring the pipe during modeset, it should use
> max clock and max lane count and reduce the bpp until
> the requested mode rate is less than or equal to
> available link BW.
> This is required to pass DP Compliance.
> 
> v2:
> * Removed the loop since we use max values of clock
> and lane count (Dhinakaran Pandiyan)
> 
> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp.c | 22 ++++++++--------------
>  1 file changed, 8 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 1378116..60c8857 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1567,20 +1567,14 @@ intel_dp_compute_config(struct intel_encoder *encoder,
>  	for (; bpp >= 6*3; bpp -= 2*3) {
>  		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
>  						   bpp);
> -
> -		for (clock = min_clock; clock <= max_clock; clock++) {
> -			for (lane_count = min_lane_count;
> -				lane_count <= max_lane_count;
> -				lane_count <<= 1) {
> -
> -				link_clock = common_rates[clock];
> -				link_avail = intel_dp_max_data_rate(link_clock,
> -								    lane_count);
> -
> -				if (mode_rate <= link_avail) {
> -					goto found;
> -				}
> -			}
> +		clock = max_clock;
> +		lane_count = max_lane_count;

Do we still need lane_count? We can eliminate it if it's always going to
be max_lane_count. 


> +		link_clock = common_rates[clock];

Same here for link_clock.

> +		link_avail = intel_dp_max_data_rate(link_clock,
> +						    lane_count);
> +
> +		if (mode_rate <= link_avail) {
> +			goto found;

Print KMS debug if we cannot satisfy the mode_rate at the max DP link
rate?

>  		}
>  	}
>  

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

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

* Re: [PATCH v3 8/14] drm/i915/dp: Move max. vswing check to it's own function
  2016-09-08  7:38       ` Mika Kahola
@ 2016-09-13 11:44         ` Jani Nikula
  0 siblings, 0 replies; 81+ messages in thread
From: Jani Nikula @ 2016-09-13 11:44 UTC (permalink / raw)
  To: mika.kahola, Manasi Navare, intel-gfx; +Cc: Dhinakaran Pandiyan

On Thu, 08 Sep 2016, Mika Kahola <mika.kahola@intel.com> wrote:
> This compiler warning is fixed with the next patch of the series.
>
> drivers/gpu/drm/i915/intel_dp_link_training.c: In function
> ‘intel_dp_link_training_clock_recovery’:
> drivers/gpu/drm/i915/intel_dp_link_training.c:131:6: warning: unused
> variable ‘i’ [-Wunused-variable]
>
> Therefore,

This may seem like a minor thing, but this is not the way we generally
work. Each patch must be self contained, and not depend on the follow-up
work, which may get stalled or reverted or whatnot.

And I don't like to receive stuff like this [1], especially for things
that were known in advance.


BR,
Jani.


[1] https://lists.freedesktop.org/archives/intel-gfx/2016-September/106306.html


>
> Reviewed-by: Mika Kahola <mika.kahola@intel.com>
>
> On Wed, 2016-09-07 at 11:28 -0700, Manasi Navare wrote:
>> From: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
>> 
>> Wrap the max. vswing check in a separate function.
>> This makes the clock recovery phase of DP link training cleaner
>> 
>> v3:
>> Fixed the paranthesis warning (Mika Kahola)
>> v2:
>> Fixed the Compiler warning (Mika Kahola)
>> 
>> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
>> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
>> ---
>>  drivers/gpu/drm/i915/intel_dp_link_training.c | 17 +++++++++++++----
>>  1 file changed, 13 insertions(+), 4 deletions(-)
>> 
>> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
>> b/drivers/gpu/drm/i915/intel_dp_link_training.c
>> index 0deebed..b9880cf 100644
>> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
>> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
>> @@ -112,6 +112,18 @@ intel_dp_update_link_train(struct intel_dp
>> *intel_dp)
>>  	return ret == intel_dp->lane_count;
>>  }
>>  
>> +static bool intel_dp_link_max_vswing_reached(struct intel_dp
>> *intel_dp)
>> +{
>> +	int lane;
>> +
>> +	for (lane = 0; lane < intel_dp->lane_count; lane++)
>> +		if ((intel_dp->train_set[lane] &
>> +		     DP_TRAIN_MAX_SWING_REACHED) == 0)
>> +			return false;
>> +
>> +	return true;
>> +}
>> +
>>  /* Enable corresponding port and start training pattern 1 */
>>  static void
>>  intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
>> @@ -170,10 +182,7 @@ intel_dp_link_training_clock_recovery(struct
>> intel_dp *intel_dp)
>>  		}
>>  
>>  		/* Check to see if we've tried the max voltage */
>> -		for (i = 0; i < intel_dp->lane_count; i++)
>> -			if ((intel_dp->train_set[i] &
>> DP_TRAIN_MAX_SWING_REACHED) == 0)
>> -				break;
>> -		if (i == intel_dp->lane_count) {
>> +		if (intel_dp_link_max_vswing_reached(intel_dp)) {
>>  			++loop_tries;
>>  			if (loop_tries == 5) {
>>  				DRM_ERROR("too many full retries,
>> give up\n");

-- 
Jani Nikula, Intel Open Source Technology Center
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant
  2016-09-07  7:50       ` Mika Kahola
@ 2016-09-13 16:09         ` Rodrigo Vivi
  0 siblings, 0 replies; 81+ messages in thread
From: Rodrigo Vivi @ 2016-09-13 16:09 UTC (permalink / raw)
  To: mika.kahola; +Cc: intel-gfx, Pandiyan, Dhinakaran

Patches 1 to 10 merged on dinq last week. Thanks for patches and
reviews and sorry for the delayed update.

On Wed, Sep 7, 2016 at 12:50 AM, Mika Kahola <mika.kahola@intel.com> wrote:
> Reviewed-by: Mika Kahola <mika.kahola@intel.com>
>
> On Fri, 2016-09-02 at 22:05 +0300, Pandiyan, Dhinakaran wrote:
>> On Fri, 2016-09-02 at 14:20 +0300, Mika Kahola wrote:
>> >
>> > On Thu, 2016-09-01 at 15:08 -0700, Manasi Navare wrote:
>> > >
>> > > Fix the number of tries in channel euqalization link training
>> > > sequence
>> > > according to DP 1.2 Spec. It returns a boolean depending on
>> > > channel
>> > > equalization pass or failure.
>> > >
>> > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com
>> > > >
>> > > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
>> > > ---
>> > >  drivers/gpu/drm/i915/intel_dp_link_training.c | 57 ++++++++++---
>> > > ----
>> > > ----------
>> > >  drivers/gpu/drm/i915/intel_drv.h              |  1 +
>> > >  2 files changed, 22 insertions(+), 36 deletions(-)
>> > >
>> > > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
>> > > b/drivers/gpu/drm/i915/intel_dp_link_training.c
>> > > index 13a0341..07f0159 100644
>> > > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
>> > > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
>> > > @@ -240,12 +240,12 @@ static u32 intel_dp_training_pattern(struct
>> > > intel_dp *intel_dp)
>> > >   return training_pattern;
>> > >  }
>> > >
>> > > -static void
>> > > +static bool
>> > >  intel_dp_link_training_channel_equalization(struct intel_dp
>> > > *intel_dp)
>> > >  {
>> > > - bool channel_eq = false;
>> > > - int tries, cr_tries;
>> > > + int tries;
>> > >   u32 training_pattern;
>> > > + uint8_t link_status[DP_LINK_STATUS_SIZE];
>> > >
>> > >   training_pattern = intel_dp_training_pattern(intel_dp);
>> > >
>> > > @@ -254,20 +254,11 @@
>> > > intel_dp_link_training_channel_equalization(struct intel_dp
>> > > *intel_dp)
>> > >                                training_pattern |
>> > >                                DP_LINK_SCRAMBLING_DISABLE)
>> > > ) {
>> > >           DRM_ERROR("failed to start channel
>> > > equalization\n");
>> > > -         return;
>> > > +         return false;
>> > >   }
>> > >
>> > > - tries = 0;
>> > > - cr_tries = 0;
>> > > - channel_eq = false;
>> > > - for (;;) {
>> > > -         uint8_t link_status[DP_LINK_STATUS_SIZE];
>> > > -
>> > > -         if (cr_tries > 5) {
>> > > -                 DRM_ERROR("failed to train DP,
>> > > aborting\n");
>> > > -                 intel_dp_dump_link_status(link_status);
>> > > -                 break;
>> > > -         }
>> > > + intel_dp->channel_eq_status = 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)) {
>> > > @@ -278,44 +269,38 @@
>> > > intel_dp_link_training_channel_equalization(struct intel_dp
>> > > *intel_dp)
>> > >           /* Make sure clock is still ok */
>> > >           if (!drm_dp_clock_recovery_ok(link_status,
>> > >                                         intel_dp-
>> > > >lane_count))
>> > > {
>> > > -                 intel_dp_link_training_clock_recovery(in
>> > > tel_
>> > > dp);
>> > > -                 intel_dp_set_link_train(intel_dp,
>> > > -                                         training_pattern
>> > > |
>> > > -                                         DP_LINK_SCRAMBLI
>> > > NG_D
>> > > ISABLE);
>> > > -                 cr_tries++;
>> > > -                 continue;
>> > > +                 intel_dp_dump_link_status(link_status);
>> > > +                 DRM_DEBUG_KMS("Clock recovery check
>> > > failed,
>> > > cannot "
>> > > +                               "continue channel
>> > > equalization\n");
>> > > +                 break;
>> > >           }
>> > This clock recovery check got me thinking. Do we really need to
>> > check
>> > if clock recovery is still ok within a loop? Could we move this
>> > outside
>> > the loop and return early if we have failed in clock recovery? One
>> > idea
>> > that I have in mind is that we wouldn't need to enter in channel
>> > equalization if we have failed with clock recovery earlier.
>> >
>> Looks like we do. This check helps us to break out of the loop for
>> link
>> rate reduction after adjusting drive setting.
> You're right we do that.
>>
>>
>> >
>> > >
>> > >
>> > >           if (drm_dp_channel_eq_ok(link_status,
>> > >                                    intel_dp->lane_count))
>> > > {
>> > > -                 channel_eq = true;
>> > > +                 intel_dp->channel_eq_status = true;
>> > > +                 DRM_DEBUG_KMS("Channel EQ done. DP
>> > > Training
>> > > "
>> > > +                               "successful\n");
>> > >                   break;
>> > >           }
>> > >
>> > > -         /* Try 5 times, then try clock recovery if that
>> > > fails */
>> > > -         if (tries > 5) {
>> > > -                 intel_dp_link_training_clock_recovery(in
>> > > tel_
>> > > dp);
>> > > -                 intel_dp_set_link_train(intel_dp,
>> > > -                                         training_pattern
>> > > |
>> > > -                                         DP_LINK_SCRAMBLI
>> > > NG_D
>> > > ISABLE);
>> > > -                 tries = 0;
>> > > -                 cr_tries++;
>> > > -                 continue;
>> > > -         }
>> > > -
>> > >           /* Update training set as requested by target */
>> > >           intel_get_adjust_train(intel_dp, link_status);
>> > >           if (!intel_dp_update_link_train(intel_dp)) {
>> > >                   DRM_ERROR("failed to update link
>> > > training\n");
>> > >                   break;
>> > >           }
>> > > -         ++tries;
>> > > + }
>> > > +
>> > > + /* Try 5 times, else fail and try at lower BW */
>> > > + if (tries == 5) {
>> > > +         intel_dp_dump_link_status(link_status);
>> > > +         DRM_DEBUG_KMS("Channel equalization failed 5
>> > > times\n");
>> > >   }
>> > >
>> > >   intel_dp_set_idle_link_train(intel_dp);
>> > >
>> > > - if (channel_eq)
>> > > -         DRM_DEBUG_KMS("Channel EQ done. DP Training
>> > > successful\n");
>> > > + return intel_dp->channel_eq_status;
>> > > +
>> > >  }
>> > >
>> > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
>> > > b/drivers/gpu/drm/i915/intel_drv.h
>> > > index efcd80b..e5bc976 100644
>> > > --- a/drivers/gpu/drm/i915/intel_drv.h
>> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
>> > > @@ -878,6 +878,7 @@ struct intel_dp {
>> > >   bool link_mst;
>> > >   bool has_audio;
>> > >   bool detect_done;
>> > > + bool channel_eq_status;
>> > >   enum hdmi_force_audio force_audio;
>> > >   bool limited_color_range;
>> > >   bool color_range_auto;
> --
> Mika Kahola - Intel OTC
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx



-- 
Rodrigo Vivi
Blog: http://blog.vivi.eng.br
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH v2 12/14] drm/i915: Remove the link rate and lane count loop in compute config
  2016-09-13  1:14     ` Pandiyan, Dhinakaran
@ 2016-09-14  1:05       ` Manasi Navare
  0 siblings, 0 replies; 81+ messages in thread
From: Manasi Navare @ 2016-09-14  1:05 UTC (permalink / raw)
  To: Pandiyan, Dhinakaran; +Cc: intel-gfx

On Mon, Sep 12, 2016 at 06:14:00PM -0700, Pandiyan, Dhinakaran wrote:
> On Thu, 2016-09-08 at 13:02 -0700, Manasi Navare wrote:
> > While configuring the pipe during modeset, it should use
> > max clock and max lane count and reduce the bpp until
> > the requested mode rate is less than or equal to
> > available link BW.
> > This is required to pass DP Compliance.
> > 
> > v2:
> > * Removed the loop since we use max values of clock
> > and lane count (Dhinakaran Pandiyan)
> > 
> > Signed-off-by: Manasi Navare <manasi.d.navare@intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_dp.c | 22 ++++++++--------------
> >  1 file changed, 8 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > index 1378116..60c8857 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -1567,20 +1567,14 @@ intel_dp_compute_config(struct intel_encoder *encoder,
> >  	for (; bpp >= 6*3; bpp -= 2*3) {
> >  		mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
> >  						   bpp);
> > -
> > -		for (clock = min_clock; clock <= max_clock; clock++) {
> > -			for (lane_count = min_lane_count;
> > -				lane_count <= max_lane_count;
> > -				lane_count <<= 1) {
> > -
> > -				link_clock = common_rates[clock];
> > -				link_avail = intel_dp_max_data_rate(link_clock,
> > -								    lane_count);
> > -
> > -				if (mode_rate <= link_avail) {
> > -					goto found;
> > -				}
> > -			}
> > +		clock = max_clock;
> > +		lane_count = max_lane_count;
> 
> Do we still need lane_count? We can eliminate it if it's always going to
> be max_lane_count. 
> 
>

This is just to follow the paradigm and use lane count and link rate here
while setting up the pipe config.

 
> > +		link_clock = common_rates[clock];
> 
> Same here for link_clock.
> 
> > +		link_avail = intel_dp_max_data_rate(link_clock,
> > +						    lane_count);
> > +
> > +		if (mode_rate <= link_avail) {
> > +			goto found;
> 
> Print KMS debug if we cannot satisfy the mode_rate at the max DP link
> rate?
>

Agree, but I am going to add it outside the bpp loop. You should see 
a new patch soon.

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

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

end of thread, other threads:[~2016-09-14  1:05 UTC | newest]

Thread overview: 81+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-01 22:08 [PATCH 00/14] Enable Upfront Link Training on DDI platforms Manasi Navare
2016-09-01 22:08 ` [PATCH v2 01/14] drm/i915: Don't pass crtc_state to intel_dp_set_link_params() Manasi Navare
2016-09-01 22:08 ` [PATCH v2 02/14] drm/i915: Remove ddi_pll_sel from intel_crtc_state Manasi Navare
2016-09-01 22:08 ` [PATCH v3 03/14] drm/i915: Split intel_ddi_pre_enable() into DP and HDMI versions Manasi Navare
2016-09-01 22:08 ` [PATCH v2 04/14] drm/i915: Split bxt_ddi_pll_select() Manasi Navare
2016-09-01 22:08 ` [PATCH 05/14] drm/i915: Split skl_get_dpll() Manasi Navare
2016-09-01 22:08 ` [PATCH 06/14] drm/i915: Split hsw_get_dpll() Manasi Navare
2016-09-01 22:08 ` [PATCH v3 07/14] drm/i915/dp: Add a standalone function to obtain shared dpll for HSW/BDW/SKL/BXT Manasi Navare
2016-09-02 20:06   ` Pandiyan, Dhinakaran
2016-09-07 22:08     ` Manasi Navare
2016-09-07 22:47   ` [PATCH v4 7/14] " Manasi Navare
2016-09-01 22:08 ` [PATCH 08/14] drm/i915/dp: Move max. vswing check to it's own function Manasi Navare
2016-09-02  8:05   ` Mika Kahola
2016-09-06  9:58     ` Mika Kahola
2016-09-06 21:25       ` Manasi Navare
2016-09-07  0:13   ` [PATCH v2 8/14] " Manasi Navare
2016-09-07  7:00     ` Mika Kahola
2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
2016-09-08  7:38       ` Mika Kahola
2016-09-13 11:44         ` Jani Nikula
2016-09-01 22:08 ` [PATCH 09/14] drm/dp/i915: Make clock recovery in the link training compliant with DP Spec 1.2 Manasi Navare
2016-09-02  9:16   ` Mika Kahola
2016-09-02 17:55     ` Pandiyan, Dhinakaran
2016-09-07  0:13   ` [PATCH v2 9/14] " Manasi Navare
2016-09-07  7:33     ` Mika Kahola
2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
2016-09-08  8:20       ` Mika Kahola
2016-09-01 22:08 ` [PATCH 10/14] drm/i915: Make DP link training channel equalization DP 1.2 Spec compliant Manasi Navare
2016-09-02 11:20   ` Mika Kahola
2016-09-02 19:05     ` Pandiyan, Dhinakaran
2016-09-07  7:50       ` Mika Kahola
2016-09-13 16:09         ` Rodrigo Vivi
2016-09-01 22:08 ` [PATCH 11/14] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
2016-09-02 12:03   ` David Weinehall
2016-09-06 17:34     ` Manasi Navare
2016-09-02 12:49   ` David Weinehall
2016-09-06 17:54     ` Manasi Navare
2016-09-02 13:00   ` Mika Kahola
2016-09-06 18:01     ` Manasi Navare
2016-09-02 19:52   ` Pandiyan, Dhinakaran
2016-09-02 20:01     ` Jim Bride
2016-09-07  0:13   ` [PATCH v2 " Manasi Navare
2016-09-07  9:47     ` Mika Kahola
2016-09-07 16:47       ` Jim Bride
2016-09-07 16:48       ` Manasi Navare
2016-09-07 18:28     ` [PATCH v3 " Manasi Navare
2016-09-08  0:30       ` [PATCH v4 " Manasi Navare
2016-09-08  9:32         ` Mika Kahola
2016-09-09  1:05         ` Rodrigo Vivi
2016-09-09  7:11           ` Jani Nikula
2016-09-09  7:11         ` Jani Nikula
2016-09-09 17:13           ` Manasi Navare
2016-09-09 23:29         ` [PATCH v5 " Manasi Navare
2016-09-01 22:08 ` [PATCH 12/14] drm/i915: Reverse the loop in intel_dp_compute_config Manasi Navare
2016-09-02 13:08   ` Mika Kahola
2016-09-08 14:47     ` Manasi Navare
2016-09-02 20:24   ` Pandiyan, Dhinakaran
2016-09-08 20:02   ` [PATCH v2 12/14] drm/i915: Remove the link rate and lane count loop in compute config Manasi Navare
2016-09-13  1:14     ` Pandiyan, Dhinakaran
2016-09-14  1:05       ` Manasi Navare
2016-09-01 22:08 ` [PATCH v11 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms) Manasi Navare
2016-09-07  0:13   ` [PATCH v12 " Manasi Navare
2016-09-07 18:28     ` [PATCH v13 " Manasi Navare
2016-09-08 12:10       ` Mika Kahola
2016-09-08 15:06         ` Manasi Navare
2016-09-08 17:22       ` [PATCH v14 " Manasi Navare
2016-09-08 20:02         ` [PATCH v15 " Manasi Navare
2016-09-09  7:34           ` Jani Nikula
2016-09-09 23:29           ` [PATCH 13-1/14] drm/i915: Change the placement of some static functions in intel_dp.c Manasi Navare
2016-09-12 23:21             ` Rodrigo Vivi
2016-09-09 23:29           ` [PATCH v16 13-2/14] drm/i915/dp: Enable Upfront link training on HSW/BDW/SKL/BXT Manasi Navare
2016-09-13  0:22             ` Rodrigo Vivi
2016-09-09  7:31         ` [PATCH v14 13/14] drm/i915/dp: Enable Upfront link training for typeC DP support on HSW/BDW/SKL/BXT (DDI platforms) Jani Nikula
2016-09-01 22:08 ` [PATCH 14/14] drm/i915/dp/mst: Add support for upfront link training for DP MST Manasi Navare
2016-09-07  0:13   ` [PATCH v2 " Manasi Navare
2016-09-07 10:53     ` Mika Kahola
2016-09-07 16:40       ` Jim Bride
2016-09-08 10:21         ` Mika Kahola
2016-09-08 11:50       ` Mika Kahola
2016-09-01 22:48 ` ✗ Fi.CI.BAT: failure for Enable upfront link training on DDI platforms (rev3) Patchwork
2016-09-07  0:54 ` ✗ Fi.CI.BAT: warning for Enable upfront link training on DDI platforms (rev8) Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.