From 19c8b8343d9cb9674fa47103bf2a4abb43757e65 Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Fri, 14 Oct 2011 13:29:46 +0900 Subject: [PATCH] drm/exynos: fixed overlay data updating. 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 Signed-off-by: Kyungmin Park Signed-off-by: Dave Airlie --- 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); -- 2.7.4