On Wed, Jan 21, 2026 at 09:23:21AM +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.
>
> Signed-off-by: Ankit Nautiyal <[email protected]>
> ---
> drivers/gpu/drm/i915/display/intel_dp.c | 102 +++++++++++++++++++-----
> 1 file changed, 84 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c
> b/drivers/gpu/drm/i915/display/intel_dp.c
> index 02381f84fa58..d96d9ac1e830 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -2790,33 +2790,20 @@ 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_config(struct intel_encoder *encoder,
intel_dp_compute_link_for_joined_pipes(), similarly to the MST
counterpart?
> + 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);
> 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 ||
> @@ -2879,6 +2866,85 @@ 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 ret = 0;
> + int i;
> +
> + if (crtc_state->fec_enable &&
> + !intel_dp_supports_fec(intel_dp, connector, crtc_state))
> + return -EINVAL;
> +
> + for (i = 0; i < ARRAY_SIZE(joiner_candidates); i++) {
> + enum joiner_type joiner = joiner_candidates[i];
> + int max_dotclk = display->cdclk.max_dotclk_freq;
> +
> + if (joiner == FORCED_JOINER) {
> + if (!connector->force_joined_pipes)
> + continue;
> + num_joined_pipes = connector->force_joined_pipes;
> + } else {
> + num_joined_pipes = 1 << joiner;
> + }
> +
> + if ((joiner >= NO_JOINER && !intel_dp_has_joiner(intel_dp)) ||
> + (joiner == BIG_JOINER && !HAS_BIGJOINER(display)) ||
> + (joiner == ULTRA_JOINER && !HAS_ULTRAJOINER(display))) {
> + ret = -EINVAL;
> + break;
A simple loop over the number of possible joined pipes would be simpler
here as well, as in the mode_valid() function.
> + }
> +
> + if (adjusted_mode->hdisplay > num_joined_pipes *
> intel_dp_hdisplay_limit(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_config(encoder, crtc_state,
> conn_state,
> + respect_downstream_limits);
> + if (ret)
> + continue;
> +
> + max_dotclk *= num_joined_pipes;
> +
> + if (adjusted_mode->crtc_clock <= max_dotclk) {
There seems to be a difference in the maximum dotclock for the DSC and
non-DSC modes, introduced later in the patchset. Since the non-DSC max
dotclock may be lower than the DSC one (oddly), there should be a
fallback to DSC mode for a given number of joined pipes if the non-DSC
mode is not possible with the same number of joined pipes because of the
mode specific dot clock limit. So the above check should be moved to
intel_dp_compute_link_for_joined_pipes() and performed for both the DSC
and non-DSC modes.
> + 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
>