diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-10-12 08:22:25 +0200 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-10-12 08:22:25 +0200 |
commit | c0c8b9ed1b0c14d91ff73624df6d918bb47c8a5e (patch) | |
tree | 7fb6f2c7c028cd4926b827d3b5937c49afefa63a /drivers/gpu/drm/exynos/exynos_drm_fimd.c | |
parent | 5a920b85f2c6e3fd7d9dd9bb3f3345e9085e2360 (diff) | |
parent | 69405d3da98b48633b78a49403e4f9cdb7c6a0f5 (diff) | |
download | op-kernel-dev-c0c8b9ed1b0c14d91ff73624df6d918bb47c8a5e.zip op-kernel-dev-c0c8b9ed1b0c14d91ff73624df6d918bb47c8a5e.tar.gz |
Merge tag 'drm-for-v4.9' into drm-intel-next-queued
It's been over two months, git definitely lost it's marbles. Conflicts
resolved by picking our version, plus manually checking the diff with
the parent in drm-intel-next-queued to make sure git didn't do
anything stupid. It did, so I removed 2 occasions where it
double-inserted a bit of code. The diff is now just
- kernel-doc changes
- drm format/name changes
- display-info changes
so looks all reasonable.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fimd.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 54 |
1 files changed, 29 insertions, 25 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index d472164..e2e4051 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -198,6 +198,7 @@ struct fimd_context { atomic_t wait_vsync_event; atomic_t win_updated; atomic_t triggering; + u32 clkdiv; const struct fimd_driver_data *driver_data; struct drm_encoder *encoder; @@ -389,15 +390,18 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc) pm_runtime_put(ctx->dev); } -static u32 fimd_calc_clkdiv(struct fimd_context *ctx, - const struct drm_display_mode *mode) + +static int fimd_atomic_check(struct exynos_drm_crtc *crtc, + struct drm_crtc_state *state) { - unsigned long ideal_clk; + struct drm_display_mode *mode = &state->adjusted_mode; + struct fimd_context *ctx = crtc->ctx; + unsigned long ideal_clk, lcd_rate; u32 clkdiv; if (mode->clock == 0) { - DRM_ERROR("Mode has zero clock value.\n"); - return 0xff; + DRM_INFO("Mode has zero clock value.\n"); + return -EINVAL; } ideal_clk = mode->clock * 1000; @@ -410,10 +414,23 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx, ideal_clk *= 2; } + lcd_rate = clk_get_rate(ctx->lcd_clk); + if (2 * lcd_rate < ideal_clk) { + DRM_INFO("sclk_fimd clock too low(%lu) for requested pixel clock(%lu)\n", + lcd_rate, ideal_clk); + return -EINVAL; + } + /* Find the clock divider value that gets us closest to ideal_clk */ - clkdiv = DIV_ROUND_CLOSEST(clk_get_rate(ctx->lcd_clk), ideal_clk); + clkdiv = DIV_ROUND_CLOSEST(lcd_rate, ideal_clk); + if (clkdiv >= 0x200) { + DRM_INFO("requested pixel clock(%lu) too low\n", ideal_clk); + return -EINVAL; + } + + ctx->clkdiv = (clkdiv < 0x100) ? clkdiv : 0xff; - return (clkdiv < 0x100) ? clkdiv : 0xff; + return 0; } static void fimd_setup_trigger(struct fimd_context *ctx) @@ -442,7 +459,7 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; const struct fimd_driver_data *driver_data = ctx->driver_data; void *timing_base = ctx->regs + driver_data->timing_base; - u32 val, clkdiv; + u32 val; if (ctx->suspended) return; @@ -543,9 +560,8 @@ static void fimd_commit(struct exynos_drm_crtc *crtc) if (ctx->driver_data->has_clksel) val |= VIDCON0_CLKSEL_LCD; - clkdiv = fimd_calc_clkdiv(ctx, mode); - if (clkdiv > 1) - val |= VIDCON0_CLKVAL_F(clkdiv - 1) | VIDCON0_CLKDIR; + if (ctx->clkdiv > 1) + val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR; writel(val, ctx->regs + VIDCON0); } @@ -939,14 +955,14 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .update_plane = fimd_update_plane, .disable_plane = fimd_disable_plane, .atomic_flush = fimd_atomic_flush, + .atomic_check = fimd_atomic_check, .te_handler = fimd_te_handler, }; static irqreturn_t fimd_irq_handler(int irq, void *dev_id) { struct fimd_context *ctx = (struct fimd_context *)dev_id; - u32 val, clear_bit, start, start_s; - int win; + u32 val, clear_bit; val = readl(ctx->regs + VIDINTCON1); @@ -961,18 +977,6 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) if (!ctx->i80_if) drm_crtc_handle_vblank(&ctx->crtc->base); - for (win = 0 ; win < WINDOWS_NR ; win++) { - struct exynos_drm_plane *plane = &ctx->planes[win]; - - if (!plane->pending_fb) - continue; - - start = readl(ctx->regs + VIDWx_BUF_START(win, 0)); - start_s = readl(ctx->regs + VIDWx_BUF_START_S(win, 0)); - if (start == start_s) - exynos_drm_crtc_finish_update(ctx->crtc, plane); - } - if (ctx->i80_if) { /* Exits triggering mode */ atomic_set(&ctx->triggering, 0); |