From aeb99ba3659e8147e9f01a5ddfd529f1e1b16358 Mon Sep 17 00:00:00 2001 From: Ondrej Jirman Date: Sat, 9 Aug 2025 14:47:14 +0200 Subject: [PATCH 3/3] drm: sun4i: Report page flip after vsync is complete, not in the middle See: https://xnux.eu/log/080.html Signed-off-by: Ondrej Jirman --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 ++++++++++++++++++++++++-- drivers/gpu/drm/sun4i/sun4i_tcon.h | 4 ++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 221df37406d8..25c8bff308f2 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -240,6 +240,9 @@ void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable) if (enable) val = mask; + if (!enable && tcon->quirks->vblank_delay) + hrtimer_cancel(&tcon->flip_timer); + regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val); } EXPORT_SYMBOL(sun4i_tcon_enable_vblank); @@ -838,6 +841,17 @@ static void sun4i_tcon_finish_page_flip(struct drm_device *dev, spin_unlock_irqrestore(&dev->event_lock, flags); } +static enum hrtimer_restart sun4i_tcon_flip_timer_cb(struct hrtimer *timer) +{ + struct sun4i_tcon *tcon = container_of(timer, + struct sun4i_tcon, flip_timer); + + drm_crtc_handle_vblank(&tcon->crtc->crtc); + sun4i_tcon_finish_page_flip(tcon->drm, tcon->crtc); + + return HRTIMER_NORESTART; +} + static irqreturn_t sun4i_tcon_handler(int irq, void *private) { struct sun4i_tcon *tcon = private; @@ -853,8 +867,12 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private) SUN4I_TCON_GINT0_TCON0_TRI_FINISH_INT))) return IRQ_NONE; - drm_crtc_handle_vblank(&scrtc->crtc); - sun4i_tcon_finish_page_flip(drm, scrtc); + if (tcon->quirks->vblank_delay) { + hrtimer_start(&tcon->flip_timer, us_to_ktime(250), HRTIMER_MODE_REL); + } else { + drm_crtc_handle_vblank(&scrtc->crtc); + sun4i_tcon_finish_page_flip(drm, scrtc); + } /* Acknowledge the interrupt */ regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, @@ -903,6 +921,9 @@ static int sun4i_tcon_init_irq(struct device *dev, struct platform_device *pdev = to_platform_device(dev); int irq, ret; + hrtimer_setup(&tcon->flip_timer, sun4i_tcon_flip_timer_cb, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -1616,6 +1637,7 @@ static const struct sun4i_tcon_quirks sun50i_a64_lcd_quirks = { .restores_rate = true, .dclk_min_div = 1, .setup_lvds_phy = sun6i_tcon_setup_lvds_phy, + .vblank_delay = true, }; static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = { diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 729d64b78846..2bf91fb4872c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -252,6 +253,8 @@ struct sun4i_tcon_quirks { bool polarity_in_ch0; /* some tcon1 channels have polarity bits in tcon0 pol register */ bool restores_rate; /* restores the initial rate when rate changes */ u8 dclk_min_div; /* minimum divider for TCON0 DCLK */ + bool vblank_delay; /* delay page flip reporting for 250us (TCON report vblank + shortly before register flip) */ /* callback to handle tcon muxing options */ int (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *); @@ -289,6 +292,7 @@ struct sun4i_tcon { /* Associated crtc */ struct sun4i_crtc *crtc; + struct hrtimer flip_timer; int id; -- 2.51.0