drm/rockchip: Don't key off vblank for psr
authorSean Paul <seanpaul@chromium.org>
Thu, 18 Aug 2016 19:01:46 +0000 (12:01 -0700)
committerSean Paul <seanpaul@chromium.org>
Wed, 21 Sep 2016 13:55:47 +0000 (06:55 -0700)
Instead of keying off vblank for psr, just flush every time
we get an atomic update. This ensures that cursor updates
will properly disable psr (without turning vblank on/off),
and unifies the paths between fb_dirty and atomic psr
enable/disable.

Reviewed-by: Yakir Yang <ykk@rock-chips.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
drivers/gpu/drm/rockchip/rockchip_drm_fb.c
drivers/gpu/drm/rockchip/rockchip_drm_psr.c
drivers/gpu/drm/rockchip/rockchip_drm_psr.h
drivers/gpu/drm/rockchip/rockchip_drm_vop.c

index 60bcc48f84b9a667932e35b18c46d17d1bab3e49..9890eccadd3bd48dcc0aec3faf00846b60c3dc0b 100644 (file)
@@ -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;
 }
 
index c6ac5d01c8e439071f6eab96a0292448afa2ae6c..de6252f6cb8905c127b7bc892fbe0d7005d3f378 100644 (file)
@@ -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);
+
+       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_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 - 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);
 
-       psr_set_state(psr, PSR_DISABLE);
+       rockchip_drm_do_flush(psr);
        return 0;
 }
-EXPORT_SYMBOL(rockchip_drm_psr_disable);
+EXPORT_SYMBOL(rockchip_drm_psr_flush);
 
 /**
- * rockchip_drm_psr_flush - force to flush all registered PSR encoders
+ * 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;
index c35b68873a30525487df9621ea7cf99de2b7ead8..b420cf1bf9027b875a5d4f50d8482b1e04ba30cd 100644 (file)
 #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));
index d486049f97228131d67eb77873d0cd03bba9ddbd..efb216005baad7808692752575ac2e8b0842fd2f 100644 (file)
@@ -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);