On Wed, Jan 28, 2026 at 07:36:25PM +0530, Ankit Nautiyal wrote:
> Currently, the number of joined pipes are determined early in the flow,
> which limits flexibility for accounting DSC slice overhead. To address
> this, recompute the joined pipe count during DSC configuration.
> 
> Refactor intel_dp_dsc_compute_config() to iterate over joiner candidates
> and select the minimal joiner configuration that satisfies the mode
> requirements. This prepares the logic for future changes that will
> consider DSC slice overhead.
> 
> v2:
>  - Rename helper to intel_dp_compute_link_for_joined_pipes(). (Imre)
>  - Move the check for max dotclock inside the helper so that if dotclock
>    check fails for non DSC case for a given number of joined pipes, we
>    are able to fallback to the DSC mode. (Imre)
> 
> Signed-off-by: Ankit Nautiyal <[email protected]>
> ---
>  drivers/gpu/drm/i915/display/intel_dp.c | 93 ++++++++++++++++++++-----
>  1 file changed, 77 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
> b/drivers/gpu/drm/i915/display/intel_dp.c
> index 599965a6e1a6..f8986f0acc79 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -2804,33 +2804,23 @@ bool intel_dp_joiner_needs_dsc(struct intel_display 
> *display,
>  }
>  
>  static int
> -intel_dp_compute_link_config(struct intel_encoder *encoder,
> -                          struct intel_crtc_state *pipe_config,
> -                          struct drm_connector_state *conn_state,
> -                          bool respect_downstream_limits)
> +intel_dp_compute_link_for_joined_pipes(struct intel_encoder *encoder,
> +                                    struct intel_crtc_state *pipe_config,
> +                                    struct drm_connector_state *conn_state,
> +                                    bool respect_downstream_limits)
>  {
>       struct intel_display *display = to_intel_display(encoder);
> -     struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc);
> +     int num_joined_pipes = intel_crtc_num_joined_pipes(pipe_config);
>       struct intel_connector *connector =
>               to_intel_connector(conn_state->connector);
>       const struct drm_display_mode *adjusted_mode =
>               &pipe_config->hw.adjusted_mode;
>       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
> +     int max_dotclk = display->cdclk.max_dotclk_freq;
>       struct link_config_limits limits;
>       bool dsc_needed, joiner_needs_dsc;
> -     int num_joined_pipes;
>       int ret = 0;
>  
> -     if (pipe_config->fec_enable &&
> -         !intel_dp_supports_fec(intel_dp, connector, pipe_config))
> -             return -EINVAL;
> -
> -     num_joined_pipes = intel_dp_num_joined_pipes(intel_dp, connector,
> -                                                  
> adjusted_mode->crtc_hdisplay,
> -                                                  adjusted_mode->crtc_clock);
> -     if (num_joined_pipes > 1)
> -             pipe_config->joiner_pipes = GENMASK(crtc->pipe + 
> num_joined_pipes - 1, crtc->pipe);
> -
>       joiner_needs_dsc = intel_dp_joiner_needs_dsc(display, num_joined_pipes);
>  
>       dsc_needed = joiner_needs_dsc || intel_dp->force_dsc_en ||
> @@ -2880,6 +2870,11 @@ intel_dp_compute_link_config(struct intel_encoder 
> *encoder,
>                       return ret;
>       }
>  
> +     max_dotclk *= num_joined_pipes;
> +
> +     if (adjusted_mode->crtc_clock > max_dotclk)
> +             return -EINVAL;

When you make max_dotclk dependent on dsc vs. non-dsc mode later in the
patchset, this also needs to be checked for the non-dsc case as well
earlier in the function, falling back to dsc if crtc_clock is too high
for it (as for non-dsc max_dotclk may be lower than for dsc). I suppose
it's easier to move this check earlier already in this patch and later
change the error return to be a fallback, rechecking the clock for dsc
as well here.

> +
>       drm_dbg_kms(display->drm,
>                   "DP lane count %d clock %d bpp input %d compressed " 
> FXP_Q4_FMT " link rate required %d available %d\n",
>                   pipe_config->lane_count, pipe_config->port_clock,
> @@ -2893,6 +2888,72 @@ intel_dp_compute_link_config(struct intel_encoder 
> *encoder,
>       return 0;
>  }
>  
> +static int
> +intel_dp_compute_link_config(struct intel_encoder *encoder,
> +                          struct intel_crtc_state *crtc_state,
> +                          struct drm_connector_state *conn_state,
> +                          bool respect_downstream_limits)
> +{
> +     struct intel_display *display = to_intel_display(encoder);
> +     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +     struct intel_connector *connector =
> +             to_intel_connector(conn_state->connector);
> +     const struct drm_display_mode *adjusted_mode =
> +             &crtc_state->hw.adjusted_mode;
> +     struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
> +     int num_joined_pipes;
> +     int num_pipes;
> +     int ret = 0;
> +
> +     if (crtc_state->fec_enable &&
> +         !intel_dp_supports_fec(intel_dp, connector, crtc_state))
> +             return -EINVAL;
> +

Even though num_pipes == 1 should always work, for clarity I initialize
ret to -EINVAL explicitly for the case where no pipes would work. Not
doing a fallback from a forced joined-pipe config would need this
anyway.

> +     for (num_pipes = 0; num_pipes < I915_MAX_PIPES; num_pipes++) {
> +             if (num_pipes == 0) {
> +                     if (!connector->force_joined_pipes)
> +                             continue;
> +                     num_joined_pipes = connector->force_joined_pipes;
> +             } else {
> +                     num_joined_pipes = num_pipes;
> +             }

As in the previous patch, I'd just skip the force_joined_pipes &&
num_pipes != force_joined_pipes case.

> +
> +             if (!intel_dp_can_join(display, num_joined_pipes))
> +                     continue;
> +
> +             if (adjusted_mode->hdisplay >
> +                 num_joined_pipes * intel_dp_max_hdisplay_per_pipe(display))
> +                     continue;
> +
> +             /*
> +              * NOTE:
> +              * The crtc_state->joiner_pipes should have been set at the end
> +              * only if all the conditions are met. However that would mean
> +              * that num_joined_pipes is passed around to all helpers and
> +              * make them use it instead of using crtc_state->joiner_pipes
> +              * directly or indirectly (via intel_crtc_num_joined_pipes()).
> +              *
> +              * For now, setting crtc_state->joiner_pipes to the candidate
> +              * value to avoid the above churn and resetting it to 0, in case
> +              * no joiner candidate is found to be suitable for the given
> +              * configuration.
> +              */
> +             if (num_joined_pipes > 1)
> +                     crtc_state->joiner_pipes = GENMASK(crtc->pipe + 
> num_joined_pipes - 1,
> +                                                        crtc->pipe);
> +
> +             ret = intel_dp_compute_link_for_joined_pipes(encoder, 
> crtc_state, conn_state,
> +                                                          
> respect_downstream_limits);
> +             if (ret == 0)
> +                     break;
> +     }
> +
> +     if (ret < 0)
> +             crtc_state->joiner_pipes = 0;
> +
> +     return ret;
> +}
> +
>  bool intel_dp_limited_color_range(const struct intel_crtc_state *crtc_state,
>                                 const struct drm_connector_state *conn_state)
>  {
> -- 
> 2.45.2
> 

Reply via email to