On 9/11/2025 7:55 PM, Ville Syrjälä wrote:
On Thu, Sep 11, 2025 at 08:15:50AM +0530, Ankit Nautiyal wrote:
When VRR TG is always enabled and an optimized guardband is used, the pipe
vblank start is derived from the guardband.
Currently TRANS_SET_CONTEXT_LATENCY is programmed with crtc_vblank_start -
crtc_vdisplay, which is ~1 when guardband matches the vblank length.
With shorter guardband this become a large window.

To avoid misprogramming TRANS_SET_CONTEXT_LATENCY, clamp the scl value to 1
when using optimized guardband.

Also update the VRR get config logic to set crtc_vblank_start based on
vtotal - guardband, during readback.

Signed-off-by: Ankit Nautiyal <ankit.k.nauti...@intel.com>
---
  drivers/gpu/drm/i915/display/intel_display.c | 36 ++++++++++++++++----
  drivers/gpu/drm/i915/display/intel_vrr.c     |  9 ++++-
  2 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c 
b/drivers/gpu/drm/i915/display/intel_display.c
index 55bea1374dc4..73aec6d4686a 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -2638,6 +2638,30 @@ transcoder_has_vrr(const struct intel_crtc_state 
*crtc_state)
        return HAS_VRR(display) && !transcoder_is_dsi(cpu_transcoder);
  }
+static int intel_set_context_latency(const struct intel_crtc_state *crtc_state,
+                                    int crtc_vblank_start,
+                                    int crtc_vdisplay)
+{
+       struct intel_display *display = to_intel_display(crtc_state);
+
+       /*
+        * When VRR TG is always on and optimized guardband is used,
+        * the pipe vblank start is based on the guardband,
+        * TRANS_SET_CONTEXT_LATENCY cannot be used to configure it.
+        */
+       if (intel_vrr_always_use_vrr_tg(display))
+               return clamp(crtc_vblank_start - crtc_vdisplay, 0, 1);
What are you trying to achieve with this? As in what problem are you
seeing with the current SCL programming?

In VRR TG mode with optimized guardband, the guardband is shortened and vblank start is moved to match the delayed vblank position.

The SCL value which we are currently writing as difference between delayed vblank and undelayed vblank becomes quite large.

With this large SCL, the flipline decision boundary which is given by delayed vblank start and SCL lines is same as the undelayed vblank.

It seems that intel_dsb_wait_vblank_delay() (in turn intel_dsb_wait_usec()) does not behave correctly within the W2 window (between flipdone decision boundary and delayed vblank start).

It seems to return prematurely. Since the push bit hasn’t cleared yet, this leads to DSB poll errors.


AFAIU we are not using the SCL (Set Context Latency) lines to write registers via DSB.

The evasion logic ensures we write within a separate window, making the actual SCL value less critical for register programming.

So I have clamped the SCL value to (0,1). With this after the push is sent the send push bit is cleared after (0,1) lines.

But we still need to wait for the delayed vblank. For this we need either intel_dsb_wait_vblank_delay() or dsb_wait_for_scanline_in().


Do you have any ideas, what could have been going wrong or if anything we might have been missing?


Regards,

Ankit



+
+       /*
+        * VBLANK_START no longer works on ADL+, instead we must use
+        * TRANS_SET_CONTEXT_LATENCY to configure the pipe vblank start.
+        */
+       if (DISPLAY_VER(display) >= 13)
+               return crtc_vblank_start - crtc_vdisplay;
+
+       return 0;
+}
+
  static void intel_set_transcoder_timings(const struct intel_crtc_state 
*crtc_state)
  {
        struct intel_display *display = to_intel_display(crtc_state);
@@ -2671,14 +2695,12 @@ static void intel_set_transcoder_timings(const struct 
intel_crtc_state *crtc_sta
                        vsyncshift += adjusted_mode->crtc_htotal;
        }
- /*
-        * VBLANK_START no longer works on ADL+, instead we must use
-        * TRANS_SET_CONTEXT_LATENCY to configure the pipe vblank start.
-        */
        if (DISPLAY_VER(display) >= 13) {
                intel_de_write(display,
                               TRANS_SET_CONTEXT_LATENCY(display, 
cpu_transcoder),
-                              crtc_vblank_start - crtc_vdisplay);
+                              intel_set_context_latency(crtc_state,
+                                                        crtc_vblank_start,
+                                                        crtc_vdisplay));
/*
                 * VBLANK_START not used by hw, just clear it
@@ -2768,7 +2790,9 @@ static void intel_set_transcoder_timings_lrr(const struct 
intel_crtc_state *crtc
        if (DISPLAY_VER(display) >= 13) {
                intel_de_write(display,
                               TRANS_SET_CONTEXT_LATENCY(display, 
cpu_transcoder),
-                              crtc_vblank_start - crtc_vdisplay);
+                              intel_set_context_latency(crtc_state,
+                                                        crtc_vblank_start,
+                                                        crtc_vdisplay));
/*
                 * VBLANK_START not used by hw, just clear it
diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c 
b/drivers/gpu/drm/i915/display/intel_vrr.c
index 855974174afd..e124ef4e0ff4 100644
--- a/drivers/gpu/drm/i915/display/intel_vrr.c
+++ b/drivers/gpu/drm/i915/display/intel_vrr.c
@@ -749,11 +749,18 @@ void intel_vrr_get_config(struct intel_crtc_state 
*crtc_state)
                 * bits are not filled. Since vrr.vsync_start is computed as:
                 * crtc_vtotal - crtc_vsync_start, we can derive vtotal from
                 * vrr.vsync_start and crtc_vsync_start.
+                *
+                * With Optimized guardband, the vblank start is Vtotal - 
guardband
                 */
-               if (intel_vrr_always_use_vrr_tg(display))
+               if (intel_vrr_always_use_vrr_tg(display)) {
                        crtc_state->hw.adjusted_mode.crtc_vtotal =
                                crtc_state->hw.adjusted_mode.crtc_vsync_start +
                                crtc_state->vrr.vsync_start;
+
+                       crtc_state->hw.adjusted_mode.crtc_vblank_start =
+                               crtc_state->hw.adjusted_mode.crtc_vtotal -
+                               crtc_state->vrr.guardband;
+               }
        }
vrr_enable = trans_vrr_ctl & VRR_CTL_VRR_ENABLE;
--
2.45.2

Reply via email to