summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2013-09-17 21:01:47 +0900
committerChanho Park <chanho61.park@samsung.com>2014-11-18 11:47:27 +0900
commitc3a91a5262c0aa8a01573d32daeec054b2820e31 (patch)
tree28884664daf919971188ffd02b1c6b86255d26b5 /drivers
parent267f6c96e9016c8c91ce15598f89c4157fe0f05d (diff)
downloadlinux-3.10-c3a91a5262c0aa8a01573d32daeec054b2820e31.tar.gz
linux-3.10-c3a91a5262c0aa8a01573d32daeec054b2820e31.tar.bz2
linux-3.10-c3a91a5262c0aa8a01573d32daeec054b2820e31.zip
drm/exynos: add dmabuf sync support for kms framework
Change-Id: I5937869e5fa2ec2a41e864494eac0077ccdbdb51 Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c129
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c73
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.h24
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c13
4 files changed, 218 insertions, 21 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 311a36ed84a..4aee34487e6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -19,6 +19,10 @@
#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);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index ea39e0ef2ae..55300593d37 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -24,20 +24,7 @@
#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;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h
index 517471b3756..dbedbfc4a7f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h
@@ -14,6 +14,21 @@
#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
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index fcb0652e77d..c9a034f0033 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -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;
}