Commit 70aff66c authored by Jani Nikula's avatar Jani Nikula Committed by Daniel Vetter

drm/i915/dp: do not write DP_TRAINING_PATTERN_SET all the time

Neither the DP spec nor the compliance test spec state or imply that we
should write the DP_TRAINING_PATTERN_SET at every voltage swing and
pre-emphasis change. Indeed we probably shouldn't. So don't.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=49402Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
Smoke-tested-by: default avatarPaulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 58c67ce9
...@@ -2318,7 +2318,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) ...@@ -2318,7 +2318,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
static bool static bool
intel_dp_set_link_train(struct intel_dp *intel_dp, intel_dp_set_link_train(struct intel_dp *intel_dp,
uint32_t dp_reg_value, uint32_t *DP,
uint8_t dp_train_pat) uint8_t dp_train_pat)
{ {
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
...@@ -2354,50 +2354,51 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, ...@@ -2354,50 +2354,51 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
I915_WRITE(DP_TP_CTL(port), temp); I915_WRITE(DP_TP_CTL(port), temp);
} else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) { } else if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || port != PORT_A)) {
dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT; *DP &= ~DP_LINK_TRAIN_MASK_CPT;
switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
case DP_TRAINING_PATTERN_DISABLE: case DP_TRAINING_PATTERN_DISABLE:
dp_reg_value |= DP_LINK_TRAIN_OFF_CPT; *DP |= DP_LINK_TRAIN_OFF_CPT;
break; break;
case DP_TRAINING_PATTERN_1: case DP_TRAINING_PATTERN_1:
dp_reg_value |= DP_LINK_TRAIN_PAT_1_CPT; *DP |= DP_LINK_TRAIN_PAT_1_CPT;
break; break;
case DP_TRAINING_PATTERN_2: case DP_TRAINING_PATTERN_2:
dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT; *DP |= DP_LINK_TRAIN_PAT_2_CPT;
break; break;
case DP_TRAINING_PATTERN_3: case DP_TRAINING_PATTERN_3:
DRM_ERROR("DP training pattern 3 not supported\n"); DRM_ERROR("DP training pattern 3 not supported\n");
dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT; *DP |= DP_LINK_TRAIN_PAT_2_CPT;
break; break;
} }
} else { } else {
dp_reg_value &= ~DP_LINK_TRAIN_MASK; *DP &= ~DP_LINK_TRAIN_MASK;
switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) { switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
case DP_TRAINING_PATTERN_DISABLE: case DP_TRAINING_PATTERN_DISABLE:
dp_reg_value |= DP_LINK_TRAIN_OFF; *DP |= DP_LINK_TRAIN_OFF;
break; break;
case DP_TRAINING_PATTERN_1: case DP_TRAINING_PATTERN_1:
dp_reg_value |= DP_LINK_TRAIN_PAT_1; *DP |= DP_LINK_TRAIN_PAT_1;
break; break;
case DP_TRAINING_PATTERN_2: case DP_TRAINING_PATTERN_2:
dp_reg_value |= DP_LINK_TRAIN_PAT_2; *DP |= DP_LINK_TRAIN_PAT_2;
break; break;
case DP_TRAINING_PATTERN_3: case DP_TRAINING_PATTERN_3:
DRM_ERROR("DP training pattern 3 not supported\n"); DRM_ERROR("DP training pattern 3 not supported\n");
dp_reg_value |= DP_LINK_TRAIN_PAT_2; *DP |= DP_LINK_TRAIN_PAT_2;
break; break;
} }
} }
I915_WRITE(intel_dp->output_reg, dp_reg_value); I915_WRITE(intel_dp->output_reg, *DP);
POSTING_READ(intel_dp->output_reg); POSTING_READ(intel_dp->output_reg);
intel_dp_aux_native_write_1(intel_dp, ret = intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET,
DP_TRAINING_PATTERN_SET, dp_train_pat);
dp_train_pat); if (ret != 1)
return false;
if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) != if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) !=
DP_TRAINING_PATTERN_DISABLE) { DP_TRAINING_PATTERN_DISABLE) {
...@@ -2412,6 +2413,37 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, ...@@ -2412,6 +2413,37 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
return true; return true;
} }
static bool
intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP,
uint8_t dp_train_pat)
{
memset(intel_dp->train_set, 0, 4);
intel_dp_set_signal_levels(intel_dp, DP);
return intel_dp_set_link_train(intel_dp, DP, dp_train_pat);
}
static bool
intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP,
uint8_t link_status[DP_LINK_STATUS_SIZE])
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
intel_get_adjust_train(intel_dp, link_status);
intel_dp_set_signal_levels(intel_dp, DP);
I915_WRITE(intel_dp->output_reg, *DP);
POSTING_READ(intel_dp->output_reg);
ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_LANE0_SET,
intel_dp->train_set,
intel_dp->lane_count);
return ret == intel_dp->lane_count;
}
static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) static 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 intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
...@@ -2464,21 +2496,19 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) ...@@ -2464,21 +2496,19 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
DP |= DP_PORT_EN; DP |= DP_PORT_EN;
memset(intel_dp->train_set, 0, 4); /* clock recovery */
if (!intel_dp_reset_link_train(intel_dp, &DP,
DP_TRAINING_PATTERN_1 |
DP_LINK_SCRAMBLING_DISABLE)) {
DRM_ERROR("failed to enable link training\n");
return;
}
voltage = 0xff; voltage = 0xff;
voltage_tries = 0; voltage_tries = 0;
loop_tries = 0; loop_tries = 0;
for (;;) { for (;;) {
/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ uint8_t link_status[DP_LINK_STATUS_SIZE];
uint8_t link_status[DP_LINK_STATUS_SIZE];
intel_dp_set_signal_levels(intel_dp, &DP);
/* Set training pattern 1 */
if (!intel_dp_set_link_train(intel_dp, DP,
DP_TRAINING_PATTERN_1 |
DP_LINK_SCRAMBLING_DISABLE))
break;
drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd); drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
if (!intel_dp_get_link_status(intel_dp, link_status)) { if (!intel_dp_get_link_status(intel_dp, link_status)) {
...@@ -2501,7 +2531,9 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) ...@@ -2501,7 +2531,9 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
DRM_DEBUG_KMS("too many full retries, give up\n"); DRM_DEBUG_KMS("too many full retries, give up\n");
break; break;
} }
memset(intel_dp->train_set, 0, 4); intel_dp_reset_link_train(intel_dp, &DP,
DP_TRAINING_PATTERN_1 |
DP_LINK_SCRAMBLING_DISABLE);
voltage_tries = 0; voltage_tries = 0;
continue; continue;
} }
...@@ -2517,8 +2549,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) ...@@ -2517,8 +2549,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
voltage_tries = 0; voltage_tries = 0;
voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Compute new intel_dp->train_set as requested by target */ /* Update training set as requested by target */
intel_get_adjust_train(intel_dp, link_status); if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
DRM_ERROR("failed to update link training\n");
break;
}
} }
intel_dp->DP = DP; intel_dp->DP = DP;
...@@ -2532,11 +2567,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ...@@ -2532,11 +2567,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
uint32_t DP = intel_dp->DP; uint32_t DP = intel_dp->DP;
/* channel equalization */ /* channel equalization */
if (!intel_dp_set_link_train(intel_dp, &DP,
DP_TRAINING_PATTERN_2 |
DP_LINK_SCRAMBLING_DISABLE)) {
DRM_ERROR("failed to start channel equalization\n");
return;
}
tries = 0; tries = 0;
cr_tries = 0; cr_tries = 0;
channel_eq = false; channel_eq = false;
for (;;) { for (;;) {
uint8_t link_status[DP_LINK_STATUS_SIZE]; uint8_t link_status[DP_LINK_STATUS_SIZE];
if (cr_tries > 5) { if (cr_tries > 5) {
DRM_ERROR("failed to train DP, aborting\n"); DRM_ERROR("failed to train DP, aborting\n");
...@@ -2544,21 +2586,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ...@@ -2544,21 +2586,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
break; break;
} }
intel_dp_set_signal_levels(intel_dp, &DP);
/* channel eq pattern */
if (!intel_dp_set_link_train(intel_dp, DP,
DP_TRAINING_PATTERN_2 |
DP_LINK_SCRAMBLING_DISABLE))
break;
drm_dp_link_train_channel_eq_delay(intel_dp->dpcd); drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
if (!intel_dp_get_link_status(intel_dp, link_status)) if (!intel_dp_get_link_status(intel_dp, link_status)) {
DRM_ERROR("failed to get link status\n");
break; break;
}
/* Make sure clock is still ok */ /* Make sure clock is still ok */
if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_set_link_train(intel_dp, &DP,
DP_TRAINING_PATTERN_2 |
DP_LINK_SCRAMBLING_DISABLE);
cr_tries++; cr_tries++;
continue; continue;
} }
...@@ -2572,13 +2611,19 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ...@@ -2572,13 +2611,19 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
if (tries > 5) { if (tries > 5) {
intel_dp_link_down(intel_dp); intel_dp_link_down(intel_dp);
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_set_link_train(intel_dp, &DP,
DP_TRAINING_PATTERN_2 |
DP_LINK_SCRAMBLING_DISABLE);
tries = 0; tries = 0;
cr_tries++; cr_tries++;
continue; continue;
} }
/* Compute new intel_dp->train_set as requested by target */ /* Update training set as requested by target */
intel_get_adjust_train(intel_dp, link_status); if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) {
DRM_ERROR("failed to update link training\n");
break;
}
++tries; ++tries;
} }
...@@ -2593,7 +2638,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ...@@ -2593,7 +2638,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
void intel_dp_stop_link_train(struct intel_dp *intel_dp) void intel_dp_stop_link_train(struct intel_dp *intel_dp)
{ {
intel_dp_set_link_train(intel_dp, intel_dp->DP, intel_dp_set_link_train(intel_dp, &intel_dp->DP,
DP_TRAINING_PATTERN_DISABLE); DP_TRAINING_PATTERN_DISABLE);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment