]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/i915/psr: Consider SCL lines when validating vblank for wake latency
authorAnkit Nautiyal <ankit.k.nautiyal@intel.com>
Thu, 16 Oct 2025 05:54:09 +0000 (11:24 +0530)
committerAnkit Nautiyal <ankit.k.nautiyal@intel.com>
Thu, 16 Oct 2025 13:57:38 +0000 (19:27 +0530)
Panel Replay and PSR2 selective update require sufficient vblank duration
to accommodate wake latencies. However, the current
wake_lines_fit_into_vblank() logic does not account for the minimum
Set Context Latency (SCL) lines.

Separate out _intel_psr_min_set_context_latency() to compute the minimum
SCL requirement based on platform and feature usage.

The alpm_config_valid() helper is updated to pass the necessary context for
determining whether Panel Replay or PSR2 selective update is enabled.

v2: While calling alpm_config_valid() for selective_update use false flag
    instead of has_panel_replay. (Jouni)
v3: Correct ordering of the panel_replay, sel_update flags. (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-6-ankit.k.nautiyal@intel.com
drivers/gpu/drm/i915/display/intel_psr.c

index 2131473cead6d254467cd8238018dace2fd57af8..1d06011a97cef754689f75754397c9977dd71538 100644 (file)
@@ -1361,14 +1361,64 @@ static int intel_psr_entry_setup_frames(struct intel_dp *intel_dp,
        return entry_setup_frames;
 }
 
+static
+int _intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state,
+                                      bool needs_panel_replay,
+                                      bool needs_sel_update)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+
+       if (!crtc_state->has_psr)
+               return 0;
+
+       /* Wa_14015401596 */
+       if (intel_vrr_possible(crtc_state) && IS_DISPLAY_VER(display, 13, 14))
+               return 1;
+
+       /* Rest is for SRD_STATUS needed on LunarLake and onwards */
+       if (DISPLAY_VER(display) < 20)
+               return 0;
+
+       /*
+        * Comment on SRD_STATUS register in Bspec for LunarLake and onwards:
+        *
+        * To deterministically capture the transition of the state machine
+        * going from SRDOFFACK to IDLE, the delayed V. Blank should be at least
+        * one line after the non-delayed V. Blank.
+        *
+        * Legacy TG: TRANS_SET_CONTEXT_LATENCY > 0
+        * VRR TG: TRANS_VRR_CTL[ VRR Guardband ] < (TRANS_VRR_VMAX[ VRR Vmax ]
+        * - TRANS_VTOTAL[ Vertical Active ])
+        *
+        * SRD_STATUS is used only by PSR1 on PantherLake.
+        * SRD_STATUS is used by PSR1 and Panel Replay DP on LunarLake.
+        */
+
+       if (DISPLAY_VER(display) >= 30 && (needs_panel_replay ||
+                                          needs_sel_update))
+               return 0;
+       else if (DISPLAY_VER(display) < 30 && (needs_sel_update ||
+                                              intel_crtc_has_type(crtc_state,
+                                                                  INTEL_OUTPUT_EDP)))
+               return 0;
+       else
+               return 1;
+}
+
 static bool wake_lines_fit_into_vblank(struct intel_dp *intel_dp,
                                       const struct intel_crtc_state *crtc_state,
-                                      bool aux_less)
+                                      bool aux_less,
+                                      bool needs_panel_replay,
+                                      bool needs_sel_update)
 {
        struct intel_display *display = to_intel_display(intel_dp);
        int vblank = crtc_state->hw.adjusted_mode.crtc_vblank_end -
                crtc_state->hw.adjusted_mode.crtc_vblank_start;
        int wake_lines;
+       int scl = _intel_psr_min_set_context_latency(crtc_state,
+                                                    needs_panel_replay,
+                                                    needs_sel_update);
+       vblank -= scl;
 
        if (aux_less)
                wake_lines = crtc_state->alpm_state.aux_less_wake_lines;
@@ -1390,7 +1440,9 @@ static bool wake_lines_fit_into_vblank(struct intel_dp *intel_dp,
 
 static bool alpm_config_valid(struct intel_dp *intel_dp,
                              struct intel_crtc_state *crtc_state,
-                             bool aux_less)
+                             bool aux_less,
+                             bool needs_panel_replay,
+                             bool needs_sel_update)
 {
        struct intel_display *display = to_intel_display(intel_dp);
 
@@ -1400,7 +1452,8 @@ static bool alpm_config_valid(struct intel_dp *intel_dp,
                return false;
        }
 
-       if (!wake_lines_fit_into_vblank(intel_dp, crtc_state, aux_less)) {
+       if (!wake_lines_fit_into_vblank(intel_dp, crtc_state, aux_less,
+                                       needs_panel_replay, needs_sel_update)) {
                drm_dbg_kms(display->drm,
                            "PSR2/Panel Replay not enabled, too short vblank time\n");
                return false;
@@ -1492,7 +1545,7 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp,
                return false;
        }
 
-       if (!alpm_config_valid(intel_dp, crtc_state, false))
+       if (!alpm_config_valid(intel_dp, crtc_state, false, false, true))
                return false;
 
        if (!crtc_state->enable_psr2_sel_fetch &&
@@ -1643,7 +1696,7 @@ _panel_replay_compute_config(struct intel_dp *intel_dp,
                return false;
        }
 
-       if (!alpm_config_valid(intel_dp, crtc_state, true))
+       if (!alpm_config_valid(intel_dp, crtc_state, true, true, false))
                return false;
 
        return true;
@@ -2371,43 +2424,10 @@ void intel_psr_trigger_frame_change_event(struct intel_dsb *dsb,
  */
 int intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state)
 {
-       struct intel_display *display = to_intel_display(crtc_state);
-
-       if (!crtc_state->has_psr)
-               return 0;
-
-       /* Wa_14015401596 */
-       if (intel_vrr_possible(crtc_state) && IS_DISPLAY_VER(display, 13, 14))
-               return 1;
-
-       /* Rest is for SRD_STATUS needed on LunarLake and onwards */
-       if (DISPLAY_VER(display) < 20)
-               return 0;
 
-       /*
-        * Comment on SRD_STATUS register in Bspec for LunarLake and onwards:
-        *
-        * To deterministically capture the transition of the state machine
-        * going from SRDOFFACK to IDLE, the delayed V. Blank should be at least
-        * one line after the non-delayed V. Blank.
-        *
-        * Legacy TG: TRANS_SET_CONTEXT_LATENCY > 0
-        * VRR TG: TRANS_VRR_CTL[ VRR Guardband ] < (TRANS_VRR_VMAX[ VRR Vmax ]
-        * - TRANS_VTOTAL[ Vertical Active ])
-        *
-        * SRD_STATUS is used only by PSR1 on PantherLake.
-        * SRD_STATUS is used by PSR1 and Panel Replay DP on LunarLake.
-        */
-
-       if (DISPLAY_VER(display) >= 30 && (crtc_state->has_panel_replay ||
-                                          crtc_state->has_sel_update))
-               return 0;
-       else if (DISPLAY_VER(display) < 30 && (crtc_state->has_sel_update ||
-                                              intel_crtc_has_type(crtc_state,
-                                                                  INTEL_OUTPUT_EDP)))
-               return 0;
-       else
-               return 1;
+       return _intel_psr_min_set_context_latency(crtc_state,
+                                                 crtc_state->has_panel_replay,
+                                                 crtc_state->has_sel_update);
 }
 
 static u32 man_trk_ctl_enable_bit_get(struct intel_display *display)