From: Todd Previte <tprevite@gmail.com>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH 08/12] drm/i915: Improve reliability for Displayport link training
Date: Mon, 14 Jul 2014 12:10:43 -0700 [thread overview]
Message-ID: <1405365047-6866-9-git-send-email-tprevite@gmail.com> (raw)
In-Reply-To: <1405365047-6866-1-git-send-email-tprevite@gmail.com>
Link training for Displayport can fail in many ways and at multiple different points
during the training process. Previously, errors were logged but no additional action
was taken based on them. Consequently, training attempts could continue even after
errors have occured that would prevent successful link training. This patch updates
the link training functions and where/how they're used to be more intelligent about
failures and to stop trying to train the link when it's a lost cause.
Signed-off-by: Todd Previte <tprevite@gmail.com>
---
drivers/gpu/drm/i915/intel_ddi.c | 23 +++++++++--
drivers/gpu/drm/i915/intel_dp.c | 89 +++++++++++++++++++++++++++++-----------
drivers/gpu/drm/i915/intel_drv.h | 7 ++--
3 files changed, 90 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index ded6013..c0727b8 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1246,6 +1246,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
enum port port = intel_ddi_get_encoder_port(intel_encoder);
int type = intel_encoder->type;
+ uint8_t fail_code = 0;
if (crtc->config.has_audio) {
DRM_DEBUG_DRIVER("Audio on pipe %c on DDI\n",
@@ -1274,10 +1275,19 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
intel_dp->DP |= DDI_PORT_WIDTH(intel_dp->lane_count);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
- intel_dp_start_link_train(intel_dp);
- intel_dp_complete_link_train(intel_dp);
+ if (!intel_dp_start_link_train(intel_dp)) {
+ fail_code = 1;
+ goto failed;
+ }
+ if (!intel_dp_complete_link_train(intel_dp)) {
+ fail_code = 2;
+ goto failed;
+ }
if (port != PORT_A)
- intel_dp_stop_link_train(intel_dp);
+ if (!intel_dp_stop_link_train(intel_dp)) {
+ fail_code = 3;
+ goto failed;
+ }
} else if (type == INTEL_OUTPUT_HDMI) {
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
@@ -1285,6 +1295,13 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
crtc->config.has_hdmi_sink,
&crtc->config.adjusted_mode);
}
+
+ return;
+
+failed:
+ /* Clear link training here */
+ intel_dp_set_idle_link_train(enc_to_intel_dp(encoder));
+ DRM_DEBUG_KMS("Failed to pre-enable DP, fail code %d\n", fail_code);
}
static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 88f1bbe..1c6ee34 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2018,23 +2018,42 @@ static void chv_post_disable_dp(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->dpio_lock);
}
-static void intel_enable_dp(struct intel_encoder *encoder)
+static bool intel_enable_dp(struct intel_encoder *encoder)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t dp_reg = I915_READ(intel_dp->output_reg);
+ uint8_t fail_code = 0;
+ /* FIXME: Not sure this needs to be a WARN() */
if (WARN_ON(dp_reg & DP_PORT_EN))
- return;
+ return false;
intel_edp_panel_vdd_on(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
- intel_dp_start_link_train(intel_dp);
+ if (!intel_dp_start_link_train(intel_dp)) {
+ fail_code = 1;
+ goto failed;
+ }
intel_edp_panel_on(intel_dp);
edp_panel_vdd_off(intel_dp, true);
- intel_dp_complete_link_train(intel_dp);
- intel_dp_stop_link_train(intel_dp);
+ if (!intel_dp_complete_link_train(intel_dp)) {
+ fail_code = 2;
+ goto failed;
+ }
+ if (!intel_dp_stop_link_train(intel_dp)) {
+ fail_code = 3;
+ goto failed;
+ }
+
+ return true;
+
+failed:
+ /* Clear link training here */
+ intel_dp_set_idle_link_train(intel_dp);
+ DRM_DEBUG_KMS("Failed to enable DP with code %d\n", fail_code);
+ return false;
}
static void g4x_enable_dp(struct intel_encoder *encoder)
@@ -2956,7 +2975,7 @@ intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP,
return ret == intel_dp->lane_count;
}
-static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
+void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -2988,7 +3007,7 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
}
/* Enable corresponding port and start training pattern 1 */
-void
+bool
intel_dp_start_link_train(struct intel_dp *intel_dp)
{
struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base;
@@ -3007,11 +3026,17 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
link_config[1] = intel_dp->lane_count;
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 (drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2) != 2) {
+ DRM_DEBUG_KMS("Failed to write sink DPCD for link rate and lane count\n");
+ goto failed;
+ }
link_config[0] = 0;
link_config[1] = DP_SET_ANSI_8B10B;
- drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
+ if (drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2) != 2) {
+ DRM_DEBUG_KMS("Failed to write sink DPCD for downspread control\n");
+ goto failed;
+ }
DP |= DP_PORT_EN;
@@ -3020,7 +3045,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
DP_TRAINING_PATTERN_1 |
DP_LINK_SCRAMBLING_DISABLE)) {
DRM_ERROR("failed to enable link training\n");
- return;
+ goto failed;
}
voltage = 0xff;
@@ -3032,12 +3057,12 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
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;
+ goto failed;
}
if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
DRM_DEBUG_KMS("clock recovery OK\n");
- break;
+ goto cr_done;
}
/* Check to see if we've tried the max voltage */
@@ -3048,7 +3073,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
++loop_tries;
if (loop_tries == 5) {
DRM_ERROR("too many full retries, give up\n");
- break;
+ goto failed;
}
intel_dp_reset_link_train(intel_dp, &DP,
DP_TRAINING_PATTERN_1 |
@@ -3062,7 +3087,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
++voltage_tries;
if (voltage_tries == 5) {
DRM_ERROR("too many voltage retries, give up\n");
- break;
+ goto failed;
}
} else
voltage_tries = 0;
@@ -3071,14 +3096,20 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
/* Update training set as requested by target */
if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
DRM_ERROR("failed to update link training\n");
- break;
+ goto failed;
}
}
+cr_done:
intel_dp->DP = DP;
+ return true;
+
+failed:
+ DRM_DEBUG_KMS("Failed to initiate link training\n");
+ return false;
}
-void
+bool
intel_dp_complete_link_train(struct intel_dp *intel_dp)
{
bool channel_eq = false;
@@ -3095,7 +3126,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
training_pattern |
DP_LINK_SCRAMBLING_DISABLE)) {
DRM_ERROR("failed to start channel equalization\n");
- return;
+ return false;
}
tries = 0;
@@ -3154,14 +3185,17 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
intel_dp->DP = DP;
- if (channel_eq)
+ if (channel_eq) {
DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
+ return true;
+ }
+ return false;
}
-void intel_dp_stop_link_train(struct intel_dp *intel_dp)
+bool intel_dp_stop_link_train(struct intel_dp *intel_dp)
{
- intel_dp_set_link_train(intel_dp, &intel_dp->DP,
+ return intel_dp_set_link_train(intel_dp, &intel_dp->DP,
DP_TRAINING_PATTERN_DISABLE);
}
@@ -3600,9 +3634,18 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
intel_encoder->base.name);
- intel_dp_start_link_train(intel_dp);
- intel_dp_complete_link_train(intel_dp);
- intel_dp_stop_link_train(intel_dp);
+ if (!intel_dp_start_link_train(intel_dp)) {
+ DRM_DEBUG_KMS("Start link training failed\n");
+ return;
+ }
+ if (!intel_dp_complete_link_train(intel_dp)) {
+ DRM_DEBUG_KMS("Complete link training failed\n");
+ return;
+ }
+ if (!intel_dp_stop_link_train(intel_dp)) {
+ DRM_DEBUG_KMS("Stop link training failed\n");
+ return;
+ }
}
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index d2ae54f..79876df 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -844,9 +844,10 @@ int intel_dp_set_config(struct drm_mode_set *set);
void intel_dp_init(struct drm_device *dev, int 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_start_link_train(struct intel_dp *intel_dp);
-void intel_dp_complete_link_train(struct intel_dp *intel_dp);
-void intel_dp_stop_link_train(struct intel_dp *intel_dp);
+bool intel_dp_start_link_train(struct intel_dp *intel_dp);
+bool intel_dp_complete_link_train(struct intel_dp *intel_dp);
+bool intel_dp_stop_link_train(struct intel_dp *intel_dp);
+void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
void intel_dp_encoder_destroy(struct drm_encoder *encoder);
void intel_dp_check_link_status(struct intel_dp *intel_dp);
--
1.9.1
next prev parent reply other threads:[~2014-07-14 19:11 UTC|newest]
Thread overview: 44+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-14 19:10 [PATCH v2] Displayport compliance testing Todd Previte
2014-07-14 19:10 ` [PATCH 01/12] drm/i915: Add automated testing support for " Todd Previte
2014-07-21 22:09 ` Paulo Zanoni
2014-07-30 14:49 ` Paulo Zanoni
2014-07-14 19:10 ` [PATCH 02/12] drm/i915: Add a function to compute the EDID checksum for Displayport compliance Todd Previte
2014-07-21 22:28 ` Paulo Zanoni
2014-07-14 19:10 ` [PATCH 03/12] drm/i915: Add counters in the drm_dp_aux struct for I2C NACKs and DEFERs Todd Previte
2014-07-21 22:37 ` Paulo Zanoni
2014-11-04 22:17 ` [PATCH 02/10] " Todd Previte
2014-11-04 22:26 ` Daniel Vetter
2014-07-14 19:10 ` [PATCH 04/12] drm/i915: Add wrapper function for intel_crtc_set_config() Todd Previte
2014-07-21 23:34 ` Paulo Zanoni
2014-07-14 19:10 ` [PATCH 05/12] drm/i915: Add a function to get the EDID preferred mode for Displayport compliance testing Todd Previte
2014-07-21 23:41 ` Paulo Zanoni
2014-07-14 19:10 ` [PATCH 06/12] drm/i915: Add a constant and function for getting the Displayport compliance failsafe video mode Todd Previte
2014-07-21 23:42 ` Paulo Zanoni
2014-07-14 19:10 ` [PATCH 07/12] drm/i915: Update EDID automated test function for Displayport compliance Todd Previte
2014-07-29 22:37 ` Paulo Zanoni
2014-07-31 18:27 ` Todd Previte
2014-07-14 19:10 ` Todd Previte [this message]
2014-07-30 14:07 ` [PATCH 08/12] drm/i915: Improve reliability for Displayport link training Paulo Zanoni
2014-07-30 15:25 ` Daniel Vetter
2014-07-14 19:10 ` [PATCH 09/12] drm/i915: Update intel_dp_check_link_status() for Displayport compliance testing Todd Previte
2014-07-30 14:29 ` Paulo Zanoni
2014-07-14 19:10 ` [PATCH 10/12] drm/i915: Update link training automated test function for Displayport compliance Todd Previte
2014-07-22 6:15 ` Daniel Vetter
2014-07-22 20:40 ` Jesse Barnes
2014-07-22 20:44 ` Daniel Vetter
2014-07-22 21:03 ` Jesse Barnes
2014-07-14 19:10 ` [PATCH 11/12] drm/i915: Minor code clean up in intel_dp.c Todd Previte
2014-07-15 7:47 ` Daniel Vetter
2014-07-15 15:35 ` Todd Previte
2014-07-14 19:10 ` [PATCH 12/12] drm/i915: Add a delay in Displayport AUX transactions for compliance testing Todd Previte
2014-07-15 7:46 ` Daniel Vetter
2014-07-15 15:34 ` Todd Previte
2014-07-30 14:46 ` Paulo Zanoni
2014-07-22 6:41 ` [PATCH v2] Displayport " Daniel Vetter
2014-07-22 20:48 ` Jesse Barnes
2014-07-22 20:53 ` Daniel Vetter
2014-07-22 21:11 ` Jesse Barnes
2014-07-29 21:53 ` Paulo Zanoni
2014-07-30 9:31 ` Daniel Vetter
2014-07-31 18:27 ` Todd Previte
2014-07-22 20:57 ` Jesse Barnes
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=1405365047-6866-9-git-send-email-tprevite@gmail.com \
--to=tprevite@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox