diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos7_drm_decon.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.c | 69 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_crtc.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.h | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fb.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_plane.c | 55 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_plane.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_vidi.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_mixer.c | 155 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/regs-mixer.h | 4 |
13 files changed, 235 insertions, 143 deletions
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index c7362b99ce28..1bf6a21130c7 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -248,15 +248,16 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win, protect ? ~0 : 0); } -static void decon_atomic_begin(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) +static void decon_atomic_begin(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; + int i; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; - decon_shadow_protect_win(ctx, plane->zpos, true); + for (i = ctx->first_win; i < WINDOWS_NR; i++) + decon_shadow_protect_win(ctx, i, true); } #define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) @@ -270,7 +271,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, to_exynos_plane_state(plane->base.state); struct decon_context *ctx = crtc->ctx; struct drm_framebuffer *fb = state->base.fb; - unsigned int win = plane->zpos; + unsigned int win = plane->index; unsigned int bpp = fb->bits_per_pixel >> 3; unsigned int pitch = fb->pitches[0]; dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); @@ -320,7 +321,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; - unsigned int win = plane->zpos; + unsigned int win = plane->index; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; @@ -336,15 +337,16 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); } -static void decon_atomic_flush(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) +static void decon_atomic_flush(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; + int i; if (test_bit(BIT_SUSPENDED, &ctx->flags)) return; - decon_shadow_protect_win(ctx, plane->zpos, false); + for (i = ctx->first_win; i < WINDOWS_NR; i++) + decon_shadow_protect_win(ctx, i, false); if (ctx->out_type == IFTYPE_I80) set_bit(BIT_WIN_UPDATED, &ctx->flags); @@ -502,7 +504,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ctx->configs[win].zpos = win; ctx->configs[win].type = decon_win_types[tmp]; - ret = exynos_plane_init(drm_dev, &ctx->planes[win], + ret = exynos_plane_init(drm_dev, &ctx->planes[win], win, 1 << ctx->pipe, &ctx->configs[win]); if (ret) return ret; diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index c47f9af8170b..52bda3b42fe0 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -385,15 +385,16 @@ static void decon_shadow_protect_win(struct decon_context *ctx, writel(val, ctx->regs + SHADOWCON); } -static void decon_atomic_begin(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) +static void decon_atomic_begin(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; + int i; if (ctx->suspended) return; - decon_shadow_protect_win(ctx, plane->zpos, true); + for (i = 0; i < WINDOWS_NR; i++) + decon_shadow_protect_win(ctx, i, true); } static void decon_update_plane(struct exynos_drm_crtc *crtc, @@ -407,7 +408,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, unsigned long val, alpha; unsigned int last_x; unsigned int last_y; - unsigned int win = plane->zpos; + unsigned int win = plane->index; unsigned int bpp = fb->bits_per_pixel >> 3; unsigned int pitch = fb->pitches[0]; @@ -498,7 +499,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct decon_context *ctx = crtc->ctx; - unsigned int win = plane->zpos; + unsigned int win = plane->index; u32 val; if (ctx->suspended) @@ -517,15 +518,16 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, writel(val, ctx->regs + DECON_UPDATE); } -static void decon_atomic_flush(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) +static void decon_atomic_flush(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; + int i; if (ctx->suspended) return; - decon_shadow_protect_win(ctx, plane->zpos, false); + for (i = 0; i < WINDOWS_NR; i++) + decon_shadow_protect_win(ctx, i, false); } static void decon_init(struct decon_context *ctx) @@ -657,7 +659,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ctx->configs[i].zpos = i; ctx->configs[i].type = decon_win_types[i]; - ret = exynos_plane_init(drm_dev, &ctx->planes[i], + ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, 1 << ctx->pipe, &ctx->configs[i]); if (ret) return ret; diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 8f5ac535d809..e36579c1c025 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -68,32 +68,20 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct drm_plane *plane; exynos_crtc->event = crtc->state->event; - drm_atomic_crtc_for_each_plane(plane, crtc) { - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - - if (exynos_crtc->ops->atomic_begin) - exynos_crtc->ops->atomic_begin(exynos_crtc, - exynos_plane); - } + if (exynos_crtc->ops->atomic_begin) + exynos_crtc->ops->atomic_begin(exynos_crtc); } static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct drm_plane *plane; - drm_atomic_crtc_for_each_plane(plane, crtc) { - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); - - if (exynos_crtc->ops->atomic_flush) - exynos_crtc->ops->atomic_flush(exynos_crtc, - exynos_plane); - } + if (exynos_crtc->ops->atomic_flush) + exynos_crtc->ops->atomic_flush(exynos_crtc); } static const struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { @@ -215,29 +203,6 @@ void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, spin_unlock_irqrestore(&crtc->dev->event_lock, flags); } -void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) -{ - struct exynos_drm_crtc *exynos_crtc; - struct drm_device *dev = fb->dev; - struct drm_crtc *crtc; - - /* - * make sure that overlay data are updated to real hardware - * for all encoders. - */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - exynos_crtc = to_exynos_crtc(crtc); - - /* - * wait for vblank interrupt - * - this makes sure that overlay data are updated to - * real hardware. - */ - if (exynos_crtc->ops->wait_for_vblank) - exynos_crtc->ops->wait_for_vblank(exynos_crtc); - } -} - int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, enum exynos_drm_output_type out_type) { @@ -261,3 +226,29 @@ void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) if (exynos_crtc->ops->te_handler) exynos_crtc->ops->te_handler(exynos_crtc); } + +void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc, + struct drm_file *file) +{ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct drm_pending_vblank_event *e; + unsigned long flags; + + spin_lock_irqsave(&crtc->dev->event_lock, flags); + e = exynos_crtc->event; + if (e && e->base.file_priv == file) { + exynos_crtc->event = NULL; + /* + * event will be destroyed by core part + * so below line should be removed later with core changes + */ + e->base.destroy(&e->base); + /* + * event_space will be increased by core part + * so below line should be removed later with core changes. + */ + file->event_space += sizeof(e->event); + atomic_dec(&exynos_crtc->pending_update); + } + spin_unlock_irqrestore(&crtc->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 f9f365bd0257..cfdcf3e4eb1b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -28,7 +28,6 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, unsigned int pipe); void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc); void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, struct exynos_drm_plane *exynos_plane); -void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); /* 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, @@ -41,4 +40,8 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, */ void exynos_drm_crtc_te_handler(struct drm_crtc *crtc); +/* This function cancels a page flip request. */ +void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc, + struct drm_file *file); + #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 9756797a15a5..68f0f36f6e7e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -330,7 +330,12 @@ err_file_priv_free: static void exynos_drm_preclose(struct drm_device *dev, struct drm_file *file) { + struct drm_crtc *crtc; + exynos_drm_subdrv_close(dev, file); + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + exynos_drm_crtc_cancel_page_flip(crtc, file); } static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 82bbd7f4b316..17b5ded72ff1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -64,6 +64,7 @@ struct exynos_drm_plane_state { struct exynos_drm_rect src; unsigned int h_ratio; unsigned int v_ratio; + unsigned int zpos; }; static inline struct exynos_drm_plane_state * @@ -76,7 +77,7 @@ to_exynos_plane_state(struct drm_plane_state *state) * Exynos drm common overlay structure. * * @base: plane object - * @zpos: order of overlay layer(z position). + * @index: hardware index of the overlay layer * * this structure is common to exynos SoC and its contents would be copied * to hardware specific overlay info. @@ -85,17 +86,18 @@ to_exynos_plane_state(struct drm_plane_state *state) struct exynos_drm_plane { struct drm_plane base; const struct exynos_drm_plane_config *config; - unsigned int zpos; + unsigned int index; struct drm_framebuffer *pending_fb; }; #define EXYNOS_DRM_PLANE_CAP_DOUBLE (1 << 0) #define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1) +#define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2) /* * Exynos DRM plane configuration structure. * - * @zpos: z-position of the plane. + * @zpos: initial z-position of the plane. * @type: type of the plane (primary, cursor or overlay). * @pixel_formats: supported pixel formats. * @num_pixel_formats: number of elements in 'pixel_formats'. @@ -121,8 +123,8 @@ struct exynos_drm_plane_config { * @wait_for_vblank: wait for vblank interrupt to make sure that * hardware overlay is updated. * @atomic_check: validate state - * @atomic_begin: prepare a window to receive a update - * @atomic_flush: mark the end of a window update + * @atomic_begin: prepare device to receive an update + * @atomic_flush: mark the end of device update * @update_plane: apply hardware specific overlay data to registers. * @disable_plane: disable hardware specific overlay. * @te_handler: trigger to transfer video image at the tearing effect @@ -142,14 +144,12 @@ struct exynos_drm_crtc_ops { void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); int (*atomic_check)(struct exynos_drm_crtc *crtc, struct drm_crtc_state *state); - void (*atomic_begin)(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane); + void (*atomic_begin)(struct exynos_drm_crtc *crtc); void (*update_plane)(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane); void (*disable_plane)(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane); - void (*atomic_flush)(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane); + void (*atomic_flush)(struct exynos_drm_crtc *crtc); void (*te_handler)(struct exynos_drm_crtc *crtc); void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index cbbb1a86e70a..d614194644c8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -71,9 +71,6 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); unsigned int i; - /* make sure that overlay data are updated before relesing fb. */ - exynos_drm_crtc_complete_scanout(fb); - drm_framebuffer_cleanup(fb); for (i = 0; i < ARRAY_SIZE(exynos_fb->exynos_gem); i++) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 2e2247126581..70194d0e4fe4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -622,26 +622,28 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, writel(val, ctx->regs + reg); } -static void fimd_atomic_begin(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) +static void fimd_atomic_begin(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; + int i; if (ctx->suspended) return; - fimd_shadow_protect_win(ctx, plane->zpos, true); + for (i = 0; i < WINDOWS_NR; i++) + fimd_shadow_protect_win(ctx, i, true); } -static void fimd_atomic_flush(struct exynos_drm_crtc *crtc, - struct exynos_drm_plane *plane) +static void fimd_atomic_flush(struct exynos_drm_crtc *crtc) { struct fimd_context *ctx = crtc->ctx; + int i; if (ctx->suspended) return; - fimd_shadow_protect_win(ctx, plane->zpos, false); + for (i = 0; i < WINDOWS_NR; i++) + fimd_shadow_protect_win(ctx, i, false); } static void fimd_update_plane(struct exynos_drm_crtc *crtc, @@ -654,7 +656,7 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, dma_addr_t dma_addr; unsigned long val, size, offset; unsigned int last_x, last_y, buf_offsize, line_size; - unsigned int win = plane->zpos; + unsigned int win = plane->index; unsigned int bpp = fb->bits_per_pixel >> 3; unsigned int pitch = fb->pitches[0]; @@ -740,7 +742,7 @@ static void fimd_disable_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct fimd_context *ctx = crtc->ctx; - unsigned int win = plane->zpos; + unsigned int win = plane->index; if (ctx->suspended) return; @@ -944,7 +946,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ctx->configs[i].num_pixel_formats = ARRAY_SIZE(fimd_formats); ctx->configs[i].zpos = i; ctx->configs[i].type = fimd_win_types[i]; - ret = exynos_plane_init(drm_dev, &ctx->planes[i], + ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, 1 << ctx->pipe, &ctx->configs[i]); if (ret) return ret; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index e668fcdbcafc..d86227236f55 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -124,6 +124,7 @@ static void exynos_plane_mode_set(struct exynos_drm_plane_state *exynos_state) static void exynos_drm_plane_reset(struct drm_plane *plane) { + struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); struct exynos_drm_plane_state *exynos_state; if (plane->state) { @@ -136,6 +137,7 @@ static void exynos_drm_plane_reset(struct drm_plane *plane) exynos_state = kzalloc(sizeof(*exynos_state), GFP_KERNEL); if (exynos_state) { + exynos_state->zpos = exynos_plane->config->zpos; plane->state = &exynos_state->base; plane->state->plane = plane; } @@ -153,6 +155,7 @@ exynos_drm_plane_duplicate_state(struct drm_plane *plane) return NULL; __drm_atomic_helper_plane_duplicate_state(plane, ©->base); + copy->zpos = exynos_state->zpos; return ©->base; } @@ -165,13 +168,53 @@ static void exynos_drm_plane_destroy_state(struct drm_plane *plane, kfree(old_exynos_state); } +static int exynos_drm_plane_atomic_set_property(struct drm_plane *plane, + struct drm_plane_state *state, + struct drm_property *property, + uint64_t val) +{ + struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + struct exynos_drm_plane_state *exynos_state = + to_exynos_plane_state(state); + struct exynos_drm_private *dev_priv = plane->dev->dev_private; + const struct exynos_drm_plane_config *config = exynos_plane->config; + + if (property == dev_priv->plane_zpos_property && + (config->capabilities & EXYNOS_DRM_PLANE_CAP_ZPOS)) + exynos_state->zpos = val; + else + return -EINVAL; + + return 0; +} + +static int exynos_drm_plane_atomic_get_property(struct drm_plane *plane, + const struct drm_plane_state *state, + struct drm_property *property, + uint64_t *val) +{ + const struct exynos_drm_plane_state *exynos_state = + container_of(state, const struct exynos_drm_plane_state, base); + struct exynos_drm_private *dev_priv = plane->dev->dev_private; + + if (property == dev_priv->plane_zpos_property) + *val = exynos_state->zpos; + else + return -EINVAL; + + return 0; +} + static struct drm_plane_funcs exynos_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, .destroy = drm_plane_cleanup, + .set_property = drm_atomic_helper_plane_set_property, .reset = exynos_drm_plane_reset, .atomic_duplicate_state = exynos_drm_plane_duplicate_state, .atomic_destroy_state = exynos_drm_plane_destroy_state, + .atomic_set_property = exynos_drm_plane_atomic_set_property, + .atomic_get_property = exynos_drm_plane_atomic_get_property, }; static int @@ -267,8 +310,8 @@ 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, DRM_MODE_PROP_IMMUTABLE, - "zpos", 0, MAX_PLANE - 1); + prop = drm_property_create_range(dev, 0, "zpos", + 0, MAX_PLANE - 1); if (!prop) return; @@ -280,7 +323,7 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane, int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *exynos_plane, - unsigned long possible_crtcs, + unsigned int index, unsigned long possible_crtcs, const struct exynos_drm_plane_config *config) { int err; @@ -298,12 +341,10 @@ int exynos_plane_init(struct drm_device *dev, drm_plane_helper_add(&exynos_plane->base, &plane_helper_funcs); - exynos_plane->zpos = config->zpos; + exynos_plane->index = index; exynos_plane->config = config; - if (config->type == DRM_PLANE_TYPE_OVERLAY) - exynos_plane_attach_zpos_property(&exynos_plane->base, - config->zpos); + exynos_plane_attach_zpos_property(&exynos_plane->base, config->zpos); return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index 0dd096548284..9aafad164cdf 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -10,6 +10,6 @@ */ int exynos_plane_init(struct drm_device *dev, - struct exynos_drm_plane *exynos_plane, + struct exynos_drm_plane *exynos_plane, unsigned int index, unsigned long possible_crtcs, const struct exynos_drm_plane_config *config); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 0be29c1b2c05..62ac4e5fa51d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -461,7 +461,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) plane_config.zpos = i; plane_config.type = vidi_win_types[i]; - ret = exynos_plane_init(drm_dev, &ctx->planes[i], + ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, 1 << ctx->pipe, &plane_config); if (ret) return ret; diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index dfb35e2da4db..b5fbc1cbf024 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -76,7 +76,9 @@ enum mixer_flag_bits { static const uint32_t mixer_formats[] = { DRM_FORMAT_XRGB4444, + DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555, + DRM_FORMAT_ARGB1555, DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888, DRM_FORMAT_ARGB8888, @@ -117,19 +119,22 @@ static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = { .type = DRM_PLANE_TYPE_PRIMARY, .pixel_formats = mixer_formats, .num_pixel_formats = ARRAY_SIZE(mixer_formats), - .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE, + .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE | + EXYNOS_DRM_PLANE_CAP_ZPOS, }, { .zpos = 1, .type = DRM_PLANE_TYPE_CURSOR, .pixel_formats = mixer_formats, .num_pixel_formats = ARRAY_SIZE(mixer_formats), - .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE, + .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE | + EXYNOS_DRM_PLANE_CAP_ZPOS, }, { .zpos = 2, .type = DRM_PLANE_TYPE_OVERLAY, .pixel_formats = vp_formats, .num_pixel_formats = ARRAY_SIZE(vp_formats), - .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE, + .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE | + EXYNOS_DRM_PLANE_CAP_ZPOS, }, }; @@ -162,6 +167,18 @@ static const u8 filter_cr_horiz_tap4[] = { 70, 59, 48, 37, 27, 19, 11, 5, }; +static inline bool is_alpha_format(unsigned int pixel_format) +{ + switch (pixel_format) { + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ARGB1555: + case DRM_FORMAT_ARGB4444: + return true; + default: + return false; + } +} + static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id) { return readl(res->vp_regs + reg_id); @@ -291,6 +308,37 @@ static void vp_default_filter(struct mixer_resources *res) filter_cr_horiz_tap4, sizeof(filter_cr_horiz_tap4)); } +static void mixer_cfg_gfx_blend(struct mixer_context *ctx, unsigned int win, + bool alpha) +{ + struct mixer_resources *res = &ctx->mixer_res; + u32 val; + + val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ + if (alpha) { + /* blending based on pixel alpha */ + val |= MXR_GRP_CFG_BLEND_PRE_MUL; + val |= MXR_GRP_CFG_PIXEL_BLEND_EN; + } + mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win), + val, MXR_GRP_CFG_MISC_MASK); +} + +static void mixer_cfg_vp_blend(struct mixer_context *ctx) +{ + struct mixer_resources *res = &ctx->mixer_res; + u32 val; + + /* + * No blending at the moment since the NV12/NV21 pixelformats don't + * have an alpha channel. However the mixer supports a global alpha + * value for a layer. Once this functionality is exposed, we can + * support blending of the video layer through this. + */ + val = 0; + mixer_reg_write(res, MXR_VIDEO_CFG, val); +} + static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable) { struct mixer_resources *res = &ctx->mixer_res; @@ -372,7 +420,7 @@ static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height) } static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win, - bool enable) + unsigned int priority, bool enable) { struct mixer_resources *res = &ctx->mixer_res; u32 val = enable ? ~0 : 0; @@ -380,20 +428,24 @@ static void mixer_cfg_layer(struct mixer_context *ctx, unsigned int win, switch (win) { case 0: mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE); + mixer_reg_writemask(res, MXR_LAYER_CFG, + MXR_LAYER_CFG_GRP0_VAL(priority), + MXR_LAYER_CFG_GRP0_MASK); break; case 1: mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE); + mixer_reg_writemask(res, MXR_LAYER_CFG, + MXR_LAYER_CFG_GRP1_VAL(priority), + MXR_LAYER_CFG_GRP1_MASK); break; - case 2: + case VP_DEFAULT_WIN: if (ctx->vp_enabled) { vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON); mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE); - - /* control blending of graphic layer 0 */ - mixer_reg_writemask(res, MXR_GRAPHIC_CFG(0), val, - MXR_GRP_CFG_BLEND_PRE_MUL | - MXR_GRP_CFG_PIXEL_BLEND_EN); + mixer_reg_writemask(res, MXR_LAYER_CFG, + MXR_LAYER_CFG_VP_VAL(priority), + MXR_LAYER_CFG_VP_MASK); } break; } @@ -464,7 +516,6 @@ static void vp_video_buffer(struct mixer_context *ctx, } spin_lock_irqsave(&res->reg_slock, flags); - mixer_vsync_set_update(ctx, false); /* interlace or progressive scan mode */ val = (ctx->interlace ? ~0 : 0); @@ -511,10 +562,10 @@ static void vp_video_buffer(struct mixer_context *ctx, mixer_cfg_scan(ctx, mode->vdisplay); mixer_cfg_rgb_fmt(ctx, mode->vdisplay); - mixer_cfg_layer(ctx, plane->zpos, true); + mixer_cfg_layer(ctx, plane->index, state->zpos + 1, true); + mixer_cfg_vp_blend(ctx); mixer_run(ctx); - mixer_vsync_set_update(ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); mixer_regs_dump(ctx); @@ -537,7 +588,7 @@ static void mixer_graph_buffer(struct mixer_context *ctx, struct mixer_resources *res = &ctx->mixer_res; struct drm_framebuffer *fb = state->base.fb; unsigned long flags; - unsigned int win = plane->zpos; + unsigned int win = plane->index; 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; @@ -546,10 +597,12 @@ static void mixer_graph_buffer(struct mixer_context *ctx, switch (fb->pixel_format) { case DRM_FORMAT_XRGB4444: + case DRM_FORMAT_ARGB4444: fmt = MXR_FORMAT_ARGB4444; break; case DRM_FORMAT_XRGB1555: + case DRM_FORMAT_ARGB1555: fmt = MXR_FORMAT_ARGB1555; break; @@ -587,7 +640,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx, ctx->interlace = false; spin_lock_irqsave(&res->reg_slock, flags); - mixer_vsync_set_update(ctx, false); /* setup format */ mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win), @@ -626,7 +678,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, mixer_cfg_scan(ctx, mode->vdisplay); mixer_cfg_rgb_fmt(ctx, mode->vdisplay); - mixer_cfg_layer(ctx, win, true); + mixer_cfg_layer(ctx, win, state->zpos + 1, true); + mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->pixel_format)); /* layer update mandatory for mixer 16.0.33.0 */ if (ctx->mxr_ver == MXR_VER_16_0_33_0 || @@ -635,7 +688,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx, mixer_run(ctx); - mixer_vsync_set_update(ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); mixer_regs_dump(ctx); @@ -660,10 +712,8 @@ static void mixer_win_reset(struct mixer_context *ctx) { struct mixer_resources *res = &ctx->mixer_res; unsigned long flags; - u32 val; /* value stored to register */ spin_lock_irqsave(&res->reg_slock, flags); - mixer_vsync_set_update(ctx, false); mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK); @@ -674,40 +724,14 @@ static void mixer_win_reset(struct mixer_context *ctx) mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST, MXR_STATUS_BURST_MASK); - /* setting default layer priority: layer1 > layer0 > video - * because typical usage scenario would be - * layer1 - OSD - * layer0 - framebuffer - * video - video overlay - */ - val = MXR_LAYER_CFG_GRP1_VAL(3); - val |= MXR_LAYER_CFG_GRP0_VAL(2); - if (ctx->vp_enabled) - val |= MXR_LAYER_CFG_VP_VAL(1); - mixer_reg_write(res, MXR_LAYER_CFG, val); + /* reset default layer priority */ + mixer_reg_write(res, MXR_LAYER_CFG, 0); /* setting background color */ mixer_reg_write(res, MXR_BG_COLOR0, 0x008080); mixer_reg_write(res, MXR_BG_COLOR1, 0x008080); mixer_reg_write(res, MXR_BG_COLOR2, 0x008080); - /* setting graphical layers */ - val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */ - val |= MXR_GRP_CFG_WIN_BLEND_EN; - val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */ - - /* Don't blend layer 0 onto the mixer background */ - mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val); - - /* Blend layer 1 into layer 0 */ - val |= MXR_GRP_CFG_BLEND_PRE_MUL; - val |= MXR_GRP_CFG_PIXEL_BLEND_EN; - mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val); - - /* setting video layers */ - val = MXR_GRP_CFG_ALPHA_VAL(0); - mixer_reg_write(res, MXR_VIDEO_CFG, val); - if (ctx->vp_enabled) { /* configuration of Video Processor Registers */ vp_win_reset(ctx); @@ -720,7 +744,6 @@ static void mixer_win_reset(struct mixer_context *ctx) if (ctx->vp_enabled) mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE); - mixer_vsync_set_update(ctx, true); spin_unlock_irqrestore(&res->reg_slock, flags); } @@ -951,17 +974,27 @@ 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_atomic_begin(struct exynos_drm_crtc *crtc) +{ + struct mixer_context *mixer_ctx = crtc->ctx; + + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) + return; + + mixer_vsync_set_update(mixer_ctx, false); +} + static void mixer_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct mixer_context *mixer_ctx = crtc->ctx; - DRM_DEBUG_KMS("win: %d\n", plane->zpos); + DRM_DEBUG_KMS("win: %d\n", plane->index); if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; - if (plane->zpos > 1 && mixer_ctx->vp_enabled) + if (plane->index == VP_DEFAULT_WIN) vp_video_buffer(mixer_ctx, plane); else mixer_graph_buffer(mixer_ctx, plane); @@ -974,18 +1007,24 @@ static void mixer_disable_plane(struct exynos_drm_crtc *crtc, struct mixer_resources *res = &mixer_ctx->mixer_res; unsigned long flags; - DRM_DEBUG_KMS("win: %d\n", plane->zpos); + DRM_DEBUG_KMS("win: %d\n", plane->index); if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; spin_lock_irqsave(&res->reg_slock, flags); - mixer_vsync_set_update(mixer_ctx, false); + mixer_cfg_layer(mixer_ctx, plane->index, 0, false); + spin_unlock_irqrestore(&res->reg_slock, flags); +} - mixer_cfg_layer(mixer_ctx, plane->zpos, false); +static void mixer_atomic_flush(struct exynos_drm_crtc *crtc) +{ + struct mixer_context *mixer_ctx = crtc->ctx; + + if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) + return; mixer_vsync_set_update(mixer_ctx, true); - spin_unlock_irqrestore(&res->reg_slock, flags); } static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc) @@ -1026,6 +1065,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) pm_runtime_get_sync(ctx->dev); + mixer_vsync_set_update(ctx, false); + mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); if (test_bit(MXR_BIT_VSYNC, &ctx->flags)) { @@ -1034,6 +1075,8 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) } mixer_win_reset(ctx); + mixer_vsync_set_update(ctx, true); + set_bit(MXR_BIT_POWERED, &ctx->flags); } @@ -1084,8 +1127,10 @@ static const 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, + .atomic_begin = mixer_atomic_begin, .update_plane = mixer_update_plane, .disable_plane = mixer_disable_plane, + .atomic_flush = mixer_atomic_flush, .atomic_check = mixer_atomic_check, }; @@ -1160,7 +1205,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) if (i == VP_DEFAULT_WIN && !ctx->vp_enabled) continue; - ret = exynos_plane_init(drm_dev, &ctx->planes[i], + ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, 1 << ctx->pipe, &plane_configs[i]); if (ret) return ret; diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index ac60260c2389..7f22df5bf707 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h @@ -113,6 +113,7 @@ #define MXR_GRP_CFG_BLEND_PRE_MUL (1 << 20) #define MXR_GRP_CFG_WIN_BLEND_EN (1 << 17) #define MXR_GRP_CFG_PIXEL_BLEND_EN (1 << 16) +#define MXR_GRP_CFG_MISC_MASK ((3 << 16) | (3 << 20)) #define MXR_GRP_CFG_FORMAT_VAL(x) MXR_MASK_VAL(x, 11, 8) #define MXR_GRP_CFG_FORMAT_MASK MXR_GRP_CFG_FORMAT_VAL(~0) #define MXR_GRP_CFG_ALPHA_VAL(x) MXR_MASK_VAL(x, 7, 0) @@ -145,8 +146,11 @@ /* bit for MXR_LAYER_CFG */ #define MXR_LAYER_CFG_GRP1_VAL(x) MXR_MASK_VAL(x, 11, 8) +#define MXR_LAYER_CFG_GRP1_MASK MXR_LAYER_CFG_GRP1_VAL(~0) #define MXR_LAYER_CFG_GRP0_VAL(x) MXR_MASK_VAL(x, 7, 4) +#define MXR_LAYER_CFG_GRP0_MASK MXR_LAYER_CFG_GRP0_VAL(~0) #define MXR_LAYER_CFG_VP_VAL(x) MXR_MASK_VAL(x, 3, 0) +#define MXR_LAYER_CFG_VP_MASK MXR_LAYER_CFG_VP_VAL(~0) #endif /* SAMSUNG_REGS_MIXER_H */ |