From 229d3534f5bd73fe6247a9e2a92ab0ef69fbc980 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Thu, 15 Dec 2011 14:36:22 +0900 Subject: [PATCH] drm/exynos: Support multi buffers 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 Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae Signed-off-by: Kyungmin Park --- drivers/gpu/drm/exynos/exynos_drm_buf.h | 3 --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 28 +++++++++++--------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 13 +++++---- drivers/gpu/drm/exynos/exynos_drm_fb.c | 44 +++++++++++++++++++++++++------ drivers/gpu/drm/exynos/exynos_drm_fb.h | 17 ++++++++++++ drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 4 +-- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 4 +-- 7 files changed, 81 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h index 6e91f9caa5d..c913f2bad76 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.h +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h @@ -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); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index e1ce9fd5a16..e3861ac4929 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -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; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 8e8d8f0f8f3..24f4ef48e47 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -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; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 8f36ae5e5d7..3733fe6723d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -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) @@ -42,11 +41,11 @@ * 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; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index 8b3e12f9771..3ecb30d9355 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -28,11 +28,28 @@ #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 diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 26992d3e970..d7ae29d2f3d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -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; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 95c62101844..777b93c0718 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -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); -- 2.11.4.GIT