All of lore.kernel.org
 help / color / mirror / Atom feed
From: Manasi Navare <manasi.d.navare@intel.com>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH v17 4/5] drm/i915/dp: Enable Upfront link training on DDI platforms
Date: Tue, 13 Sep 2016 18:08:18 -0700	[thread overview]
Message-ID: <1473815299-26961-5-git-send-email-manasi.d.navare@intel.com> (raw)
In-Reply-To: <1473815299-26961-1-git-send-email-manasi.d.navare@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 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 v16:
* Use HAS_DDI macro for enabling this feature (Rodrigo Vivi)
* Fix some unnecessary removals/changes due to rebase (Rodrigo Vivi)

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               | 190 +++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_dp_link_training.c |   1 -
 drivers/gpu/drm/i915/intel_drv.h              |  14 +-
 4 files changed, 218 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 4d3a931..1b24d71 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1676,7 +1676,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;
 }
@@ -2464,7 +2465,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;
@@ -2513,6 +2514,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);
@@ -2521,6 +2523,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 a319102..9042d28 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)
 {
@@ -258,6 +303,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,
@@ -265,6 +321,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)
@@ -286,6 +428,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;
@@ -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];
@@ -1596,7 +1769,6 @@ found:
 	}
 
 	pipe_config->lane_count = lane_count;
-
 	pipe_config->pipe_bpp = bpp;
 	pipe_config->port_clock = common_rates[clock];
 
@@ -4374,8 +4546,12 @@ intel_dp_long_pulse(struct intel_connector *intel_connector)
 
 out:
 	if ((status != connector_status_connected) &&
-	    (intel_dp->is_mst == false))
+	    (intel_dp->is_mst == false)) {
 		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;
@@ -5619,6 +5795,12 @@ 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 (HAS_DDI(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 69c8051..fc2f1bc 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

  parent reply	other threads:[~2016-09-14  1:08 UTC|newest]

Thread overview: 56+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-14  1:08 [PATCH 0/5] Remaining patches for upfront link training on DDI platforms Manasi Navare
2016-09-14  1:08 ` [PATCH v5 1/5] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
2016-09-14  8:15   ` Mika Kahola
2016-09-15 19:56     ` Manasi Navare
2016-09-14  1:08 ` [PATCH v3 2/5] drm/i915: Remove the link rate and lane count loop in compute config Manasi Navare
2016-09-14  1:08 ` [PATCH v2 3/5] drm/i915: Change the placement of some static functions in intel_dp.c Manasi Navare
2016-09-15  7:41   ` Mika Kahola
2016-09-15 19:08     ` Manasi Navare
2016-09-14  1:08 ` Manasi Navare [this message]
2016-09-14  1:08 ` [PATCH v3 5/5] drm/i915/dp/mst: Add support for upfront link training for DP MST Manasi Navare
2016-09-15 17:48   ` Pandiyan, Dhinakaran
2016-09-15 19:25     ` Manasi Navare
2016-09-19 17:03       ` Jim Bride
2016-09-19 17:22         ` Manasi Navare
2016-09-14  5:38 ` ✓ Fi.CI.BAT: success for Remaining patches for upfront link training on DDI platforms Patchwork
2016-09-16  0:03 ` [PATCH 0/6] " Manasi Navare
2016-09-16  0:03   ` [PATCH v6 1/6] drm/i915: Fallback to lower link rate and lane count during link training Manasi Navare
2016-09-16  9:29     ` Mika Kahola
2016-09-16 18:45     ` [PATCH v7 " Manasi Navare
2016-09-26 13:39       ` Jani Nikula
2016-09-27 15:25         ` Manasi Navare
2016-09-27 17:07           ` Jani Nikula
2016-09-29  6:41             ` Manasi Navare
2016-09-29 11:26               ` Jani Nikula
2016-09-29 11:44                 ` Chris Wilson
2016-09-29 15:10                   ` Ville Syrjälä
2016-09-29 15:48                     ` Jani Nikula
2016-09-29 16:05                       ` Manasi Navare
2016-09-29 23:17                         ` Manasi Navare
2016-10-03 23:29                           ` Manasi Navare
2016-09-16  0:04   ` [PATCH v3 2/6] drm/i915: Remove the link rate and lane count loop in compute config Manasi Navare
2016-09-26 13:41     ` Jani Nikula
2016-09-27 13:39       ` Jani Nikula
2016-09-27 22:13         ` Manasi Navare
2016-09-28  7:14           ` Jani Nikula
2016-09-28 22:30             ` Manasi Navare
2016-09-27 21:55       ` Manasi Navare
2016-09-28  7:38         ` Jani Nikula
2016-09-28 16:45           ` Manasi Navare
2016-09-29 14:52             ` Jani Nikula
2016-09-16  0:04   ` [PATCH v3 3/6] drm/i915: Change the placement of some static functions in intel_dp.c Manasi Navare
2016-09-16  8:12     ` Mika Kahola
2016-09-16  0:04   ` [PATCH 4/6] drm/i915: Code cleanup to use dev_priv and INTEL_GEN Manasi Navare
2016-09-16  7:40     ` Mika Kahola
2016-09-26 13:45     ` Jani Nikula
2016-09-28  0:03       ` Manasi Navare
2016-09-16  0:04   ` [PATCH v17 5/6] drm/i915/dp: Enable Upfront link training on DDI platforms Manasi Navare
2016-09-20 22:04     ` [PATCH v18 " Manasi Navare
2016-09-27 13:59       ` Jani Nikula
2016-09-29 12:15       ` Jani Nikula
2016-09-29 16:05         ` Jani Nikula
2016-09-16  0:04   ` [PATCH v3 6/6] drm/i915/dp/mst: Add support for upfront link training for DP MST Manasi Navare
2016-09-16  0:47   ` ✓ Fi.CI.BAT: success for series starting with [v6,1/6] drm/i915: Fallback to lower link rate and lane count during link training Patchwork
2016-09-16 19:25   ` ✓ Fi.CI.BAT: success for series starting with [v7,1/6] drm/i915: Fallback to lower link rate and lane count during link training (rev2) Patchwork
2016-09-20  8:45   ` [PATCH 0/6] Remaining patches for upfront link training on DDI platforms Jani Nikula
2016-09-20 22:49   ` ✓ Fi.CI.BAT: success for series starting with [v7,1/6] drm/i915: Fallback to lower link rate and lane count during link training (rev3) Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1473815299-26961-5-git-send-email-manasi.d.navare@intel.com \
    --to=manasi.d.navare@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.