On Wed, Oct 15, 2025 at 11:23:50AM +0000, Shankar, Uma wrote:
>
>
> > -----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.
Yeah, it's due to the scalers not being assigned yet when we do the
vblank length check. I think I'll just hardcode the adjustment factors
to 1.0 for now.
>
> 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
>
--
Ville Syrjälä
Intel