drm/gma500: Add page flip support on psb/cdv
authorPaul Kocialkowski <paul.kocialkowski@bootlin.com>
Wed, 6 Nov 2019 09:44:00 +0000 (10:44 +0100)
committerPatrik Jakobsson <patrik.r.jakobsson@gmail.com>
Thu, 7 Nov 2019 09:16:31 +0000 (10:16 +0100)
Legacy (non-atomic) page flip support is added to the driver by using the
mode_set_base CRTC function, that allows configuring a new framebuffer for
display. Since the function requires the primary plane's fb to be set
already, this is done prior to calling the function in the page flip helper
and reverted if the flip fails.

The vblank interrupt handler is also refactored to support passing an event.
The PIPE_TE_STATUS bit is also considered to indicate vblank on medfield
only, as explained in psb_enable_vblank.

It was tested by running weston on both poulsbo and cedartrail.

Signed-off-by: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
Reviewed-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
Signed-off-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191106094400.445834-3-paul.kocialkowski@bootlin.com
drivers/gpu/drm/gma500/cdv_intel_display.c
drivers/gpu/drm/gma500/gma_display.c
drivers/gpu/drm/gma500/gma_display.h
drivers/gpu/drm/gma500/psb_intel_display.c
drivers/gpu/drm/gma500/psb_intel_drv.h
drivers/gpu/drm/gma500/psb_irq.c

index 8b784947ed3b91940af86f96f8f342cfce46b7bc..7109d3d19be00c15457809a1f2405c7de1ccd982 100644 (file)
@@ -979,6 +979,7 @@ const struct drm_crtc_funcs cdv_intel_crtc_funcs = {
        .gamma_set = gma_crtc_gamma_set,
        .set_config = gma_crtc_set_config,
        .destroy = gma_crtc_destroy,
+       .page_flip = gma_crtc_page_flip,
 };
 
 const struct gma_clock_funcs cdv_clock_funcs = {
index bc07ae2a9a1dea03111dae5c860ca42ae5614386..17f136985d21456b1ec4228e8946cfd5228f4fa4 100644 (file)
@@ -503,6 +503,52 @@ void gma_crtc_destroy(struct drm_crtc *crtc)
        kfree(gma_crtc);
 }
 
+int gma_crtc_page_flip(struct drm_crtc *crtc,
+                      struct drm_framebuffer *fb,
+                      struct drm_pending_vblank_event *event,
+                      uint32_t page_flip_flags,
+                      struct drm_modeset_acquire_ctx *ctx)
+{
+       struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
+       struct drm_framebuffer *current_fb = crtc->primary->fb;
+       struct drm_framebuffer *old_fb = crtc->primary->old_fb;
+       const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       struct drm_device *dev = crtc->dev;
+       unsigned long flags;
+       int ret;
+
+       if (!crtc_funcs->mode_set_base)
+               return -EINVAL;
+
+       /* Using mode_set_base requires the new fb to be set already. */
+       crtc->primary->fb = fb;
+
+       if (event) {
+               spin_lock_irqsave(&dev->event_lock, flags);
+
+               WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+               gma_crtc->page_flip_event = event;
+
+               /* Call this locked if we want an event at vblank interrupt. */
+               ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb);
+               if (ret) {
+                       gma_crtc->page_flip_event = NULL;
+                       drm_crtc_vblank_put(crtc);
+               }
+
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+       } else {
+               ret = crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y, old_fb);
+       }
+
+       /* Restore previous fb in case of failure. */
+       if (ret)
+               crtc->primary->fb = current_fb;
+
+       return ret;
+}
+
 int gma_crtc_set_config(struct drm_mode_set *set,
                        struct drm_modeset_acquire_ctx *ctx)
 {
index fdbd7ecaa59ca2c21208f9f01754e3ed9249e721..7bd6c1ee8b21a948d45229a5facbc093ff0ceffa 100644 (file)
@@ -11,6 +11,7 @@
 #define _GMA_DISPLAY_H_
 
 #include <linux/pm_runtime.h>
+#include <drm/drm_vblank.h>
 
 struct drm_encoder;
 struct drm_mode_set;
@@ -71,6 +72,11 @@ extern void gma_crtc_prepare(struct drm_crtc *crtc);
 extern void gma_crtc_commit(struct drm_crtc *crtc);
 extern void gma_crtc_disable(struct drm_crtc *crtc);
 extern void gma_crtc_destroy(struct drm_crtc *crtc);
+extern int gma_crtc_page_flip(struct drm_crtc *crtc,
+                             struct drm_framebuffer *fb,
+                             struct drm_pending_vblank_event *event,
+                             uint32_t page_flip_flags,
+                             struct drm_modeset_acquire_ctx *ctx);
 extern int gma_crtc_set_config(struct drm_mode_set *set,
                               struct drm_modeset_acquire_ctx *ctx);
 
index 4256410535f06636370226d8c2d2189dcd173913..fed3b563e62e62673add13ead9a2f27a443400ca 100644 (file)
@@ -432,6 +432,7 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = {
        .gamma_set = gma_crtc_gamma_set,
        .set_config = gma_crtc_set_config,
        .destroy = gma_crtc_destroy,
+       .page_flip = gma_crtc_page_flip,
 };
 
 const struct gma_clock_funcs psb_clock_funcs = {
index cdf10333d1c22c9ea681f56b05263f3b4f3789af..16c6136f778b07c32bc7642e4ad2bb79a0b28e74 100644 (file)
@@ -12,6 +12,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_encoder.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
 #include <linux/gpio.h>
 #include "gma_display.h"
 
@@ -182,6 +183,8 @@ struct gma_crtc {
        struct psb_intel_crtc_state *crtc_state;
 
        const struct gma_clock_funcs *clock_funcs;
+
+       struct drm_pending_vblank_event *page_flip_event;
 };
 
 #define to_gma_crtc(x) \
index e6265fb85626ee67e4c2075a5bd4c2f838209833..f787a51f6335b7b1410f94fd95372ed4ada8735b 100644 (file)
@@ -165,11 +165,23 @@ static void mid_pipe_event_handler(struct drm_device *dev, int pipe)
                "%s, can't clear status bits for pipe %d, its value = 0x%x.\n",
                __func__, pipe, PSB_RVDC32(pipe_stat_reg));
 
-       if (pipe_stat_val & PIPE_VBLANK_STATUS)
-               drm_handle_vblank(dev, pipe);
+       if (pipe_stat_val & PIPE_VBLANK_STATUS ||
+           (IS_MFLD(dev) && pipe_stat_val & PIPE_TE_STATUS)) {
+               struct drm_crtc *crtc = drm_crtc_from_index(dev, pipe);
+               struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
+               unsigned long flags;
 
-       if (pipe_stat_val & PIPE_TE_STATUS)
                drm_handle_vblank(dev, pipe);
+
+               spin_lock_irqsave(&dev->event_lock, flags);
+               if (gma_crtc->page_flip_event) {
+                       drm_crtc_send_vblank_event(crtc,
+                                                  gma_crtc->page_flip_event);
+                       gma_crtc->page_flip_event = NULL;
+                       drm_crtc_vblank_put(crtc);
+               }
+               spin_unlock_irqrestore(&dev->event_lock, flags);
+       }
 }
 
 /*