Re: [PATCH v3 8/9] drm/bridge: ti-sn65dsi86: Train at faster rates if slower ones fail

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed 18 Dec 14:35 PST 2019, Douglas Anderson wrote:

> If we fail training at a lower DP link rate let's now keep trying
> until we run out of rates to try.  Basically the algorithm here is to
> start at the link rate that is the theoretical minimum and then slowly
> bump up until we run out of rates or hit the max rate of the sink.  We
> query the sink using a DPCD read.
> 
> This is, in fact, important in practice.  Specifically at least one
> panel hooked up to the bridge (AUO B116XAK01) had a theoretical min
> rate more than 1.62 GHz (if run at 24 bpp) and fails to train at the
> next rate (2.16 GHz).  It would train at 2.7 GHz, though.
> 
> Signed-off-by: Douglas Anderson <dianders@xxxxxxxxxxxx>
> Tested-by: Rob Clark <robdclark@xxxxxxxxx>
> Reviewed-by: Rob Clark <robdclark@xxxxxxxxx>

Reviewed-by: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>

> ---
> 
> Changes in v3: None
> Changes in v2:
> - Squash in maybe-uninitialized fix from Rob Clark.
> 
>  drivers/gpu/drm/bridge/ti-sn65dsi86.c | 71 ++++++++++++++++++++++-----
>  1 file changed, 60 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> index 48fb4dc72e1c..e1b817ccd9c7 100644
> --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
> @@ -454,7 +454,7 @@ static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
>  	0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
>  };
>  
> -static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
> +static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata)
>  {
>  	unsigned int bit_rate_khz, dp_rate_mhz;
>  	unsigned int i;
> @@ -472,8 +472,42 @@ static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
>  		if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
>  			break;
>  
> -	regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
> -			   DP_DATARATE_MASK, DP_DATARATE(i));
> +	return i;
> +}
> +
> +static int ti_sn_bridge_get_max_dp_rate_idx(struct ti_sn_bridge *pdata)
> +{
> +	u8 data;
> +	int ret;
> +
> +	ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &data);
> +	if (ret != 1) {
> +		DRM_DEV_ERROR(pdata->dev,
> +			      "Can't read max rate (%d); assuming 5.4 GHz\n",
> +			      ret);
> +		return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
> +	}
> +
> +	/*
> +	 * Return an index into ti_sn_bridge_dp_rate_lut.  Just hardcode
> +	 * these indicies since it's not like the register spec is ever going
> +	 * to change and a loop would just be more complicated.  Apparently
> +	 * the DP sink can only return these few rates as supported even
> +	 * though the bridge allows some rates in between.
> +	 */
> +	switch (data) {
> +	case DP_LINK_BW_1_62:
> +		return 1;
> +	case DP_LINK_BW_2_7:
> +		return 4;
> +	case DP_LINK_BW_5_4:
> +		return 7;
> +	}
> +
> +	DRM_DEV_ERROR(pdata->dev,
> +		      "Unexpected max data rate (%#x); assuming 5.4 GHz\n",
> +		      (int)data);
> +	return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
>  }
>  
>  static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
> @@ -530,13 +564,15 @@ static unsigned int ti_sn_get_max_lanes(struct ti_sn_bridge *pdata)
>  	return data & DP_LANE_COUNT_MASK;
>  }
>  
> -static int ti_sn_link_training(struct ti_sn_bridge *pdata)
> +static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx,
> +			       const char **last_err_str)
>  {
>  	unsigned int val;
>  	int ret;
>  
>  	/* set dp clk frequency value */
> -	ti_sn_bridge_set_dp_rate(pdata);
> +	regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
> +			   DP_DATARATE_MASK, DP_DATARATE(dp_rate_idx));
>  
>  	/* enable DP PLL */
>  	regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
> @@ -545,7 +581,7 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata)
>  				       val & DPPLL_SRC_DP_PLL_LOCK, 1000,
>  				       50 * 1000);
>  	if (ret) {
> -		DRM_ERROR("DP_PLL_LOCK polling failed (%d)\n", ret);
> +		*last_err_str = "DP_PLL_LOCK polling failed";
>  		goto exit;
>  	}
>  
> @@ -556,9 +592,9 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata)
>  				       val == ML_TX_NORMAL_MODE, 1000,
>  				       500 * 1000);
>  	if (ret) {
> -		DRM_ERROR("Training complete polling failed (%d)\n", ret);
> +		*last_err_str = "Training complete polling failed";
>  	} else if (val == ML_TX_MAIN_LINK_OFF) {
> -		DRM_ERROR("Link training failed, link is off\n");
> +		*last_err_str = "Link training failed, link is off";
>  		ret = -EIO;
>  	}
>  
> @@ -573,8 +609,11 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata)
>  static void ti_sn_bridge_enable(struct drm_bridge *bridge)
>  {
>  	struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
> +	const char *last_err_str = "No supported DP rate";
> +	int dp_rate_idx;
> +	int max_dp_rate_idx;
>  	unsigned int val;
> -	int ret;
> +	int ret = -EINVAL;
>  
>  	/*
>  	 * Run with the maximum number of lanes that the DP sink supports.
> @@ -616,9 +655,19 @@ static void ti_sn_bridge_enable(struct drm_bridge *bridge)
>  	regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
>  			   val);
>  
> -	ret = ti_sn_link_training(pdata);
> -	if (ret)
> +	/* Train until we run out of rates */
> +	max_dp_rate_idx = ti_sn_bridge_get_max_dp_rate_idx(pdata);
> +	for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata);
> +	     dp_rate_idx <= max_dp_rate_idx;
> +	     dp_rate_idx++) {
> +		ret = ti_sn_link_training(pdata, dp_rate_idx, &last_err_str);
> +		if (!ret)
> +			break;
> +	}
> +	if (ret) {
> +		DRM_DEV_ERROR(pdata->dev, "%s (%d)\n", last_err_str, ret);
>  		return;
> +	}
>  
>  	/* config video parameters */
>  	ti_sn_bridge_set_video_timings(pdata);
> -- 
> 2.24.1.735.g03f4e72817-goog
> 
_______________________________________________
dri-devel mailing list
dri-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/dri-devel



[Index of Archives]     [Linux DRI Users]     [Linux Intel Graphics]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux