I am sending patch sets again because of some conflicts. I am sorry for that.
the patch sets are as the following. - updated common overlay structure to support hdmi. - fixed page flip feature for two devices to be supported. - fixed a bug that fbdev reinitialization is failed. - added comments and code clean.
this patch is based on git repository below: git://people.freedesktop.org/~airlied/linux.git branch name: drm-next commit-id: b07759bf41d52aaecd5de92c7d725d6834b23349
Inki Dae (5): drm/exynos: fixed overlay data updating. drm/exynos: added device object as argument of subdrv_probe(). drm/exynos: fixed bug to exynos_drm_fb_dev_reinit(). drm/exynos: added comments and code clean. drm/exynos: fixed build warnings and comments.
Seung-Woo Kim (1): drm/exynos: fixed page flip bug.
Joonyoung Shim (1): drm/exynos: fixed overlay updating time at page flip.
drivers/gpu/drm/exynos/exynos_drm_buf.h | 3 + drivers/gpu/drm/exynos/exynos_drm_core.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 123 +++++++++++++++++++---------- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.c | 14 +++ drivers/gpu/drm/exynos/exynos_drm_drv.h | 50 +++++++----- 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 | 39 ++++++--- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 89 ++++++++++++--------- 10 files changed, 215 insertions(+), 136 deletions(-)
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@samsung.com Signed-off-by: Kyungmin Park kyungmin.park@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);
buffer addess is set to shadow register and then applied to real register at vsync front porch time.
Signed-off-by: Joonyoung Shim jy0922.shim@samsung.com Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 4 +++- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 1 - drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 654bf3a..0587b52 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -78,7 +78,7 @@ struct exynos_drm_crtc { unsigned int pipe; };
-void exynos_drm_crtc_apply(struct drm_crtc *crtc) +static void exynos_drm_crtc_apply(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct exynos_drm_overlay *overlay = &exynos_crtc->overlay; @@ -279,6 +279,8 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, goto out; }
+ exynos_drm_crtc_apply(crtc); + dev_priv->pageflip_event = true; } out: diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 452b62b..c584042 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -31,7 +31,6 @@
struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev, struct drm_crtc *crtc); -void exynos_drm_crtc_apply(struct drm_crtc *crtc); int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr); int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc); void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 623ba33..9d1138e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -500,8 +500,6 @@ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
spin_lock_irqsave(&drm_dev->event_lock, flags);
- exynos_drm_crtc_apply(dev_priv->crtc[crtc]); - list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, base.link) { do_gettimeofday(&now);
sub drivers should refer to its own device object to access its own context.
Signed-off-by: Inki Dae inki.dae@samsung.com Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_core.c | 2 +- drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index edb0ee1..661a035 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -55,7 +55,7 @@ static int exynos_drm_subdrv_probe(struct drm_device *dev, * * P.S. note that this driver is considered for modularization. */ - ret = subdrv->probe(dev); + ret = subdrv->probe(dev, subdrv->manager.dev); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 4ea1371..002f292 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -219,7 +219,7 @@ struct exynos_drm_subdrv { struct list_head list; struct drm_device *drm_dev;
- int (*probe)(struct drm_device *dev); + int (*probe)(struct drm_device *drm_dev, struct device *dev); void (*remove)(struct drm_device *dev);
struct exynos_drm_manager manager; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 9d1138e..b0afa84 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -538,7 +538,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; }
-static int fimd_subdrv_probe(struct drm_device *drm_dev) +static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev) { struct drm_driver *drm_driver = drm_dev->driver;
this patch solves the problem that fb_helper is released when exynos_drm_fbdev_reinit() was called. if this function call is ok then just return.
Signed-off-by: Inki Dae inki.dae@samsung.com Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 6134515..4366dc5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -432,6 +432,8 @@ int exynos_drm_fbdev_reinit(struct drm_device *dev) return exynos_drm_fbdev_init(dev); }
+ return ret; + err: /* * if drm_load() failed when drm load() was called prior
this patch adds the following comments and code clean. - add comment of exynos_drm_crtc_apply() call at page flip time. - add comment that when exynos_drm_fbdev_reinit() is called, why num_connector is 0 and also the framebuffers should be destroyed. - remove buf_off member from struct exynos_drm_overlay because this member isn't used anymore.
Signed-off-by: Inki Dae inki.dae@samsung.com Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 6 ++++++ drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 -- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 0587b52..8cd9d8e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -279,6 +279,12 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, goto out; }
+ /* + * the values related to a buffer of the drm framebuffer + * to be applied should be set at here. because these values + * first, is set to shadow registers and then to + * real registers at vsync front porch period. + */ exynos_drm_crtc_apply(crtc);
dev_priv->pageflip_event = true; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 002f292..63c1422 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -82,7 +82,6 @@ struct exynos_drm_overlay_ops { * @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. * @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 @@ -111,7 +110,6 @@ struct exynos_drm_overlay { unsigned int pitch; dma_addr_t paddr; void __iomem *vaddr; - unsigned int buf_off;
bool default_win; bool color_key; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 4366dc5..1f4b3d1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -393,6 +393,10 @@ int exynos_drm_fbdev_reinit(struct drm_device *dev) if (!private) return -EINVAL;
+ /* + * if all sub drivers were unloaded then num_connector is 0 + * so at this time, the framebuffers also should be destroyed. + */ if (!dev->mode_config.num_connector) { exynos_drm_fbdev_fini(dev); return 0; @@ -429,7 +433,7 @@ int exynos_drm_fbdev_reinit(struct drm_device *dev) * re-configure the fb helper. it means that this function * has been called by the specific drivers. */ - return exynos_drm_fbdev_init(dev); + ret = exynos_drm_fbdev_init(dev); }
return ret;
in case of using two drivers such as fimd and hdmi controller that they have their own hardware interrupt, drm framework doesn't provide pipe number corresponding to it. so the pipe should be set to event's from specific crtc.
Signed-off-by: Seung-Woo Kim sw0312.kim@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_crtc.c | 16 +++++++++++----- drivers/gpu/drm/exynos/exynos_drm_drv.c | 14 ++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_drv.h | 3 +-- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 15 +++++++++------ 4 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 8cd9d8e..9337e5e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -259,13 +259,21 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
mutex_lock(&dev->struct_mutex);
- if (event && !dev_priv->pageflip_event) { + if (event) { + /* + * the pipe from user always is 0 so we can set pipe number + * of current owner to event. + */ + event->pipe = exynos_crtc->pipe; + list_add_tail(&event->base.link, &dev_priv->pageflip_event_list);
ret = drm_vblank_get(dev, exynos_crtc->pipe); if (ret) { DRM_DEBUG("failed to acquire vblank counter\n"); + list_del(&event->base.link); + goto out; }
@@ -274,7 +282,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, if (ret) { crtc->fb = old_fb; drm_vblank_put(dev, exynos_crtc->pipe); - dev_priv->pageflip_event = false; + list_del(&event->base.link);
goto out; } @@ -282,12 +290,10 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, /* * the values related to a buffer of the drm framebuffer * to be applied should be set at here. because these values - * first, is set to shadow registers and then to + * first, are set to shadow registers and then to * real registers at vsync front porch period. */ exynos_drm_crtc_apply(crtc); - - dev_priv->pageflip_event = true; } out: mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index a190348..83810cb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -124,6 +124,19 @@ static int exynos_drm_unload(struct drm_device *dev) return 0; }
+static void exynos_drm_preclose(struct drm_device *dev, + struct drm_file *file_priv) +{ + struct exynos_drm_private *dev_priv = dev->dev_private; + + /* + * drm framework frees all events at release time, + * so private event list should be cleared. + */ + if (!list_empty(&dev_priv->pageflip_event_list)) + INIT_LIST_HEAD(&dev_priv->pageflip_event_list); +} + static void exynos_drm_lastclose(struct drm_device *dev) { DRM_DEBUG_DRIVER("%s\n", __FILE__); @@ -152,6 +165,7 @@ static struct drm_driver exynos_drm_driver = { DRIVER_MODESET | DRIVER_GEM, .load = exynos_drm_load, .unload = exynos_drm_unload, + .preclose = exynos_drm_preclose, .lastclose = exynos_drm_lastclose, .get_vblank_counter = drm_vblank_count, .enable_vblank = exynos_drm_crtc_enable_vblank, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 63c1422..915f5cd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -187,9 +187,8 @@ struct exynos_drm_manager { struct exynos_drm_private { struct drm_fb_helper *fb_helper;
- /* for pageflip */ + /* list head for new event to be added. */ struct list_head pageflip_event_list; - bool pageflip_event;
/* * created crtc object would be contained at this array and diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b0afa84..68446b3b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -487,21 +487,24 @@ static struct exynos_drm_overlay_ops fimd_overlay_ops = { .disable = fimd_win_disable, };
-/* for pageflip event */ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc) { struct exynos_drm_private *dev_priv = drm_dev->dev_private; struct drm_pending_vblank_event *e, *t; struct timeval now; unsigned long flags; - - if (!dev_priv->pageflip_event) - return; + bool is_checked = false;
spin_lock_irqsave(&drm_dev->event_lock, flags);
list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, base.link) { + /* if event's pipe isn't same as crtc then ignor it. */ + if (crtc != e->pipe) + continue; + + is_checked = true; + do_gettimeofday(&now); e->event.sequence = 0; e->event.tv_sec = now.tv_sec; @@ -511,8 +514,8 @@ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc) wake_up_interruptible(&e->base.file_priv->event_wait); }
- drm_vblank_put(drm_dev, crtc); - dev_priv->pageflip_event = false; + if (is_checked) + drm_vblank_put(drm_dev, crtc);
spin_unlock_irqrestore(&drm_dev->event_lock, flags); }
Signed-off-by: Inki Dae inki.dae@samsung.com Signed-off-by: Kyungmin Park kyungmin.park@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 915f5cd..c03683f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -123,7 +123,7 @@ struct exynos_drm_overlay { * Exynos DRM Display Structure. * - this structure is common to analog tv, digital tv and lcd panel. * - * @type: one of exynos_DISPLAY_TYPE_LCD and HDMI. + * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. * @is_connected: check for that display is connected or not. * @get_edid: get edid modes from display driver. * @get_timing: get timing object from display driver. diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 68446b3b..4659c88 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -90,8 +90,6 @@ struct fimd_context {
static bool fimd_display_is_connected(struct device *dev) { - struct fimd_context *ctx = get_fimd_context(dev); - DRM_DEBUG_KMS("%s\n", __FILE__);
/* TODO. */ @@ -110,8 +108,6 @@ static void *fimd_get_timing(struct device *dev)
static int fimd_check_timing(struct device *dev, void *timing) { - struct fimd_context *ctx = get_fimd_context(dev); - DRM_DEBUG_KMS("%s\n", __FILE__);
/* TODO. */ @@ -121,8 +117,6 @@ static int fimd_check_timing(struct device *dev, void *timing)
static int fimd_display_power_on(struct device *dev, int mode) { - struct fimd_context *ctx = get_fimd_context(dev); - DRM_DEBUG_KMS("%s\n", __FILE__);
/* TODO. */ @@ -499,7 +493,7 @@ static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc)
list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, base.link) { - /* if event's pipe isn't same as crtc then ignor it. */ + /* if event's pipe isn't same as crtc then ignore it. */ if (crtc != e->pipe) continue;
@@ -525,7 +519,6 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) struct fimd_context *ctx = (struct fimd_context *)dev_id; struct exynos_drm_subdrv *subdrv = &ctx->subdrv; struct drm_device *drm_dev = subdrv->drm_dev; - struct device *dev = subdrv->manager.dev; struct exynos_drm_manager *manager = &subdrv->manager; u32 val;
@@ -543,8 +536,6 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev) { - struct drm_driver *drm_driver = drm_dev->driver; - DRM_DEBUG_KMS("%s\n", __FILE__);
/* @@ -569,8 +560,6 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
static void fimd_subdrv_remove(struct drm_device *drm_dev) { - struct drm_driver *drm_driver = drm_dev->driver; - DRM_DEBUG_KMS("%s\n", __FILE__);
/* TODO. */
dri-devel@lists.freedesktop.org