diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 6b7a9766f020..031381f0af6d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1912,8 +1912,13 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc) spin_lock_irqsave(&vop->irq_lock, flags); - VOP_INTR_SET_TYPE(vop, clear, FS_INTR, 1); - VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1); + if (VOP_MAJOR(vop->version) == 3 && VOP_MINOR(vop->version) >= 7) { + VOP_INTR_SET_TYPE(vop, clear, FS_FIELD_INTR, 1); + VOP_INTR_SET_TYPE(vop, enable, FS_FIELD_INTR, 1); + } else { + VOP_INTR_SET_TYPE(vop, clear, FS_INTR, 1); + VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 1); + } spin_unlock_irqrestore(&vop->irq_lock, flags); @@ -1930,7 +1935,10 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) spin_lock_irqsave(&vop->irq_lock, flags); - VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0); + if (VOP_MAJOR(vop->version) == 3 && VOP_MINOR(vop->version) >= 7) + VOP_INTR_SET_TYPE(vop, enable, FS_FIELD_INTR, 0); + else + VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0); spin_unlock_irqrestore(&vop->irq_lock, flags); } @@ -3181,7 +3189,10 @@ static void vop_cfg_update(struct drm_crtc *crtc, static bool vop_fs_irq_is_pending(struct vop *vop) { - return VOP_INTR_GET_TYPE(vop, status, FS_INTR); + if (VOP_MAJOR(vop->version) == 3 && VOP_MINOR(vop->version) >= 7) + return VOP_INTR_GET_TYPE(vop, status, FS_FIELD_INTR); + else + return VOP_INTR_GET_TYPE(vop, status, FS_INTR); } static void vop_wait_for_irq_handler(struct vop *vop) @@ -3277,6 +3288,18 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, spin_lock_irqsave(&vop->irq_lock, flags); vop->pre_overlay = s->hdr.pre_overlay; vop_cfg_done(vop); + /* + * rk322x and rk332x odd-even field will mistake when in interlace mode. + * we must switch to frame effect before switch screen and switch to + * field effect after switch screen complete. + */ + if (VOP_MAJOR(vop->version) == 3 && + (VOP_MINOR(vop->version) == 7 || VOP_MINOR(vop->version) == 8)) { + if (!vop->mode_update && VOP_CTRL_GET(vop, reg_done_frm)) + VOP_CTRL_SET(vop, reg_done_frm, 0); + } else { + VOP_CTRL_SET(vop, reg_done_frm, 0); + } vop->mode_update = false; spin_unlock_irqrestore(&vop->irq_lock, flags); @@ -3611,7 +3634,7 @@ static irqreturn_t vop_isr(int irq, void *data) ret = IRQ_HANDLED; } - if (active_irqs & FS_INTR) { + if ((active_irqs & FS_INTR) || (active_irqs & FS_FIELD_INTR)) { /* This is IC design not reasonable, this two register bit need * frame effective, but actually it's effective immediately, so * we config this register at frame start. @@ -3622,7 +3645,7 @@ static irqreturn_t vop_isr(int irq, void *data) spin_unlock_irqrestore(&vop->irq_lock, flags); drm_crtc_handle_vblank(crtc); vop_handle_vblank(vop); - active_irqs &= ~FS_INTR; + active_irqs &= ~(FS_INTR | FS_FIELD_INTR); ret = IRQ_HANDLED; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 37c31f3e98ca..3b079a09c87a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -465,6 +465,8 @@ struct vop_data { #define POST_BUF_EMPTY_INTR BIT(12) #define PWM_GEN_INTR BIT(13) #define DMA_FINISH_INTR BIT(14) +#define FS_FIELD_INTR BIT(15) +#define FE_INTR BIT(16) #define INTR_MASK (DSP_HOLD_VALID_INTR | FS_INTR | \ LINE_FLAG_INTR | BUS_ERROR_INTR | \ @@ -473,8 +475,8 @@ struct vop_data { WIN2_EMPTY_INTR | WIN3_EMPTY_INTR | \ HWC_EMPTY_INTR | \ POST_BUF_EMPTY_INTR | \ - DMA_FINISH_INTR) - + DMA_FINISH_INTR | FS_FIELD_INTR | \ + FE_INTR) #define DSP_HOLD_VALID_INTR_EN(x) ((x) << 4) #define FS_INTR_EN(x) ((x) << 5) #define LINE_FLAG_INTR_EN(x) ((x) << 6)