#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)
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)
{
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;
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;
}
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)
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.
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);
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;
}
return -ENOMEM;
}
+ INIT_LIST_HEAD(&exynos_crtc->sync_committed);
+
crtc = &exynos_crtc->drm_crtc;
private->crtc[nr] = 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,
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);
#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)
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;