> -----Original Message-----
> From: Ville Syrjala <[email protected]>
> Sent: Wednesday, October 15, 2025 12:48 AM
> To: [email protected]
> Cc: [email protected]; Shankar, Uma <[email protected]>
> Subject: [PATCH v2 6/9] drm/i915/scaler: Add scaler prefill helpers
> 
> From: Ville Syrjälä <[email protected]>
> 
> Add helpers to compute the required prefill line count and adjustment factors 
> for
> the scalers.
> 
> The "1st" variants hand out numbers for the first scaler stage in the 
> pipeline (pipe
> scaler if no plane scalers are enabled, or the max from all the plane 
> scaler). The
> "2nd" variants deal with second scaler stage (pipe scaler when plane scaling 
> is
> also enabled, otherwise there is no second stage).
> 
> The _worst() variants give out worst case estimates, meant for guardband 
> sizing.
> The other variants are meant for the actual vblank/guardband length check vs.
> prefill+pkgc/sagv latency.
> 
> A few other helpers are added for the purpose of the WM0 prefill worst case
> estimates (to be introduced later).
> 
> The returned numbers are in .16 binary fixed point.
> 
> TODO: pretty rough, should check the actual scaler max scaling
>       factors instead of just assuming 3x everywhere
> 
> v2: Drop debugs
> 
> Reviewed-by: Uma Shankar <[email protected]> #v1
> Signed-off-by: Ville Syrjälä <[email protected]>
> ---
>  drivers/gpu/drm/i915/display/skl_scaler.c | 168 ++++++++++++++++++++++
> drivers/gpu/drm/i915/display/skl_scaler.h |  11 ++
>  2 files changed, 179 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/skl_scaler.c
> b/drivers/gpu/drm/i915/display/skl_scaler.c
> index c6cccf170ff1..47cdea75d27c 100644
> --- a/drivers/gpu/drm/i915/display/skl_scaler.c
> +++ b/drivers/gpu/drm/i915/display/skl_scaler.c
> @@ -968,3 +968,171 @@ void adl_scaler_ecc_unmask(const struct
> intel_crtc_state *crtc_state)
>                         1);
>       intel_de_write(display, XELPD_DISPLAY_ERR_FATAL_MASK, 0);  }
> +
> +static unsigned int skl_scaler_scale(const struct intel_crtc_state
> +*crtc_state, int i) {
> +     const struct intel_crtc_scaler_state *scaler_state =
> +             &crtc_state->scaler_state;
> +
> +     return DIV_ROUND_UP_ULL(mul_u32_u32(scaler_state-
> >scalers[i].hscale,
> +                                         scaler_state->scalers[i].vscale),
> +                             0x10000);
> +}
> +
> +static unsigned int skl_scaler_downscale(const struct intel_crtc_state
> +*crtc_state, int i) {
> +     return max(0x10000, skl_scaler_scale(crtc_state, i)); }
> +
> +static unsigned int skl_plane_scaler_downscale(const struct
> +intel_crtc_state *crtc_state) {
> +     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +     const struct intel_crtc_scaler_state *scaler_state =
> +             &crtc_state->scaler_state;
> +     unsigned int scale = 0x10000;
> +     int i;
> +
> +     for (i = 0; i < crtc->num_scalers; i++) {
> +             /* ignore pfit */
> +             if (i == scaler_state->scaler_id)
> +                     continue;
> +
> +             if (!scaler_state->scalers[i].in_use)
> +                     continue;
> +
> +             scale = max(scale, skl_scaler_downscale(crtc_state, i));
> +     }
> +
> +     return scale;
> +}
> +
> +static unsigned int skl_pipe_scaler_downscale(const struct
> +intel_crtc_state *crtc_state) {
> +     const struct intel_crtc_scaler_state *scaler_state =
> +             &crtc_state->scaler_state;
> +
> +     if (!crtc_state->pch_pfit.enabled)
> +             return 0x10000;

Hi Ville,
It seems CI has some issue with bound check for scaler.
Maybe good to add a check here.

Regards,
Uma Shankar

> +     return skl_scaler_downscale(crtc_state, scaler_state->scaler_id); }
> +
> +unsigned int skl_scaler_1st_prefill_adjustment(const struct
> +intel_crtc_state *crtc_state) {
> +     const struct intel_crtc_scaler_state *scaler_state =
> +             &crtc_state->scaler_state;
> +     int num_scalers = hweight32(scaler_state->scaler_users);
> +
> +     if (num_scalers < 1)
> +             return 0x10000;
> +
> +     if (num_scalers == 1 && crtc_state->pch_pfit.enabled)
> +             return skl_pipe_scaler_downscale(crtc_state);
> +     else
> +             return skl_plane_scaler_downscale(crtc_state);
> +}
> +
> +unsigned int skl_scaler_2nd_prefill_adjustment(const struct
> +intel_crtc_state *crtc_state) {
> +     const struct intel_crtc_scaler_state *scaler_state =
> +             &crtc_state->scaler_state;
> +     int num_scalers = hweight32(scaler_state->scaler_users);
> +
> +     if (num_scalers < 2)
> +             return 0x10000;
> +
> +     return skl_pipe_scaler_downscale(crtc_state);
> +}
> +
> +unsigned int skl_scaler_1st_prefill_lines(const struct intel_crtc_state
> +*crtc_state) {
> +     const struct intel_crtc_scaler_state *scaler_state =
> +             &crtc_state->scaler_state;
> +     int num_scalers = hweight32(scaler_state->scaler_users);
> +
> +     if (num_scalers > 0)
> +             return 4 << 16;
> +
> +     return 0;
> +}
> +
> +unsigned int skl_scaler_2nd_prefill_lines(const struct intel_crtc_state
> +*crtc_state) {
> +     const struct intel_crtc_scaler_state *scaler_state =
> +             &crtc_state->scaler_state;
> +     int num_scalers = hweight32(scaler_state->scaler_users);
> +
> +     if (num_scalers > 1 && crtc_state->pch_pfit.enabled)
> +             return 4 << 16;
> +
> +     return 0;
> +}
> +
> +static unsigned int _skl_scaler_max_scale(const struct intel_crtc_state
> *crtc_state,
> +                                       unsigned int max_scale)
> +{
> +     struct intel_display *display = to_intel_display(crtc_state);
> +
> +     /*
> +      * Downscaling requires increasing cdclk, so max scale
> +      * factor is limited to the max_dotclock/dotclock ratio.
> +      *
> +      * FIXME find out the max downscale factors properly
> +      */
> +     return min(max_scale, DIV_ROUND_UP_ULL((u64)display-
> >cdclk.max_dotclk_freq << 16,
> +                                            crtc_state-
> >hw.pipe_mode.crtc_clock));
> +}
> +
> +static unsigned int skl_scaler_max_scale(const struct intel_crtc_state
> +*crtc_state) {
> +     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +     unsigned int max_scale;
> +
> +     if (crtc->num_scalers < 1)
> +             return 0x10000;
> +
> +     /* FIXME find out the max downscale factors properly */
> +     max_scale = 9 << 16;
> +
> +     return _skl_scaler_max_scale(crtc_state, max_scale); }
> +
> +unsigned int skl_scaler_1st_prefill_adjustment_worst(const struct
> +intel_crtc_state *crtc_state) {
> +     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +
> +     if (crtc->num_scalers > 0)
> +             return skl_scaler_max_scale(crtc_state);
> +     else
> +             return 0x10000;
> +}
> +
> +unsigned int skl_scaler_2nd_prefill_adjustment_worst(const struct
> +intel_crtc_state *crtc_state) {
> +     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +
> +     if (crtc->num_scalers > 1)
> +             return skl_scaler_max_scale(crtc_state);
> +     else
> +             return 0x10000;
> +}
> +
> +unsigned int skl_scaler_1st_prefill_lines_worst(const struct
> +intel_crtc_state *crtc_state) {
> +     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +
> +     if (crtc->num_scalers > 0)
> +             return 4 << 16;
> +     else
> +             return 0;
> +}
> +
> +unsigned int skl_scaler_2nd_prefill_lines_worst(const struct
> +intel_crtc_state *crtc_state) {
> +     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
> +
> +     if (crtc->num_scalers > 1)
> +             return 4 << 16;
> +     else
> +             return 0;
> +}
> diff --git a/drivers/gpu/drm/i915/display/skl_scaler.h
> b/drivers/gpu/drm/i915/display/skl_scaler.h
> index 12a19016c5f6..6fab40d2b4ee 100644
> --- a/drivers/gpu/drm/i915/display/skl_scaler.h
> +++ b/drivers/gpu/drm/i915/display/skl_scaler.h
> @@ -45,4 +45,15 @@ skl_scaler_mode_valid(struct intel_display *display,  void
> adl_scaler_ecc_mask(const struct intel_crtc_state *crtc_state);
> 
>  void adl_scaler_ecc_unmask(const struct intel_crtc_state *crtc_state);
> +
> +unsigned int skl_scaler_1st_prefill_adjustment_worst(const struct
> +intel_crtc_state *crtc_state); unsigned int
> +skl_scaler_2nd_prefill_adjustment_worst(const struct intel_crtc_state
> +*crtc_state); unsigned int skl_scaler_1st_prefill_lines_worst(const
> +struct intel_crtc_state *crtc_state); unsigned int
> +skl_scaler_2nd_prefill_lines_worst(const struct intel_crtc_state
> +*crtc_state);
> +
> +unsigned int skl_scaler_1st_prefill_adjustment(const struct
> +intel_crtc_state *crtc_state); unsigned int
> +skl_scaler_2nd_prefill_adjustment(const struct intel_crtc_state
> +*crtc_state); unsigned int skl_scaler_1st_prefill_lines(const struct
> +intel_crtc_state *crtc_state); unsigned int
> +skl_scaler_2nd_prefill_lines(const struct intel_crtc_state
> +*crtc_state);
> +
>  #endif
> --
> 2.49.1

Reply via email to