diff options
-rw-r--r-- | drivers/gpu/drm/exynos/exynos7_drm_decon.c | 178 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_dp_core.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.c | 101 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.h | 40 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_dsi.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fb.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 251 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.h | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_ipp.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_plane.c | 78 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_plane.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_vidi.c | 136 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_hdmi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_mixer.c | 260 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/regs-mixer.h | 2 | ||||
-rw-r--r-- | include/video/samsung_fimd.h | 11 |
18 files changed, 495 insertions, 691 deletions
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 970046199608..1f7e33f59de6 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -28,6 +28,7 @@ #include <video/exynos7_decon.h> #include "exynos_drm_crtc.h" +#include "exynos_drm_plane.h" #include "exynos_drm_drv.h" #include "exynos_drm_fbdev.h" #include "exynos_drm_iommu.h" @@ -41,32 +42,16 @@ #define WINDOWS_NR 2 -struct decon_win_data { - unsigned int ovl_x; - unsigned int ovl_y; - unsigned int offset_x; - unsigned int offset_y; - unsigned int ovl_width; - unsigned int ovl_height; - unsigned int fb_width; - unsigned int fb_height; - unsigned int bpp; - unsigned int pixel_format; - dma_addr_t dma_addr; - bool enabled; - bool resume; -}; - struct decon_context { struct device *dev; struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; + struct exynos_drm_plane planes[WINDOWS_NR]; struct clk *pclk; struct clk *aclk; struct clk *eclk; struct clk *vclk; void __iomem *regs; - struct decon_win_data win_data[WINDOWS_NR]; unsigned int default_win; unsigned long irq_flags; bool i80_if; @@ -296,59 +281,16 @@ static void decon_disable_vblank(struct exynos_drm_crtc *crtc) } } -static void decon_win_mode_set(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) -{ - struct decon_context *ctx = crtc->ctx; - struct decon_win_data *win_data; - int win, padding; - - if (!plane) { - DRM_ERROR("plane is NULL\n"); - return; - } - - win = plane->zpos; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - - if (win < 0 || win >= WINDOWS_NR) - return; - - - win_data = &ctx->win_data[win]; - - padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; - win_data->offset_x = plane->fb_x; - win_data->offset_y = plane->fb_y; - win_data->fb_width = plane->fb_width + padding; - win_data->fb_height = plane->fb_height; - win_data->ovl_x = plane->crtc_x; - win_data->ovl_y = plane->crtc_y; - win_data->ovl_width = plane->crtc_width; - win_data->ovl_height = plane->crtc_height; - win_data->dma_addr = plane->dma_addr[0]; - win_data->bpp = plane->bpp; - win_data->pixel_format = plane->pixel_format; - - 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\n", (unsigned long)win_data->dma_addr); - DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", - plane->fb_width, plane->crtc_width); -} - static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) { - struct decon_win_data *win_data = &ctx->win_data[win]; + struct exynos_drm_plane *plane = &ctx->planes[win]; unsigned long val; + int padding; val = readl(ctx->regs + WINCON(win)); val &= ~WINCONx_BPPMODE_MASK; - switch (win_data->pixel_format) { + switch (plane->pixel_format) { case DRM_FORMAT_RGB565: val |= WINCONx_BPPMODE_16BPP_565; val |= WINCONx_BURSTLEN_16WORD; @@ -397,7 +339,7 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) break; } - DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp); + DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); /* * In case of exynos, setting dma-burst to 16Word causes permanent @@ -407,7 +349,8 @@ static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win) * movement causes unstable DMA which results into iommu crash/tear. */ - if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { + padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; + if (plane->fb_width + padding < MIN_FB_WIDTH_FOR_16WORD_BURST) { val &= ~WINCONx_BURSTLEN_MASK; val |= WINCONx_BURSTLEN_8WORD; } @@ -435,7 +378,7 @@ static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win) * @protect: 1 to protect (disable updates) */ static void decon_shadow_protect_win(struct decon_context *ctx, - int win, bool protect) + unsigned int win, bool protect) { u32 bits, val; @@ -449,12 +392,12 @@ static void decon_shadow_protect_win(struct decon_context *ctx, writel(val, ctx->regs + SHADOWCON); } -static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos) +static void decon_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) { struct decon_context *ctx = crtc->ctx; struct drm_display_mode *mode = &crtc->base.mode; - struct decon_win_data *win_data; - int win = zpos; + struct exynos_drm_plane *plane; + int padding; unsigned long val, alpha; unsigned int last_x; unsigned int last_y; @@ -462,17 +405,14 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos) if (ctx->suspended) return; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - if (win < 0 || win >= WINDOWS_NR) return; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; /* If suspended, enable this on resume */ if (ctx->suspended) { - win_data->resume = true; + plane->resume = true; return; } @@ -490,39 +430,41 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos) decon_shadow_protect_win(ctx, win, true); /* buffer start address */ - val = (unsigned long)win_data->dma_addr; + val = (unsigned long)plane->dma_addr[0]; writel(val, ctx->regs + VIDW_BUF_START(win)); + padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width; + /* buffer size */ - writel(win_data->fb_width, ctx->regs + VIDW_WHOLE_X(win)); - writel(win_data->fb_height, ctx->regs + VIDW_WHOLE_Y(win)); + writel(plane->fb_width + padding, ctx->regs + VIDW_WHOLE_X(win)); + writel(plane->fb_height, ctx->regs + VIDW_WHOLE_Y(win)); /* offset from the start of the buffer to read */ - writel(win_data->offset_x, ctx->regs + VIDW_OFFSET_X(win)); - writel(win_data->offset_y, ctx->regs + VIDW_OFFSET_Y(win)); + writel(plane->src_x, ctx->regs + VIDW_OFFSET_X(win)); + writel(plane->src_y, ctx->regs + VIDW_OFFSET_Y(win)); DRM_DEBUG_KMS("start addr = 0x%lx\n", - (unsigned long)win_data->dma_addr); + (unsigned long)val); DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", - win_data->ovl_width, win_data->ovl_height); + plane->crtc_width, plane->crtc_height); /* * OSD position. * In case the window layout goes of LCD layout, DECON fails. */ - if ((win_data->ovl_x + win_data->ovl_width) > mode->hdisplay) - win_data->ovl_x = mode->hdisplay - win_data->ovl_width; - if ((win_data->ovl_y + win_data->ovl_height) > mode->vdisplay) - win_data->ovl_y = mode->vdisplay - win_data->ovl_height; + if ((plane->crtc_x + plane->crtc_width) > mode->hdisplay) + plane->crtc_x = mode->hdisplay - plane->crtc_width; + if ((plane->crtc_y + plane->crtc_height) > mode->vdisplay) + plane->crtc_y = mode->vdisplay - plane->crtc_height; - val = VIDOSDxA_TOPLEFT_X(win_data->ovl_x) | - VIDOSDxA_TOPLEFT_Y(win_data->ovl_y); + val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) | + VIDOSDxA_TOPLEFT_Y(plane->crtc_y); writel(val, ctx->regs + VIDOSD_A(win)); - last_x = win_data->ovl_x + win_data->ovl_width; + last_x = plane->crtc_x + plane->crtc_width; if (last_x) last_x--; - last_y = win_data->ovl_y + win_data->ovl_height; + last_y = plane->crtc_y + plane->crtc_height; if (last_y) last_y--; @@ -531,7 +473,7 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos) writel(val, ctx->regs + VIDOSD_B(win)); DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n", - win_data->ovl_x, win_data->ovl_y, last_x, last_y); + plane->crtc_x, plane->crtc_y, last_x, last_y); /* OSD alpha */ alpha = VIDOSDxC_ALPHA0_R_F(0x0) | @@ -565,27 +507,23 @@ static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos) val |= DECON_UPDATE_STANDALONE_F; writel(val, ctx->regs + DECON_UPDATE); - win_data->enabled = true; + plane->enabled = true; } -static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos) +static void decon_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) { struct decon_context *ctx = crtc->ctx; - struct decon_win_data *win_data; - int win = zpos; + struct exynos_drm_plane *plane; u32 val; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - if (win < 0 || win >= WINDOWS_NR) return; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; if (ctx->suspended) { /* do not resume this window*/ - win_data->resume = false; + plane->resume = false; return; } @@ -604,42 +542,42 @@ static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos) val |= DECON_UPDATE_STANDALONE_F; writel(val, ctx->regs + DECON_UPDATE); - win_data->enabled = false; + plane->enabled = false; } static void decon_window_suspend(struct decon_context *ctx) { - struct decon_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - win_data->resume = win_data->enabled; - if (win_data->enabled) + plane = &ctx->planes[i]; + plane->resume = plane->enabled; + if (plane->enabled) decon_win_disable(ctx->crtc, i); } } static void decon_window_resume(struct decon_context *ctx) { - struct decon_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - win_data->enabled = win_data->resume; - win_data->resume = false; + plane = &ctx->planes[i]; + plane->enabled = plane->resume; + plane->resume = false; } } static void decon_apply(struct decon_context *ctx) { - struct decon_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - if (win_data->enabled) + plane = &ctx->planes[i]; + if (plane->enabled) decon_win_commit(ctx->crtc, i); else decon_win_disable(ctx->crtc, i); @@ -779,7 +717,6 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = { .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, .wait_for_vblank = decon_wait_for_vblank, - .win_mode_set = decon_win_mode_set, .win_commit = decon_win_commit, .win_disable = decon_win_disable, }; @@ -818,6 +755,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data) { struct decon_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; + struct exynos_drm_plane *exynos_plane; + enum drm_plane_type type; + unsigned int zpos; int ret; ret = decon_ctx_initialize(ctx, drm_dev); @@ -826,8 +766,18 @@ static int decon_bind(struct device *dev, struct device *master, void *data) return ret; } - ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe, - EXYNOS_DISPLAY_TYPE_LCD, + for (zpos = 0; zpos < WINDOWS_NR; zpos++) { + type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + DRM_PLANE_TYPE_OVERLAY; + ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], + 1 << ctx->pipe, type, zpos); + if (ret) + return ret; + } + + exynos_plane = &ctx->planes[ctx->default_win]; + ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, + ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, &decon_crtc_ops, ctx); if (IS_ERR(ctx->crtc)) { decon_ctx_remove(ctx); diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index bf17a60b40ed..1dbfba58f909 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -32,10 +32,16 @@ #include <drm/bridge/ptn3460.h> #include "exynos_dp_core.h" +#include "exynos_drm_fimd.h" #define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ connector) +static inline struct exynos_drm_crtc *dp_to_crtc(struct exynos_dp_device *dp) +{ + return to_exynos_crtc(dp->encoder->crtc); +} + static inline struct exynos_dp_device * display_to_dp(struct exynos_drm_display *d) { @@ -1070,6 +1076,8 @@ static void exynos_dp_poweron(struct exynos_dp_device *dp) } } + fimd_dp_clock_enable(dp_to_crtc(dp), true); + clk_prepare_enable(dp->clock); exynos_dp_phy_init(dp); exynos_dp_init_dp(dp); @@ -1094,6 +1102,8 @@ static void exynos_dp_poweroff(struct exynos_dp_device *dp) exynos_dp_phy_exit(dp); clk_disable_unprepare(dp->clock); + fimd_dp_clock_enable(dp_to_crtc(dp), false); + if (dp->panel) { if (drm_panel_unprepare(dp->panel)) DRM_ERROR("failed to turnoff the panel\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 48ccab7fdf63..eb49195cec5c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -34,9 +34,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) if (mode > DRM_MODE_DPMS_ON) { /* wait for the completion of page flip. */ if (!wait_event_timeout(exynos_crtc->pending_flip_queue, - !atomic_read(&exynos_crtc->pending_flip), - HZ/20)) - atomic_set(&exynos_crtc->pending_flip, 0); + (exynos_crtc->event == NULL), HZ/20)) + exynos_crtc->event = NULL; drm_crtc_vblank_off(crtc); } @@ -164,11 +163,10 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, uint32_t page_flip_flags) { struct drm_device *dev = crtc->dev; - struct exynos_drm_private *dev_priv = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_framebuffer *old_fb = crtc->primary->fb; unsigned int crtc_w, crtc_h; - int ret = -EINVAL; + int ret; /* when the page flip is requested, crtc's dpms should be on */ if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { @@ -176,48 +174,49 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, return -EINVAL; } - mutex_lock(&dev->struct_mutex); + if (!event) + return -EINVAL; - 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; + spin_lock_irq(&dev->event_lock); + if (exynos_crtc->event) { + ret = -EBUSY; + goto out; + } - ret = drm_vblank_get(dev, exynos_crtc->pipe); - if (ret) { - DRM_DEBUG("failed to acquire vblank counter\n"); + ret = drm_vblank_get(dev, exynos_crtc->pipe); + if (ret) { + DRM_DEBUG("failed to acquire vblank counter\n"); + goto out; + } - goto out; - } + exynos_crtc->event = event; + spin_unlock_irq(&dev->event_lock); + /* + * the pipe from user always is 0 so we can set pipe number + * of current owner to event. + */ + event->pipe = exynos_crtc->pipe; + + crtc->primary->fb = fb; + crtc_w = fb->width - crtc->x; + crtc_h = fb->height - crtc->y; + ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0, + crtc_w, crtc_h, crtc->x, crtc->y, + crtc_w, crtc_h); + if (ret) { + crtc->primary->fb = old_fb; spin_lock_irq(&dev->event_lock); - list_add_tail(&event->base.link, - &dev_priv->pageflip_event_list); - atomic_set(&exynos_crtc->pending_flip, 1); + exynos_crtc->event = NULL; + drm_vblank_put(dev, exynos_crtc->pipe); spin_unlock_irq(&dev->event_lock); - - crtc->primary->fb = fb; - crtc_w = fb->width - crtc->x; - crtc_h = fb->height - crtc->y; - ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0, - crtc_w, crtc_h, crtc->x, crtc->y, - crtc_w, crtc_h); - if (ret) { - crtc->primary->fb = old_fb; - - spin_lock_irq(&dev->event_lock); - drm_vblank_put(dev, exynos_crtc->pipe); - list_del(&event->base.link); - atomic_set(&exynos_crtc->pending_flip, 0); - spin_unlock_irq(&dev->event_lock); - - goto out; - } + return ret; } + + return 0; + out: - mutex_unlock(&dev->struct_mutex); + spin_unlock_irq(&dev->event_lock); return ret; } @@ -239,13 +238,13 @@ static struct drm_crtc_funcs exynos_crtc_funcs = { }; struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, + struct drm_plane *plane, int pipe, enum exynos_drm_output_type type, struct exynos_drm_crtc_ops *ops, void *ctx) { struct exynos_drm_crtc *exynos_crtc; - struct drm_plane *plane; struct exynos_drm_private *private = drm_dev->dev_private; struct drm_crtc *crtc; int ret; @@ -255,19 +254,12 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, return ERR_PTR(-ENOMEM); init_waitqueue_head(&exynos_crtc->pending_flip_queue); - atomic_set(&exynos_crtc->pending_flip, 0); exynos_crtc->dpms = DRM_MODE_DPMS_OFF; exynos_crtc->pipe = pipe; exynos_crtc->type = type; exynos_crtc->ops = ops; exynos_crtc->ctx = ctx; - plane = exynos_plane_init(drm_dev, 1 << pipe, - DRM_PLANE_TYPE_PRIMARY); - if (IS_ERR(plane)) { - ret = PTR_ERR(plane); - goto err_plane; - } crtc = &exynos_crtc->base; @@ -284,7 +276,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, err_crtc: plane->funcs->destroy(plane); -err_plane: kfree(exynos_crtc); return ERR_PTR(ret); } @@ -320,26 +311,20 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) { struct exynos_drm_private *dev_priv = dev->dev_private; - struct drm_pending_vblank_event *e, *t; struct drm_crtc *drm_crtc = dev_priv->crtc[pipe]; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); unsigned long flags; spin_lock_irqsave(&dev->event_lock, flags); + if (exynos_crtc->event) { - list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, - base.link) { - /* if event's pipe isn't same as crtc then ignore it. */ - if (pipe != e->pipe) - continue; - - list_del(&e->base.link); - drm_send_vblank_event(dev, -1, e); + drm_send_vblank_event(dev, -1, exynos_crtc->event); drm_vblank_put(dev, pipe); - atomic_set(&exynos_crtc->pending_flip, 0); wake_up(&exynos_crtc->pending_flip_queue); + } + exynos_crtc->event = NULL; spin_unlock_irqrestore(&dev->event_lock, flags); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 6258b800aab8..0ecd8fc45cff 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -18,6 +18,7 @@ #include "exynos_drm_drv.h" struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, + struct drm_plane *plane, int pipe, enum exynos_drm_output_type type, struct exynos_drm_crtc_ops *ops, @@ -27,12 +28,6 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe); void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); -void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc, - struct exynos_drm_plane *plane); -void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos); -void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos); -void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos); - /* This function gets pipe value to crtc device matched with out_type. */ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, unsigned int out_type); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 90168d7cf66a..8ac465208eae 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -55,13 +55,11 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) { struct exynos_drm_private *private; int ret; - int nr; private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL); if (!private) return -ENOMEM; - INIT_LIST_HEAD(&private->pageflip_event_list); dev_set_drvdata(dev->dev, dev); dev->dev_private = (void *)private; @@ -81,19 +79,6 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) exynos_drm_mode_config_init(dev); - for (nr = 0; nr < MAX_PLANE; nr++) { - struct drm_plane *plane; - unsigned long possible_crtcs = (1 << MAX_CRTC) - 1; - - plane = exynos_plane_init(dev, possible_crtcs, - DRM_PLANE_TYPE_OVERLAY); - if (!IS_ERR(plane)) - continue; - - ret = PTR_ERR(plane); - goto err_mode_config_cleanup; - } - /* setup possible_clones. */ exynos_drm_encoder_setup(dev); @@ -237,25 +222,13 @@ static void exynos_drm_preclose(struct drm_device *dev, static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) { - struct exynos_drm_private *private = dev->dev_private; - struct drm_pending_vblank_event *v, *vt; struct drm_pending_event *e, *et; unsigned long flags; if (!file->driver_priv) return; - /* Release all events not unhandled by page flip handler. */ spin_lock_irqsave(&dev->event_lock, flags); - list_for_each_entry_safe(v, vt, &private->pageflip_event_list, - base.link) { - if (v->base.file_priv == file) { - list_del(&v->base.link); - drm_vblank_put(dev, v->pipe); - v->base.destroy(&v->base); - } - } - /* Release all events handled by page flip handler but not freed. */ list_for_each_entry_safe(e, et, &file->event_list, link) { list_del(&e->link); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 9afd390d4674..e12ecb5d5d9a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -21,7 +21,6 @@ #define MAX_CRTC 3 #define MAX_PLANE 5 #define MAX_FB_BUFFER 4 -#define DEFAULT_ZPOS -1 #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base) #define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base) @@ -48,20 +47,22 @@ enum exynos_drm_output_type { * Exynos drm common overlay structure. * * @base: plane object - * @fb_x: offset x on a framebuffer to be displayed. + * @src_x: offset x on a framebuffer to be displayed. * - the unit is screen coordinates. - * @fb_y: offset y on a framebuffer to be displayed. + * @src_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. * @src_width: width of a partial image to be displayed from framebuffer. * @src_height: height of a partial image to be displayed from framebuffer. + * @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. + * @h_ratio: horizontal scaling ratio, 16.16 fixed point + * @v_ratio: vertical scaling ratio, 16.16 fixed point * @refresh: refresh rate. * @scan_flag: interlace or progressive way. * (it could be DRM_MODE_FLAG_*) @@ -78,6 +79,7 @@ enum exynos_drm_output_type { * @transparency: transparency on or off. * @activated: activated or not. * @enabled: enabled or not. + * @resume: to resume or not. * * this structure is common to exynos SoC and its contents would be copied * to hardware specific overlay info. @@ -85,25 +87,27 @@ enum exynos_drm_output_type { struct exynos_drm_plane { struct drm_plane base; - unsigned int fb_x; - unsigned int fb_y; - unsigned int fb_width; - unsigned int fb_height; + unsigned int src_x; + unsigned int src_y; unsigned int src_width; unsigned int src_height; + 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 h_ratio; + unsigned int v_ratio; unsigned int refresh; unsigned int scan_flag; unsigned int bpp; unsigned int pitch; uint32_t pixel_format; dma_addr_t dma_addr[MAX_FB_BUFFER]; - int zpos; + unsigned int zpos; unsigned int index_color; bool default_win:1; @@ -112,6 +116,7 @@ struct exynos_drm_plane { bool transparency:1; bool activated:1; bool enabled:1; + bool resume:1; }; /* @@ -172,9 +177,7 @@ struct exynos_drm_display { * @disable_vblank: specific driver callback for disabling vblank interrupt. * @wait_for_vblank: wait for vblank interrupt to make sure that * hardware overlay is updated. - * @win_mode_set: copy drm overlay info to hw specific overlay info. * @win_commit: apply hardware specific overlay data to registers. - * @win_enable: enable hardware specific overlay. * @win_disable: disable hardware specific overlay. * @te_handler: trigger to transfer video image at the tearing effect * synchronization signal if there is a page flip request. @@ -189,11 +192,8 @@ struct exynos_drm_crtc_ops { int (*enable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); - void (*win_mode_set)(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane); - void (*win_commit)(struct exynos_drm_crtc *crtc, int zpos); - void (*win_enable)(struct exynos_drm_crtc *crtc, int zpos); - void (*win_disable)(struct exynos_drm_crtc *crtc, int zpos); + void (*win_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos); + void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos); void (*te_handler)(struct exynos_drm_crtc *crtc); }; @@ -210,6 +210,7 @@ struct exynos_drm_crtc_ops { * we can refer to the crtc to current hardware interrupt occurred through * this pipe value. * @dpms: store the crtc dpms value + * @event: vblank event that is currently queued for flip * @ops: pointer to callbacks for exynos drm specific functionality * @ctx: A pointer to the crtc's implementation specific context */ @@ -219,7 +220,7 @@ struct exynos_drm_crtc { unsigned int pipe; unsigned int dpms; wait_queue_head_t pending_flip_queue; - atomic_t pending_flip; + struct drm_pending_vblank_event *event; struct exynos_drm_crtc_ops *ops; void *ctx; }; @@ -249,9 +250,6 @@ struct drm_exynos_file_private { struct exynos_drm_private { struct drm_fb_helper *fb_helper; - /* list head for new event to be added. */ - struct list_head pageflip_event_list; - /* * created crtc object would be contained at this array and * this array is used to be aware of which crtc did it request vblank. diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 05fe93dc57a8..04927153bf38 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1473,12 +1473,6 @@ static int exynos_dsi_get_modes(struct drm_connector *connector) return 0; } -static int exynos_dsi_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return MODE_OK; -} - static struct drm_encoder * exynos_dsi_best_encoder(struct drm_connector *connector) { @@ -1489,7 +1483,6 @@ exynos_dsi_best_encoder(struct drm_connector *connector) static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { .get_modes = exynos_dsi_get_modes, - .mode_valid = exynos_dsi_mode_valid, .best_encoder = exynos_dsi_best_encoder, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index d346d1e6eda0..929cb03a8eab 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -151,10 +151,8 @@ exynos_drm_framebuffer_init(struct drm_device *dev, exynos_gem_obj = to_exynos_gem_obj(obj); ret = check_fb_gem_memory_type(dev, exynos_gem_obj); - if (ret < 0) { - DRM_ERROR("cannot use this gem memory type for fb.\n"); - return ERR_PTR(-EINVAL); - } + if (ret < 0) + return ERR_PTR(ret); exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); if (!exynos_fb) @@ -250,10 +248,8 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, exynos_fb->exynos_gem_obj[i] = exynos_gem_obj; ret = check_fb_gem_memory_type(dev, exynos_gem_obj); - if (ret < 0) { - DRM_ERROR("cannot use this gem memory type for fb.\n"); + if (ret < 0) goto err_unreference; - } } ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 33a10ce967ea..9819fa6a9e2a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -31,7 +31,9 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fbdev.h" #include "exynos_drm_crtc.h" +#include "exynos_drm_plane.h" #include "exynos_drm_iommu.h" +#include "exynos_drm_fimd.h" /* * FIMD stands for Fully Interactive Mobile Display and @@ -54,6 +56,9 @@ /* size control register for hardware windows 1 ~ 2. */ #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) +#define VIDWnALPHA0(win) (VIDW_ALPHA + 0x00 + (win) * 8) +#define VIDWnALPHA1(win) (VIDW_ALPHA + 0x04 + (win) * 8) + #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) #define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8) #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) @@ -140,32 +145,15 @@ static struct fimd_driver_data exynos5_fimd_driver_data = { .has_vtsel = 1, }; -struct fimd_win_data { - unsigned int offset_x; - unsigned int offset_y; - unsigned int ovl_width; - unsigned int ovl_height; - unsigned int fb_width; - unsigned int fb_height; - unsigned int fb_pitch; - unsigned int bpp; - unsigned int pixel_format; - dma_addr_t dma_addr; - unsigned int buf_offsize; - unsigned int line_size; /* bytes */ - bool enabled; - bool resume; -}; - struct fimd_context { struct device *dev; struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; + struct exynos_drm_plane planes[WINDOWS_NR]; struct clk *bus_clk; struct clk *lcd_clk; void __iomem *regs; struct regmap *sysreg; - struct fimd_win_data win_data[WINDOWS_NR]; unsigned int default_win; unsigned long irq_flags; u32 vidcon0; @@ -502,59 +490,9 @@ static void fimd_disable_vblank(struct exynos_drm_crtc *crtc) } } -static void fimd_win_mode_set(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) -{ - struct fimd_context *ctx = crtc->ctx; - struct fimd_win_data *win_data; - int win; - unsigned long offset; - - if (!plane) { - DRM_ERROR("plane is NULL\n"); - return; - } - - win = plane->zpos; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - - if (win < 0 || win >= WINDOWS_NR) - return; - - offset = plane->fb_x * (plane->bpp >> 3); - offset += plane->fb_y * plane->pitch; - - DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch); - - win_data = &ctx->win_data[win]; - - win_data->offset_x = plane->crtc_x; - win_data->offset_y = plane->crtc_y; - win_data->ovl_width = plane->crtc_width; - win_data->ovl_height = plane->crtc_height; - win_data->fb_pitch = plane->pitch; - win_data->fb_width = plane->fb_width; - win_data->fb_height = plane->fb_height; - win_data->dma_addr = plane->dma_addr[0] + offset; - win_data->bpp = plane->bpp; - win_data->pixel_format = plane->pixel_format; - win_data->buf_offsize = - plane->pitch - (plane->crtc_width * (plane->bpp >> 3)); - win_data->line_size = plane->crtc_width * (plane->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\n", (unsigned long)win_data->dma_addr); - DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", - plane->fb_width, plane->crtc_width); -} - static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) { - struct fimd_win_data *win_data = &ctx->win_data[win]; + struct exynos_drm_plane *plane = &ctx->planes[win]; unsigned long val; val = WINCONx_ENWIN; @@ -564,11 +502,11 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) * So the request format is ARGB8888 then change it to XRGB8888. */ if (ctx->driver_data->has_limited_fmt && !win) { - if (win_data->pixel_format == DRM_FORMAT_ARGB8888) - win_data->pixel_format = DRM_FORMAT_XRGB8888; + if (plane->pixel_format == DRM_FORMAT_ARGB8888) + plane->pixel_format = DRM_FORMAT_XRGB8888; } - switch (win_data->pixel_format) { + switch (plane->pixel_format) { case DRM_FORMAT_C8: val |= WINCON0_BPPMODE_8BPP_PALETTE; val |= WINCONx_BURSTLEN_8WORD; @@ -604,7 +542,7 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) break; } - DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp); + DRM_DEBUG_KMS("bpp = %d\n", plane->bpp); /* * In case of exynos, setting dma-burst to 16Word causes permanent @@ -614,12 +552,30 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) * movement causes unstable DMA which results into iommu crash/tear. */ - if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { + if (plane->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) { val &= ~WINCONx_BURSTLEN_MASK; val |= WINCONx_BURSTLEN_4WORD; } writel(val, ctx->regs + WINCON(win)); + + /* hardware window 0 doesn't support alpha channel. */ + if (win != 0) { + /* OSD alpha */ + val = VIDISD14C_ALPHA0_R(0xf) | + VIDISD14C_ALPHA0_G(0xf) | + VIDISD14C_ALPHA0_B(0xf) | + VIDISD14C_ALPHA1_R(0xf) | + VIDISD14C_ALPHA1_G(0xf) | + VIDISD14C_ALPHA1_B(0xf); + + writel(val, ctx->regs + VIDOSD_C(win)); + + val = VIDW_ALPHA_R(0xf) | VIDW_ALPHA_G(0xf) | + VIDW_ALPHA_G(0xf); + writel(val, ctx->regs + VIDWnALPHA0(win)); + writel(val, ctx->regs + VIDWnALPHA1(win)); + } } static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win) @@ -642,7 +598,7 @@ static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win) * @protect: 1 to protect (disable updates) */ static void fimd_shadow_protect_win(struct fimd_context *ctx, - int win, bool protect) + unsigned int win, bool protect) { u32 reg, bits, val; @@ -662,29 +618,25 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, writel(val, ctx->regs + reg); } -static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos) +static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) { struct fimd_context *ctx = crtc->ctx; - struct fimd_win_data *win_data; - int win = zpos; - unsigned long val, alpha, size; - unsigned int last_x; - unsigned int last_y; + struct exynos_drm_plane *plane; + dma_addr_t dma_addr; + unsigned long val, size, offset; + unsigned int last_x, last_y, buf_offsize, line_size; if (ctx->suspended) return; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - if (win < 0 || win >= WINDOWS_NR) return; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; /* If suspended, enable this on resume */ if (ctx->suspended) { - win_data->resume = true; + plane->resume = true; return; } @@ -701,38 +653,45 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos) /* protect windows */ fimd_shadow_protect_win(ctx, win, true); + + offset = plane->src_x * (plane->bpp >> 3); + offset += plane->src_y * plane->pitch; + /* buffer start address */ - val = (unsigned long)win_data->dma_addr; + dma_addr = plane->dma_addr[0] + offset; + val = (unsigned long)dma_addr; writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); /* buffer end address */ - size = win_data->fb_pitch * win_data->ovl_height * (win_data->bpp >> 3); - val = (unsigned long)(win_data->dma_addr + size); + size = plane->pitch * plane->crtc_height; + val = (unsigned long)(dma_addr + 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->dma_addr, val, size); + (unsigned long)dma_addr, val, size); DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", - win_data->ovl_width, win_data->ovl_height); + plane->crtc_width, plane->crtc_height); /* buffer size */ - val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) | - VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size) | - VIDW_BUF_SIZE_OFFSET_E(win_data->buf_offsize) | - VIDW_BUF_SIZE_PAGEWIDTH_E(win_data->line_size); + buf_offsize = plane->pitch - (plane->crtc_width * (plane->bpp >> 3)); + line_size = plane->crtc_width * (plane->bpp >> 3); + val = VIDW_BUF_SIZE_OFFSET(buf_offsize) | + VIDW_BUF_SIZE_PAGEWIDTH(line_size) | + VIDW_BUF_SIZE_OFFSET_E(buf_offsize) | + VIDW_BUF_SIZE_PAGEWIDTH_E(line_size); writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0)); /* OSD position */ - val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) | - VIDOSDxA_TOPLEFT_Y(win_data->offset_y) | - VIDOSDxA_TOPLEFT_X_E(win_data->offset_x) | - VIDOSDxA_TOPLEFT_Y_E(win_data->offset_y); + val = VIDOSDxA_TOPLEFT_X(plane->crtc_x) | + VIDOSDxA_TOPLEFT_Y(plane->crtc_y) | + VIDOSDxA_TOPLEFT_X_E(plane->crtc_x) | + VIDOSDxA_TOPLEFT_Y_E(plane->crtc_y); writel(val, ctx->regs + VIDOSD_A(win)); - last_x = win_data->offset_x + win_data->ovl_width; + last_x = plane->crtc_x + plane->crtc_width; if (last_x) last_x--; - last_y = win_data->offset_y + win_data->ovl_height; + last_y = plane->crtc_y + plane->crtc_height; if (last_y) last_y--; @@ -742,24 +701,14 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos) writel(val, ctx->regs + VIDOSD_B(win)); DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n", - win_data->offset_x, win_data->offset_y, last_x, last_y); - - /* hardware window 0 doesn't support alpha channel. */ - if (win != 0) { - /* OSD alpha */ - alpha = VIDISD14C_ALPHA1_R(0xf) | - VIDISD14C_ALPHA1_G(0xf) | - VIDISD14C_ALPHA1_B(0xf); - - writel(alpha, ctx->regs + VIDOSD_C(win)); - } + plane->crtc_x, plane->crtc_y, last_x, last_y); /* OSD size */ if (win != 3 && win != 4) { u32 offset = VIDOSD_D(win); if (win == 0) offset = VIDOSD_C(win); - val = win_data->ovl_width * win_data->ovl_height; + val = plane->crtc_width * plane->crtc_height; writel(val, ctx->regs + offset); DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); @@ -779,29 +728,25 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos) /* Enable DMA channel and unprotect windows */ fimd_shadow_protect_win(ctx, win, false); - win_data->enabled = true; + plane->enabled = true; if (ctx->i80_if) atomic_set(&ctx->win_updated, 1); } -static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos) +static void fimd_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) { struct fimd_context *ctx = crtc->ctx; - struct fimd_win_data *win_data; - int win = zpos; - - if (win == DEFAULT_ZPOS) - win = ctx->default_win; + struct exynos_drm_plane *plane; if (win < 0 || win >= WINDOWS_NR) return; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; if (ctx->suspended) { /* do not resume this window*/ - win_data->resume = false; + plane->resume = false; return; } @@ -816,42 +761,42 @@ static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos) /* unprotect windows */ fimd_shadow_protect_win(ctx, win, false); - win_data->enabled = false; + plane->enabled = false; } static void fimd_window_suspend(struct fimd_context *ctx) { - struct fimd_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - win_data->resume = win_data->enabled; - if (win_data->enabled) + plane = &ctx->planes[i]; + plane->resume = plane->enabled; + if (plane->enabled) fimd_win_disable(ctx->crtc, i); } } static void fimd_window_resume(struct fimd_context *ctx) { - struct fimd_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - win_data->enabled = win_data->resume; - win_data->resume = false; + plane = &ctx->planes[i]; + plane->enabled = plane->resume; + plane->resume = false; } } static void fimd_apply(struct fimd_context *ctx) { - struct fimd_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - if (win_data->enabled) + plane = &ctx->planes[i]; + if (plane->enabled) fimd_win_commit(ctx->crtc, i); else fimd_win_disable(ctx->crtc, i); @@ -1008,7 +953,6 @@ static struct exynos_drm_crtc_ops fimd_crtc_ops = { .enable_vblank = fimd_enable_vblank, .disable_vblank = fimd_disable_vblank, .wait_for_vblank = fimd_wait_for_vblank, - .win_mode_set = fimd_win_mode_set, .win_commit = fimd_win_commit, .win_disable = fimd_win_disable, .te_handler = fimd_te_handler, @@ -1054,14 +998,29 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) struct fimd_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; struct exynos_drm_private *priv = drm_dev->dev_private; + struct exynos_drm_plane *exynos_plane; + enum drm_plane_type type; + unsigned int zpos; int ret; ctx->drm_dev = drm_dev; ctx->pipe = priv->pipe++; - ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe, - EXYNOS_DISPLAY_TYPE_LCD, + for (zpos = 0; zpos < WINDOWS_NR; zpos++) { + type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + DRM_PLANE_TYPE_OVERLAY; + ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], + 1 << ctx->pipe, type, zpos); + if (ret) + return ret; + } + + exynos_plane = &ctx->planes[ctx->default_win]; + ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, + ctx->pipe, EXYNOS_DISPLAY_TYPE_LCD, &fimd_crtc_ops, ctx); + if (IS_ERR(ctx->crtc)) + return PTR_ERR(ctx->crtc); if (ctx->display) exynos_drm_create_enc_conn(drm_dev, ctx->display); @@ -1233,6 +1192,24 @@ static int fimd_remove(struct platform_device *pdev) return 0; } +void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable) +{ + struct fimd_context *ctx = crtc->ctx; + u32 val; + + /* + * Only Exynos 5250, 5260, 5410 and 542x requires enabling DP/MIE + * clock. On these SoCs the bootloader may enable it but any + * power domain off/on will reset it to disable state. + */ + if (ctx->driver_data != &exynos5_fimd_driver_data) + return; + + val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE; + writel(DP_MIE_CLK_DP_ENABLE, ctx->regs + DP_MIE_CLKCON); +} +EXPORT_SYMBOL_GPL(fimd_dp_clock_enable); + struct platform_driver fimd_driver = { .probe = fimd_probe, .remove = fimd_remove, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.h b/drivers/gpu/drm/exynos/exynos_drm_fimd.h new file mode 100644 index 000000000000..b4fcaa568456 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _EXYNOS_DRM_FIMD_H_ +#define _EXYNOS_DRM_FIMD_H_ + +extern void fimd_dp_clock_enable(struct exynos_drm_crtc *crtc, bool enable); + +#endif /* _EXYNOS_DRM_FIMD_H_ */ diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index d5ad17dfc24d..b7f1cbc46cc2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -476,6 +476,45 @@ err_clear: return ret; } +static int ipp_validate_mem_node(struct drm_device *drm_dev, + struct drm_exynos_ipp_mem_node *m_node, + struct drm_exynos_ipp_cmd_node *c_node) +{ + struct drm_exynos_ipp_config *ipp_cfg; + unsigned int num_plane; + unsigned long min_size, size; + unsigned int bpp; + int i; + + /* The property id should already be varified */ + ipp_cfg = &c_node->property.config[m_node->prop_id]; + num_plane = drm_format_num_planes(ipp_cfg->fmt); + + /** + * This is a rather simplified validation of a memory node. + * It basically verifies provided gem object handles + * and the buffer sizes with respect to current configuration. + * This is not the best that can be done + * but it seems more than enough + */ + for (i = 0; i < num_plane; ++i) { + if (!m_node->buf_info.handles[i]) { + DRM_ERROR("invalid handle for plane %d\n", i); + return -EINVAL; + } + bpp = drm_format_plane_cpp(ipp_cfg->fmt, i); + min_size = (ipp_cfg->sz.hsize * ipp_cfg->sz.vsize * bpp) >> 3; + size = exynos_drm_gem_get_size(drm_dev, + m_node->buf_info.handles[i], + c_node->filp); + if (min_size > size) { + DRM_ERROR("invalid size for plane %d\n", i); + return -EINVAL; + } + } + return 0; +} + static int ipp_put_mem_node(struct drm_device *drm_dev, struct drm_exynos_ipp_cmd_node *c_node, struct drm_exynos_ipp_mem_node *m_node) @@ -552,6 +591,11 @@ static struct drm_exynos_ipp_mem_node } mutex_lock(&c_node->mem_lock); + if (ipp_validate_mem_node(drm_dev, m_node, c_node)) { + ipp_put_mem_node(drm_dev, c_node, m_node); + mutex_unlock(&c_node->mem_lock); + return ERR_PTR(-EFAULT); + } list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]); mutex_unlock(&c_node->mem_lock); diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 8ad5b7294eb4..13ea3349363b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -92,7 +92,6 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_w, uint32_t src_h) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); unsigned int actual_w; unsigned int actual_h; @@ -111,13 +110,17 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, crtc_y = 0; } + /* set ratio */ + exynos_plane->h_ratio = (src_w << 16) / crtc_w; + exynos_plane->v_ratio = (src_h << 16) / crtc_h; + /* set drm framebuffer data. */ - exynos_plane->fb_x = src_x; - exynos_plane->fb_y = src_y; + exynos_plane->src_x = src_x; + exynos_plane->src_y = src_y; + exynos_plane->src_width = (actual_w * exynos_plane->h_ratio) >> 16; + exynos_plane->src_height = (actual_h * exynos_plane->v_ratio) >> 16; exynos_plane->fb_width = fb->width; exynos_plane->fb_height = fb->height; - exynos_plane->src_width = src_w; - exynos_plane->src_height = src_h; exynos_plane->bpp = fb->bits_per_pixel; exynos_plane->pitch = fb->pitches[0]; exynos_plane->pixel_format = fb->pixel_format; @@ -139,9 +142,6 @@ void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, exynos_plane->crtc_width, exynos_plane->crtc_height); plane->crtc = crtc; - - if (exynos_crtc->ops->win_mode_set) - exynos_crtc->ops->win_mode_set(exynos_crtc, exynos_plane); } int @@ -182,39 +182,14 @@ static int exynos_disable_plane(struct drm_plane *plane) return 0; } -static void exynos_plane_destroy(struct drm_plane *plane) -{ - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - - exynos_disable_plane(plane); - drm_plane_cleanup(plane); - kfree(exynos_plane); -} - -static int exynos_plane_set_property(struct drm_plane *plane, - struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = plane->dev; - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - struct exynos_drm_private *dev_priv = dev->dev_private; - - if (property == dev_priv->plane_zpos_property) { - exynos_plane->zpos = val; - return 0; - } - - return -EINVAL; -} - static struct drm_plane_funcs exynos_plane_funcs = { .update_plane = exynos_update_plane, .disable_plane = exynos_disable_plane, - .destroy = exynos_plane_destroy, - .set_property = exynos_plane_set_property, + .destroy = drm_plane_cleanup, }; -static void exynos_plane_attach_zpos_property(struct drm_plane *plane) +static void exynos_plane_attach_zpos_property(struct drm_plane *plane, + unsigned int zpos) { struct drm_device *dev = plane->dev; struct exynos_drm_private *dev_priv = dev->dev_private; @@ -222,41 +197,36 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane) prop = dev_priv->plane_zpos_property; if (!prop) { - prop = drm_property_create_range(dev, 0, "zpos", 0, - MAX_PLANE - 1); + prop = drm_property_create_range(dev, DRM_MODE_PROP_IMMUTABLE, + "zpos", 0, MAX_PLANE - 1); if (!prop) return; dev_priv->plane_zpos_property = prop; } - drm_object_attach_property(&plane->base, prop, 0); + drm_object_attach_property(&plane->base, prop, zpos); } -struct drm_plane *exynos_plane_init(struct drm_device *dev, - unsigned long possible_crtcs, - enum drm_plane_type type) +int exynos_plane_init(struct drm_device *dev, + struct exynos_drm_plane *exynos_plane, + unsigned long possible_crtcs, enum drm_plane_type type, + unsigned int zpos) { - struct exynos_drm_plane *exynos_plane; int err; - exynos_plane = kzalloc(sizeof(struct exynos_drm_plane), GFP_KERNEL); - if (!exynos_plane) - return ERR_PTR(-ENOMEM); - err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs, &exynos_plane_funcs, formats, ARRAY_SIZE(formats), type); if (err) { DRM_ERROR("failed to initialize plane\n"); - kfree(exynos_plane); - return ERR_PTR(err); + return err; } - if (type == DRM_PLANE_TYPE_PRIMARY) - exynos_plane->zpos = DEFAULT_ZPOS; - else - exynos_plane_attach_zpos_property(&exynos_plane->base); + exynos_plane->zpos = zpos; - return &exynos_plane->base; + if (type == DRM_PLANE_TYPE_OVERLAY) + exynos_plane_attach_zpos_property(&exynos_plane->base, zpos); + + return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index 9d3c374e7b3e..f360590d1412 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -20,6 +20,7 @@ int exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, unsigned int crtc_w, unsigned int crtc_h, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); -struct drm_plane *exynos_plane_init(struct drm_device *dev, - unsigned long possible_crtcs, - enum drm_plane_type type); +int exynos_plane_init(struct drm_device *dev, + struct exynos_drm_plane *exynos_plane, + unsigned long possible_crtcs, enum drm_plane_type type, + unsigned int zpos); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index b886972b5888..27e84ec21694 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -23,6 +23,7 @@ #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" +#include "exynos_drm_plane.h" #include "exynos_drm_encoder.h" #include "exynos_drm_vidi.h" @@ -32,20 +33,6 @@ #define ctx_from_connector(c) container_of(c, struct vidi_context, \ connector) -struct vidi_win_data { - unsigned int offset_x; - unsigned int offset_y; - unsigned int ovl_width; - unsigned int ovl_height; - unsigned int fb_width; - unsigned int fb_height; - unsigned int bpp; - dma_addr_t dma_addr; - unsigned int buf_offsize; - unsigned int line_size; /* bytes */ - bool enabled; -}; - struct vidi_context { struct exynos_drm_display display; struct platform_device *pdev; @@ -53,7 +40,7 @@ struct vidi_context { struct exynos_drm_crtc *crtc; struct drm_encoder *encoder; struct drm_connector connector; - struct vidi_win_data win_data[WINDOWS_NR]; + struct exynos_drm_plane planes[WINDOWS_NR]; struct edid *raw_edid; unsigned int clkdiv; unsigned int default_win; @@ -97,19 +84,6 @@ static const char fake_edid_info[] = { 0x00, 0x00, 0x00, 0x06 }; -static void vidi_apply(struct vidi_context *ctx) -{ - struct exynos_drm_crtc_ops *crtc_ops = ctx->crtc->ops; - struct vidi_win_data *win_data; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - if (win_data->enabled && (crtc_ops && crtc_ops->win_commit)) - crtc_ops->win_commit(ctx->crtc, i); - } -} - static int vidi_enable_vblank(struct exynos_drm_crtc *crtc) { struct vidi_context *ctx = crtc->ctx; @@ -143,104 +117,46 @@ static void vidi_disable_vblank(struct exynos_drm_crtc *crtc) ctx->vblank_on = false; } -static void vidi_win_mode_set(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) -{ - struct vidi_context *ctx = crtc->ctx; - struct vidi_win_data *win_data; - int win; - unsigned long offset; - - if (!plane) { - DRM_ERROR("plane is NULL\n"); - return; - } - - win = plane->zpos; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - - if (win < 0 || win >= WINDOWS_NR) - return; - - offset = plane->fb_x * (plane->bpp >> 3); - offset += plane->fb_y * plane->pitch; - - DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch); - - win_data = &ctx->win_data[win]; - - win_data->offset_x = plane->crtc_x; - win_data->offset_y = plane->crtc_y; - win_data->ovl_width = plane->crtc_width; - win_data->ovl_height = plane->crtc_height; - win_data->fb_width = plane->fb_width; - win_data->fb_height = plane->fb_height; - win_data->dma_addr = plane->dma_addr[0] + offset; - win_data->bpp = plane->bpp; - win_data->buf_offsize = (plane->fb_width - plane->crtc_width) * - (plane->bpp >> 3); - win_data->line_size = plane->crtc_width * (plane->bpp >> 3); - - /* - * some parts of win_data should be transferred to user side - * through specific ioctl. - */ - - 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\n", (unsigned long)win_data->dma_addr); - DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", - plane->fb_width, plane->crtc_width); -} - -static void vidi_win_commit(struct exynos_drm_crtc *crtc, int zpos) +static void vidi_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) { struct vidi_context *ctx = crtc->ctx; - struct vidi_win_data *win_data; - int win = zpos; + struct exynos_drm_plane *plane; if (ctx->suspended) return; - if (win == DEFAULT_ZPOS) - win = ctx->default_win; - if (win < 0 || win >= WINDOWS_NR) return; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; - win_data->enabled = true; + plane->enabled = true; - DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr); + DRM_DEBUG_KMS("dma_addr = %pad\n", plane->dma_addr); if (ctx->vblank_on) schedule_work(&ctx->work); } -static void vidi_win_disable(struct exynos_drm_crtc *crtc, int zpos) +static void vidi_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) { struct vidi_context *ctx = crtc->ctx; - struct vidi_win_data *win_data; - int win = zpos; - - if (win == DEFAULT_ZPOS) - win = ctx->default_win; + struct exynos_drm_plane *plane; if (win < 0 || win >= WINDOWS_NR) return; - win_data = &ctx->win_data[win]; - win_data->enabled = false; + plane = &ctx->planes[win]; + plane->enabled = false; /* TODO. */ } static int vidi_power_on(struct vidi_context *ctx, bool enable) { + struct exynos_drm_plane *plane; + int i; + DRM_DEBUG_KMS("%s\n", __FILE__); if (enable != false && enable != true) @@ -253,7 +169,11 @@ static int vidi_power_on(struct vidi_context *ctx, bool enable) if (test_and_clear_bit(0, &ctx->irq_flags)) vidi_enable_vblank(ctx->crtc); - vidi_apply(ctx); + for (i = 0; i < WINDOWS_NR; i++) { + plane = &ctx->planes[i]; + if (plane->enabled) + vidi_win_commit(ctx->crtc, i); + } } else { ctx->suspended = true; } @@ -301,7 +221,6 @@ static struct exynos_drm_crtc_ops vidi_crtc_ops = { .dpms = vidi_dpms, .enable_vblank = vidi_enable_vblank, .disable_vblank = vidi_disable_vblank, - .win_mode_set = vidi_win_mode_set, .win_commit = vidi_win_commit, .win_disable = vidi_win_disable, }; @@ -543,12 +462,25 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) { struct vidi_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; + struct exynos_drm_plane *exynos_plane; + enum drm_plane_type type; + unsigned int zpos; int ret; vidi_ctx_initialize(ctx, drm_dev); - ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe, - EXYNOS_DISPLAY_TYPE_VIDI, + for (zpos = 0; zpos < WINDOWS_NR; zpos++) { + type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : + DRM_PLANE_TYPE_OVERLAY; + ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], + 1 << ctx->pipe, type, zpos); + if (ret) + return ret; + } + + exynos_plane = &ctx->planes[ctx->default_win]; + ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, + ctx->pipe, EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx); if (IS_ERR(ctx->crtc)) { DRM_ERROR("failed to create crtc.\n"); diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index 229b3613c60b..722cbf32192a 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -2007,7 +2007,7 @@ static void hdmi_mode_set(struct exynos_drm_display *display, DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n", m->hdisplay, m->vdisplay, m->vrefresh, (m->flags & DRM_MODE_FLAG_INTERLACE) ? - "INTERLACED" : "PROGERESSIVE"); + "INTERLACED" : "PROGRESSIVE"); /* preserve mode information for later use. */ drm_mode_copy(&hdata->current_mode, mode); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 2e3bc57ea50e..fbec750574e6 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -37,35 +37,13 @@ #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" +#include "exynos_drm_plane.h" #include "exynos_drm_iommu.h" #include "exynos_mixer.h" #define MIXER_WIN_NR 3 #define MIXER_DEFAULT_WIN 0 -struct hdmi_win_data { - dma_addr_t dma_addr; - dma_addr_t chroma_dma_addr; - uint32_t pixel_format; - unsigned int bpp; - unsigned int crtc_x; - unsigned int crtc_y; - unsigned int crtc_width; - unsigned int crtc_height; - unsigned int fb_x; - unsigned int fb_y; - unsigned int fb_width; - unsigned int fb_pitch; - unsigned int fb_height; - unsigned int src_width; - unsigned int src_height; - unsigned int mode_width; - unsigned int mode_height; - unsigned int scan_flags; - bool enabled; - bool resume; -}; - struct mixer_resources { int irq; void __iomem *mixer_regs; @@ -90,6 +68,7 @@ struct mixer_context { struct device *dev; struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; + struct exynos_drm_plane planes[MIXER_WIN_NR]; int pipe; bool interlace; bool powered; @@ -99,7 +78,6 @@ struct mixer_context { struct mutex mixer_mutex; struct mixer_resources mixer_res; - struct hdmi_win_data win_data[MIXER_WIN_NR]; enum mixer_version_id mxr_ver; wait_queue_head_t wait_vsync_queue; atomic_t wait_vsync_event; @@ -289,7 +267,7 @@ static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height) /* choosing between interlace and progressive mode */ val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE : - MXR_CFG_SCAN_PROGRASSIVE); + MXR_CFG_SCAN_PROGRESSIVE); if (ctx->mxr_ver != MXR_VER_128_0_0_184) { /* choosing between proper HD and SD mode */ @@ -403,17 +381,16 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) { struct mixer_resources *res = &ctx->mixer_res; unsigned long flags; - struct hdmi_win_data *win_data; - unsigned int x_ratio, y_ratio; + struct exynos_drm_plane *plane; unsigned int buf_num = 1; dma_addr_t luma_addr[2], chroma_addr[2]; bool tiled_mode = false; bool crcb_mode = false; u32 val; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; - switch (win_data->pixel_format) { + switch (plane->pixel_format) { case DRM_FORMAT_NV12: crcb_mode = false; buf_num = 2; @@ -421,35 +398,31 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) /* TODO: single buffer format NV12, NV21 */ default: /* ignore pixel format at disable time */ - if (!win_data->dma_addr) + if (!plane->dma_addr[0]) break; DRM_ERROR("pixel format for vp is wrong [%d].\n", - win_data->pixel_format); + plane->pixel_format); return; } - /* scaling feature: (src << 16) / dst */ - x_ratio = (win_data->src_width << 16) / win_data->crtc_width; - y_ratio = (win_data->src_height << 16) / win_data->crtc_height; - if (buf_num == 2) { - luma_addr[0] = win_data->dma_addr; - chroma_addr[0] = win_data->chroma_dma_addr; + luma_addr[0] = plane->dma_addr[0]; + chroma_addr[0] = plane->dma_addr[1]; } else { - luma_addr[0] = win_data->dma_addr; - chroma_addr[0] = win_data->dma_addr - + (win_data->fb_pitch * win_data->fb_height); + luma_addr[0] = plane->dma_addr[0]; + chroma_addr[0] = plane->dma_addr[0] + + (plane->pitch * plane->fb_height); } - if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) { + if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) { ctx->interlace = true; if (tiled_mode) { luma_addr[1] = luma_addr[0] + 0x40; chroma_addr[1] = chroma_addr[0] + 0x40; } else { - luma_addr[1] = luma_addr[0] + win_data->fb_pitch; - chroma_addr[1] = chroma_addr[0] + win_data->fb_pitch; + luma_addr[1] = luma_addr[0] + plane->pitch; + chroma_addr[1] = chroma_addr[0] + plane->pitch; } } else { ctx->interlace = false; @@ -470,30 +443,30 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK); /* setting size of input image */ - vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_pitch) | - VP_IMG_VSIZE(win_data->fb_height)); + vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(plane->pitch) | + VP_IMG_VSIZE(plane->fb_height)); /* chroma height has to reduced by 2 to avoid chroma distorions */ - vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_pitch) | - VP_IMG_VSIZE(win_data->fb_height / 2)); + vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(plane->pitch) | + VP_IMG_VSIZE(plane->fb_height / 2)); - vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width); - vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height); + vp_reg_write(res, VP_SRC_WIDTH, plane->src_width); + vp_reg_write(res, VP_SRC_HEIGHT, plane->src_height); vp_reg_write(res, VP_SRC_H_POSITION, - VP_SRC_H_POSITION_VAL(win_data->fb_x)); - vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y); + VP_SRC_H_POSITION_VAL(plane->src_x)); + vp_reg_write(res, VP_SRC_V_POSITION, plane->src_y); - vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width); - vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x); + vp_reg_write(res, VP_DST_WIDTH, plane->crtc_width); + vp_reg_write(res, VP_DST_H_POSITION, plane->crtc_x); if (ctx->interlace) { - vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2); - vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2); + vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height / 2); + vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y / 2); } else { - vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height); - vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y); + vp_reg_write(res, VP_DST_HEIGHT, plane->crtc_height); + vp_reg_write(res, VP_DST_V_POSITION, plane->crtc_y); } - vp_reg_write(res, VP_H_RATIO, x_ratio); - vp_reg_write(res, VP_V_RATIO, y_ratio); + vp_reg_write(res, VP_H_RATIO, plane->h_ratio); + vp_reg_write(res, VP_V_RATIO, plane->v_ratio); vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE); @@ -503,8 +476,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win) vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]); vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]); - mixer_cfg_scan(ctx, win_data->mode_height); - mixer_cfg_rgb_fmt(ctx, win_data->mode_height); + mixer_cfg_scan(ctx, plane->mode_height); + mixer_cfg_rgb_fmt(ctx, plane->mode_height); mixer_cfg_layer(ctx, win, true); mixer_run(ctx); @@ -521,25 +494,49 @@ static void mixer_layer_update(struct mixer_context *ctx) mixer_reg_writemask(res, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); } +static int mixer_setup_scale(const struct exynos_drm_plane *plane, + unsigned int *x_ratio, unsigned int *y_ratio) +{ + if (plane->crtc_width != plane->src_width) { + if (plane->crtc_width == 2 * plane->src_width) + *x_ratio = 1; + else + goto fail; + } + + if (plane->crtc_height != plane->src_height) { + if (plane->crtc_height == 2 * plane->src_height) + *y_ratio = 1; + else + goto fail; + } + + return 0; + +fail: + DRM_DEBUG_KMS("only 2x width/height scaling of plane supported\n"); + return -ENOTSUPP; +} + static void mixer_graph_buffer(struct mixer_context *ctx, int win) { struct mixer_resources *res = &ctx->mixer_res; unsigned long flags; - struct hdmi_win_data *win_data; - unsigned int x_ratio, y_ratio; + struct exynos_drm_plane *plane; + unsigned int x_ratio = 0, y_ratio = 0; unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset; dma_addr_t dma_addr; unsigned int fmt; u32 val; - win_data = &ctx->win_data[win]; + plane = &ctx->planes[win]; #define RGB565 4 #define ARGB1555 5 #define ARGB4444 6 #define ARGB8888 7 - switch (win_data->bpp) { + switch (plane->bpp) { case 16: fmt = ARGB4444; break; @@ -550,21 +547,21 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) fmt = ARGB8888; } - /* 2x scaling feature */ - x_ratio = 0; - y_ratio = 0; + /* check if mixer supports requested scaling setup */ + if (mixer_setup_scale(plane, &x_ratio, &y_ratio)) + return; - dst_x_offset = win_data->crtc_x; - dst_y_offset = win_data->crtc_y; + dst_x_offset = plane->crtc_x; + dst_y_offset = plane->crtc_y; /* converting dma address base and source offset */ - dma_addr = win_data->dma_addr - + (win_data->fb_x * win_data->bpp >> 3) - + (win_data->fb_y * win_data->fb_pitch); + dma_addr = plane->dma_addr[0] + + (plane->src_x * plane->bpp >> 3) + + (plane->src_y * plane->pitch); src_x_offset = 0; src_y_offset = 0; - if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) + if (plane->scan_flag & DRM_MODE_FLAG_INTERLACE) ctx->interlace = true; else ctx->interlace = false; @@ -578,18 +575,18 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) /* setup geometry */ mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), - win_data->fb_pitch / (win_data->bpp >> 3)); + plane->pitch / (plane->bpp >> 3)); /* setup display size */ if (ctx->mxr_ver == MXR_VER_128_0_0_184 && win == MIXER_DEFAULT_WIN) { - val = MXR_MXR_RES_HEIGHT(win_data->mode_height); - val |= MXR_MXR_RES_WIDTH(win_data->mode_width); + val = MXR_MXR_RES_HEIGHT(plane->mode_height); + val |= MXR_MXR_RES_WIDTH(plane->mode_width); mixer_reg_write(res, MXR_RESOLUTION, val); } - val = MXR_GRP_WH_WIDTH(win_data->crtc_width); - val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height); + val = MXR_GRP_WH_WIDTH(plane->src_width); + val |= MXR_GRP_WH_HEIGHT(plane->src_height); val |= MXR_GRP_WH_H_SCALE(x_ratio); val |= MXR_GRP_WH_V_SCALE(y_ratio); mixer_reg_write(res, MXR_GRAPHIC_WH(win), val); @@ -607,8 +604,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win) /* set buffer address to mixer */ mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr); - mixer_cfg_scan(ctx, win_data->mode_height); - mixer_cfg_rgb_fmt(ctx, win_data->mode_height); + mixer_cfg_scan(ctx, plane->mode_height); + mixer_cfg_rgb_fmt(ctx, plane->mode_height); mixer_cfg_layer(ctx, win, true); /* layer update mandatory for mixer 16.0.33.0 */ @@ -920,63 +917,9 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); } -static void mixer_win_mode_set(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) -{ - struct mixer_context *mixer_ctx = crtc->ctx; - struct hdmi_win_data *win_data; - int win; - - if (!plane) { - DRM_ERROR("plane is NULL\n"); - return; - } - - DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n", - plane->fb_width, plane->fb_height, - plane->fb_x, plane->fb_y, - plane->crtc_width, plane->crtc_height, - plane->crtc_x, plane->crtc_y); - - win = plane->zpos; - if (win == DEFAULT_ZPOS) - win = MIXER_DEFAULT_WIN; - - if (win < 0 || win >= MIXER_WIN_NR) { - DRM_ERROR("mixer window[%d] is wrong\n", win); - return; - } - - win_data = &mixer_ctx->win_data[win]; - - win_data->dma_addr = plane->dma_addr[0]; - win_data->chroma_dma_addr = plane->dma_addr[1]; - win_data->pixel_format = plane->pixel_format; - win_data->bpp = plane->bpp; - - win_data->crtc_x = plane->crtc_x; - win_data->crtc_y = plane->crtc_y; - win_data->crtc_width = plane->crtc_width; - win_data->crtc_height = plane->crtc_height; - - win_data->fb_x = plane->fb_x; - win_data->fb_y = plane->fb_y; - win_data->fb_width = plane->fb_width; - win_data->fb_height = plane->fb_height; - win_data->fb_pitch = plane->pitch; - win_data->src_width = plane->src_width; - win_data->src_height = plane->src_height; - - win_data->mode_width = plane->mode_width; - win_data->mode_height = plane->mode_height; - - win_data->scan_flags = plane->scan_flag; -} - -static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos) +static void mixer_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) { struct mixer_context *mixer_ctx = crtc->ctx; - int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; DRM_DEBUG_KMS("win: %d\n", win); @@ -992,14 +935,13 @@ static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos) else mixer_graph_buffer(mixer_ctx, win); - mixer_ctx->win_data[win].enabled = true; + mixer_ctx->planes[win].enabled = true; } -static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos) +static void mixer_win_disable(struct exynos_drm_crtc *crtc, unsigned int win) { struct mixer_context *mixer_ctx = crtc->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; - int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; unsigned long flags; DRM_DEBUG_KMS("win: %d\n", win); @@ -1007,7 +949,7 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos) mutex_lock(&mixer_ctx->mixer_mutex); if (!mixer_ctx->powered) { mutex_unlock(&mixer_ctx->mixer_mutex); - mixer_ctx->win_data[win].resume = false; + mixer_ctx->planes[win].resume = false; return; } mutex_unlock(&mixer_ctx->mixer_mutex); @@ -1020,7 +962,7 @@ static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos) mixer_vsync_set_update(mixer_ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); - mixer_ctx->win_data[win].enabled = false; + mixer_ctx->planes[win].enabled = false; } static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) @@ -1057,12 +999,12 @@ static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) static void mixer_window_suspend(struct mixer_context *ctx) { - struct hdmi_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < MIXER_WIN_NR; i++) { - win_data = &ctx->win_data[i]; - win_data->resume = win_data->enabled; + plane = &ctx->planes[i]; + plane->resume = plane->enabled; mixer_win_disable(ctx->crtc, i); } mixer_wait_for_vblank(ctx->crtc); @@ -1070,14 +1012,14 @@ static void mixer_window_suspend(struct mixer_context *ctx) static void mixer_window_resume(struct mixer_context *ctx) { - struct hdmi_win_data *win_data; + struct exynos_drm_plane *plane; int i; for (i = 0; i < MIXER_WIN_NR; i++) { - win_data = &ctx->win_data[i]; - win_data->enabled = win_data->resume; - win_data->resume = false; - if (win_data->enabled) + plane = &ctx->planes[i]; + plane->enabled = plane->resume; + plane->resume = false; + if (plane->enabled) mixer_win_commit(ctx->crtc, i); } } @@ -1189,7 +1131,6 @@ static struct exynos_drm_crtc_ops mixer_crtc_ops = { .enable_vblank = mixer_enable_vblank, .disable_vblank = mixer_disable_vblank, .wait_for_vblank = mixer_wait_for_vblank, - .win_mode_set = mixer_win_mode_set, .win_commit = mixer_win_commit, .win_disable = mixer_win_disable, }; @@ -1253,15 +1194,28 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) { struct mixer_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; + struct exynos_drm_plane *exynos_plane; + enum drm_plane_type type; + unsigned int zpos; int ret; ret = mixer_initialize(ctx, drm_dev); if (ret) return ret; - ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe, - EXYNOS_DISPLAY_TYPE_HDMI, - &mixer_crtc_ops, ctx); + for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) { + type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : + DRM_PLANE_TYPE_OVERLAY; + ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], + 1 << ctx->pipe, type, zpos); + if (ret) + return ret; + } + + exynos_plane = &ctx->planes[MIXER_DEFAULT_WIN]; + ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, + ctx->pipe, EXYNOS_DISPLAY_TYPE_HDMI, + &mixer_crtc_ops, ctx); if (IS_ERR(ctx->crtc)) { mixer_ctx_remove(ctx); ret = PTR_ERR(ctx->crtc); diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index 5f32e1a29411..ac60260c2389 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h @@ -101,7 +101,7 @@ #define MXR_CFG_GRP0_ENABLE (1 << 4) #define MXR_CFG_VP_ENABLE (1 << 3) #define MXR_CFG_SCAN_INTERLACE (0 << 2) -#define MXR_CFG_SCAN_PROGRASSIVE (1 << 2) +#define MXR_CFG_SCAN_PROGRESSIVE (1 << 2) #define MXR_CFG_SCAN_NTSC (0 << 1) #define MXR_CFG_SCAN_PAL (1 << 1) #define MXR_CFG_SCAN_SD (0 << 0) diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h index a20e4a3a8b15..0530e5a4c6b1 100644 --- a/include/video/samsung_fimd.h +++ b/include/video/samsung_fimd.h @@ -289,6 +289,11 @@ #define VIDISD14C_ALPHA1_B_LIMIT 0xf #define VIDISD14C_ALPHA1_B(_x) ((_x) << 0) +#define VIDW_ALPHA 0x021c +#define VIDW_ALPHA_R(_x) ((_x) << 16) +#define VIDW_ALPHA_G(_x) ((_x) << 8) +#define VIDW_ALPHA_B(_x) ((_x) << 0) + /* Video buffer addresses */ #define VIDW_BUF_START(_buff) (0xA0 + ((_buff) * 8)) #define VIDW_BUF_START1(_buff) (0xA4 + ((_buff) * 8)) @@ -436,6 +441,12 @@ #define BLENDCON_NEW_8BIT_ALPHA_VALUE (1 << 0) #define BLENDCON_NEW_4BIT_ALPHA_VALUE (0 << 0) +/* Display port clock control */ +#define DP_MIE_CLKCON 0x27c +#define DP_MIE_CLK_DISABLE 0x0 +#define DP_MIE_CLK_DP_ENABLE 0x2 +#define DP_MIE_CLK_MIE_ENABLE 0x3 + /* Notes on per-window bpp settings * * Value Win0 Win1 Win2 Win3 Win 4 |