When inheriting the display state from BIOS (fastboot/seamless boot),
the DRM core's vblank timestamping constants (`linedur_ns`, `framedur_ns`)
may not be correctly initialized, leading to warnings or incorrect
timestamp values in pageflip events.

Additionally, the standard `intel_pipe_update_start/end` sequences perform
operations (vblank evasion, PSR locking, tracepoints) that are unnecessary
or harmful when we are merely synchronizing the software state to the
already-active hardware.

This patch addresses these issues:

1.  **Manual Timestamp Calculation**: Re-implements 
`intel_calc_timestamping_constants`
    to force-update `vblank->hwmode` and duration variables from the
    adjusted mode, ensuring valid timestamps even without a full modeset.

2.  **Inherited State Bypass**: In `intel_pipe_update_start` and
    `intel_pipe_update_end`, skip the standard hardware-touching logic
    if the CRTC state is marked as `inherited`.

3.  **Vblank Event Handling**: Within the `intel_pipe_update_end` bypass
    path, explicitly send any pending vblank events. This is critical to
    signal completion to userspace (e.g., SurfaceFlinger) without waiting
    for hardware vblanks that the driver isn't tracking yet.

4.  **Assertion Fixes**: Skip `assert_vblank_disabled` in `intel_crtc_vblank_on`
    for inherited states, as the vblank interrupt might already be running
    or the hardware state is effectively active.

Signed-off-by: Juasheem Sultan <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_crtc.c | 59 +++++++++++++++++++++++++++++--
 1 file changed, 56 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_crtc.c 
b/drivers/gpu/drm/i915/display/intel_crtc.c
index 
a187db6df2d36ec7dbbba56fe7aa4e9f9b92751c..a218f10c3b2c4ae6d85e115b0bb48b14e79347eb
 100644
--- a/drivers/gpu/drm/i915/display/intel_crtc.c
+++ b/drivers/gpu/drm/i915/display/intel_crtc.c
@@ -20,6 +20,7 @@
 #include "intel_color.h"
 #include "intel_crtc.h"
 #include "intel_cursor.h"
+#include "intel_display.h"
 #include "intel_display_debugfs.h"
 #include "intel_display_irq.h"
 #include "intel_display_trace.h"
@@ -120,15 +121,45 @@ u32 intel_crtc_max_vblank_count(const struct 
intel_crtc_state *crtc_state)
                return 0; /* Gen2 doesn't have a hardware frame counter */
 }
 
+static void intel_calc_timestamping_constants(struct drm_crtc *crtc,
+                                             const struct drm_display_mode 
*mode)
+{
+       struct drm_vblank_crtc *vblank = drm_crtc_vblank_crtc(crtc);
+       int linedur_ns = 0, framedur_ns = 0;
+       int dotclock = mode->crtc_clock;
+
+       if (dotclock > 0) {
+               int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
+
+               linedur_ns  = div_u64((u64) mode->crtc_htotal * 1000000, 
dotclock);
+               framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
+       }
+
+       vblank->linedur_ns  = linedur_ns;
+       vblank->framedur_ns = framedur_ns;
+
+       if (drm_drv_uses_atomic_modeset(crtc->dev)) {
+               drm_mode_copy(&vblank->hwmode, mode);
+               drm_dbg_kms(crtc->dev, "[FB-FIX] Updated vblank->hwmode: 
clock=%d\n", mode->crtc_clock);
+       }
+}
+
 void intel_crtc_vblank_on(const struct intel_crtc_state *crtc_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 
        crtc->vblank_psr_notify = 
intel_psr_needs_vblank_notification(crtc_state);
 
-       assert_vblank_disabled(&crtc->base);
-       drm_crtc_set_max_vblank_count(&crtc->base,
-                                     intel_crtc_max_vblank_count(crtc_state));
+       if (crtc_state->inherited) {
+       } else {
+               assert_vblank_disabled(&crtc->base);
+               drm_crtc_set_max_vblank_count(&crtc->base,
+                                             
intel_crtc_max_vblank_count(crtc_state));
+       }
+
+       /* [FB-FIX] Force calculation of constants to ensure framedur_ns is set 
*/
+       intel_calc_timestamping_constants(&crtc->base, 
&crtc_state->hw.adjusted_mode);
+
        drm_crtc_vblank_on(&crtc->base);
 
        /*
@@ -524,6 +555,13 @@ void intel_pipe_update_start(struct intel_atomic_state 
*state,
        struct intel_vblank_evade_ctx evade;
        int scanline;
 
+       /* [FB-FIX] Ensure timestamping constants are set for all updates */
+       intel_calc_timestamping_constants(&crtc->base, 
&new_crtc_state->hw.adjusted_mode);
+
+       if (new_crtc_state->inherited || old_crtc_state->inherited) {
+               return;
+       }
+
        drm_WARN_ON(display->drm, new_crtc_state->use_dsb);
 
        intel_psr_lock(new_crtc_state);
@@ -658,12 +696,27 @@ void intel_pipe_update_end(struct intel_atomic_state 
*state,
        struct intel_display *display = to_intel_display(state);
        struct intel_crtc_state *new_crtc_state =
                intel_atomic_get_new_crtc_state(state, crtc);
+       const struct intel_crtc_state *old_crtc_state =
+               intel_atomic_get_old_crtc_state(state, crtc);
        enum pipe pipe = crtc->pipe;
        int scanline_end = intel_get_crtc_scanline(crtc);
        u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
        ktime_t end_vbl_time = ktime_get();
        struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 
+       if (new_crtc_state->inherited || old_crtc_state->inherited) {
+               unsigned long irqflags;
+
+               if (new_crtc_state->uapi.event) {
+                       spin_lock_irqsave(&dev_priv->drm.event_lock, irqflags);
+                       drm_crtc_send_vblank_event(&crtc->base, 
new_crtc_state->uapi.event);
+                       spin_unlock_irqrestore(&dev_priv->drm.event_lock, 
irqflags);
+                       new_crtc_state->uapi.event = NULL;
+               }
+
+               return;
+       }
+
        drm_WARN_ON(display->drm, new_crtc_state->use_dsb);
 
        if (new_crtc_state->do_async_flip)

-- 
2.52.0.457.g6b5491de43-goog

Reply via email to