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