VIGS: Support DP memory and planar pixel formats 48/26348/1
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Wed, 11 Jun 2014 15:25:52 +0000 (19:25 +0400)
committerStanislav Vorobiov <s.vorobiov@samsung.com>
Tue, 19 Aug 2014 12:17:30 +0000 (16:17 +0400)
DP memory is used by some of the tizen
gstreamer plugins, TBM and X.Org video driver.
Its main purpose is to share GEM buffers between
media decoding and presentation layers

Planar pixel formats such as NV21 need to be
supported in order to be able to play video right
from decoder's output buffer, i.e. without
converting it to RGB

Change-Id: Ic16f1bd8b53e73b8ca0d3a5a3a52442f3c04770c
Signed-off-by: Stanislav Vorobiov <s.vorobiov@samsung.com>
17 files changed:
drivers/gpu/drm/vigs/Makefile
drivers/gpu/drm/vigs/vigs_comm.c
drivers/gpu/drm/vigs/vigs_comm.h
drivers/gpu/drm/vigs/vigs_crtc.c
drivers/gpu/drm/vigs/vigs_device.c
drivers/gpu/drm/vigs/vigs_device.h
drivers/gpu/drm/vigs/vigs_dp.c [new file with mode: 0644]
drivers/gpu/drm/vigs/vigs_dp.h [new file with mode: 0644]
drivers/gpu/drm/vigs/vigs_driver.c
drivers/gpu/drm/vigs/vigs_execbuffer.c
drivers/gpu/drm/vigs/vigs_execbuffer.h
drivers/gpu/drm/vigs/vigs_framebuffer.c
drivers/gpu/drm/vigs/vigs_framebuffer.h
drivers/gpu/drm/vigs/vigs_gem.c
drivers/gpu/drm/vigs/vigs_plane.c
drivers/gpu/drm/vigs/vigs_protocol.h
include/drm/vigs_drm.h

index 7312d42fc87db70822f39fe385e7f5d09aa4cb47..5e4dccb7a412eda9805879e7b40a02a6dfd26e0a 100644 (file)
@@ -19,6 +19,7 @@ vigs_drm-y := main.o \
               vigs_fence.o \
               vigs_fenceman.o \
               vigs_file.o \
-              vigs_plane.o
+              vigs_plane.o \
+              vigs_dp.o
 
 obj-$(CONFIG_DRM_VIGS) += vigs_drm.o
index 5dfb749a4328fff697c44d8ec91cab12f9da797e..758786f2f124d411f265029628c0033ae14fb023 100644 (file)
@@ -421,7 +421,10 @@ int vigs_comm_update_gpu(struct vigs_comm *comm,
 
 int vigs_comm_set_plane(struct vigs_comm *comm,
                         u32 plane,
-                        vigsp_surface_id sfc_id,
+                        u32 width,
+                        u32 height,
+                        vigsp_plane_format format,
+                        vigsp_surface_id surfaces[4],
                         unsigned int src_x,
                         unsigned int src_y,
                         unsigned int src_w,
@@ -435,8 +438,8 @@ int vigs_comm_set_plane(struct vigs_comm *comm,
     int ret;
     struct vigsp_cmd_set_plane_request *request;
 
-    DRM_DEBUG_DRIVER("plane = %u, sfc_id = %u, src_x = %u, src_y = %u, src_w = %u, src_h = %u, dst_x = %d, dst_y = %d, dst_w = %u, dst_h = %u, z_pos = %d\n",
-                     plane, sfc_id, src_x, src_y, src_w, src_h,
+    DRM_DEBUG_DRIVER("plane = %u, src_x = %u, src_y = %u, src_w = %u, src_h = %u, dst_x = %d, dst_y = %d, dst_w = %u, dst_h = %u, z_pos = %d\n",
+                     plane, src_x, src_y, src_w, src_h,
                      dst_x, dst_y, dst_w, dst_h, z_pos);
 
     mutex_lock(&comm->mutex);
@@ -448,7 +451,10 @@ int vigs_comm_set_plane(struct vigs_comm *comm,
 
     if (ret == 0) {
         request->plane = plane;
-        request->sfc_id = sfc_id;
+        request->width = width;
+        request->height = height;
+        request->format = format;
+        memcpy(request->surfaces, surfaces, sizeof(request->surfaces));
         request->src_rect.pos.x = src_x;
         request->src_rect.pos.y = src_y;
         request->src_rect.size.w = src_w;
index c57f35da9526400f98b8e93f3c55f79d9ab8f71e..1242e9c97a999f2f3ea472cf9e771fd68294a17f 100644 (file)
@@ -67,7 +67,10 @@ int vigs_comm_update_gpu(struct vigs_comm *comm,
 
 int vigs_comm_set_plane(struct vigs_comm *comm,
                         u32 plane,
-                        vigsp_surface_id sfc_id,
+                        u32 width,
+                        u32 height,
+                        vigsp_plane_format format,
+                        vigsp_surface_id surfaces[4],
                         unsigned int src_x,
                         unsigned int src_y,
                         unsigned int src_w,
index dbc3487fc5b112b3d846dbb4b1a5589df55e3ef9..da578a3a02b3c2bc7d757eb86d43b01fe6e8a73d 100644 (file)
@@ -31,7 +31,7 @@ static int vigs_crtc_update(struct drm_crtc *crtc,
 
     vigs_fb = fb_to_vigs_fb(crtc->fb);
 
-    if (vigs_fb->fb_sfc->scanout) {
+    if (vigs_fb->surfaces[0]->scanout) {
 retry:
         ret = vigs_framebuffer_pin(vigs_fb);
 
@@ -55,14 +55,14 @@ retry:
             goto retry;
         }
 
-        vigs_gem_reserve(&vigs_fb->fb_sfc->gem);
+        vigs_gem_reserve(&vigs_fb->surfaces[0]->gem);
 
         ret = vigs_comm_set_root_surface(vigs_dev->comm,
-                                         vigs_fb->fb_sfc->id,
+                                         vigs_fb->surfaces[0]->id,
                                          1,
-                                         vigs_gem_offset(&vigs_fb->fb_sfc->gem));
+                                         vigs_gem_offset(&vigs_fb->surfaces[0]->gem));
 
-        vigs_gem_unreserve(&vigs_fb->fb_sfc->gem);
+        vigs_gem_unreserve(&vigs_fb->surfaces[0]->gem);
 
         if (ret != 0) {
             vigs_framebuffer_unpin(vigs_fb);
@@ -71,7 +71,7 @@ retry:
         }
     } else {
         ret = vigs_comm_set_root_surface(vigs_dev->comm,
-                                         vigs_fb->fb_sfc->id,
+                                         vigs_fb->surfaces[0]->id,
                                          0,
                                          0);
 
@@ -80,7 +80,7 @@ retry:
         }
     }
 
-    if (vigs_old_fb && vigs_old_fb->fb_sfc->scanout) {
+    if (vigs_old_fb && vigs_old_fb->surfaces[0]->scanout) {
         vigs_framebuffer_unpin(vigs_old_fb);
     }
 
@@ -302,7 +302,7 @@ static void vigs_crtc_disable(struct drm_crtc *crtc)
 
     vigs_comm_set_root_surface(vigs_dev->comm, 0, 0, 0);
 
-    if (vigs_fb->fb_sfc->scanout) {
+    if (vigs_fb->surfaces[0]->scanout) {
         vigs_framebuffer_unpin(vigs_fb);
     }
 }
index 14b64187a224c167f3648261c90866a8ca5f8bf9..14a9956ef6d00ea6b86c01e84d7816b445545151 100644 (file)
@@ -9,6 +9,7 @@
 #include "vigs_fbdev.h"
 #include "vigs_execbuffer.h"
 #include "vigs_surface.h"
+#include "vigs_dp.h"
 #include <drm/vigs_drm.h>
 
 static void vigs_device_mman_vram_to_gpu(void *user_data,
@@ -170,12 +171,18 @@ int vigs_device_init(struct vigs_device *vigs_dev,
         goto fail4;
     }
 
-    ret = vigs_comm_create(vigs_dev, &vigs_dev->comm);
+    ret = vigs_dp_create(vigs_dev, &vigs_dev->dp);
 
     if (ret != 0) {
         goto fail5;
     }
 
+    ret = vigs_comm_create(vigs_dev, &vigs_dev->comm);
+
+    if (ret != 0) {
+        goto fail6;
+    }
+
     spin_lock_init(&vigs_dev->irq_lock);
 
     drm_mode_config_init(vigs_dev->drm_dev);
@@ -185,27 +192,27 @@ int vigs_device_init(struct vigs_device *vigs_dev,
     ret = vigs_crtc_init(vigs_dev);
 
     if (ret != 0) {
-        goto fail6;
+        goto fail7;
     }
 
     ret = vigs_output_init(vigs_dev);
 
     if (ret != 0) {
-        goto fail6;
+        goto fail7;
     }
 
     for (i = 0; i < VIGS_MAX_PLANES; ++i) {
         ret = vigs_plane_init(vigs_dev, i);
 
         if (ret != 0) {
-            goto fail6;
+            goto fail7;
         }
     }
 
     ret = drm_vblank_init(drm_dev, 1);
 
     if (ret != 0) {
-        goto fail6;
+        goto fail7;
     }
 
     /*
@@ -217,24 +224,26 @@ int vigs_device_init(struct vigs_device *vigs_dev,
     ret = drm_irq_install(drm_dev);
 
     if (ret != 0) {
-        goto fail7;
+        goto fail8;
     }
 
     ret = vigs_fbdev_create(vigs_dev, &vigs_dev->fbdev);
 
     if (ret != 0) {
-        goto fail8;
+        goto fail9;
     }
 
     return 0;
 
-fail8:
+fail9:
     drm_irq_uninstall(drm_dev);
-fail7:
+fail8:
     drm_vblank_cleanup(drm_dev);
-fail6:
+fail7:
     drm_mode_config_cleanup(vigs_dev->drm_dev);
     vigs_comm_destroy(vigs_dev->comm);
+fail6:
+    vigs_dp_destroy(vigs_dev->dp);
 fail5:
     vigs_fenceman_destroy(vigs_dev->fenceman);
 fail4:
@@ -259,6 +268,7 @@ void vigs_device_cleanup(struct vigs_device *vigs_dev)
     drm_vblank_cleanup(vigs_dev->drm_dev);
     drm_mode_config_cleanup(vigs_dev->drm_dev);
     vigs_comm_destroy(vigs_dev->comm);
+    vigs_dp_destroy(vigs_dev->dp);
     vigs_fenceman_destroy(vigs_dev->fenceman);
     ttm_object_device_release(&vigs_dev->obj_dev);
     vigs_mman_destroy(vigs_dev->mman);
index 1ea36dab6e9a1c93e740b536b585f12c1f40ac79..183898137881b2dc257df2e75ed8742e55a8380c 100644 (file)
@@ -6,6 +6,7 @@
 
 struct vigs_mman;
 struct vigs_fenceman;
+struct vigs_dp;
 struct vigs_comm;
 struct vigs_fbdev;
 struct vigs_surface;
@@ -39,6 +40,8 @@ struct vigs_device
 
     struct vigs_fenceman *fenceman;
 
+    struct vigs_dp *dp;
+
     struct vigs_comm *comm;
 
     struct vigs_fbdev *fbdev;
diff --git a/drivers/gpu/drm/vigs/vigs_dp.c b/drivers/gpu/drm/vigs/vigs_dp.c
new file mode 100644 (file)
index 0000000..7680230
--- /dev/null
@@ -0,0 +1,228 @@
+#include "vigs_dp.h"
+#include "vigs_surface.h"
+#include "vigs_device.h"
+
+int vigs_dp_create(struct vigs_device *vigs_dev,
+                   struct vigs_dp **dp)
+{
+    int ret = 0;
+
+    DRM_DEBUG_DRIVER("enter\n");
+
+    *dp = kzalloc(sizeof(**dp), GFP_KERNEL);
+
+    if (!*dp) {
+        ret = -ENOMEM;
+        goto fail1;
+    }
+
+    return 0;
+
+fail1:
+    *dp = NULL;
+
+    return ret;
+}
+
+void vigs_dp_destroy(struct vigs_dp *dp)
+{
+    DRM_DEBUG_DRIVER("enter\n");
+
+    kfree(dp);
+}
+
+void vigs_dp_remove_surface(struct vigs_dp *dp, struct vigs_surface *sfc)
+{
+    int i, j;
+
+    for (i = 0; i < VIGS_MAX_PLANES; ++i) {
+        for (j = 0; j < DRM_VIGS_NUM_DP_FB_BUF; ++j) {
+            if (dp->planes[i].fb_bufs[j].y == sfc) {
+                dp->planes[i].fb_bufs[j].y = NULL;
+            }
+            if (dp->planes[i].fb_bufs[j].c == sfc) {
+                dp->planes[i].fb_bufs[j].c = NULL;
+            }
+        }
+    }
+}
+
+int vigs_dp_surface_create_ioctl(struct drm_device *drm_dev,
+                                 void *data,
+                                 struct drm_file *file_priv)
+{
+    struct vigs_device *vigs_dev = drm_dev->dev_private;
+    struct vigs_dp *dp = vigs_dev->dp;
+    struct drm_vigs_dp_create_surface *args = data;
+    struct vigs_surface *sfc = NULL;
+    bool busy;
+    uint32_t handle;
+    int ret;
+
+    if (args->dp_plane >= VIGS_MAX_PLANES) {
+        DRM_ERROR("bad DP plane = %u\n", args->dp_plane);
+        return -ENOMEM;
+    }
+
+    if (args->dp_fb_buf >= DRM_VIGS_NUM_DP_FB_BUF) {
+        DRM_ERROR("bad DP fb buf = %u\n", args->dp_fb_buf);
+        return -ENOMEM;
+    }
+
+    mutex_lock(&vigs_dev->drm_dev->struct_mutex);
+
+    switch (args->dp_mem_flag) {
+    case DRM_VIGS_DP_FB_Y:
+        busy = dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].y != NULL;
+        break;
+    case DRM_VIGS_DP_FB_C:
+        busy = dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].c != NULL;
+        break;
+    default:
+        mutex_unlock(&vigs_dev->drm_dev->struct_mutex);
+        DRM_ERROR("bad DP mem flag = %u\n", args->dp_mem_flag);
+        return -ENOMEM;
+    }
+
+    mutex_unlock(&vigs_dev->drm_dev->struct_mutex);
+
+    if (busy) {
+        DRM_INFO("DP mem %u:%u:%u is busy\n", args->dp_plane,
+                                              args->dp_fb_buf,
+                                              args->dp_mem_flag);
+        return -ENOMEM;
+    }
+
+    ret = vigs_surface_create(vigs_dev,
+                              args->width,
+                              args->height,
+                              args->stride,
+                              args->format,
+                              false,
+                              &sfc);
+
+    if (ret != 0) {
+        return ret;
+    }
+
+    /*
+     * Check busy again since DP mem might
+     * gotten busy while we were creating our surface.
+     * If it's not busy then occupy it.
+     */
+
+    mutex_lock(&vigs_dev->drm_dev->struct_mutex);
+
+    switch (args->dp_mem_flag) {
+    case DRM_VIGS_DP_FB_Y:
+        if (dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].y) {
+            busy = true;
+        } else {
+            dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].y = sfc;
+        }
+        break;
+    case DRM_VIGS_DP_FB_C:
+        if (dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].c) {
+            busy = true;
+        } else {
+            dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].c = sfc;
+        }
+        break;
+    default:
+        drm_gem_object_unreference(&sfc->gem.base);
+        mutex_unlock(&vigs_dev->drm_dev->struct_mutex);
+        BUG();
+        return -ENOMEM;
+    }
+
+    mutex_unlock(&vigs_dev->drm_dev->struct_mutex);
+
+    if (busy) {
+        drm_gem_object_unreference_unlocked(&sfc->gem.base);
+
+        DRM_INFO("DP mem %u:%u:%u is busy\n", args->dp_plane,
+                                              args->dp_fb_buf,
+                                              args->dp_mem_flag);
+        return -ENOMEM;
+    }
+
+    ret = drm_gem_handle_create(file_priv,
+                                &sfc->gem.base,
+                                &handle);
+
+    if (ret == 0) {
+        args->handle = handle;
+        args->size = vigs_gem_size(&sfc->gem);
+        args->id = sfc->id;
+    } else {
+        /*
+         * Don't bother setting DP mem slot to NULL here, DRM
+         * will do this for us once the GEM is freed.
+         */
+    }
+
+    drm_gem_object_unreference_unlocked(&sfc->gem.base);
+
+    return ret;
+}
+
+int vigs_dp_surface_open_ioctl(struct drm_device *drm_dev,
+                               void *data,
+                               struct drm_file *file_priv)
+{
+    struct vigs_device *vigs_dev = drm_dev->dev_private;
+    struct vigs_dp *dp = vigs_dev->dp;
+    struct drm_vigs_dp_open_surface *args = data;
+    struct vigs_surface *sfc = NULL;
+    uint32_t handle;
+    int ret;
+
+    if (args->dp_plane >= VIGS_MAX_PLANES) {
+        DRM_ERROR("bad DP plane = %u\n", args->dp_plane);
+        return -ENOMEM;
+    }
+
+    if (args->dp_fb_buf >= DRM_VIGS_NUM_DP_FB_BUF) {
+        DRM_ERROR("bad DP fb buf = %u\n", args->dp_fb_buf);
+        return -ENOMEM;
+    }
+
+    mutex_lock(&vigs_dev->drm_dev->struct_mutex);
+
+    switch (args->dp_mem_flag) {
+    case DRM_VIGS_DP_FB_Y:
+        sfc = dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].y;
+        break;
+    case DRM_VIGS_DP_FB_C:
+        sfc = dp->planes[args->dp_plane].fb_bufs[args->dp_fb_buf].c;
+        break;
+    default:
+        mutex_unlock(&vigs_dev->drm_dev->struct_mutex);
+        DRM_ERROR("bad DP mem flag = %u\n", args->dp_mem_flag);
+        return -ENOMEM;
+    }
+
+    if (sfc) {
+        drm_gem_object_reference(&sfc->gem.base);
+    } else {
+        mutex_unlock(&vigs_dev->drm_dev->struct_mutex);
+        DRM_INFO("DP mem %u:%u:%u is empty\n", args->dp_plane,
+                                               args->dp_fb_buf,
+                                               args->dp_mem_flag);
+        return -ENOMEM;
+    }
+
+    mutex_unlock(&vigs_dev->drm_dev->struct_mutex);
+
+    ret = drm_gem_handle_create(file_priv,
+                                &sfc->gem.base,
+                                &handle);
+
+    if (ret == 0) {
+        args->handle = handle;
+    }
+
+    drm_gem_object_unreference_unlocked(&sfc->gem.base);
+
+    return ret;
+}
diff --git a/drivers/gpu/drm/vigs/vigs_dp.h b/drivers/gpu/drm/vigs/vigs_dp.h
new file mode 100644 (file)
index 0000000..46093ec
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _VIGS_DP_H_
+#define _VIGS_DP_H_
+
+#include "drmP.h"
+#include "vigs_protocol.h"
+#include <drm/vigs_drm.h>
+
+struct vigs_device;
+struct vigs_surface;
+
+struct vigs_dp_fb_buf
+{
+    /*
+     * These are weak pointers, no reference is kept
+     * for them. When surface is destroyed they're
+     * automatically reset to NULL. Must be
+     * accessed only with drm_device::struct_mutex held.
+     * @{
+     */
+
+    struct vigs_surface *y;
+    struct vigs_surface *c;
+
+    /*
+     * @}
+     */
+};
+
+struct vigs_dp_plane
+{
+    struct vigs_dp_fb_buf fb_bufs[DRM_VIGS_NUM_DP_FB_BUF];
+};
+
+struct vigs_dp
+{
+    struct vigs_dp_plane planes[VIGS_MAX_PLANES];
+};
+
+int vigs_dp_create(struct vigs_device *vigs_dev,
+                   struct vigs_dp **dp);
+
+void vigs_dp_destroy(struct vigs_dp *dp);
+
+/*
+ * Must be called with drm_device::struct_mutex held.
+ * @{
+ */
+
+void vigs_dp_remove_surface(struct vigs_dp *dp, struct vigs_surface *sfc);
+
+/*
+ * @}
+ */
+
+/*
+ * IOCTLs
+ * @{
+ */
+
+int vigs_dp_surface_create_ioctl(struct drm_device *drm_dev,
+                                 void *data,
+                                 struct drm_file *file_priv);
+
+int vigs_dp_surface_open_ioctl(struct drm_device *drm_dev,
+                               void *data,
+                               struct drm_file *file_priv);
+
+/*
+ * @}
+ */
+
+#endif
index 110ba4d6415a83a4b3d9b326f47fffbf42ee54b8..07cd0e68aa86b5926e2dfc84cf0a1509de3b373f 100644 (file)
@@ -10,6 +10,7 @@
 #include "vigs_file.h"
 #include "vigs_plane.h"
 #include "vigs_mman.h"
+#include "vigs_dp.h"
 #include <drm/drmP.h>
 #include <linux/module.h>
 #include <drm/vigs_drm.h>
@@ -66,7 +67,12 @@ static struct drm_ioctl_desc vigs_drm_ioctls[] =
     DRM_IOCTL_DEF_DRV(VIGS_FENCE_UNREF, vigs_fence_unref_ioctl,
                                         DRM_UNLOCKED | DRM_AUTH),
     DRM_IOCTL_DEF_DRV(VIGS_PLANE_SET_ZPOS, vigs_plane_set_zpos_ioctl,
-                                           DRM_UNLOCKED | DRM_AUTH)
+                                           DRM_UNLOCKED | DRM_AUTH),
+
+    DRM_IOCTL_DEF_DRV(VIGS_DP_CREATE_SURFACE, vigs_dp_surface_create_ioctl,
+                                              DRM_UNLOCKED | DRM_AUTH),
+    DRM_IOCTL_DEF_DRV(VIGS_DP_OPEN_SURFACE, vigs_dp_surface_open_ioctl,
+                                            DRM_UNLOCKED | DRM_AUTH)
 };
 
 static const struct file_operations vigs_drm_driver_fops =
index db73cdbb66df2997db4958cd979705f11b0c8f70..d6094489af92c7a0d6d992f65bd20d506555c9f5 100644 (file)
@@ -11,6 +11,7 @@ union vigs_request
     struct vigsp_cmd_update_gpu_request *update_gpu;
     struct vigsp_cmd_copy_request *copy;
     struct vigsp_cmd_solid_fill_request *solid_fill;
+    struct vigsp_cmd_ga_copy_request *ga_copy;
     void *data;
 };
 
@@ -146,6 +147,9 @@ int vigs_execbuffer_validate_buffers(struct vigs_execbuffer *execbuffer,
         case vigsp_cmd_solid_fill:
             *num_buffers += 1;
             break;
+        case vigsp_cmd_ga_copy:
+            *num_buffers += 2;
+            break;
         default:
             break;
         }
@@ -251,6 +255,36 @@ int vigs_execbuffer_validate_buffers(struct vigs_execbuffer *execbuffer,
 
             ++*num_buffers;
 
+            break;
+        case vigsp_cmd_ga_copy:
+            ret = vigs_execbuffer_validate_buffer(vigs_dev,
+                                                  &(*buffers)[*num_buffers],
+                                                  list,
+                                                  request.ga_copy->src_id,
+                                                  request_header->cmd,
+                                                  0,
+                                                  request.data);
+
+            if (ret != 0) {
+                goto fail2;
+            }
+
+            ++*num_buffers;
+
+            ret = vigs_execbuffer_validate_buffer(vigs_dev,
+                                                  &(*buffers)[*num_buffers],
+                                                  list,
+                                                  request.ga_copy->dst_id,
+                                                  request_header->cmd,
+                                                  1,
+                                                  request.data);
+
+            if (ret != 0) {
+                goto fail2;
+            }
+
+            ++*num_buffers;
+
             break;
         default:
             break;
@@ -279,7 +313,8 @@ fail1:
 
 void vigs_execbuffer_process_buffers(struct vigs_execbuffer *execbuffer,
                                      struct vigs_validate_buffer *buffers,
-                                     int num_buffers)
+                                     int num_buffers,
+                                     bool *sync)
 {
     union vigs_request request;
     struct vigs_gem_object *gem;
@@ -334,6 +369,20 @@ void vigs_execbuffer_process_buffers(struct vigs_execbuffer *execbuffer,
                 sfc->is_gpu_dirty = true;
             }
             break;
+        case vigsp_cmd_ga_copy:
+            if (buffers[i].which && vigs_gem_in_vram(&sfc->gem)) {
+                sfc->is_gpu_dirty = true;
+            } else if (buffers[i].which == 0) {
+                if (vigs_gem_in_vram(&sfc->gem)) {
+                    request.ga_copy->src_scanout = true;
+                    request.ga_copy->src_offset = vigs_gem_offset(&sfc->gem);
+                    *sync = true;
+                } else {
+                    request.ga_copy->src_scanout = false;
+                    request.ga_copy->src_offset = 0;
+                }
+            }
+            break;
         default:
             break;
         }
@@ -475,7 +524,7 @@ int vigs_execbuffer_exec_ioctl(struct drm_device *drm_dev,
             goto out3;
         }
 
-        vigs_execbuffer_process_buffers(execbuffer, buffers, num_buffers);
+        vigs_execbuffer_process_buffers(execbuffer, buffers, num_buffers, &sync);
 
         vigs_execbuffer_fence(execbuffer, fence);
 
index 96af8a1ba1b745d0d0f99092799bec9a57de9569..0564954ea2afa2fabf9e83abf1f63f55e46cddcb 100644 (file)
@@ -45,7 +45,8 @@ int vigs_execbuffer_validate_buffers(struct vigs_execbuffer *execbuffer,
 
 void vigs_execbuffer_process_buffers(struct vigs_execbuffer *execbuffer,
                                      struct vigs_validate_buffer *buffers,
-                                     int num_buffers);
+                                     int num_buffers,
+                                     bool *sync);
 
 void vigs_execbuffer_fence(struct vigs_execbuffer *execbuffer,
                            struct vigs_fence *fence);
index 712f23dd8912e53556bea73d598af766d57b9ea0..65c78f584fc930f436130f19cb5b2d6607d813dc 100644 (file)
@@ -6,65 +6,10 @@
 #include "drm_crtc_helper.h"
 #include <drm/vigs_drm.h>
 
-static struct drm_framebuffer *vigs_fb_create(struct drm_device *drm_dev,
-                                              struct drm_file *file_priv,
-                                              struct drm_mode_fb_cmd2 *mode_cmd)
-{
-    struct vigs_device *vigs_dev = drm_dev->dev_private;
-    struct drm_gem_object *gem;
-    struct vigs_gem_object *vigs_gem;
-    struct vigs_surface *vigs_sfc;
-    struct vigs_framebuffer *vigs_fb;
-    int ret;
-
-    DRM_DEBUG_KMS("enter\n");
-
-    gem = drm_gem_object_lookup(drm_dev, file_priv, mode_cmd->handles[0]);
-
-    if (!gem) {
-        DRM_ERROR("GEM lookup failed, handle = %u\n", mode_cmd->handles[0]);
-        return ERR_PTR(-ENOENT);
-    }
-
-    vigs_gem = gem_to_vigs_gem(gem);
-
-    if (vigs_gem->type != VIGS_GEM_TYPE_SURFACE) {
-        DRM_ERROR("GEM is not a surface, handle = %u\n", mode_cmd->handles[0]);
-        drm_gem_object_unreference_unlocked(gem);
-        return ERR_PTR(-ENOENT);
-    }
-
-    vigs_sfc = vigs_gem_to_vigs_surface(vigs_gem);
-
-    ret = vigs_framebuffer_create(vigs_dev,
-                                  mode_cmd,
-                                  vigs_sfc,
-                                  &vigs_fb);
-
-    drm_gem_object_unreference_unlocked(gem);
-
-    if (ret != 0) {
-        DRM_ERROR("unable to create the framebuffer: %d\n", ret);
-        return ERR_PTR(ret);
-    }
-
-    return &vigs_fb->base;
-}
-
-static void vigs_output_poll_changed(struct drm_device *drm_dev)
-{
-    struct vigs_device *vigs_dev = drm_dev->dev_private;
-
-    DRM_DEBUG_KMS("enter\n");
-
-    if (vigs_dev->fbdev) {
-        vigs_fbdev_output_poll_changed(vigs_dev->fbdev);
-    }
-}
-
 static void vigs_framebuffer_destroy(struct drm_framebuffer *fb)
 {
     struct vigs_framebuffer *vigs_fb = fb_to_vigs_fb(fb);
+    int i;
 
     DRM_DEBUG_KMS("enter\n");
 
@@ -77,13 +22,28 @@ static void vigs_framebuffer_destroy(struct drm_framebuffer *fb)
     drm_framebuffer_cleanup(fb);
 
     /*
-     * And we can finally free the GEM.
+     * And we can finally free the GEMs.
      */
 
-    drm_gem_object_unreference_unlocked(&vigs_fb->fb_sfc->gem.base);
+    for (i = 0; i < 4; ++i) {
+        if (vigs_fb->surfaces[i]) {
+            drm_gem_object_unreference_unlocked(&vigs_fb->surfaces[i]->gem.base);
+        }
+    }
     kfree(vigs_fb);
 }
 
+static int vigs_framebuffer_create_handle(struct drm_framebuffer *fb,
+                                          struct drm_file *file_priv,
+                                          unsigned int *handle)
+{
+    struct vigs_framebuffer *vigs_fb = fb_to_vigs_fb(fb);
+
+    DRM_DEBUG_KMS("enter\n");
+
+    return drm_gem_handle_create(file_priv, &vigs_fb->surfaces[0]->gem.base, handle);
+}
+
 static int vigs_framebuffer_dirty(struct drm_framebuffer *fb,
                                   struct drm_file *file_priv,
                                   unsigned flags, unsigned color,
@@ -95,15 +55,93 @@ static int vigs_framebuffer_dirty(struct drm_framebuffer *fb,
     return 0;
 }
 
-static int vigs_framebuffer_create_handle(struct drm_framebuffer *fb,
-                                          struct drm_file *file_priv,
-                                          unsigned int *handle)
+static struct drm_framebuffer_funcs vigs_framebuffer_funcs =
 {
-    struct vigs_framebuffer *vigs_fb = fb_to_vigs_fb(fb);
+    .destroy = vigs_framebuffer_destroy,
+    .create_handle = vigs_framebuffer_create_handle,
+    .dirty = vigs_framebuffer_dirty,
+};
+
+static struct drm_framebuffer *vigs_fb_create(struct drm_device *drm_dev,
+                                              struct drm_file *file_priv,
+                                              struct drm_mode_fb_cmd2 *mode_cmd)
+{
+    struct vigs_device *vigs_dev = drm_dev->dev_private;
+    struct vigs_surface *surfaces[4];
+    int ret, i;
+    int num_planes = drm_format_num_planes(mode_cmd->pixel_format);
+    struct vigs_framebuffer *vigs_fb;
+
+    DRM_DEBUG_KMS("enter\n");
+
+    for (i = 0; i < num_planes; ++i) {
+        struct drm_gem_object *gem;
+        struct vigs_gem_object *vigs_gem;
+
+        gem = drm_gem_object_lookup(drm_dev, file_priv, mode_cmd->handles[i]);
+
+        if (!gem) {
+            DRM_ERROR("GEM lookup failed, handle = %u\n", mode_cmd->handles[i]);
+            ret = -ENOENT;
+            goto fail;
+        }
+
+        vigs_gem = gem_to_vigs_gem(gem);
+
+        if (vigs_gem->type != VIGS_GEM_TYPE_SURFACE) {
+            DRM_ERROR("GEM is not a surface, handle = %u\n", mode_cmd->handles[i]);
+            drm_gem_object_unreference_unlocked(gem);
+            ret = -ENOENT;
+            goto fail;
+        }
+
+        surfaces[i] = vigs_gem_to_vigs_surface(vigs_gem);
+    }
+
+    vigs_fb = kzalloc(sizeof(*vigs_fb), GFP_KERNEL);
+
+    if (!vigs_fb) {
+        ret = -ENOMEM;
+        goto fail;
+    }
+
+    vigs_fb->comm = vigs_dev->comm;
+
+    for (i = 0; i < num_planes; ++i) {
+        vigs_fb->surfaces[i] = surfaces[i];
+    }
+
+    ret = drm_framebuffer_init(vigs_dev->drm_dev,
+                               &vigs_fb->base,
+                               &vigs_framebuffer_funcs);
+
+    if (ret != 0) {
+        DRM_ERROR("unable to create the framebuffer: %d\n", ret);
+        kfree(vigs_fb);
+        goto fail;
+    }
+
+    drm_helper_mode_fill_fb_struct(&vigs_fb->base, mode_cmd);
+
+    return &vigs_fb->base;
+
+fail:
+    for (i--; i >= 0; i--) {
+        drm_gem_object_unreference_unlocked(&surfaces[i]->gem.base);
+    }
+
+    return ERR_PTR(ret);
+}
+
+static void vigs_output_poll_changed(struct drm_device *drm_dev)
+{
+    struct vigs_device *vigs_dev = drm_dev->dev_private;
 
     DRM_DEBUG_KMS("enter\n");
 
-    return drm_gem_handle_create(file_priv, &vigs_fb->fb_sfc->gem.base, handle);
+    if (vigs_dev->fbdev) {
+        vigs_fbdev_output_poll_changed(vigs_dev->fbdev);
+    }
 }
 
 static struct drm_mode_config_funcs vigs_mode_config_funcs =
@@ -112,13 +150,6 @@ static struct drm_mode_config_funcs vigs_mode_config_funcs =
     .output_poll_changed = vigs_output_poll_changed
 };
 
-static struct drm_framebuffer_funcs vigs_framebuffer_funcs =
-{
-    .destroy = vigs_framebuffer_destroy,
-    .create_handle = vigs_framebuffer_create_handle,
-    .dirty = vigs_framebuffer_dirty,
-};
-
 void vigs_framebuffer_config_init(struct vigs_device *vigs_dev)
 {
     DRM_DEBUG_KMS("enter\n");
@@ -159,7 +190,7 @@ int vigs_framebuffer_create(struct vigs_device *vigs_dev,
     }
 
     (*vigs_fb)->comm = vigs_dev->comm;
-    (*vigs_fb)->fb_sfc = fb_sfc;
+    (*vigs_fb)->surfaces[0] = fb_sfc;
 
     ret = drm_framebuffer_init(vigs_dev->drm_dev,
                                &(*vigs_fb)->base,
@@ -187,20 +218,20 @@ int vigs_framebuffer_pin(struct vigs_framebuffer *vigs_fb)
 {
     int ret;
 
-    vigs_gem_reserve(&vigs_fb->fb_sfc->gem);
+    vigs_gem_reserve(&vigs_fb->surfaces[0]->gem);
 
-    ret = vigs_gem_pin(&vigs_fb->fb_sfc->gem);
+    ret = vigs_gem_pin(&vigs_fb->surfaces[0]->gem);
 
-    vigs_gem_unreserve(&vigs_fb->fb_sfc->gem);
+    vigs_gem_unreserve(&vigs_fb->surfaces[0]->gem);
 
     return ret;
 }
 
 void vigs_framebuffer_unpin(struct vigs_framebuffer *vigs_fb)
 {
-    vigs_gem_reserve(&vigs_fb->fb_sfc->gem);
+    vigs_gem_reserve(&vigs_fb->surfaces[0]->gem);
 
-    vigs_gem_unpin(&vigs_fb->fb_sfc->gem);
+    vigs_gem_unpin(&vigs_fb->surfaces[0]->gem);
 
-    vigs_gem_unreserve(&vigs_fb->fb_sfc->gem);
+    vigs_gem_unreserve(&vigs_fb->surfaces[0]->gem);
 }
index e18024d9be6cbbca3522848537248462d202e30f..f95728ef57dc465754a01219faebab30bea43e61 100644 (file)
@@ -17,7 +17,7 @@ struct vigs_framebuffer
      */
     struct vigs_comm *comm;
 
-    struct vigs_surface *fb_sfc;
+    struct vigs_surface *surfaces[4];
 };
 
 static inline struct vigs_framebuffer *fb_to_vigs_fb(struct drm_framebuffer *fb)
index 1a15b043e8fb30fabce46ef7a2e25ef5333470ed..b1ef09b6cd7a93db2d74a915561a412de31e5a32 100644 (file)
@@ -2,6 +2,7 @@
 #include "vigs_device.h"
 #include "vigs_mman.h"
 #include "vigs_surface.h"
+#include "vigs_dp.h"
 #include <drm/vigs_drm.h>
 #include <ttm/ttm_placement.h>
 
@@ -261,6 +262,13 @@ void vigs_gem_free_object(struct drm_gem_object *gem)
 {
     struct vigs_gem_object *vigs_gem = gem_to_vigs_gem(gem);
 
+    if (vigs_gem->type == VIGS_GEM_TYPE_SURFACE) {
+        struct vigs_device *vigs_dev = gem->dev->dev_private;
+
+        vigs_dp_remove_surface(vigs_dev->dp,
+                               vigs_gem_to_vigs_surface(vigs_gem));
+    }
+
     vigs_gem_reserve(vigs_gem);
 
     vigs_gem_kunmap(vigs_gem);
index f7f06711f0faf0bf0d44529282975fd58242e55d..c95c2226694fda2ef2ab4858a54f83b14aabbf7a 100644 (file)
@@ -9,6 +9,9 @@ static const uint32_t formats[] =
 {
     DRM_FORMAT_XRGB8888,
     DRM_FORMAT_ARGB8888,
+    DRM_FORMAT_NV21,
+    fourcc_code('N', 'V', '4', '2'),
+    DRM_FORMAT_NV61
 };
 
 static int vigs_plane_update(struct drm_plane *plane,
@@ -23,33 +26,66 @@ static int vigs_plane_update(struct drm_plane *plane,
     struct vigs_plane *vigs_plane = plane_to_vigs_plane(plane);
     struct vigs_device *vigs_dev = plane->dev->dev_private;
     struct vigs_framebuffer *vigs_fb = fb_to_vigs_fb(fb);
-    int ret;
+    int ret, i;
     uint32_t src_x_whole = src_x >> 16;
     uint32_t src_y_whole = src_y >> 16;
     uint32_t src_w_whole = src_w >> 16;
     uint32_t src_h_whole = src_h >> 16;
+    vigsp_surface_id surface_ids[4] = { 0, 0, 0, 0 };
+    vigsp_plane_format format;
 
     DRM_DEBUG_KMS("enter: crtc_x = %d, crtc_y = %d, crtc_w = %u, crtc_h = %u, src_x = %u, src_y = %u, src_w = %u, src_h = %u\n",
                   crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h);
 
-    if (vigs_fb->fb_sfc->scanout) {
-        vigs_gem_reserve(&vigs_fb->fb_sfc->gem);
+    if (vigs_fb->surfaces[0]->scanout) {
+        vigs_gem_reserve(&vigs_fb->surfaces[0]->gem);
 
-        if (vigs_gem_in_vram(&vigs_fb->fb_sfc->gem) &&
-            vigs_surface_need_gpu_update(vigs_fb->fb_sfc)) {
+        if (vigs_gem_in_vram(&vigs_fb->surfaces[0]->gem) &&
+            vigs_surface_need_gpu_update(vigs_fb->surfaces[0])) {
             vigs_comm_update_gpu(vigs_dev->comm,
-                                 vigs_fb->fb_sfc->id,
-                                 vigs_fb->fb_sfc->width,
-                                 vigs_fb->fb_sfc->height,
-                                 vigs_gem_offset(&vigs_fb->fb_sfc->gem));
+                                 vigs_fb->surfaces[0]->id,
+                                 vigs_fb->surfaces[0]->width,
+                                 vigs_fb->surfaces[0]->height,
+                                 vigs_gem_offset(&vigs_fb->surfaces[0]->gem));
+        }
+
+        vigs_gem_unreserve(&vigs_fb->surfaces[0]->gem);
+    }
+
+    for (i = 0; i < 4; ++i) {
+        if (vigs_fb->surfaces[i]) {
+            surface_ids[i] = vigs_fb->surfaces[i]->id;
         }
+    }
 
-        vigs_gem_unreserve(&vigs_fb->fb_sfc->gem);
+    switch (fb->pixel_format) {
+    case DRM_FORMAT_XRGB8888:
+        format = vigsp_plane_bgrx8888;
+        break;
+    case DRM_FORMAT_ARGB8888:
+        format = vigsp_plane_bgra8888;
+        break;
+    case DRM_FORMAT_NV21:
+        format = vigsp_plane_nv21;
+        break;
+    case fourcc_code('N', 'V', '4', '2'):
+        format = vigsp_plane_nv42;
+        break;
+    case DRM_FORMAT_NV61:
+        format = vigsp_plane_nv61;
+        break;
+    default:
+        BUG();
+        format = vigsp_plane_bgrx8888;
+        break;
     }
 
     ret = vigs_comm_set_plane(vigs_dev->comm,
                               vigs_plane->index,
-                              vigs_fb->fb_sfc->id,
+                              fb->width,
+                              fb->height,
+                              format,
+                              surface_ids,
                               src_x_whole,
                               src_y_whole,
                               src_w_whole,
@@ -82,6 +118,7 @@ static int vigs_plane_disable(struct drm_plane *plane)
     struct vigs_plane *vigs_plane = plane_to_vigs_plane(plane);
     struct vigs_device *vigs_dev = plane->dev->dev_private;
     int ret;
+    vigsp_surface_id surface_ids[4] = { 0, 0, 0, 0 };
 
     DRM_DEBUG_KMS("enter\n");
 
@@ -94,6 +131,9 @@ static int vigs_plane_disable(struct drm_plane *plane)
                               0,
                               0,
                               0,
+                              surface_ids,
+                              0,
+                              0,
                               0,
                               0,
                               0,
index f75b9af4dd3afbfe69157350f901c3d3ffe1ccb9..cf535ede244722c76c345195dc7820952d2468a3 100644 (file)
@@ -8,7 +8,7 @@
 /*
  * Bump this whenever protocol changes.
  */
-#define VIGS_PROTOCOL_VERSION 17
+#define VIGS_PROTOCOL_VERSION 18
 
 #define VIGS_MAX_PLANES 2
 
@@ -52,6 +52,7 @@ typedef enum
     vigsp_cmd_copy = 0x8,
     vigsp_cmd_solid_fill = 0x9,
     vigsp_cmd_set_plane = 0xA,
+    vigsp_cmd_ga_copy = 0xB
     /*
      * @}
      */
@@ -63,6 +64,15 @@ typedef enum
     vigsp_surface_bgra8888 = 0x1,
 } vigsp_surface_format;
 
+typedef enum
+{
+    vigsp_plane_bgrx8888 = 0x0,
+    vigsp_plane_bgra8888 = 0x1,
+    vigsp_plane_nv21 = 0x2,
+    vigsp_plane_nv42 = 0x3,
+    vigsp_plane_nv61 = 0x4
+} vigsp_plane_format;
+
 #pragma pack(1)
 
 struct vigsp_point
@@ -303,9 +313,9 @@ struct vigsp_cmd_solid_fill_request
 /*
  * cmd_set_plane
  *
- * Assigns surface 'sfc_id' to plane identified by 'plane'.
+ * Assigns surfaces 'surfaces' to plane identified by 'plane'.
  *
- * Pass 0 as sfc_id in order to disable the plane.
+ * Pass 0 as surfaces[0] in order to disable the plane.
  *
  * @{
  */
@@ -313,7 +323,10 @@ struct vigsp_cmd_solid_fill_request
 struct vigsp_cmd_set_plane_request
 {
     vigsp_u32 plane;
-    vigsp_surface_id sfc_id;
+    vigsp_u32 width;
+    vigsp_u32 height;
+    vigsp_plane_format format;
+    vigsp_surface_id surfaces[4];
     struct vigsp_rect src_rect;
     vigsp_s32 dst_x;
     vigsp_s32 dst_y;
@@ -321,6 +334,31 @@ struct vigsp_cmd_set_plane_request
     vigsp_s32 z_pos;
 };
 
+/*
+ * @}
+ */
+
+/*
+ * cmd_ga_copy
+ *
+ * Copies part of surface 'src_id' to
+ * surface 'dst_id' given surface
+ * sizes.
+ *
+ * @{
+ */
+
+struct vigsp_cmd_ga_copy_request
+{
+    vigsp_surface_id src_id;
+    vigsp_bool src_scanout;
+    vigsp_offset src_offset;
+    vigsp_u32 src_stride;
+    vigsp_surface_id dst_id;
+    vigsp_u32 dst_stride;
+    struct vigsp_copy entry;
+};
+
 /*
  * @}
  */
index 9211a17c11e26d00699124bedfd3db74cdaabd2e..933fc85cac16b599edcd8806148a0be45fdae741 100644 (file)
@@ -8,7 +8,7 @@
 /*
  * Bump this whenever driver interface changes.
  */
-#define DRM_VIGS_DRIVER_VERSION 12
+#define DRM_VIGS_DRIVER_VERSION 13
 
 /*
  * Surface access flags.
 #define DRM_VIGS_SAF_WRITE 2
 #define DRM_VIGS_SAF_MASK 3
 
+/*
+ * Number of DP framebuffers.
+ */
+#define DRM_VIGS_NUM_DP_FB_BUF 4
+
+/*
+ * DP memory types.
+ */
+#define DRM_VIGS_DP_FB_Y 2
+#define DRM_VIGS_DP_FB_C 3
+
 struct drm_vigs_get_protocol_version
 {
     uint32_t version;
@@ -115,6 +126,28 @@ struct drm_vigs_plane_set_zpos
     int zpos;
 };
 
+struct drm_vigs_dp_create_surface
+{
+    uint32_t dp_plane;
+    uint32_t dp_fb_buf;
+    uint32_t dp_mem_flag;
+    uint32_t width;
+    uint32_t height;
+    uint32_t stride;
+    uint32_t format;
+    uint32_t handle;
+    uint32_t size;
+    uint32_t id;
+};
+
+struct drm_vigs_dp_open_surface
+{
+    uint32_t dp_plane;
+    uint32_t dp_fb_buf;
+    uint32_t dp_mem_flag;
+    uint32_t handle;
+};
+
 #define DRM_VIGS_GET_PROTOCOL_VERSION 0x00
 #define DRM_VIGS_CREATE_SURFACE 0x01
 #define DRM_VIGS_CREATE_EXECBUFFER 0x02
@@ -131,6 +164,9 @@ struct drm_vigs_plane_set_zpos
 #define DRM_VIGS_FENCE_UNREF 0x0D
 #define DRM_VIGS_PLANE_SET_ZPOS 0x0E
 
+#define DRM_VIGS_DP_CREATE_SURFACE 0x20
+#define DRM_VIGS_DP_OPEN_SURFACE 0x21
+
 #define DRM_IOCTL_VIGS_GET_PROTOCOL_VERSION DRM_IOR(DRM_COMMAND_BASE + \
             DRM_VIGS_GET_PROTOCOL_VERSION, struct drm_vigs_get_protocol_version)
 #define DRM_IOCTL_VIGS_CREATE_SURFACE DRM_IOWR(DRM_COMMAND_BASE + \
@@ -162,4 +198,9 @@ struct drm_vigs_plane_set_zpos
 #define DRM_IOCTL_VIGS_PLANE_SET_ZPOS DRM_IOW(DRM_COMMAND_BASE + \
             DRM_VIGS_PLANE_SET_ZPOS, struct drm_vigs_plane_set_zpos)
 
+#define DRM_IOCTL_VIGS_DP_CREATE_SURFACE DRM_IOWR(DRM_COMMAND_BASE + \
+            DRM_VIGS_DP_CREATE_SURFACE, struct drm_vigs_dp_create_surface)
+#define DRM_IOCTL_VIGS_DP_OPEN_SURFACE DRM_IOWR(DRM_COMMAND_BASE + \
+            DRM_VIGS_DP_OPEN_SURFACE, struct drm_vigs_dp_open_surface)
+
 #endif