From ec3a347beaa21b4a041f636b7081d17677fb3f56 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 24 Jun 2025 20:00:45 +0300 Subject: [PATCH] drm/i915/flipq: Implement flip queue based commit path MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Support commits via the flip queue (as opposed to DSB or MMIO). As it's somewhat unknown if we can actually use it is currently gated behind the new use_flipq modparam, which defaults to disabled. The implementation has a bunch of limitations that would need real though to solve: - disabled when PSR is used - disabled when VRR is used - color management updates not performed via the flip queue v2: Don't use flip queue if there is no dmc v3: Use intel_flipq_supported() v3: Configure PKG_C_LATENCY appropriately Ignore INT_VECTOR if there is a real PIPEDMC interrupt (nothing in the hw appears to clear INT_VECTOR) v4: Leave added_wake_time=0 when flip queue isn't used, to avoid needleslly increasing pkg_c_latency on lnl/ptl due to Wa_22020432604. This is a bit racy though... Use IS_DISPLAY_VER() Reviewed-by: Uma Shankar Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20250624170049.27284-6-ville.syrjala@linux.intel.com --- drivers/gpu/drm/i915/display/intel_display.c | 44 +++++++++++++++---- .../drm/i915/display/intel_display_params.c | 3 ++ .../drm/i915/display/intel_display_params.h | 1 + .../drm/i915/display/intel_display_types.h | 3 ++ drivers/gpu/drm/i915/display/intel_dmc.c | 26 +++++++++-- drivers/gpu/drm/i915/display/intel_flipq.c | 5 ++- drivers/gpu/drm/i915/display/intel_flipq.h | 1 + drivers/gpu/drm/i915/display/skl_watermark.c | 7 ++- 8 files changed, 75 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index a687d315d2050..42780d7d8eed1 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -93,6 +93,7 @@ #include "intel_fbc.h" #include "intel_fdi.h" #include "intel_fifo_underrun.h" +#include "intel_flipq.h" #include "intel_frontbuffer.h" #include "intel_hdmi.h" #include "intel_hotplug.h" @@ -6619,7 +6620,7 @@ static void commit_pipe_pre_planes(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); bool modeset = intel_crtc_needs_modeset(new_crtc_state); - drm_WARN_ON(display->drm, new_crtc_state->use_dsb); + drm_WARN_ON(display->drm, new_crtc_state->use_dsb || new_crtc_state->use_flipq); /* * During modesets pipe configuration was programmed as the @@ -6649,7 +6650,7 @@ static void commit_pipe_post_planes(struct intel_atomic_state *state, intel_atomic_get_new_crtc_state(state, crtc); bool modeset = intel_crtc_needs_modeset(new_crtc_state); - drm_WARN_ON(display->drm, new_crtc_state->use_dsb); + drm_WARN_ON(display->drm, new_crtc_state->use_dsb || new_crtc_state->use_flipq); /* * Disable the scaler(s) after the plane(s) so that we don't @@ -6738,10 +6739,10 @@ static void intel_pre_update_crtc(struct intel_atomic_state *state, if (!modeset && intel_crtc_needs_color_update(new_crtc_state) && - !new_crtc_state->use_dsb) + !new_crtc_state->use_dsb && !new_crtc_state->use_flipq) intel_color_commit_noarm(NULL, new_crtc_state); - if (!new_crtc_state->use_dsb) + if (!new_crtc_state->use_dsb && !new_crtc_state->use_flipq) intel_crtc_planes_update_noarm(NULL, state, crtc); } @@ -6753,7 +6754,14 @@ static void intel_update_crtc(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - if (new_crtc_state->use_dsb) { + if (new_crtc_state->use_flipq) { + intel_flipq_enable(new_crtc_state); + + intel_crtc_prepare_vblank_event(new_crtc_state, &crtc->flipq_event); + + intel_flipq_add(crtc, INTEL_FLIPQ_PLANE_1, 0, INTEL_DSB_0, + new_crtc_state->dsb_commit); + } else if (new_crtc_state->use_dsb) { intel_crtc_prepare_vblank_event(new_crtc_state, &crtc->dsb_event); intel_dsb_commit(new_crtc_state->dsb_commit); @@ -7191,7 +7199,17 @@ static void intel_atomic_dsb_prepare(struct intel_atomic_state *state, return; /* FIXME deal with everything */ + new_crtc_state->use_flipq = + intel_flipq_supported(display) && + !new_crtc_state->do_async_flip && + !new_crtc_state->vrr.enable && + !new_crtc_state->has_psr && + !intel_crtc_needs_modeset(new_crtc_state) && + !intel_crtc_needs_fastset(new_crtc_state) && + !intel_crtc_needs_color_update(new_crtc_state); + new_crtc_state->use_dsb = + !new_crtc_state->use_flipq && !new_crtc_state->do_async_flip && (DISPLAY_VER(display) >= 20 || !new_crtc_state->has_psr) && !intel_crtc_needs_modeset(new_crtc_state) && @@ -7207,7 +7225,9 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, struct intel_crtc_state *new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc); - if (!new_crtc_state->use_dsb && !new_crtc_state->dsb_color) + if (!new_crtc_state->use_flipq && + !new_crtc_state->use_dsb && + !new_crtc_state->dsb_color) return; /* @@ -7216,14 +7236,16 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, * Double that for pipe stuff and other overhead. */ new_crtc_state->dsb_commit = intel_dsb_prepare(state, crtc, INTEL_DSB_0, - new_crtc_state->use_dsb ? 1024 : 16); + new_crtc_state->use_dsb || + new_crtc_state->use_flipq ? 1024 : 16); if (!new_crtc_state->dsb_commit) { + new_crtc_state->use_flipq = false; new_crtc_state->use_dsb = false; intel_color_cleanup_commit(new_crtc_state); return; } - if (new_crtc_state->use_dsb) { + if (new_crtc_state->use_flipq || new_crtc_state->use_dsb) { if (intel_crtc_needs_color_update(new_crtc_state)) intel_color_commit_noarm(new_crtc_state->dsb_commit, new_crtc_state); @@ -7238,7 +7260,8 @@ static void intel_atomic_dsb_finish(struct intel_atomic_state *state, intel_psr_trigger_frame_change_event(new_crtc_state->dsb_commit, state, crtc); - intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit); + if (new_crtc_state->use_dsb) + intel_dsb_vblank_evade(state, new_crtc_state->dsb_commit); if (intel_crtc_needs_color_update(new_crtc_state)) intel_color_commit_arm(new_crtc_state->dsb_commit, @@ -7417,6 +7440,9 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) if (!state->base.legacy_cursor_update && !new_crtc_state->use_dsb) intel_vrr_check_push_sent(NULL, new_crtc_state); + + if (new_crtc_state->use_flipq) + intel_flipq_disable(new_crtc_state); } /* diff --git a/drivers/gpu/drm/i915/display/intel_display_params.c b/drivers/gpu/drm/i915/display/intel_display_params.c index c4f1ab43fc0c8..75316247ee8a8 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.c +++ b/drivers/gpu/drm/i915/display/intel_display_params.c @@ -62,6 +62,9 @@ intel_display_param_named_unsafe(enable_dpt, bool, 0400, intel_display_param_named_unsafe(enable_dsb, bool, 0400, "Enable display state buffer (DSB) (default: true)"); +intel_display_param_named_unsafe(enable_flipq, bool, 0400, + "Enable DMC flip queue (default: false)"); + intel_display_param_named_unsafe(enable_sagv, bool, 0400, "Enable system agent voltage/frequency scaling (SAGV) (default: true)"); diff --git a/drivers/gpu/drm/i915/display/intel_display_params.h b/drivers/gpu/drm/i915/display/intel_display_params.h index 5317138e6044b..784e6bae86154 100644 --- a/drivers/gpu/drm/i915/display/intel_display_params.h +++ b/drivers/gpu/drm/i915/display/intel_display_params.h @@ -31,6 +31,7 @@ struct drm_printer; param(int, enable_dc, -1, 0400) \ param(bool, enable_dpt, true, 0400) \ param(bool, enable_dsb, true, 0600) \ + param(bool, enable_flipq, false, 0600) \ param(bool, enable_sagv, true, 0600) \ param(int, disable_power_well, -1, 0400) \ param(bool, enable_ips, true, 0600) \ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 9e355d781e5c7..ce45261c4a8f4 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1305,6 +1305,7 @@ struct intel_crtc_state { /* For DSB based pipe updates */ struct intel_dsb *dsb_color, *dsb_commit; bool use_dsb; + bool use_flipq; u32 psr2_man_track_ctl; @@ -1412,6 +1413,8 @@ struct intel_crtc { struct drm_pending_vblank_event *flip_done_event; /* armed event for DSB based updates */ struct drm_pending_vblank_event *dsb_event; + /* armed event for flip queue based updates */ + struct drm_pending_vblank_event *flipq_event; /* Access to these should be protected by display->irq.lock. */ bool cpu_fifo_underrun_disabled; diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index b8fe9a089bf20..af9eb67718ea0 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -501,7 +501,8 @@ static u32 pipedmc_interrupt_mask(struct intel_display *display) * triggering it during the first DC state transition. Figure * out what is going on... */ - return PIPEDMC_GTT_FAULT | + return PIPEDMC_FLIPQ_PROG_DONE | + PIPEDMC_GTT_FAULT | PIPEDMC_ATS_FAULT; } @@ -1608,12 +1609,29 @@ void intel_dmc_debugfs_register(struct intel_display *display) void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe) { struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe); - u32 tmp; + u32 tmp = 0, int_vector; if (DISPLAY_VER(display) >= 20) { tmp = intel_de_read(display, PIPEDMC_INTERRUPT(pipe)); intel_de_write(display, PIPEDMC_INTERRUPT(pipe), tmp); + if (tmp & PIPEDMC_FLIPQ_PROG_DONE) { + spin_lock(&display->drm->event_lock); + + if (crtc->flipq_event) { + /* + * Update vblank counter/timestamp in case it + * hasn't been done yet for this frame. + */ + drm_crtc_accurate_vblank_count(&crtc->base); + + drm_crtc_send_vblank_event(&crtc->base, crtc->flipq_event); + crtc->flipq_event = NULL; + } + + spin_unlock(&display->drm->event_lock); + } + if (tmp & PIPEDMC_ATS_FAULT) drm_err_ratelimited(display->drm, "[CRTC:%d:%s] PIPEDMC ATS fault\n", crtc->base.base.id, crtc->base.name); @@ -1625,8 +1643,8 @@ void intel_pipedmc_irq_handler(struct intel_display *display, enum pipe pipe) crtc->base.base.id, crtc->base.name); } - tmp = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK; - if (tmp) + int_vector = intel_de_read(display, PIPEDMC_STATUS(pipe)) & PIPEDMC_INT_VECTOR_MASK; + if (tmp == 0 && int_vector != 0) drm_err(display->drm, "[CRTC:%d:%s]] PIPEDMC interrupt vector 0x%x\n", crtc->base.base.id, crtc->base.name, tmp); } diff --git a/drivers/gpu/drm/i915/display/intel_flipq.c b/drivers/gpu/drm/i915/display/intel_flipq.c index 92324d207c247..9dbe0104c9ef6 100644 --- a/drivers/gpu/drm/i915/display/intel_flipq.c +++ b/drivers/gpu/drm/i915/display/intel_flipq.c @@ -112,6 +112,9 @@ static void intel_flipq_crtc_init(struct intel_crtc *crtc) bool intel_flipq_supported(struct intel_display *display) { + if (!display->params.enable_flipq) + return false; + if (!display->dmc.dmc) return false; @@ -140,7 +143,7 @@ static int cdclk_factor(struct intel_display *display) return 280; } -static int intel_flipq_exec_time_us(struct intel_display *display) +int intel_flipq_exec_time_us(struct intel_display *display) { return intel_dsb_exec_time_us() + DIV_ROUND_UP(display->cdclk.hw.cdclk * cdclk_factor(display), 540000) + diff --git a/drivers/gpu/drm/i915/display/intel_flipq.h b/drivers/gpu/drm/i915/display/intel_flipq.h index 64d3c2a5bb7b8..195ff0dd83f52 100644 --- a/drivers/gpu/drm/i915/display/intel_flipq.h +++ b/drivers/gpu/drm/i915/display/intel_flipq.h @@ -28,5 +28,6 @@ void intel_flipq_add(struct intel_crtc *crtc, unsigned int pts, enum intel_dsb_id dsb_id, struct intel_dsb *dsb); +int intel_flipq_exec_time_us(struct intel_display *display); #endif /* __INTEL_FLIPQ_H__ */ diff --git a/drivers/gpu/drm/i915/display/skl_watermark.c b/drivers/gpu/drm/i915/display/skl_watermark.c index 9ab9e2ed1089d..222c069fdadb5 100644 --- a/drivers/gpu/drm/i915/display/skl_watermark.c +++ b/drivers/gpu/drm/i915/display/skl_watermark.c @@ -26,6 +26,7 @@ #include "intel_display_types.h" #include "intel_fb.h" #include "intel_fixed.h" +#include "intel_flipq.h" #include "intel_pcode.h" #include "intel_plane.h" #include "intel_wm.h" @@ -2897,11 +2898,15 @@ intel_program_dpkgc_latency(struct intel_atomic_state *state) latency = skl_watermark_max_latency(display, 1); + /* FIXME runtime changes to enable_flipq are racy */ + if (display->params.enable_flipq) + added_wake_time = intel_flipq_exec_time_us(display); + /* * Wa_22020432604 * "PKG_C_LATENCY Added Wake Time field is not working" */ - if (latency && (DISPLAY_VER(display) == 20 || DISPLAY_VER(display) == 30)) { + if (latency && IS_DISPLAY_VER(display, 20, 30)) { latency += added_wake_time; added_wake_time = 0; } -- 2.47.2