[PATCH 1/7] drm/exynos: fixed overlay data updating.

Inki Dae inki.dae at samsung.com
Thu Oct 13 20:52:26 PDT 2011


this patch adds common members to overlay structure and
makes each driver such as fimd or hdmi driver set them to
its own structure.

Signed-off-by: Inki Dae <inki.dae at samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_buf.h   |    3 +
 drivers/gpu/drm/exynos/exynos_drm_crtc.c  |  101 ++++++++++++++++++-----------
 drivers/gpu/drm/exynos/exynos_drm_drv.h   |   41 ++++++++----
 drivers/gpu/drm/exynos/exynos_drm_fb.c    |   20 ++----
 drivers/gpu/drm/exynos/exynos_drm_fb.h    |   10 ---
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c |   31 ++++++---
 drivers/gpu/drm/exynos/exynos_drm_fimd.c  |   59 ++++++++++++-----
 7 files changed, 162 insertions(+), 103 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h
index 9b1f0fb..045d59e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h
@@ -43,6 +43,9 @@ struct exynos_drm_buf_entry {
 struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev,
 		unsigned int size);
 
+/* get physical memory information of a drm framebuffer. */
+struct exynos_drm_buf_entry *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_buf_entry *entry);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 683ceb0..654bf3a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -32,23 +32,28 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_encoder.h"
+#include "exynos_drm_buf.h"
 
 #define to_exynos_crtc(x)	container_of(x, struct exynos_drm_crtc,\
 				drm_crtc)
 
 /*
- * @fb_x: horizontal position from framebuffer base
- * @fb_y: vertical position from framebuffer base
- * @base_x: horizontal position from screen base
- * @base_y: vertical position from screen base
- * @crtc_w: width of crtc
- * @crtc_h: height of crtc
+ * Exynos specific crtc postion structure.
+ *
+ * @fb_x: offset x on a framebuffer to be displyed
+ *	- the unit is screen coordinates.
+ * @fb_y: offset y on a framebuffer to be displayed
+ *	- the unit is screen coordinates.
+ * @crtc_x: offset x on hardware screen.
+ * @crtc_y: offset y on hardware screen.
+ * @crtc_w: width of hardware screen.
+ * @crtc_h: height of hardware screen.
  */
 struct exynos_drm_crtc_pos {
 	unsigned int fb_x;
 	unsigned int fb_y;
-	unsigned int base_x;
-	unsigned int base_y;
+	unsigned int crtc_x;
+	unsigned int crtc_y;
 	unsigned int crtc_w;
 	unsigned int crtc_h;
 };
@@ -83,42 +88,56 @@ void exynos_drm_crtc_apply(struct drm_crtc *crtc)
 	exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit);
 }
 
-static void exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
+static int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
 				       struct drm_framebuffer *fb,
 				       struct drm_display_mode *mode,
 				       struct exynos_drm_crtc_pos *pos)
 {
-	struct exynos_drm_buffer_info buffer_info;
-	unsigned int actual_w = pos->crtc_w;
-	unsigned int actual_h = pos->crtc_h;
-	unsigned int hw_w;
-	unsigned int hw_h;
-
-	/* update buffer address of framebuffer. */
-	exynos_drm_fb_update_buf_off(fb, pos->fb_x, pos->fb_y, &buffer_info);
-	overlay->paddr = buffer_info.paddr;
-	overlay->vaddr = buffer_info.vaddr;
-
-	hw_w = mode->hdisplay - pos->base_x;
-	hw_h = mode->vdisplay - pos->base_y;
-
-	if (actual_w > hw_w)
-		actual_w = hw_w;
-	if (actual_h > hw_h)
-		actual_h = hw_h;
-
-	overlay->offset_x = pos->base_x;
-	overlay->offset_y = pos->base_y;
-	overlay->width = actual_w;
-	overlay->height = actual_h;
+	struct exynos_drm_buf_entry *entry;
+	unsigned int actual_w;
+	unsigned int actual_h;
+
+	entry = exynos_drm_fb_get_buf(fb);
+	if (!entry) {
+		DRM_LOG_KMS("entry is null.\n");
+		return -EFAULT;
+	}
+
+	overlay->paddr = entry->paddr;
+	overlay->vaddr = entry->vaddr;
+
+	DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n",
+			(unsigned long)overlay->vaddr,
+			(unsigned long)overlay->paddr);
+
+	actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
+	actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
+
+	/* set drm framebuffer data. */
+	overlay->fb_x = pos->fb_x;
+	overlay->fb_y = pos->fb_y;
+	overlay->fb_width = fb->width;
+	overlay->fb_height = fb->height;
 	overlay->bpp = fb->bits_per_pixel;
+	overlay->pitch = fb->pitch;
+
+	/* set overlay range to be displayed. */
+	overlay->crtc_x = pos->crtc_x;
+	overlay->crtc_y = pos->crtc_y;
+	overlay->crtc_width = actual_w;
+	overlay->crtc_height = actual_h;
+
+	/* set drm mode data. */
+	overlay->mode_width = mode->hdisplay;
+	overlay->mode_height = mode->vdisplay;
+	overlay->refresh = mode->vrefresh;
+	overlay->scan_flag = mode->flags;
 
 	DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
-			overlay->offset_x, overlay->offset_y,
-			overlay->width, overlay->height);
+			overlay->crtc_x, overlay->crtc_y,
+			overlay->crtc_width, overlay->crtc_height);
 
-	overlay->buf_offsize = fb->width - actual_w;
-	overlay->line_size = actual_w;
+	return 0;
 }
 
 static int exynos_drm_crtc_update(struct drm_crtc *crtc)
@@ -136,14 +155,18 @@ static int exynos_drm_crtc_update(struct drm_crtc *crtc)
 	overlay = &exynos_crtc->overlay;
 
 	memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
+
+	/* it means the offset of framebuffer to be displayed. */
 	pos.fb_x = crtc->x;
 	pos.fb_y = crtc->y;
+
+	/* OSD position to be displayed. */
+	pos.crtc_x = 0;
+	pos.crtc_y = 0;
 	pos.crtc_w = fb->width - crtc->x;
 	pos.crtc_h = fb->height - crtc->y;
 
-	exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
-
-	return 0;
+	return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
 }
 
 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 832b650..4ea1371 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -63,18 +63,26 @@ struct exynos_drm_overlay_ops {
 /*
  * Exynos drm common overlay structure.
  *
- * @offset_x: offset to x position.
- * @offset_y: offset to y position.
- * @width: window width.
- * @height: window height.
+ * @fb_x: offset x on a framebuffer to be displayed.
+ *	- the unit is screen coordinates.
+ * @fb_y: offset y on a framebuffer to be displayed.
+ *	- the unit is screen coordinates.
+ * @fb_width: width of a framebuffer.
+ * @fb_height: height of a framebuffer.
+ * @crtc_x: offset x on hardware screen.
+ * @crtc_y: offset y on hardware screen.
+ * @crtc_width: window width to be displayed (hardware screen).
+ * @crtc_height: window height to be displayed (hardware screen).
+ * @mode_width: width of screen mode.
+ * @mode_height: height of screen mode.
+ * @refresh: refresh rate.
+ * @scan_flag: interlace or progressive way.
+ *	(it could be DRM_MODE_FLAG_*)
  * @bpp: pixel size.(in bit)
  * @paddr: bus(accessed by dma) physical memory address to this overlay
  *		and this is physically continuous.
  * @vaddr: virtual memory addresss to this overlay.
  * @buf_off: start offset of framebuffer to be displayed.
- * @buf_offsize: this value has result from
- *			(framebuffer width - display width) * bpp.
- * @line_size: line size to this overlay memory in bytes.
  * @default_win: a window to be enabled.
  * @color_key: color key on or off.
  * @index_color: if using color key feature then this value would be used
@@ -87,16 +95,23 @@ struct exynos_drm_overlay_ops {
  * to hardware specific overlay info.
  */
 struct exynos_drm_overlay {
-	unsigned int offset_x;
-	unsigned int offset_y;
-	unsigned int width;
-	unsigned int height;
+	unsigned int fb_x;
+	unsigned int fb_y;
+	unsigned int fb_width;
+	unsigned int fb_height;
+	unsigned int crtc_x;
+	unsigned int crtc_y;
+	unsigned int crtc_width;
+	unsigned int crtc_height;
+	unsigned int mode_width;
+	unsigned int mode_height;
+	unsigned int refresh;
+	unsigned int scan_flag;
 	unsigned int bpp;
+	unsigned int pitch;
 	dma_addr_t paddr;
 	void __iomem *vaddr;
 	unsigned int buf_off;
-	unsigned int buf_offsize;
-	unsigned int line_size;
 
 	bool default_win;
 	bool color_key;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index 4505d90..48d29cf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -220,28 +220,22 @@ struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
 	return exynos_drm_fb_init(file_priv, dev, mode_cmd);
 }
 
-void exynos_drm_fb_update_buf_off(struct drm_framebuffer *fb,
-				   unsigned int x, unsigned int y,
-				   struct exynos_drm_buffer_info *info)
+struct exynos_drm_buf_entry *exynos_drm_fb_get_buf(struct drm_framebuffer *fb)
 {
 	struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb);
 	struct exynos_drm_buf_entry *entry;
-	unsigned long offset;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	offset = x * (fb->bits_per_pixel >> 3);
-	offset += y * fb->pitch;
-
 	entry = exynos_fb->entry;
+	if (!entry)
+		return NULL;
 
-	info->base_addr = entry->paddr;
-	info->vaddr = entry->vaddr + offset;
-	info->paddr = entry->paddr + offset;
+	DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n",
+			(unsigned long)entry->vaddr,
+			(unsigned long)entry->paddr);
 
-	DRM_DEBUG_KMS("updated vaddr = 0x%lx, paddr = 0x%lx, offset = 0x%x\n",
-			(unsigned long)info->vaddr, (unsigned long)info->paddr,
-			(unsigned int)offset);
+	return entry;
 }
 
 static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h
index eaa478a..eb35931 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h
@@ -28,16 +28,6 @@
 #ifndef _EXYNOS_DRM_FB_H_
 #define _EXYNOS_DRM_FB_H
 
-struct exynos_drm_buffer_info {
-	unsigned long base_addr;
-	dma_addr_t paddr;
-	void __iomem *vaddr;
-};
-
-void exynos_drm_fb_update_buf_off(struct drm_framebuffer *fb,
-				   unsigned int x, unsigned int y,
-				   struct exynos_drm_buffer_info *info);
-
 struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev,
 					      struct drm_file *filp,
 					      struct drm_mode_fb_cmd *mode_cmd);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index ac43bfc..6134515 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -33,6 +33,7 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
+#include "exynos_drm_buf.h"
 
 #define MAX_CONNECTOR		4
 #define PREFERRED_BPP		32
@@ -83,7 +84,7 @@ static struct fb_ops exynos_drm_fb_ops = {
 	.fb_setcmap	= drm_fb_helper_setcmap,
 };
 
-static void exynos_drm_fbdev_update(struct drm_fb_helper *helper,
+static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
 				     struct drm_framebuffer *fb,
 				     unsigned int fb_width,
 				     unsigned int fb_height)
@@ -91,8 +92,9 @@ static void exynos_drm_fbdev_update(struct drm_fb_helper *helper,
 	struct fb_info *fbi = helper->fbdev;
 	struct drm_device *dev = helper->dev;
 	struct exynos_drm_fbdev *exynos_fb = to_exynos_fbdev(helper);
-	struct exynos_drm_buffer_info buffer_info;
+	struct exynos_drm_buf_entry *entry;
 	unsigned int size = fb_width * fb_height * (fb->bits_per_pixel >> 3);
+	unsigned long offset;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -101,15 +103,22 @@ static void exynos_drm_fbdev_update(struct drm_fb_helper *helper,
 	drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth);
 	drm_fb_helper_fill_var(fbi, helper, fb_width, fb_height);
 
-	exynos_drm_fb_update_buf_off(fb, fbi->var.xoffset, fbi->var.yoffset,
-			&buffer_info);
+	entry = exynos_drm_fb_get_buf(fb);
+	if (!entry) {
+		DRM_LOG_KMS("entry is null.\n");
+		return -EFAULT;
+	}
 
-	dev->mode_config.fb_base = buffer_info.base_addr;
+	offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
+	offset += fbi->var.yoffset * fb->pitch;
 
-	fbi->screen_base = buffer_info.vaddr;
+	dev->mode_config.fb_base = entry->paddr;
+	fbi->screen_base = entry->vaddr + offset;
+	fbi->fix.smem_start = entry->paddr + offset;
 	fbi->screen_size = size;
-	fbi->fix.smem_start = buffer_info.paddr;
 	fbi->fix.smem_len = size;
+
+	return 0;
 }
 
 static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
@@ -162,8 +171,10 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper,
 		goto out;
 	}
 
-	exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
+	ret = exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
 			sizes->fb_height);
+	if (ret < 0)
+		fb_dealloc_cmap(&fbi->cmap);
 
 /*
  * if failed, all resources allocated above would be released by
@@ -224,10 +235,8 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper,
 	}
 
 	helper->fb = exynos_fbdev->fb;
-	exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
+	return exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width,
 			sizes->fb_height);
-
-	return 0;
 }
 
 static int exynos_drm_fbdev_probe(struct drm_fb_helper *helper,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 620ad2d..623ba33 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -59,8 +59,10 @@
 struct fimd_win_data {
 	unsigned int		offset_x;
 	unsigned int		offset_y;
-	unsigned int		width;
-	unsigned int		height;
+	unsigned int		ovl_width;
+	unsigned int		ovl_height;
+	unsigned int		fb_width;
+	unsigned int		fb_height;
 	unsigned int		bpp;
 	dma_addr_t		paddr;
 	void __iomem		*vaddr;
@@ -233,6 +235,7 @@ static void fimd_win_mode_set(struct device *dev,
 {
 	struct fimd_context *ctx = get_fimd_context(dev);
 	struct fimd_win_data *win_data;
+	unsigned long offset;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -241,17 +244,35 @@ static void fimd_win_mode_set(struct device *dev,
 		return;
 	}
 
+	offset = overlay->fb_x * (overlay->bpp >> 3);
+	offset += overlay->fb_y * overlay->pitch;
+
+	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+
 	win_data = &ctx->win_data[ctx->default_win];
 
-	win_data->offset_x = overlay->offset_x;
-	win_data->offset_y = overlay->offset_y;
-	win_data->width = overlay->width;
-	win_data->height = overlay->height;
-	win_data->paddr = overlay->paddr;
-	win_data->vaddr = overlay->vaddr;
+	win_data->offset_x = overlay->crtc_x;
+	win_data->offset_y = overlay->crtc_y;
+	win_data->ovl_width = overlay->crtc_width;
+	win_data->ovl_height = overlay->crtc_height;
+	win_data->fb_width = overlay->fb_width;
+	win_data->fb_height = overlay->fb_height;
+	win_data->paddr = overlay->paddr + offset;
+	win_data->vaddr = overlay->vaddr + offset;
 	win_data->bpp = overlay->bpp;
-	win_data->buf_offsize = overlay->buf_offsize * (overlay->bpp >> 3);
-	win_data->line_size = overlay->line_size * (overlay->bpp >> 3);
+	win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
+				(overlay->bpp >> 3);
+	win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+
+	DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
+			win_data->offset_x, win_data->offset_y);
+	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+			win_data->ovl_width, win_data->ovl_height);
+	DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
+			(unsigned long)win_data->paddr,
+			(unsigned long)win_data->vaddr);
+	DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
+			overlay->fb_width, overlay->crtc_width);
 }
 
 static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
@@ -365,12 +386,14 @@ static void fimd_win_commit(struct device *dev)
 	writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
 
 	/* buffer end address */
-	size = win_data->width * win_data->height * (win_data->bpp >> 3);
+	size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3);
 	val = win_data->paddr + size;
 	writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
 
 	DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
 			(unsigned long)win_data->paddr, val, size);
+	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+			win_data->ovl_width, win_data->ovl_height);
 
 	/* buffer size */
 	val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
@@ -382,14 +405,16 @@ static void fimd_win_commit(struct device *dev)
 		VIDOSDxA_TOPLEFT_Y(win_data->offset_y);
 	writel(val, ctx->regs + VIDOSD_A(win));
 
-	val = VIDOSDxB_BOTRIGHT_X(win_data->offset_x + win_data->width - 1) |
-		VIDOSDxB_BOTRIGHT_Y(win_data->offset_y + win_data->height - 1);
+	val = VIDOSDxB_BOTRIGHT_X(win_data->offset_x +
+					win_data->ovl_width - 1) |
+		VIDOSDxB_BOTRIGHT_Y(win_data->offset_y +
+					win_data->ovl_height - 1);
 	writel(val, ctx->regs + VIDOSD_B(win));
 
-	DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %x\n",
+	DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
 			win_data->offset_x, win_data->offset_y,
-			win_data->offset_x + win_data->width - 1,
-			win_data->offset_y + win_data->height - 1);
+			win_data->offset_x + win_data->ovl_width - 1,
+			win_data->offset_y + win_data->ovl_height - 1);
 
 	/* hardware window 0 doesn't support alpha channel. */
 	if (win != 0) {
@@ -406,7 +431,7 @@ static void fimd_win_commit(struct device *dev)
 		u32 offset = VIDOSD_D(win);
 		if (win == 0)
 			offset = VIDOSD_C_SIZE_W0;
-		val = win_data->width * win_data->height;
+		val = win_data->ovl_width * win_data->ovl_height;
 		writel(val, ctx->regs + offset);
 
 		DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
-- 
1.7.4.1



More information about the dri-devel mailing list