[PATCH v2 14/27] drm/rockchip: vop2: Enable VRR
From: Nicolas Frattaroli
Date: Thu Nov 05 2026 - 11:34:04 EST
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 <derek.foreman@xxxxxxxxxxxxx>
Signed-off-by: Derek Foreman <derek.foreman@xxxxxxxxxxxxx>
Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@xxxxxxxxxxxxx>
---
drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 65 +++++++++++++++++++++++-----
drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 10 +++++
drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 4 ++
3 files changed, 67 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..d93b49025795 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;
}
@@ -2635,6 +2673,9 @@ static int vop2_create_crtcs(struct vop2 *vop2)
drm_crtc_attach_background_color_property(&vp->crtc);
+ if (vp->data->vrr_limiter_capable)
+ drm_crtc_attach_vrr_limiter_properties(&vp->crtc);
+
drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs);
if (vop2->lut_regs) {
const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id];
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
index ffcb39c130aa..323e2533de34 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h
@@ -231,6 +231,7 @@ struct vop2_video_port_data {
* @pixel_rate: pixel per cycle
*/
u8 pixel_rate;
+ bool vrr_limiter_capable;
};
struct vop2_video_port {
@@ -655,6 +656,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 +814,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;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
index c44648e1bc0d..946ca420f3f5 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c
@@ -1063,6 +1063,7 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
/* hdr2sdr sdr2hdr hdr2hdr sdr2sdr */
.pre_scan_max_dly = { 76, 65, 65, 54 },
.offset = 0xc00,
+ .vrr_limiter_capable = true,
}, {
.id = 1,
.feature = VOP2_VP_FEATURE_OUTPUT_10BIT,
@@ -1071,6 +1072,7 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
.max_output = { 4096, 2304 },
.pre_scan_max_dly = { 76, 65, 65, 54 },
.offset = 0xd00,
+ .vrr_limiter_capable = true,
}, {
.id = 2,
.feature = VOP2_VP_FEATURE_OUTPUT_10BIT,
@@ -1079,12 +1081,14 @@ static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
.max_output = { 4096, 2304 },
.pre_scan_max_dly = { 52, 52, 52, 52 },
.offset = 0xe00,
+ .vrr_limiter_capable = true,
}, {
.id = 3,
.gamma_lut_len = 1024,
.max_output = { 2048, 1536 },
.pre_scan_max_dly = { 52, 52, 52, 52 },
.offset = 0xf00,
+ .vrr_limiter_capable = true,
},
};
--
2.56.0