All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Thulasimani, Sivakumar" <sivakumar.thulasimani@intel.com>
To: Ander Conselvan de Oliveira
	<ander.conselvan.de.oliveira@intel.com>,
	intel-gfx@lists.freedesktop.org, jim.bride@linux.intel.com
Subject: Re: [PATCH 05/22] drm/i915: Move generic link training code to a separate file
Date: Sun, 25 Oct 2015 08:07:45 +0530	[thread overview]
Message-ID: <562C4079.7060706@intel.com> (raw)
In-Reply-To: <1445594525-7174-6-git-send-email-ander.conselvan.de.oliveira@intel.com>

Reviewed-by: Sivakumar Thulasimani <sivakumar.thulasimani@intel.com>

On 10/23/2015 3:31 PM, Ander Conselvan de Oliveira wrote:
> No functional changes, just moving code around.
>
> v2: Rebase
>
> Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
> ---
>   drivers/gpu/drm/i915/Makefile                 |   1 +
>   drivers/gpu/drm/i915/intel_dp.c               | 321 +------------------------
>   drivers/gpu/drm/i915/intel_dp_link_training.c | 327 ++++++++++++++++++++++++++
>   drivers/gpu/drm/i915/intel_drv.h              |  16 ++
>   4 files changed, 353 insertions(+), 312 deletions(-)
>   create mode 100644 drivers/gpu/drm/i915/intel_dp_link_training.c
>
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 44d290a..0851de07 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -77,6 +77,7 @@ i915-y += dvo_ch7017.o \
>   	  dvo_tfp410.o \
>   	  intel_crt.o \
>   	  intel_ddi.o \
> +	  intel_dp_link_training.o \
>   	  intel_dp_mst.o \
>   	  intel_dp.o \
>   	  intel_dsi.o \
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 4ffb2e3..4b88823 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1189,7 +1189,7 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
>   	return (intel_dp_max_link_bw(intel_dp) >> 3) + 1;
>   }
>   
> -static bool intel_dp_source_supports_hbr2(struct drm_device *dev)
> +bool intel_dp_source_supports_hbr2(struct drm_device *dev)
>   {
>   	/* WaDisableHBR2:skl */
>   	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0))
> @@ -1365,8 +1365,8 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
>   	return rate_to_index(rate, intel_dp->sink_rates);
>   }
>   
> -static void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
> -				  uint8_t *link_bw, uint8_t *rate_select)
> +void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
> +			   uint8_t *link_bw, uint8_t *rate_select)
>   {
>   	if (intel_dp->num_sink_rates) {
>   		*link_bw = 0;
> @@ -3046,7 +3046,7 @@ intel_dp_dpcd_read_wake(struct drm_dp_aux *aux, unsigned int offset,
>    * Fetch AUX CH registers 0x202 - 0x207 which contain
>    * link status information
>    */
> -static bool
> +bool
>   intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
>   {
>   	return intel_dp_dpcd_read_wake(&intel_dp->aux,
> @@ -3056,7 +3056,7 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_
>   }
>   
>   /* These are source-specific values. */
> -static uint8_t
> +uint8_t
>   intel_dp_voltage_max(struct intel_dp *intel_dp)
>   {
>   	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> @@ -3079,7 +3079,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp)
>   		return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>   }
>   
> -static uint8_t
> +uint8_t
>   intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
>   {
>   	struct drm_device *dev = intel_dp_to_dev(intel_dp);
> @@ -3421,38 +3421,6 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp)
>   	return 0;
>   }
>   
> -static void
> -intel_get_adjust_train(struct intel_dp *intel_dp,
> -		       const uint8_t link_status[DP_LINK_STATUS_SIZE])
> -{
> -	uint8_t v = 0;
> -	uint8_t p = 0;
> -	int lane;
> -	uint8_t voltage_max;
> -	uint8_t preemph_max;
> -
> -	for (lane = 0; lane < intel_dp->lane_count; lane++) {
> -		uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
> -		uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
> -
> -		if (this_v > v)
> -			v = this_v;
> -		if (this_p > p)
> -			p = this_p;
> -	}
> -
> -	voltage_max = intel_dp_voltage_max(intel_dp);
> -	if (v >= voltage_max)
> -		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
> -
> -	preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
> -	if (p >= preemph_max)
> -		p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
> -
> -	for (lane = 0; lane < 4; lane++)
> -		intel_dp->train_set[lane] = v | p;
> -}
> -
>   static uint32_t
>   gen4_signal_levels(uint8_t train_set)
>   {
> @@ -3550,7 +3518,7 @@ gen7_edp_signal_levels(uint8_t train_set)
>   	}
>   }
>   
> -static void
> +void
>   intel_dp_set_signal_levels(struct intel_dp *intel_dp)
>   {
>   	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
> @@ -3597,7 +3565,7 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp)
>   	POSTING_READ(intel_dp->output_reg);
>   }
>   
> -static void
> +void
>   intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
>   				       uint8_t dp_train_pat)
>   {
> @@ -3611,56 +3579,7 @@ intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
>   	POSTING_READ(intel_dp->output_reg);
>   }
>   
> -static bool
> -intel_dp_set_link_train(struct intel_dp *intel_dp,
> -			uint8_t dp_train_pat)
> -{
> -	uint8_t buf[sizeof(intel_dp->train_set) + 1];
> -	int ret, len;
> -
> -	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
> -
> -	buf[0] = dp_train_pat;
> -	if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
> -	    DP_TRAINING_PATTERN_DISABLE) {
> -		/* don't write DP_TRAINING_LANEx_SET on disable */
> -		len = 1;
> -	} else {
> -		/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> -		memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
> -		len = intel_dp->lane_count + 1;
> -	}
> -
> -	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
> -				buf, len);
> -
> -	return ret == len;
> -}
> -
> -static bool
> -intel_dp_reset_link_train(struct intel_dp *intel_dp,
> -			uint8_t dp_train_pat)
> -{
> -	if (!intel_dp->train_set_valid)
> -		memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
> -	intel_dp_set_signal_levels(intel_dp);
> -	return intel_dp_set_link_train(intel_dp, dp_train_pat);
> -}
> -
> -static bool
> -intel_dp_update_link_train(struct intel_dp *intel_dp)
> -{
> -	int ret;
> -
> -	intel_dp_set_signal_levels(intel_dp);
> -
> -	ret = drm_dp_dpcd_write(&intel_dp->aux, 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)
> +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;
> @@ -3691,228 +3610,6 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp)
>   		DRM_ERROR("Timed out waiting for DP idle patterns\n");
>   }
>   
> -/* Enable corresponding port and start training pattern 1 */
> -static void
> -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> -{
> -	struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base;
> -	struct drm_device *dev = encoder->dev;
> -	int i;
> -	uint8_t voltage;
> -	int voltage_tries, loop_tries;
> -	uint8_t link_config[2];
> -	uint8_t link_bw, rate_select;
> -
> -	if (HAS_DDI(dev))
> -		intel_ddi_prepare_link_retrain(encoder);
> -
> -	intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
> -			      &link_bw, &rate_select);
> -
> -	/* Write the link configuration data */
> -	link_config[0] = link_bw;
> -	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 (intel_dp->num_sink_rates)
> -		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
> -				  &rate_select, 1);
> -
> -	link_config[0] = 0;
> -	link_config[1] = DP_SET_ANSI_8B10B;
> -	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
> -
> -	intel_dp->DP |= DP_PORT_EN;
> -
> -	/* clock recovery */
> -	if (!intel_dp_reset_link_train(intel_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 (;;) {
> -		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;
> -		}
> -
> -		if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
> -			DRM_DEBUG_KMS("clock recovery OK\n");
> -			break;
> -		}
> -
> -		/*
> -		 * if we used previously trained voltage and pre-emphasis values
> -		 * and we don't get clock recovery, reset link training values
> -		 */
> -		if (intel_dp->train_set_valid) {
> -			DRM_DEBUG_KMS("clock recovery not ok, reset");
> -			/* clear the flag as we are not reusing train set */
> -			intel_dp->train_set_valid = false;
> -			if (!intel_dp_reset_link_train(intel_dp,
> -						       DP_TRAINING_PATTERN_1 |
> -						       DP_LINK_SCRAMBLING_DISABLE)) {
> -				DRM_ERROR("failed to enable link training\n");
> -				return;
> -			}
> -			continue;
> -		}
> -
> -		/* 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) {
> -			++loop_tries;
> -			if (loop_tries == 5) {
> -				DRM_ERROR("too many full retries, give up\n");
> -				break;
> -			}
> -			intel_dp_reset_link_train(intel_dp,
> -						  DP_TRAINING_PATTERN_1 |
> -						  DP_LINK_SCRAMBLING_DISABLE);
> -			voltage_tries = 0;
> -			continue;
> -		}
> -
> -		/* 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;
> -		}
> -	}
> -}
> -
> -static void
> -intel_dp_link_training_channel_equalization(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;
> -	bool channel_eq = false;
> -	int tries, cr_tries;
> -	uint32_t training_pattern = DP_TRAINING_PATTERN_2;
> -
> -	/*
> -	 * Training Pattern 3 for HBR2 or 1.2 devices that support it.
> -	 *
> -	 * Intel platforms that support HBR2 also support TPS3. TPS3 support is
> -	 * also mandatory for downstream devices that support HBR2.
> -	 *
> -	 * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
> -	 * supported but still not enabled.
> -	 */
> -	if (intel_dp_source_supports_hbr2(dev) &&
> -	    drm_dp_tps3_supported(intel_dp->dpcd))
> -		training_pattern = DP_TRAINING_PATTERN_3;
> -	else if (intel_dp->link_rate == 540000)
> -		DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
> -
> -	/* channel equalization */
> -	if (!intel_dp_set_link_train(intel_dp,
> -				     training_pattern |
> -				     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];
> -
> -		if (cr_tries > 5) {
> -			DRM_ERROR("failed to train DP, aborting\n");
> -			break;
> -		}
> -
> -		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> -		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->train_set_valid = false;
> -			intel_dp_link_training_clock_recovery(intel_dp);
> -			intel_dp_set_link_train(intel_dp,
> -						training_pattern |
> -						DP_LINK_SCRAMBLING_DISABLE);
> -			cr_tries++;
> -			continue;
> -		}
> -
> -		if (drm_dp_channel_eq_ok(link_status,
> -					 intel_dp->lane_count)) {
> -			channel_eq = true;
> -			break;
> -		}
> -
> -		/* Try 5 times, then try clock recovery if that fails */
> -		if (tries > 5) {
> -			intel_dp->train_set_valid = false;
> -			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;
> -	}
> -
> -	intel_dp_set_idle_link_train(intel_dp);
> -
> -	if (channel_eq) {
> -		intel_dp->train_set_valid = true;
> -		DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
> -	}
> -}
> -
> -void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> -{
> -	intel_dp_set_link_train(intel_dp,
> -				DP_TRAINING_PATTERN_DISABLE);
> -}
> -
> -void
> -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);
> -}
> -
>   static void
>   intel_dp_link_down(struct intel_dp *intel_dp)
>   {
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> new file mode 100644
> index 0000000..53f9c14
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -0,0 +1,327 @@
> +/*
> + * Copyright © 2008-2015 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#include "intel_drv.h"
> +
> +static void
> +intel_get_adjust_train(struct intel_dp *intel_dp,
> +		       const uint8_t link_status[DP_LINK_STATUS_SIZE])
> +{
> +	uint8_t v = 0;
> +	uint8_t p = 0;
> +	int lane;
> +	uint8_t voltage_max;
> +	uint8_t preemph_max;
> +
> +	for (lane = 0; lane < intel_dp->lane_count; lane++) {
> +		uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
> +		uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
> +
> +		if (this_v > v)
> +			v = this_v;
> +		if (this_p > p)
> +			p = this_p;
> +	}
> +
> +	voltage_max = intel_dp_voltage_max(intel_dp);
> +	if (v >= voltage_max)
> +		v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
> +
> +	preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
> +	if (p >= preemph_max)
> +		p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
> +
> +	for (lane = 0; lane < 4; lane++)
> +		intel_dp->train_set[lane] = v | p;
> +}
> +
> +static bool
> +intel_dp_set_link_train(struct intel_dp *intel_dp,
> +			uint8_t dp_train_pat)
> +{
> +	uint8_t buf[sizeof(intel_dp->train_set) + 1];
> +	int ret, len;
> +
> +	intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
> +
> +	buf[0] = dp_train_pat;
> +	if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
> +	    DP_TRAINING_PATTERN_DISABLE) {
> +		/* don't write DP_TRAINING_LANEx_SET on disable */
> +		len = 1;
> +	} else {
> +		/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
> +		memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
> +		len = intel_dp->lane_count + 1;
> +	}
> +
> +	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
> +				buf, len);
> +
> +	return ret == len;
> +}
> +
> +static bool
> +intel_dp_reset_link_train(struct intel_dp *intel_dp,
> +			uint8_t dp_train_pat)
> +{
> +	if (!intel_dp->train_set_valid)
> +		memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
> +	intel_dp_set_signal_levels(intel_dp);
> +	return intel_dp_set_link_train(intel_dp, dp_train_pat);
> +}
> +
> +static bool
> +intel_dp_update_link_train(struct intel_dp *intel_dp)
> +{
> +	int ret;
> +
> +	intel_dp_set_signal_levels(intel_dp);
> +
> +	ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
> +				intel_dp->train_set, intel_dp->lane_count);
> +
> +	return ret == intel_dp->lane_count;
> +}
> +
> +/* Enable corresponding port and start training pattern 1 */
> +static void
> +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
> +{
> +	struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base;
> +	struct drm_device *dev = encoder->dev;
> +	int i;
> +	uint8_t voltage;
> +	int voltage_tries, loop_tries;
> +	uint8_t link_config[2];
> +	uint8_t link_bw, rate_select;
> +
> +	if (HAS_DDI(dev))
> +		intel_ddi_prepare_link_retrain(encoder);
> +
> +	intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
> +			      &link_bw, &rate_select);
> +
> +	/* Write the link configuration data */
> +	link_config[0] = link_bw;
> +	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 (intel_dp->num_sink_rates)
> +		drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
> +				  &rate_select, 1);
> +
> +	link_config[0] = 0;
> +	link_config[1] = DP_SET_ANSI_8B10B;
> +	drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
> +
> +	intel_dp->DP |= DP_PORT_EN;
> +
> +	/* clock recovery */
> +	if (!intel_dp_reset_link_train(intel_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 (;;) {
> +		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;
> +		}
> +
> +		if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
> +			DRM_DEBUG_KMS("clock recovery OK\n");
> +			break;
> +		}
> +
> +		/*
> +		 * if we used previously trained voltage and pre-emphasis values
> +		 * and we don't get clock recovery, reset link training values
> +		 */
> +		if (intel_dp->train_set_valid) {
> +			DRM_DEBUG_KMS("clock recovery not ok, reset");
> +			/* clear the flag as we are not reusing train set */
> +			intel_dp->train_set_valid = false;
> +			if (!intel_dp_reset_link_train(intel_dp,
> +						       DP_TRAINING_PATTERN_1 |
> +						       DP_LINK_SCRAMBLING_DISABLE)) {
> +				DRM_ERROR("failed to enable link training\n");
> +				return;
> +			}
> +			continue;
> +		}
> +
> +		/* 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) {
> +			++loop_tries;
> +			if (loop_tries == 5) {
> +				DRM_ERROR("too many full retries, give up\n");
> +				break;
> +			}
> +			intel_dp_reset_link_train(intel_dp,
> +						  DP_TRAINING_PATTERN_1 |
> +						  DP_LINK_SCRAMBLING_DISABLE);
> +			voltage_tries = 0;
> +			continue;
> +		}
> +
> +		/* 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;
> +		}
> +	}
> +}
> +
> +static void
> +intel_dp_link_training_channel_equalization(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;
> +	bool channel_eq = false;
> +	int tries, cr_tries;
> +	uint32_t training_pattern = DP_TRAINING_PATTERN_2;
> +
> +	/*
> +	 * Training Pattern 3 for HBR2 or 1.2 devices that support it.
> +	 *
> +	 * Intel platforms that support HBR2 also support TPS3. TPS3 support is
> +	 * also mandatory for downstream devices that support HBR2.
> +	 *
> +	 * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is
> +	 * supported but still not enabled.
> +	 */
> +	if (intel_dp_source_supports_hbr2(dev) &&
> +	    drm_dp_tps3_supported(intel_dp->dpcd))
> +		training_pattern = DP_TRAINING_PATTERN_3;
> +	else if (intel_dp->link_rate == 540000)
> +		DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n");
> +
> +	/* channel equalization */
> +	if (!intel_dp_set_link_train(intel_dp,
> +				     training_pattern |
> +				     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];
> +
> +		if (cr_tries > 5) {
> +			DRM_ERROR("failed to train DP, aborting\n");
> +			break;
> +		}
> +
> +		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> +		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->train_set_valid = false;
> +			intel_dp_link_training_clock_recovery(intel_dp);
> +			intel_dp_set_link_train(intel_dp,
> +						training_pattern |
> +						DP_LINK_SCRAMBLING_DISABLE);
> +			cr_tries++;
> +			continue;
> +		}
> +
> +		if (drm_dp_channel_eq_ok(link_status,
> +					 intel_dp->lane_count)) {
> +			channel_eq = true;
> +			break;
> +		}
> +
> +		/* Try 5 times, then try clock recovery if that fails */
> +		if (tries > 5) {
> +			intel_dp->train_set_valid = false;
> +			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;
> +	}
> +
> +	intel_dp_set_idle_link_train(intel_dp);
> +
> +	if (channel_eq) {
> +		intel_dp->train_set_valid = true;
> +		DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n");
> +	}
> +}
> +
> +void intel_dp_stop_link_train(struct intel_dp *intel_dp)
> +{
> +	intel_dp_set_link_train(intel_dp,
> +				DP_TRAINING_PATTERN_DISABLE);
> +}
> +
> +void
> +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);
> +}
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 6790187..25ac5d2 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1236,6 +1236,22 @@ bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
>   					 struct intel_digital_port *port);
>   void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
>   
> +void
> +intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
> +				       uint8_t dp_train_pat);
> +void
> +intel_dp_set_signal_levels(struct intel_dp *intel_dp);
> +void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
> +uint8_t
> +intel_dp_voltage_max(struct intel_dp *intel_dp);
> +uint8_t
> +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 drm_device *dev);
> +bool
> +intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]);
> +
>   /* intel_dp_mst.c */
>   int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
>   void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port);

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

  reply	other threads:[~2015-10-25  2:37 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-23 10:01 [PATCH 00/22] DP refactoring v2 Ander Conselvan de Oliveira
2015-10-23 10:01 ` [PATCH 01/22] drm/i915: Don't pass *DP around to link training functions Ander Conselvan de Oliveira
2015-10-25  2:01   ` Thulasimani, Sivakumar
2015-10-23 10:01 ` [PATCH 02/22] drm/i915: Split write of pattern to DP reg from intel_dp_set_link_train Ander Conselvan de Oliveira
2015-10-25  2:06   ` Thulasimani, Sivakumar
2015-10-23 10:01 ` [PATCH 03/22] drm/i915 Call get_adjust_train() from clock recovery and channel eq Ander Conselvan de Oliveira
2015-10-25  2:11   ` Thulasimani, Sivakumar
2015-10-23 10:01 ` [PATCH 04/22] drm/i915: Move register write into intel_dp_set_signal_levels() Ander Conselvan de Oliveira
2015-10-25  2:28   ` Thulasimani, Sivakumar
2015-10-23 10:01 ` [PATCH 05/22] drm/i915: Move generic link training code to a separate file Ander Conselvan de Oliveira
2015-10-25  2:37   ` Thulasimani, Sivakumar [this message]
2015-10-23 10:01 ` [PATCH 06/22] drm/i915: Create intel_dp->prepare_link_retrain() hook Ander Conselvan de Oliveira
2015-10-25  2:40   ` Thulasimani, Sivakumar
2015-10-23 10:01 ` [PATCH 07/22] drm/i915: Make intel_dp_source_supports_hbr2() take an intel_dp pointer Ander Conselvan de Oliveira
2015-10-25  2:48   ` Thulasimani, Sivakumar
2015-11-05 13:22     ` Ander Conselvan De Oliveira
2015-10-23 10:01 ` [PATCH 08/22] drm/i915: Move link training setup code to separate functions (v2) Ander Conselvan de Oliveira
2015-10-23 10:01 ` [PATCH 09/22] drm/i915: Move test for max voltage on all lanes to separate function Ander Conselvan de Oliveira
2015-10-23 10:01 ` [PATCH 10/22] drm/i915: Add function for getting the current link training voltage Ander Conselvan de Oliveira
2015-10-25  3:56   ` Thulasimani, Sivakumar
2015-10-23 10:01 ` [PATCH 11/22] drm/i915: Split full retries loop out of clock recovery code (v2) Ander Conselvan de Oliveira
2015-10-23 10:01 ` [PATCH 12/22] drm/i915: Make the link training test for same voltage smaller Ander Conselvan de Oliveira
2015-10-23 10:01 ` [PATCH 13/22] drm/i915: Move the voltage changed check into intel_get_adjust_train() Ander Conselvan de Oliveira
2015-10-23 10:01 ` [PATCH 14/22] drm/i915: Add missing newline to link training debug message Ander Conselvan de Oliveira
2015-10-23 10:01 ` [PATCH 15/22] drm/i915: Split setting of vswing and pre_emph levels to separate file Ander Conselvan de Oliveira
2015-10-23 10:01 ` [PATCH 16/22] drm/i915: Introduce struct intel_dp_signal_levels Ander Conselvan de Oliveira
2015-10-25  5:24   ` Thulasimani, Sivakumar
2015-10-26  7:22     ` Ander Conselvan De Oliveira
2015-10-23 10:02 ` [PATCH 17/22] drm/i915: Use struct intel_dp_signal_levels for eDP on SNB and IVB Ander Conselvan de Oliveira
2015-10-23 10:02 ` [PATCH 18/22] drm/i915: Use struct intel_dp_signal_levels for VLV Ander Conselvan de Oliveira
2015-10-23 10:02 ` [PATCH 19/22] drm/i915: Use struct intel_dp_signal_levels for CHV Ander Conselvan de Oliveira
2015-10-23 10:02 ` [PATCH 20/22] drm/i915: Use struct intel_dp_signal_levels for DDI platforms Ander Conselvan de Oliveira
2015-10-23 10:02 ` [PATCH 21/22] drm/i915: Remove old functions for maximum DP vswing and pre-emph levels Ander Conselvan de Oliveira
2015-10-23 10:02 ` [PATCH 22/22] drm/i915: Move ddi_signal_levels() to intel_dp_signal_levels.c Ander Conselvan de Oliveira

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=562C4079.7060706@intel.com \
    --to=sivakumar.thulasimani@intel.com \
    --cc=ander.conselvan.de.oliveira@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jim.bride@linux.intel.com \
    /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.