On Tue, 06 Feb 2024, Arun R Murthy <[email protected]> wrote:
> Fallback mandates on DP link training failure. This patch just covers
> the DP2.0 fallback sequence.
>
> TODO: Need to implement the DP1.4 fallback.
>
> Signed-off-by: Arun R Murthy <[email protected]>
> ---
>  drivers/gpu/drm/i915/display/intel_dp.c | 92 ++++++++++++++++++++++---
>  1 file changed, 82 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
> b/drivers/gpu/drm/i915/display/intel_dp.c
> index 10ec231acd98..82d354a6b0cd 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -104,6 +104,50 @@ static const u8 valid_dsc_bpp[] = {6, 8, 10, 12, 15};
>   */
>  static const u8 valid_dsc_slicecount[] = {1, 2, 4};
>  
> +/* DL Link Rates */
> +#define UHBR20               2000000
> +#define UHBR13P5     1350000
> +#define UHBR10               1000000
> +#define HBR3         810000
> +#define HBR2         540000
> +#define HBR          270000
> +#define RBR          162000
> +
> +/* DP Lane Count */
> +#define LANE_COUNT_4 4
> +#define LANE_COUNT_2 2
> +#define LANE_COUNT_1 1
> +
> +/* DP2.0 fallback values */
> +struct dp_fallback {
> +     u32 link_rate;
> +     u8 lane_count;
> +};
> +
> +struct dp_fallback dp2dot0_fallback[] = {
> +     {UHBR20, LANE_COUNT_4},
> +     {UHBR13P5, LANE_COUNT_4},
> +     {UHBR20, LANE_COUNT_2},
> +     {UHBR10, LANE_COUNT_4},
> +     {UHBR13P5, LANE_COUNT_2},
> +     {HBR3, LANE_COUNT_4},
> +     {UHBR20, LANE_COUNT_1},
> +     {UHBR10, LANE_COUNT_2},
> +     {HBR2, LANE_COUNT_4},
> +     {UHBR13P5, LANE_COUNT_1},
> +     {HBR3, LANE_COUNT_2},
> +     {UHBR10, LANE_COUNT_1},
> +     {HBR2, LANE_COUNT_2},
> +     {HBR, LANE_COUNT_4},
> +     {HBR3, LANE_COUNT_1},
> +     {RBR, LANE_COUNT_4},
> +     {HBR2, LANE_COUNT_1},
> +     {HBR, LANE_COUNT_2},
> +     {RBR, LANE_COUNT_2},
> +     {HBR, LANE_COUNT_1},
> +     {RBR, LANE_COUNT_1},
> +};
> +
>  /**
>   * intel_dp_is_edp - is the given port attached to an eDP panel (either CPU 
> or PCH)
>   * @intel_dp: DP struct
> @@ -299,6 +343,19 @@ static int intel_dp_common_len_rate_limit(const struct 
> intel_dp *intel_dp,
>                                      intel_dp->num_common_rates, max_rate);
>  }
>  
> +static bool intel_dp_link_rate_supported(struct intel_dp *intel_dp, u32 
> link_rate)
> +{
> +     u8 i;
> +
> +     for (i = 0; i < ARRAY_SIZE(intel_dp->common_rates); i++) {
> +             if (intel_dp->common_rates[i] == link_rate)
> +                     return true;
> +             else
> +                     continue;
> +     }
> +     return false;
> +}
> +
>  static int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
>  {
>       if (drm_WARN_ON(&dp_to_i915(intel_dp)->drm,
> @@ -671,15 +728,6 @@ int intel_dp_get_link_train_fallback_values(struct 
> intel_dp *intel_dp,
>       struct drm_i915_private *i915 = dp_to_i915(intel_dp);
>       int index;
>  
> -     /*
> -      * TODO: Enable fallback on MST links once MST link compute can handle
> -      * the fallback params.
> -      */
> -     if (intel_dp->is_mst) {
> -             drm_err(&i915->drm, "Link Training Unsuccessful\n");
> -             return -1;
> -     }
> -

By removing this, the claim is both 8b/10b and 128b/132b DP MST link
training fallbacks work...

>       if (intel_dp_is_edp(intel_dp) && !intel_dp->use_max_params) {
>               drm_dbg_kms(&i915->drm,
>                           "Retrying Link training for eDP with max 
> parameters\n");
> @@ -687,6 +735,31 @@ int intel_dp_get_link_train_fallback_values(struct 
> intel_dp *intel_dp,
>               return 0;
>       }
>  
> +     /* DP fallback values */
> +     if (intel_dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_128B132B) 
> {

...but this only addresses 128b/132b, and the 8b/10b MST drops to the
existing SST fallback path.

And with the current code, DP_CAP_ANSI_128B132B does not decide whether
we use DP MST or not. So this will also cover 8b/10b fallback for
displays that support 128b/132b but have DP_MSTM_CAP == 0.

> +             for(index = 0; index < ARRAY_SIZE(dp2dot0_fallback); index++) {
> +                     if (link_rate == dp2dot0_fallback[index].link_rate &&
> +                             lane_count == 
> dp2dot0_fallback[index].lane_count) {
> +                             for(index += 1; index < 
> ARRAY_SIZE(dp2dot0_fallback); index++) {

I honestly do not understand the double looping here, and how index is
managed.

> +                                     if 
> (intel_dp_link_rate_supported(intel_dp,
> +                                                     
> dp2dot0_fallback[index].link_rate)) {
> +                                             
> intel_dp_set_link_params(intel_dp,
> +                                                                   
> dp2dot0_fallback[index].link_rate,
> +                                                                   
> dp2dot0_fallback[index].lane_count);

intel_dp_set_link_params() is supposed to be called in the DP encoder
(pre-)enable paths to set the link rates. If you do it here, the
subsequent enable will just overwrite whatever you did here.

The mechanism in this function should be to to adjust
intel_dp->max_link_rate and intel_dp->max_link_lane_count, and then the
caller will send an uevent to have the userspace do everything again,
but with reduced max values.

This is all very convoluted. And I admit the existing code is also
complex, but this makes it *much* harder to understand.

BR,
Jani.

> +                                             drm_dbg_kms(&i915->drm,
> +                                                         "Retrying Link 
> training with link rate %d and lane count %d\n",
> +                                                         
> dp2dot0_fallback[index].link_rate,
> +                                                         
> dp2dot0_fallback[index].lane_count);
> +                                             return 0;
> +                                     }
> +                             }
> +                     }
> +             }
> +             /* Report failure and fail link training */
> +             drm_err(&i915->drm, "Link Training Unsuccessful\n");
> +             return -1;
> +     }
> +
>       index = intel_dp_rate_index(intel_dp->common_rates,
>                                   intel_dp->num_common_rates,
>                                   link_rate);
> @@ -716,7 +789,6 @@ int intel_dp_get_link_train_fallback_values(struct 
> intel_dp *intel_dp,
>               drm_err(&i915->drm, "Link Training Unsuccessful\n");
>               return -1;
>       }
> -
>       return 0;
>  }

-- 
Jani Nikula, Intel

Reply via email to