Use the new VRR state tracking to handle VRR front porch adjustment. To avoid indenting too deeply, refactor the vblank handling into its own function while at it, where scope-based cleanup helpers for the lock can be used.
Co-developed-by: Derek Foreman <[email protected]> Signed-off-by: Derek Foreman <[email protected]> Signed-off-by: Nicolas Frattaroli <[email protected]> --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 62 ++++++++++++++++++++++------ drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 9 ++++ 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index bfb384142568..e79081c04437 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -24,6 +24,7 @@ #include <drm/drm_atomic_uapi.h> #include <drm/drm_blend.h> #include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> #include <linux/debugfs.h> #include <drm/drm_debugfs.h> #include <drm/drm_flip_work.h> @@ -2011,6 +2012,25 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, vop2->ops->setup_overlay(vp); } +static void vop2_vp_set_vrr_vtotal(struct vop2_video_port *vp, unsigned int vtotal) +{ + const u32 mask = RK3568_VP_DSP_VTOTAL_VS_END__DSP_VTOTAL | + RK3568_VP_DSP_VTOTAL_VS_END__IMD; + + if (!vtotal) { + vop2_vp_update_bits(vp, RK3568_VP_DSP_VTOTAL_VS_END, + RK3568_VP_DSP_VTOTAL_VS_END__IMD, 0); + return; + } + + /* Value is 13 bits at most, saturate it if too large */ + if (vtotal > RK3568_VP_DSP_VTOTAL_VS_END__DSP_VTOTAL >> 16) + vtotal = RK3568_VP_DSP_VTOTAL_VS_END__DSP_VTOTAL >> 16; + + vop2_vp_update_bits(vp, RK3568_VP_DSP_VTOTAL_VS_END, mask, + vtotal << 16 | RK3568_VP_DSP_VTOTAL_VS_END__IMD); +} + static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_commit *state) { @@ -2029,6 +2049,11 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, spin_lock_irq(&crtc->dev->event_lock); + if (crtc_state->vrr_enabled) { + if (drm_crtc_helper_vrr_flush(crtc_state)) + vop2_vp_set_vrr_vtotal(vp, crtc_state->vrr_state.cur_vtotal); + } + if (crtc->state->event) { WARN_ON(drm_crtc_vblank_get(crtc)); vp->event = crtc->state->event; @@ -2371,6 +2396,30 @@ static irqreturn_t rk3576_vp_isr(int irq, void *data) return ret; } +static void vop2_vp_handle_vblank(struct vop2_video_port *vp) +{ + struct drm_crtc *crtc = &vp->crtc; + struct vop2 *vop2 = vp->vop2; + u32 val; + + guard(spinlock)(&crtc->dev->event_lock); + + if (!vp->event) + return; + + val = vop2_readl(vop2, RK3568_REG_CFG_DONE); + + if (!(val & BIT(vp->id))) { + drm_crtc_send_vblank_event(crtc, vp->event); + vp->event = NULL; + drm_crtc_vblank_put(crtc); + + if (crtc->state->vrr_enabled) + if (drm_crtc_helper_vrr_vsync(crtc->state)) + vop2_vp_set_vrr_vtotal(vp, crtc->state->vrr_state.cur_vtotal); + } +} + static irqreturn_t vop2_isr(int irq, void *data) { struct vop2 *vop2 = data; @@ -2402,18 +2451,7 @@ static irqreturn_t vop2_isr(int irq, void *data) if (irqs & VP_INT_FS_FIELD) { drm_crtc_handle_vblank(crtc); - spin_lock(&crtc->dev->event_lock); - if (vp->event) { - u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE); - - if (!(val & BIT(vp->id))) { - drm_crtc_send_vblank_event(crtc, vp->event); - vp->event = NULL; - drm_crtc_vblank_put(crtc); - } - } - spin_unlock(&crtc->dev->event_lock); - + vop2_vp_handle_vblank(vp); ret = IRQ_HANDLED; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index ffcb39c130aa..fdb2030e3ad4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -655,6 +655,9 @@ enum dst_factor_mode { #define RK3588_VP_DSP_CTRL__GAMMA_UPDATE_EN BIT(22) +#define RK3568_VP_DSP_VTOTAL_VS_END__DSP_VTOTAL GENMASK(28, 16) +#define RK3568_VP_DSP_VTOTAL_VS_END__IMD BIT(15) + #define RK3588_VP_CLK_CTRL__DCLK_OUT_DIV GENMASK(3, 2) #define RK3588_VP_CLK_CTRL__DCLK_CORE_DIV GENMASK(1, 0) @@ -810,6 +813,12 @@ static inline void vop2_vp_write(struct vop2_video_port *vp, u32 offset, u32 v) regmap_write(vp->vop2->map, vp->data->offset + offset, v); } +static inline void vop2_vp_update_bits(struct vop2_video_port *vp, u32 offset, + u32 mask, u32 v) +{ + regmap_update_bits(vp->vop2->map, vp->data->offset + offset, mask, v); +} + static inline u32 vop2_readl(struct vop2 *vop2, u32 offset) { u32 val; -- 2.55.0
