]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/i915/psr: Check if final vblank is sufficient for PSR features
authorAnkit Nautiyal <ankit.k.nautiyal@intel.com>
Thu, 16 Oct 2025 05:54:12 +0000 (11:24 +0530)
committerAnkit Nautiyal <ankit.k.nautiyal@intel.com>
Thu, 16 Oct 2025 13:57:41 +0000 (19:27 +0530)
Currently, wake line latency checks rely on the vblank length,
which does not account for either the extra vblank delay for icl/tgl or for
the optimized guardband which will come into picture later at some point.

Validate whether the final vblank (with extra vblank delay) or guardband
is sufficient to support wake line latencies required by Panel Replay and
PSR2 selective update. Disable the PSR features if their wake requirements
cannot be accomodated.

v2: Add comments clarifying wake line checks and rationale for not
    resetting SCL. (Jouni)
v3: Reset other psr flags based on features that are dropped. (Jouni)
v4: Update commit message.
v5: Remove early return and simplify the checking for wakelines. (Jouni)

Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
Cc: Animesh Manna <animesh.manna@intel.com>
Cc: Jouni Högander <jouni.hogander@intel.com>
Reviewed-by: Jouni Högander <jouni.hogander@intel.com>
Link: https://lore.kernel.org/r/20251016055415.2101347-9-ankit.k.nautiyal@intel.com
drivers/gpu/drm/i915/display/intel_psr.c

index 383e6dc1ed6370ae5be203dc154ede8e41f0fbee..703e5f6af04c7480680d8fd8be9161535f6ac652 100644 (file)
@@ -1405,6 +1405,20 @@ int _intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state
                return 1;
 }
 
+static bool _wake_lines_fit_into_vblank(const struct intel_crtc_state *crtc_state,
+                                       int vblank,
+                                       int wake_lines)
+{
+       if (crtc_state->req_psr2_sdp_prior_scanline)
+               vblank -= 1;
+
+       /* Vblank >= PSR2_CTL Block Count Number maximum line count */
+       if (vblank < wake_lines)
+               return false;
+
+       return true;
+}
+
 static bool wake_lines_fit_into_vblank(struct intel_dp *intel_dp,
                                       const struct intel_crtc_state *crtc_state,
                                       bool aux_less,
@@ -1428,14 +1442,16 @@ static bool wake_lines_fit_into_vblank(struct intel_dp *intel_dp,
                                               crtc_state->alpm_state.fast_wake_lines) :
                        crtc_state->alpm_state.io_wake_lines;
 
-       if (crtc_state->req_psr2_sdp_prior_scanline)
-               vblank -= 1;
-
-       /* Vblank >= PSR2_CTL Block Count Number maximum line count */
-       if (vblank < wake_lines)
-               return false;
-
-       return true;
+       /*
+        * Guardband has not been computed yet, so we conservatively check if the
+        * full vblank duration is sufficient to accommodate wake line requirements
+        * for PSR features like Panel Replay and Selective Update.
+        *
+        * Once the actual guardband is available, a more accurate validation is
+        * performed in intel_psr_compute_config_late(), and PSR features are
+        * disabled if wake lines exceed the available guardband.
+        */
+       return _wake_lines_fit_into_vblank(crtc_state, vblank, wake_lines);
 }
 
 static bool alpm_config_valid(struct intel_dp *intel_dp,
@@ -4351,6 +4367,45 @@ void intel_psr_compute_config_late(struct intel_dp *intel_dp,
                                   struct intel_crtc_state *crtc_state)
 {
        struct intel_display *display = to_intel_display(intel_dp);
+       int vblank = intel_crtc_vblank_length(crtc_state);
+       int wake_lines;
+
+       if (intel_psr_needs_alpm_aux_less(intel_dp, crtc_state))
+               wake_lines = crtc_state->alpm_state.aux_less_wake_lines;
+       else if (intel_psr_needs_alpm(intel_dp, crtc_state))
+               wake_lines = DISPLAY_VER(display) < 20 ?
+                            psr2_block_count_lines(crtc_state->alpm_state.io_wake_lines,
+                                                   crtc_state->alpm_state.fast_wake_lines) :
+                            crtc_state->alpm_state.io_wake_lines;
+       else
+               wake_lines = 0;
+
+       /*
+        * Disable the PSR features if wake lines exceed the available vblank.
+        * Though SCL is computed based on these PSR features, it is not reset
+        * even if the PSR features are disabled to avoid changing vblank start
+        * at this stage.
+        */
+       if (wake_lines && !_wake_lines_fit_into_vblank(crtc_state, vblank, wake_lines)) {
+               drm_dbg_kms(display->drm,
+                           "Adjusting PSR/PR mode: vblank too short for wake lines = %d\n",
+                           wake_lines);
+
+               if (crtc_state->has_panel_replay) {
+                       crtc_state->has_panel_replay = false;
+                       /*
+                        * #TODO : Add fall back to PSR/PSR2
+                        * Since panel replay cannot be supported, we can fall back to PSR/PSR2.
+                        * This will require calling compute_config for psr and psr2 with check for
+                        * actual guardband instead of vblank_length.
+                        */
+                       crtc_state->has_psr = false;
+               }
+
+               crtc_state->has_sel_update = false;
+               crtc_state->enable_psr2_su_region_et = false;
+               crtc_state->enable_psr2_sel_fetch = false;
+       }
 
        /* Wa_18037818876 */
        if (intel_psr_needs_wa_18037818876(intel_dp, crtc_state)) {