From: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx> Add CRTC callbacks .atomic_begin() .atomic_flush(). On exynos they unprotect the windows before the commit and protects it after based on a plane mask tha store which plane will be updated. For that we create two new exynos_crtc callbacks: .win_protect() and .win_unprotect(). The only driver that implement those now is FIMD. Signed-off-by: Gustavo Padovan <gustavo.padovan@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 34 +++++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_drv.h | 6 ++++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 49 ++++++++++++++++++++----------- drivers/gpu/drm/exynos/exynos_drm_plane.c | 4 +++ 4 files changed, 76 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1c0d936..5e7c13e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -153,6 +153,38 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) } } +static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct drm_plane *plane; + int index = 0; + + list_for_each_entry(plane, &crtc->dev->mode_config.plane_list, head) { + if (exynos_crtc->ops->win_protect && + exynos_crtc->plane_mask & (0x01 << index)) + exynos_crtc->ops->win_protect(exynos_crtc, index); + + index++; + } +} + +static void exynos_crtc_atomic_flush(struct drm_crtc *crtc) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct drm_plane *plane; + int index = 0; + + list_for_each_entry(plane, &crtc->dev->mode_config.plane_list, head) { + if (exynos_crtc->ops->win_unprotect && + exynos_crtc->plane_mask & (0x01 << index)) + exynos_crtc->ops->win_unprotect(exynos_crtc, index); + + index++; + } + + exynos_crtc->plane_mask = 0; +} + static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .dpms = exynos_drm_crtc_dpms, .prepare = exynos_drm_crtc_prepare, @@ -161,6 +193,8 @@ static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { .mode_set = exynos_drm_crtc_mode_set, .mode_set_base = exynos_drm_crtc_mode_set_base, .disable = exynos_drm_crtc_disable, + .atomic_begin = exynos_crtc_atomic_begin, + .atomic_flush = exynos_crtc_atomic_flush, }; static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index ab82772..f025a54 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -175,6 +175,8 @@ struct exynos_drm_display { * hardware overlay is updated. * @win_commit: apply hardware specific overlay data to registers. * @win_disable: disable hardware specific overlay. + * @win_protect: protect hardware specific window. + * @win_unprotect: unprotect hardware specific window. * @te_handler: trigger to transfer video image at the tearing effect * synchronization signal if there is a page flip request. */ @@ -190,6 +192,8 @@ struct exynos_drm_crtc_ops { void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); void (*win_commit)(struct exynos_drm_crtc *crtc, unsigned int zpos); void (*win_disable)(struct exynos_drm_crtc *crtc, unsigned int zpos); + void (*win_protect)(struct exynos_drm_crtc *crtc, unsigned int zpos); + void (*win_unprotect)(struct exynos_drm_crtc *crtc, unsigned int zpos); void (*te_handler)(struct exynos_drm_crtc *crtc); }; @@ -206,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 + * @plane_mask: store planes to be updated on atomic modesetting * @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 @@ -215,6 +220,7 @@ struct exynos_drm_crtc { enum exynos_drm_output_type type; unsigned int pipe; unsigned int dpms; + unsigned int plane_mask; wait_queue_head_t pending_flip_queue; struct drm_pending_vblank_event *event; struct exynos_drm_crtc_ops *ops; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 990ead434..bea70f6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -590,6 +590,16 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, { u32 reg, bits, val; + /* + * SHADOWCON/PRTCON register is used for enabling timing. + * + * for example, once only width value of a register is set, + * if the dma is started then fimd hardware could malfunction so + * with protect window setting, the register fields with prefix '_F' + * wouldn't be updated at vsync also but updated once unprotect window + * is set. + */ + if (ctx->driver_data->has_shadowcon) { reg = SHADOWCON; bits = SHADOWCON_WINx_PROTECT(win); @@ -628,20 +638,6 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) return; } - /* - * SHADOWCON/PRTCON register is used for enabling timing. - * - * for example, once only width value of a register is set, - * if the dma is started then fimd hardware could malfunction so - * with protect window setting, the register fields with prefix '_F' - * wouldn't be updated at vsync also but updated once unprotect window - * is set. - */ - - /* protect windows */ - fimd_shadow_protect_win(ctx, win, true); - - offset = plane->fb_x * (plane->bpp >> 3); offset += plane->fb_y * plane->pitch; @@ -723,9 +719,6 @@ static void fimd_win_commit(struct exynos_drm_crtc *crtc, unsigned int win) if (ctx->driver_data->has_shadowcon) fimd_enable_shadow_channel_path(ctx, win, true); - /* Enable DMA channel and unprotect windows */ - fimd_shadow_protect_win(ctx, win, false); - plane->enabled = true; if (ctx->i80_if) @@ -944,6 +937,26 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) drm_handle_vblank(ctx->drm_dev, ctx->pipe); } +static void fimd_win_protect(struct exynos_drm_crtc *crtc, unsigned int win) +{ + struct fimd_context *ctx = crtc->ctx; + + if (win < 0 || win >= WINDOWS_NR) + return; + + fimd_shadow_protect_win(ctx, win, true); +} + +static void fimd_win_unprotect(struct exynos_drm_crtc *crtc, unsigned int win) +{ + struct fimd_context *ctx = crtc->ctx; + + if (win < 0 || win >= WINDOWS_NR) + return; + + fimd_shadow_protect_win(ctx, win, false); +} + static struct exynos_drm_crtc_ops fimd_crtc_ops = { .dpms = fimd_dpms, .mode_fixup = fimd_mode_fixup, @@ -954,6 +967,8 @@ static struct exynos_drm_crtc_ops fimd_crtc_ops = { .win_commit = fimd_win_commit, .win_disable = fimd_win_disable, .te_handler = fimd_te_handler, + .win_protect = fimd_win_protect, + .win_unprotect = fimd_win_unprotect, }; static irqreturn_t fimd_irq_handler(int irq, void *dev_id) diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 5d3243e..ee81dc2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -65,6 +65,7 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last) int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc); int nr; int i; @@ -83,6 +84,9 @@ int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb) i, (unsigned long)exynos_plane->dma_addr[i]); } + if (exynos_crtc) + exynos_crtc->plane_mask += 1 << exynos_plane->zpos; + return 0; } -- 1.9.3 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel