diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 60bcc48f84b9..9890eccadd3b 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -70,7 +70,7 @@ static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, struct drm_clip_rect *clips, unsigned int num_clips) { - rockchip_drm_psr_flush(fb->dev); + rockchip_drm_psr_flush_all(fb->dev); return 0; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c index c6ac5d01c8e4..de6252f6cb89 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c @@ -31,6 +31,7 @@ struct psr_drv { struct drm_encoder *encoder; spinlock_t lock; + bool active; enum psr_state state; struct timer_list flush_timer; @@ -67,11 +68,7 @@ static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state) * v | | * PSR_DISABLE < - - - - - - - - - */ - if (state == psr->state) - return; - - /* Requesting a flush when disabled is a noop */ - if (state == PSR_FLUSH && psr->state == PSR_DISABLE) + if (state == psr->state || !psr->active) return; psr->state = state; @@ -115,45 +112,79 @@ static void psr_flush_handler(unsigned long data) } /** - * rockchip_drm_psr_enable - enable the encoder PSR which bind to given CRTC + * rockchip_drm_psr_activate - activate PSR on the given pipe * @crtc: CRTC to obtain the PSR encoder * * Returns: * Zero on success, negative errno on failure. */ -int rockchip_drm_psr_enable(struct drm_crtc *crtc) +int rockchip_drm_psr_activate(struct drm_crtc *crtc) { struct psr_drv *psr = find_psr_by_crtc(crtc); + unsigned long flags; if (IS_ERR(psr)) return PTR_ERR(psr); - psr_set_state(psr, PSR_ENABLE); + spin_lock_irqsave(&psr->lock, flags); + psr->active = true; + spin_unlock_irqrestore(&psr->lock, flags); + return 0; } -EXPORT_SYMBOL(rockchip_drm_psr_enable); +EXPORT_SYMBOL(rockchip_drm_psr_activate); /** - * rockchip_drm_psr_disable - disable the encoder PSR which bind to given CRTC + * rockchip_drm_psr_deactivate - deactivate PSR on the given pipe * @crtc: CRTC to obtain the PSR encoder * * Returns: * Zero on success, negative errno on failure. */ -int rockchip_drm_psr_disable(struct drm_crtc *crtc) +int rockchip_drm_psr_deactivate(struct drm_crtc *crtc) { struct psr_drv *psr = find_psr_by_crtc(crtc); + unsigned long flags; if (IS_ERR(psr)) return PTR_ERR(psr); - psr_set_state(psr, PSR_DISABLE); + spin_lock_irqsave(&psr->lock, flags); + psr->active = false; + spin_unlock_irqrestore(&psr->lock, flags); + del_timer_sync(&psr->flush_timer); + return 0; } -EXPORT_SYMBOL(rockchip_drm_psr_disable); +EXPORT_SYMBOL(rockchip_drm_psr_deactivate); + +static void rockchip_drm_do_flush(struct psr_drv *psr) +{ + mod_timer(&psr->flush_timer, + round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT)); + psr_set_state(psr, PSR_FLUSH); +} /** - * rockchip_drm_psr_flush - force to flush all registered PSR encoders + * rockchip_drm_psr_flush - flush a single pipe + * @crtc: CRTC of the pipe to flush + * + * Returns: + * 0 on success, -errno on fail + */ +int rockchip_drm_psr_flush(struct drm_crtc *crtc) +{ + struct psr_drv *psr = find_psr_by_crtc(crtc); + if (IS_ERR(psr)) + return PTR_ERR(psr); + + rockchip_drm_do_flush(psr); + return 0; +} +EXPORT_SYMBOL(rockchip_drm_psr_flush); + +/** + * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders * @dev: drm device * * Disable the PSR function for all registered encoders, and then enable the @@ -164,22 +195,18 @@ EXPORT_SYMBOL(rockchip_drm_psr_disable); * Returns: * Zero on success, negative errno on failure. */ -void rockchip_drm_psr_flush(struct drm_device *dev) +void rockchip_drm_psr_flush_all(struct drm_device *dev) { struct rockchip_drm_private *drm_drv = dev->dev_private; struct psr_drv *psr; unsigned long flags; spin_lock_irqsave(&drm_drv->psr_list_lock, flags); - list_for_each_entry(psr, &drm_drv->psr_list, list) { - mod_timer(&psr->flush_timer, - round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT)); - - psr_set_state(psr, PSR_FLUSH); - } + list_for_each_entry(psr, &drm_drv->psr_list, list) + rockchip_drm_do_flush(psr); spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags); } -EXPORT_SYMBOL(rockchip_drm_psr_flush); +EXPORT_SYMBOL(rockchip_drm_psr_flush_all); /** * rockchip_drm_psr_register - register encoder to psr driver @@ -206,6 +233,7 @@ int rockchip_drm_psr_register(struct drm_encoder *encoder, setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr); spin_lock_init(&psr->lock); + psr->active = true; psr->state = PSR_DISABLE; psr->encoder = encoder; psr->set = psr_set; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h index c35b68873a30..b420cf1bf902 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h @@ -15,9 +15,11 @@ #ifndef __ROCKCHIP_DRM_PSR___ #define __ROCKCHIP_DRM_PSR___ -void rockchip_drm_psr_flush(struct drm_device *dev); -int rockchip_drm_psr_enable(struct drm_crtc *crtc); -int rockchip_drm_psr_disable(struct drm_crtc *crtc); +void rockchip_drm_psr_flush_all(struct drm_device *dev); +int rockchip_drm_psr_flush(struct drm_crtc *crtc); + +int rockchip_drm_psr_activate(struct drm_crtc *crtc); +int rockchip_drm_psr_deactivate(struct drm_crtc *crtc); int rockchip_drm_psr_register(struct drm_encoder *encoder, void (*psr_set)(struct drm_encoder *, bool enable)); diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index d486049f9722..efb216005baa 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -569,6 +569,8 @@ static void vop_crtc_disable(struct drm_crtc *crtc) WARN_ON(vop->event); + rockchip_drm_psr_deactivate(&vop->crtc); + /* * We need to make sure that all windows are disabled before we * disable that crtc. Otherwise we might try to scan from a destroyed @@ -919,8 +921,6 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc) spin_unlock_irqrestore(&vop->irq_lock, flags); - rockchip_drm_psr_disable(&vop->crtc); - return 0; } @@ -937,8 +937,6 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc) VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0); spin_unlock_irqrestore(&vop->irq_lock, flags); - - rockchip_drm_psr_enable(&vop->crtc); } static void vop_crtc_wait_for_update(struct drm_crtc *crtc) @@ -1072,6 +1070,8 @@ static void vop_crtc_enable(struct drm_crtc *crtc) clk_set_rate(vop->dclk, adjusted_mode->clock * 1000); VOP_CTRL_SET(vop, standby, 0); + + rockchip_drm_psr_activate(&vop->crtc); } static void vop_crtc_atomic_flush(struct drm_crtc *crtc, @@ -1094,6 +1094,8 @@ static void vop_crtc_atomic_begin(struct drm_crtc *crtc, { struct vop *vop = to_vop(crtc); + rockchip_drm_psr_flush(crtc); + spin_lock_irq(&crtc->dev->event_lock); vop->vblank_active = true; WARN_ON(drm_crtc_vblank_get(crtc) != 0);