drm/exynos: Support multi buffers
authorSeung-Woo Kim <sw0312.kim@samsung.com>
Thu, 15 Dec 2011 05:36:22 +0000 (14:36 +0900)
committerInki Dae <inki.dae@samsung.com>
Thu, 29 Dec 2011 02:21:42 +0000 (11:21 +0900)
These formats(NV12M, NV12MT and YUV420M) have non contiguous  multi
planes, so each plane uses different buffer. The exynos drm should
support multi buffer for them.

Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_buf.h
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fb.h
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c

index 6e91f9c..c913f2b 100644 (file)
@@ -30,9 +30,6 @@
 struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev,
                unsigned int size);
 
-/* get memory information of a drm framebuffer. */
-struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb);
-
 /* remove allocated physical memory. */
 void exynos_drm_buf_destroy(struct drm_device *dev,
                struct exynos_drm_gem_buf *buffer);
index e1ce9fd..e3861ac 100644 (file)
@@ -34,7 +34,6 @@
 #include "exynos_drm_fb.h"
 #include "exynos_drm_encoder.h"
 #include "exynos_drm_gem.h"
-#include "exynos_drm_buf.h"
 
 #define to_exynos_crtc(x)      container_of(x, struct exynos_drm_crtc,\
                                drm_crtc)
@@ -80,19 +79,23 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
        struct exynos_drm_gem_buf *buffer;
        unsigned int actual_w;
        unsigned int actual_h;
+       int nr = exynos_drm_format_num_buffers(fb->pixel_format);
+       int i;
+
+       for (i = 0; i < nr; i++) {
+               buffer = exynos_drm_fb_buffer(fb, i);
+               if (!buffer) {
+                       DRM_LOG_KMS("buffer is null\n");
+                       return -EFAULT;
+               }
 
-       buffer = exynos_drm_fb_get_buf(fb);
-       if (!buffer) {
-               DRM_LOG_KMS("buffer is null.\n");
-               return -EFAULT;
-       }
-
-       overlay->dma_addr = buffer->dma_addr;
-       overlay->vaddr = buffer->kvaddr;
+               overlay->dma_addr[i] = buffer->dma_addr;
+               overlay->vaddr[i] = buffer->kvaddr;
 
-       DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n",
-                       (unsigned long)overlay->vaddr,
-                       (unsigned long)overlay->dma_addr);
+               DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
+                               i, (unsigned long)overlay->vaddr[i],
+                               (unsigned long)overlay->dma_addr[i]);
+       }
 
        actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
        actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
@@ -104,6 +107,7 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
        overlay->fb_height = fb->height;
        overlay->bpp = fb->bits_per_pixel;
        overlay->pitch = fb->pitches[0];
+       overlay->pixel_format = fb->pixel_format;
 
        /* set overlay range to be displayed. */
        overlay->crtc_x = pos->crtc_x;
index 8e8d8f0..24f4ef4 100644 (file)
@@ -34,6 +34,7 @@
 
 #define MAX_CRTC       2
 #define MAX_PLANE      5
+#define MAX_FB_BUFFER  3
 #define DEFAULT_ZPOS   -1
 
 struct drm_device;
@@ -82,9 +83,10 @@ struct exynos_drm_overlay_ops {
  * @scan_flag: interlace or progressive way.
  *     (it could be DRM_MODE_FLAG_*)
  * @bpp: pixel size.(in bit)
- * @dma_addr: bus(accessed by dma) address to the memory region allocated
- *     for a overlay.
- * @vaddr: virtual memory addresss to this overlay.
+ * @pixel_format: fourcc pixel format of this overlay
+ * @dma_addr: array of bus(accessed by dma) address to the memory region
+ *           allocated for a overlay.
+ * @vaddr: array of virtual memory addresss to this overlay.
  * @zpos: order of overlay layer(z position).
  * @default_win: a window to be enabled.
  * @color_key: color key on or off.
@@ -112,8 +114,9 @@ struct exynos_drm_overlay {
        unsigned int scan_flag;
        unsigned int bpp;
        unsigned int pitch;
-       dma_addr_t dma_addr;
-       void __iomem *vaddr;
+       uint32_t pixel_format;
+       dma_addr_t dma_addr[MAX_FB_BUFFER];
+       void __iomem *vaddr[MAX_FB_BUFFER];
        int zpos;
 
        bool default_win;
index 8f36ae5..3733fe6 100644 (file)
@@ -33,7 +33,6 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
-#include "exynos_drm_buf.h"
 #include "exynos_drm_gem.h"
 
 #define to_exynos_fb(x)        container_of(x, struct exynos_drm_fb, fb)
  * exynos specific framebuffer structure.
  *
  * @fb: drm framebuffer obejct.
- * @exynos_gem_obj: exynos specific gem object containing a gem object.
+ * @exynos_gem_obj: array of exynos specific gem object containing a gem object.
  */
 struct exynos_drm_fb {
        struct drm_framebuffer          fb;
-       struct exynos_drm_gem_obj       *exynos_gem_obj;
+       struct exynos_drm_gem_obj       *exynos_gem_obj[MAX_FB_BUFFER];
 };
 
 static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
@@ -70,7 +69,7 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb,
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
        return drm_gem_handle_create(file_priv,
-                       &exynos_fb->exynos_gem_obj->base, handle);
+                       &exynos_fb->exynos_gem_obj[0]->base, handle);
 }
 
 static int exynos_drm_fb_dirty(struct drm_framebuffer *fb,
@@ -112,7 +111,7 @@ exynos_drm_framebuffer_init(struct drm_device *dev,
        }
 
        drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd);
-       exynos_fb->exynos_gem_obj = to_exynos_gem_obj(obj);
+       exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj);
 
        return &exynos_fb->fb;
 }
@@ -122,6 +121,10 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
                      struct drm_mode_fb_cmd2 *mode_cmd)
 {
        struct drm_gem_object *obj;
+       struct drm_framebuffer *fb;
+       struct exynos_drm_fb *exynos_fb;
+       int nr;
+       int i;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -133,17 +136,42 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
 
        drm_gem_object_unreference_unlocked(obj);
 
-       return exynos_drm_framebuffer_init(dev, mode_cmd, obj);
+       fb = exynos_drm_framebuffer_init(dev, mode_cmd, obj);
+       if (IS_ERR(fb))
+               return fb;
+
+       exynos_fb = to_exynos_fb(fb);
+       nr = exynos_drm_format_num_buffers(fb->pixel_format);
+
+       for (i = 1; i < nr; i++) {
+               obj = drm_gem_object_lookup(dev, file_priv,
+                               mode_cmd->handles[i]);
+               if (!obj) {
+                       DRM_ERROR("failed to lookup gem object\n");
+                       exynos_drm_fb_destroy(fb);
+                       return ERR_PTR(-ENOENT);
+               }
+
+               drm_gem_object_unreference_unlocked(obj);
+
+               exynos_fb->exynos_gem_obj[i] = to_exynos_gem_obj(obj);
+       }
+
+       return fb;
 }
 
-struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb)
+struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
+                                               int index)
 {
        struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
        struct exynos_drm_gem_buf *buffer;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       buffer = exynos_fb->exynos_gem_obj->buffer;
+       if (index >= MAX_FB_BUFFER)
+               return NULL;
+
+       buffer = exynos_fb->exynos_gem_obj[index]->buffer;
        if (!buffer)
                return NULL;
 
index 8b3e12f..3ecb30d 100644 (file)
 #ifndef _EXYNOS_DRM_FB_H_
 #define _EXYNOS_DRM_FB_H
 
+static inline int exynos_drm_format_num_buffers(uint32_t format)
+{
+       switch (format) {
+       case DRM_FORMAT_NV12M:
+       case DRM_FORMAT_NV12MT:
+               return 2;
+       case DRM_FORMAT_YUV420M:
+               return 3;
+       default:
+               return 1;
+       }
+}
+
 struct drm_framebuffer *
 exynos_drm_framebuffer_init(struct drm_device *dev,
                            struct drm_mode_fb_cmd2 *mode_cmd,
                            struct drm_gem_object *obj);
 
+/* get memory information of a drm framebuffer */
+struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
+                                                int index);
+
 void exynos_drm_mode_config_init(struct drm_device *dev);
 
 #endif
index 26992d3..d7ae29d 100644 (file)
@@ -34,7 +34,6 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
-#include "exynos_drm_buf.h"
 
 #define MAX_CONNECTOR          4
 #define PREFERRED_BPP          32
@@ -99,7 +98,8 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
        drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
 
-       buffer = exynos_drm_fb_get_buf(fb);
+       /* RGB formats use only one buffer */
+       buffer = exynos_drm_fb_buffer(fb, 0);
        if (!buffer) {
                DRM_LOG_KMS("buffer is null.\n");
                return -EFAULT;
index 95c6210..777b93c 100644 (file)
@@ -313,8 +313,8 @@ static void fimd_win_mode_set(struct device *dev,
        win_data->ovl_height = overlay->crtc_height;
        win_data->fb_width = overlay->fb_width;
        win_data->fb_height = overlay->fb_height;
-       win_data->dma_addr = overlay->dma_addr + offset;
-       win_data->vaddr = overlay->vaddr + offset;
+       win_data->dma_addr = overlay->dma_addr[0] + offset;
+       win_data->vaddr = overlay->vaddr[0] + offset;
        win_data->bpp = overlay->bpp;
        win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
                                (overlay->bpp >> 3);