diff options
author | Inki Dae <inki.dae@samsung.com> | 2014-11-25 15:07:23 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-11-25 01:24:59 -0800 |
commit | 8c34dbd28cfce4e09ebec8bdf1b820924c2df45b (patch) | |
tree | 8dd4afa866e74b42ae61f7c59339c18fd8467b4e /drivers | |
parent | a39e2035bcc6502ce867807a70381f40543e4c72 (diff) | |
download | linux-3.10-8c34dbd28cfce4e09ebec8bdf1b820924c2df45b.tar.gz linux-3.10-8c34dbd28cfce4e09ebec8bdf1b820924c2df45b.tar.bz2 linux-3.10-8c34dbd28cfce4e09ebec8bdf1b820924c2df45b.zip |
drm/exynos: add dmabuf sync support for page flip
This patch adds dmabuf sync support for page flip.
With this patch, a dma buffer shared with cpu or other
dma devices, which buffer is accessed by display or
HDMI controllers, could be synchronized implicitly.
Change-Id: I7bd88b293d4d99b87488c0c1c8b07cb72acfb5e6
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1ea248c032b..7e52a170d1f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -22,6 +22,8 @@ #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) @@ -55,6 +57,7 @@ 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_crtc_dpms(struct drm_crtc *crtc, int mode) @@ -244,6 +247,11 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, } 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); /* @@ -259,6 +267,45 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, return ret; } + if (!dmabuf_sync_is_supported()) + goto out_fence; + + sync = dmabuf_sync_init("DRM", NULL, (void *)event->pipe); + 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->dma_buf) + continue; + + ret = dmabuf_sync_get(sync, + obj->dma_buf, 0, + DMA_BUF_ACCESS_DMA_R); + if (WARN_ON(ret < 0)) + continue; + } + + ret = dmabuf_sync_wait_all(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); @@ -386,6 +433,8 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager) return -ENOMEM; } + INIT_LIST_HEAD(&exynos_crtc->sync_committed); + crtc = &exynos_crtc->drm_crtc; private->crtc[manager->pipe] = crtc; @@ -438,12 +487,37 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) spin_lock_irqsave(&dev->event_lock, flags); + if (!list_empty(&exynos_crtc->sync_committed) && + dmabuf_sync_is_supported()) { + struct dmabuf_sync *sync; + int ret; + + sync = list_first_entry(&exynos_crtc->sync_committed, + struct dmabuf_sync, list); + ret = dmabuf_sync_signal_all(sync); + if (ret < 0) + WARN_ON(1); + + list_del_init(&sync->list); + dmabuf_sync_put_all(sync); + dmabuf_sync_fini(sync); + } + list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, base.link) { /* if event's pipe isn't same as crtc then ignore it. */ if (pipe != 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, pipe); |