mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 05:41:55 +00:00
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=49402 Signed-off-by: Jani Nikula <jani.nikula@intel.com> Smoke-tested-by: Paulo Zanoni <paulo.r.zanoni@intel.com> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
parent
58c67ce9f0
commit
70aff66c95
@ -2318,7 +2318,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP)
|
||||
|
||||
static bool
|
||||
intel_dp_set_link_train(struct intel_dp *intel_dp,
|
||||
uint32_t dp_reg_value,
|
||||
uint32_t *DP,
|
||||
uint8_t dp_train_pat)
|
||||
{
|
||||
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,
|
||||
I915_WRITE(DP_TP_CTL(port), temp);
|
||||
|
||||
} 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) {
|
||||
case DP_TRAINING_PATTERN_DISABLE:
|
||||
dp_reg_value |= DP_LINK_TRAIN_OFF_CPT;
|
||||
*DP |= DP_LINK_TRAIN_OFF_CPT;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_1:
|
||||
dp_reg_value |= DP_LINK_TRAIN_PAT_1_CPT;
|
||||
*DP |= DP_LINK_TRAIN_PAT_1_CPT;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_2:
|
||||
dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT;
|
||||
*DP |= DP_LINK_TRAIN_PAT_2_CPT;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_3:
|
||||
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;
|
||||
}
|
||||
|
||||
} else {
|
||||
dp_reg_value &= ~DP_LINK_TRAIN_MASK;
|
||||
*DP &= ~DP_LINK_TRAIN_MASK;
|
||||
|
||||
switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
|
||||
case DP_TRAINING_PATTERN_DISABLE:
|
||||
dp_reg_value |= DP_LINK_TRAIN_OFF;
|
||||
*DP |= DP_LINK_TRAIN_OFF;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_1:
|
||||
dp_reg_value |= DP_LINK_TRAIN_PAT_1;
|
||||
*DP |= DP_LINK_TRAIN_PAT_1;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_2:
|
||||
dp_reg_value |= DP_LINK_TRAIN_PAT_2;
|
||||
*DP |= DP_LINK_TRAIN_PAT_2;
|
||||
break;
|
||||
case DP_TRAINING_PATTERN_3:
|
||||
DRM_ERROR("DP training pattern 3 not supported\n");
|
||||
dp_reg_value |= DP_LINK_TRAIN_PAT_2;
|
||||
*DP |= DP_LINK_TRAIN_PAT_2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
I915_WRITE(intel_dp->output_reg, dp_reg_value);
|
||||
I915_WRITE(intel_dp->output_reg, *DP);
|
||||
POSTING_READ(intel_dp->output_reg);
|
||||
|
||||
intel_dp_aux_native_write_1(intel_dp,
|
||||
DP_TRAINING_PATTERN_SET,
|
||||
dp_train_pat);
|
||||
ret = intel_dp_aux_native_write_1(intel_dp, DP_TRAINING_PATTERN_SET,
|
||||
dp_train_pat);
|
||||
if (ret != 1)
|
||||
return false;
|
||||
|
||||
if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) !=
|
||||
DP_TRAINING_PATTERN_DISABLE) {
|
||||
@ -2412,6 +2413,37 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
|
||||
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)
|
||||
{
|
||||
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)
|
||||
|
||||
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_tries = 0;
|
||||
loop_tries = 0;
|
||||
for (;;) {
|
||||
/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
|
||||
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;
|
||||
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)) {
|
||||
@ -2501,7 +2531,9 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
||||
DRM_DEBUG_KMS("too many full retries, give up\n");
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
@ -2517,8 +2549,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
||||
voltage_tries = 0;
|
||||
voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
|
||||
|
||||
/* Compute new intel_dp->train_set as requested by target */
|
||||
intel_get_adjust_train(intel_dp, link_status);
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
intel_dp->DP = DP;
|
||||
@ -2532,11 +2567,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
||||
uint32_t DP = intel_dp->DP;
|
||||
|
||||
/* 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;
|
||||
cr_tries = 0;
|
||||
channel_eq = false;
|
||||
for (;;) {
|
||||
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
||||
|
||||
if (cr_tries > 5) {
|
||||
DRM_ERROR("failed to train DP, aborting\n");
|
||||
@ -2544,21 +2586,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Make sure clock is still ok */
|
||||
if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
|
||||
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++;
|
||||
continue;
|
||||
}
|
||||
@ -2572,13 +2611,19 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
||||
if (tries > 5) {
|
||||
intel_dp_link_down(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;
|
||||
cr_tries++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compute new intel_dp->train_set as requested by target */
|
||||
intel_get_adjust_train(intel_dp, link_status);
|
||||
/* 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;
|
||||
}
|
||||
++tries;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
intel_dp_set_link_train(intel_dp, intel_dp->DP,
|
||||
intel_dp_set_link_train(intel_dp, &intel_dp->DP,
|
||||
DP_TRAINING_PATTERN_DISABLE);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user