From: Ville Syrjälä <[email protected]> Add a new helper thingy to deal with the pipe prefill latency.
We get three potentially useful thigns out of this: - intel_prefill_vblank_too_short() used for checking the actual vblank/guardband length - intel_prefill_min_guardband() to calculate a suitable guardband size based on some worst case scaling/etc. estimates - intel_prefill_min_cdclk() used to calculate a minimum cdclk freqency required for very small vblank lengths (in case the otherwise compute minimum cdclk doesn't result in fast enough prefill). The internal arithmetic is done terms of scanlines using .16 binary fixed point represantion. Signed-off-by: Ville Syrjälä <[email protected]> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/display/intel_prefill.c | 167 +++++++++++++++++++ drivers/gpu/drm/i915/display/intel_prefill.h | 48 ++++++ drivers/gpu/drm/xe/Makefile | 1 + 4 files changed, 217 insertions(+) create mode 100644 drivers/gpu/drm/i915/display/intel_prefill.c create mode 100644 drivers/gpu/drm/i915/display/intel_prefill.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 78a45a6681df..088a6c6cd138 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -351,6 +351,7 @@ i915-y += \ display/intel_panel.o \ display/intel_pfit.o \ display/intel_pps.o \ + display/intel_prefill.o \ display/intel_qp_tables.o \ display/intel_sdvo.o \ display/intel_snps_hdmi_pll.o \ diff --git a/drivers/gpu/drm/i915/display/intel_prefill.c b/drivers/gpu/drm/i915/display/intel_prefill.c new file mode 100644 index 000000000000..8b9c14e5c505 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_prefill.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2025 Intel Corporation + */ + +#include <linux/debugfs.h> + +#include <drm/drm_print.h> + +#include "intel_cdclk.h" +#include "intel_display_core.h" +#include "intel_display_types.h" +#include "intel_prefill.h" +#include "intel_vdsc.h" +#include "skl_scaler.h" +#include "skl_watermark.h" + +static unsigned int prefill_usecs_to_lines(const struct intel_crtc_state *crtc_state, unsigned int usecs) +{ + const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; + + return DIV_ROUND_UP_ULL(mul_u32_u32(pipe_mode->crtc_clock, usecs << 16), + pipe_mode->crtc_htotal * 1000); +} + +static void _intel_prefill_init(struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state) +{ + ctx->prefill.fixed = crtc_state->framestart_delay; + + /* 20 usec for translation walks/etc. */ + ctx->prefill.fixed += prefill_usecs_to_lines(crtc_state, 20); + + ctx->prefill.dsc = intel_vdsc_prefill_lines(crtc_state); + + ctx->prefill.full = 0; +} + +static void intel_prefill_init_nocdclk_worst(struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state) +{ + _intel_prefill_init(ctx, crtc_state); + + ctx->prefill.wm0 = skl_wm0_prefill_lines_worst(crtc_state); + ctx->prefill.scaler_1st = skl_scaler_1st_prefill_lines_worst(crtc_state); + ctx->prefill.scaler_2nd = skl_scaler_2nd_prefill_lines_worst(crtc_state); + + ctx->adj.scaler_1st = skl_scaler_1st_prefill_adjustment_worst(crtc_state); + ctx->adj.scaler_2nd = skl_scaler_2nd_prefill_adjustment_worst(crtc_state); +} + +static void intel_prefill_init_nocdclk(struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state) +{ + _intel_prefill_init(ctx, crtc_state); + + ctx->prefill.wm0 = skl_wm0_prefill_lines(crtc_state); + ctx->prefill.scaler_1st = skl_scaler_1st_prefill_lines(crtc_state); + ctx->prefill.scaler_2nd = skl_scaler_2nd_prefill_lines(crtc_state); + + ctx->adj.scaler_1st = skl_scaler_1st_prefill_adjustment(crtc_state); + ctx->adj.scaler_2nd = skl_scaler_2nd_prefill_adjustment(crtc_state); +} + +static unsigned int prefill_adjust(unsigned int value, unsigned int factor) +{ + return DIV_ROUND_UP_ULL(mul_u32_u32(value, factor), 0x10000); +} + +static unsigned int prefill_lines_nocdclk(const struct intel_prefill_ctx *ctx) +{ + unsigned int prefill = 0; + + prefill += ctx->prefill.dsc; + prefill = prefill_adjust(prefill, ctx->adj.scaler_2nd); + + prefill += ctx->prefill.scaler_2nd; + prefill = prefill_adjust(prefill, ctx->adj.scaler_1st); + + prefill += ctx->prefill.scaler_1st; + prefill += ctx->prefill.wm0; + + return prefill; +} + +static unsigned int prefill_lines_cdclk(const struct intel_prefill_ctx *ctx) +{ + return prefill_adjust(prefill_lines_nocdclk(ctx), ctx->adj.cdclk); +} + +static unsigned int prefill_lines_full(const struct intel_prefill_ctx *ctx) +{ + return ctx->prefill.fixed + prefill_lines_cdclk(ctx); +} + +void intel_prefill_init_worst(struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state) +{ + intel_prefill_init_nocdclk_worst(ctx, crtc_state); + + ctx->adj.cdclk = intel_cdclk_prefill_adjustment_worst(crtc_state); + + ctx->prefill.full = prefill_lines_full(ctx); +} + +void intel_prefill_init(struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state, + const struct intel_cdclk_state *cdclk_state) +{ + intel_prefill_init_nocdclk(ctx, crtc_state); + + ctx->adj.cdclk = intel_cdclk_prefill_adjustment(crtc_state, cdclk_state); + + ctx->prefill.full = prefill_lines_full(ctx); +} + +static unsigned int prefill_lines_with_latency(const struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state, + unsigned int latency_us) +{ + return ctx->prefill.full + prefill_usecs_to_lines(crtc_state, latency_us); +} + +int intel_prefill_min_guardband(const struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state, + unsigned int latency_us) +{ + unsigned int prefill = prefill_lines_with_latency(ctx, crtc_state, latency_us); + + return DIV_ROUND_UP(prefill, 0x10000); +} + +static int intel_guardband(const struct intel_crtc_state *crtc_state) +{ + const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; + + if (crtc_state->vrr.enable) + return crtc_state->vrr.guardband; + else + return pipe_mode->crtc_vblank_end - pipe_mode->crtc_vblank_start; +} + +static int intel_prefill_guardband(const struct intel_crtc_state *crtc_state) +{ + return intel_guardband(crtc_state) << 16; +} + +bool intel_prefill_vblank_too_short(const struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state, + unsigned int latency_us) +{ + unsigned int guardband = intel_prefill_guardband(crtc_state); + unsigned int prefill = prefill_lines_with_latency(ctx, crtc_state, latency_us); + + return guardband < prefill; +} + +int intel_prefill_min_cdclk(const struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state) +{ + unsigned int prefill_unadjusted = prefill_lines_nocdclk(ctx); + unsigned int prefill_available = intel_prefill_guardband(crtc_state) - + ctx->prefill.fixed; + + return intel_cdclk_min_cdclk_for_prefill(crtc_state, prefill_unadjusted, + prefill_available); +} diff --git a/drivers/gpu/drm/i915/display/intel_prefill.h b/drivers/gpu/drm/i915/display/intel_prefill.h new file mode 100644 index 000000000000..0f07660261dc --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_prefill.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef __INTEL_PREFILL_H__ +#define __INTEL_PREFILL_H__ + +#include <linux/types.h> + +struct intel_cdclk_state; +struct intel_crtc_state; + +struct intel_prefill_ctx { + /* .16 scanlines */ + struct { + unsigned int fixed; + unsigned int wm0; + unsigned int scaler_1st; + unsigned int scaler_2nd; + unsigned int dsc; + unsigned int full; + } prefill; + + /* .16 adjustment factors */ + struct { + unsigned int cdclk; + unsigned int scaler_1st; + unsigned int scaler_2nd; + } adj; +}; + +void intel_prefill_init_worst(struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state); +void intel_prefill_init(struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state, + const struct intel_cdclk_state *cdclk_state); + +bool intel_prefill_vblank_too_short(const struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state, + unsigned int latency_us); +int intel_prefill_min_guardband(const struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state, + unsigned int latency_us); +int intel_prefill_min_cdclk(const struct intel_prefill_ctx *ctx, + const struct intel_crtc_state *crtc_state); + +#endif /* __INTEL_PREFILL_H__ */ diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 84321fad3265..1be020cc417d 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -300,6 +300,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_pmdemand.o \ i915-display/intel_pch.o \ i915-display/intel_pps.o \ + i915-display/intel_prefill.o \ i915-display/intel_psr.o \ i915-display/intel_qp_tables.o \ i915-display/intel_quirks.o \ -- 2.49.1
