drm/exynos: add dmabuf sync support for kms framework
authorInki Dae <inki.dae@samsung.com>
Tue, 17 Sep 2013 12:01:47 +0000 (21:01 +0900)
committerMarek Szyprowski <m.szyprowski@samsung.com>
Thu, 15 May 2014 05:28:29 +0000 (07:28 +0200)
Change-Id: I5937869e5fa2ec2a41e864494eac0077ccdbdb51
Signed-off-by: Inki Dae <inki.dae@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fb.h
drivers/gpu/drm/exynos/exynos_drm_plane.c

index 311a36e..4aee344 100644 (file)
 #include "exynos_drm_drv.h"
 #include "exynos_drm_encoder.h"
 #include "exynos_drm_plane.h"
+#include "exynos_drm_fb.h"
+#include "exynos_drm_gem.h"
+
+#include <linux/dmabuf-sync.h>
 
 #define to_exynos_crtc(x)      container_of(x, struct exynos_drm_crtc,\
                                drm_crtc)
@@ -51,6 +55,18 @@ struct exynos_drm_crtc {
        enum exynos_crtc_mode           mode;
        wait_queue_head_t               pending_flip_queue;
        atomic_t                        pending_flip;
+       struct list_head                sync_committed;
+};
+
+static void exynos_drm_dmabuf_sync_free(void *priv)
+{
+       struct drm_pending_vblank_event *event = priv;
+
+       event->event.reserved = 0;
+}
+
+static struct dmabuf_sync_priv_ops dmabuf_sync_ops = {
+       .free   = exynos_drm_dmabuf_sync_free,
 };
 
 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -105,6 +121,7 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
        struct drm_plane *plane = exynos_crtc->plane;
+       struct dmabuf_sync *sync;
        unsigned int crtc_w;
        unsigned int crtc_h;
        int pipe = exynos_crtc->pipe;
@@ -129,6 +146,15 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 
        exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
 
+       if (!dmabuf_sync_is_supported())
+               return 0;
+
+       sync = (struct dmabuf_sync *)exynos_drm_dmabuf_sync_work(crtc->fb);
+       if (IS_ERR(sync)) {
+               /* just ignore buffer synchronization this time. */
+               return 0;
+       }
+
        return 0;
 }
 
@@ -169,7 +195,22 @@ static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                                          struct drm_framebuffer *old_fb)
 {
-       return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb);
+       struct dmabuf_sync *sync;
+       int ret;
+
+       ret = exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb);
+       if (ret < 0)
+               return ret;
+
+       if (!dmabuf_sync_is_supported())
+               return 0;
+
+       sync = (struct dmabuf_sync *)exynos_drm_dmabuf_sync_work(crtc->fb);
+       if (IS_ERR(sync))
+               /* just ignore buffer synchronization this time. */
+               return 0;
+
+       return 0;
 }
 
 static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
@@ -207,9 +248,14 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
-       mutex_lock(&dev->struct_mutex);
-
        if (event) {
+               struct exynos_drm_fb *exynos_fb;
+               struct drm_gem_object *obj;
+               struct dmabuf_sync *sync;
+               unsigned int i;
+
+               mutex_lock(&dev->struct_mutex);
+
                /*
                 * the pipe from user always is 0 so we can set pipe number
                 * of current owner to event.
@@ -219,10 +265,53 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                ret = drm_vblank_get(dev, exynos_crtc->pipe);
                if (ret) {
                        DRM_DEBUG("failed to acquire vblank counter\n");
+                       mutex_unlock(&dev->struct_mutex);
+                       return ret;
+               }
+
+               if (!dmabuf_sync_is_supported())
+                       goto out_fence;
 
-                       goto out;
+               sync = dmabuf_sync_init("DRM", &dmabuf_sync_ops, event);
+               if (IS_ERR(sync)) {
+                       WARN_ON(1);
+                       goto out_fence;
                }
 
+               exynos_fb = to_exynos_fb(fb);
+
+               for (i = 0; i < exynos_fb->buf_cnt; i++) {
+                       if (!exynos_fb->exynos_gem_obj[i]) {
+                               WARN_ON(1);
+                               continue;
+                       }
+
+                       obj = &exynos_fb->exynos_gem_obj[i]->base;
+                       if (!obj->export_dma_buf)
+                               continue;
+
+                       /*
+                        * set dmabuf to fence and registers reservation
+                        * object to reservation entry.
+                        */
+                       ret = dmabuf_sync_get(sync,
+                                       obj->export_dma_buf,
+                                       DMA_BUF_ACCESS_DMA_R);
+                       if (WARN_ON(ret < 0))
+                               continue;
+               }
+
+               ret = dmabuf_sync_lock(sync);
+               if (ret < 0) {
+                       dmabuf_sync_put_all(sync);
+                       dmabuf_sync_fini(sync);
+                       goto out_fence;
+               }
+
+               event->event.reserved = (unsigned long)sync;
+
+out_fence:
+
                spin_lock_irq(&dev->event_lock);
                list_add_tail(&event->base.link,
                                &dev_priv->pageflip_event_list);
@@ -240,11 +329,13 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                        list_del(&event->base.link);
                        spin_unlock_irq(&dev->event_lock);
 
-                       goto out;
+                       mutex_unlock(&dev->struct_mutex);
+                       return ret;
                }
+
+               mutex_unlock(&dev->struct_mutex);
        }
-out:
-       mutex_unlock(&dev->struct_mutex);
+
        return ret;
 }
 
@@ -344,6 +435,8 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
                return -ENOMEM;
        }
 
+       INIT_LIST_HEAD(&exynos_crtc->sync_committed);
+
        crtc = &exynos_crtc->drm_crtc;
 
        private->crtc[nr] = crtc;
@@ -392,6 +485,19 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
        unsigned long flags;
 
+       if (!list_empty(&exynos_crtc->sync_committed) &&
+                       dmabuf_sync_is_supported()) {
+               struct dmabuf_sync *sync;
+
+               sync = list_first_entry(&exynos_crtc->sync_committed,
+                                       struct dmabuf_sync, list);
+               if (!dmabuf_sync_unlock(sync)) {
+                       list_del_init(&sync->list);
+                       dmabuf_sync_put_all(sync);
+                       dmabuf_sync_fini(sync);
+               }
+       }
+
        spin_lock_irqsave(&dev->event_lock, flags);
 
        list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
@@ -400,6 +506,15 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
                if (crtc != e->pipe)
                        continue;
 
+               if (e->event.reserved && dmabuf_sync_is_supported()) {
+                       struct dmabuf_sync *sync;
+
+                       sync = (struct dmabuf_sync *)e->event.reserved;
+                       e->event.reserved = 0;
+                       list_add_tail(&sync->list,
+                                       &exynos_crtc->sync_committed);
+               }
+
                list_del(&e->base.link);
                drm_send_vblank_event(dev, -1, e);
                drm_vblank_put(dev, crtc);
index ea39e0e..5530059 100644 (file)
 #include "exynos_drm_iommu.h"
 #include "exynos_drm_encoder.h"
 
-#define to_exynos_fb(x)        container_of(x, struct exynos_drm_fb, fb)
-
-/*
- * exynos specific framebuffer structure.
- *
- * @fb: drm framebuffer obejct.
- * @buf_cnt: a buffer count to drm framebuffer.
- * @exynos_gem_obj: array of exynos specific gem object containing a gem object.
- */
-struct exynos_drm_fb {
-       struct drm_framebuffer          fb;
-       unsigned int                    buf_cnt;
-       struct exynos_drm_gem_obj       *exynos_gem_obj[MAX_FB_BUFFER];
-};
+#include <linux/dmabuf-sync.h>
 
 static int check_fb_gem_memory_type(struct drm_device *drm_dev,
                                struct exynos_drm_gem_obj *exynos_gem_obj)
@@ -171,6 +158,64 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
        return &exynos_fb->fb;
 }
 
+#ifdef CONFIG_DMABUF_SYNC
+void *exynos_drm_dmabuf_sync_work(struct drm_framebuffer *fb)
+{
+       struct exynos_drm_fb *exynos_fb;
+       struct drm_gem_object *obj;
+       struct dmabuf_sync *sync;
+       unsigned int i;
+       int ret = 0;
+
+       sync = dmabuf_sync_init("DRM", NULL, NULL);
+       if (IS_ERR(sync)) {
+               WARN_ON(1);
+               goto out_dmabuf_sync;
+       }
+
+       exynos_fb = to_exynos_fb(fb);
+
+       for (i = 0; i < exynos_fb->buf_cnt; i++) {
+               if (!exynos_fb->exynos_gem_obj[i]) {
+                       WARN_ON(1);
+                       continue;
+               }
+
+               obj = &exynos_fb->exynos_gem_obj[i]->base;
+               if (!obj->export_dma_buf)
+                       continue;
+
+               /*
+                * set dmabuf to fence and registers reservation
+                * object to reservation entry.
+                */
+               ret = dmabuf_sync_get(sync,
+                               obj->export_dma_buf,
+                               DMA_BUF_ACCESS_DMA_R);
+               if (WARN_ON(ret < 0))
+                       continue;
+
+       }
+
+       ret = dmabuf_sync_lock(sync);
+       if (ret < 0) {
+               dmabuf_sync_put_all(sync);
+               dmabuf_sync_fini(sync);
+               sync = ERR_PTR(ret);
+               goto out_dmabuf_sync;
+       }
+
+       /* buffer synchronization is done by wait_for_vblank so just signal. */
+       dmabuf_sync_unlock(sync);
+
+       dmabuf_sync_put_all(sync);
+       dmabuf_sync_fini(sync);
+
+out_dmabuf_sync:
+       return sync;
+}
+#endif
+
 static u32 exynos_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd)
 {
        unsigned int cnt = 0;
index 517471b..dbedbfc 100644 (file)
 #ifndef _EXYNOS_DRM_FB_H_
 #define _EXYNOS_DRM_FB_H
 
+#define to_exynos_fb(x)        container_of(x, struct exynos_drm_fb, fb)
+
+/*
+ * exynos specific framebuffer structure.
+ *
+ * @fb: drm framebuffer obejct.
+ * @buf_cnt: a buffer count to drm framebuffer.
+ * @exynos_gem_obj: array of exynos specific gem object containing a gem object.
+ */
+struct exynos_drm_fb {
+       struct drm_framebuffer          fb;
+       unsigned int                    buf_cnt;
+       struct exynos_drm_gem_obj       *exynos_gem_obj[MAX_FB_BUFFER];
+};
+
 struct drm_framebuffer *
 exynos_drm_framebuffer_init(struct drm_device *dev,
                            struct drm_mode_fb_cmd2 *mode_cmd,
@@ -32,4 +47,13 @@ void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
 /* get a buffer count to drm framebuffer. */
 unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb);
 
+#ifdef CONFIG_DMABUF_SYNC
+void *exynos_drm_dmabuf_sync_work(struct drm_framebuffer *fb);
+#else
+static inline void *exynos_drm_dmabuf_sync_work(struct drm_framebuffer *fb)
+{
+       return ERR_PTR(0);
+}
+#endif
+
 #endif
index fcb0652..c9a034f 100644 (file)
@@ -18,6 +18,8 @@
 #include "exynos_drm_gem.h"
 #include "exynos_drm_plane.h"
 
+#include <linux/dmabuf-sync.h>
+
 #define to_exynos_plane(x)     container_of(x, struct exynos_plane, base)
 
 struct exynos_plane {
@@ -184,6 +186,7 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                     uint32_t src_x, uint32_t src_y,
                     uint32_t src_w, uint32_t src_h)
 {
+       struct dmabuf_sync *sync;
        int ret;
 
        ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
@@ -197,6 +200,16 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        exynos_plane_commit(plane);
        exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
 
+       if (!dmabuf_sync_is_supported())
+               return 0;
+
+       sync = (struct dmabuf_sync *)exynos_drm_dmabuf_sync_work(fb);
+       if (IS_ERR(sync)) {
+               WARN_ON(1);
+               /* just ignore buffer synchronization this time. */
+               return 0;
+       }
+
        return 0;
 }