[RFC 3/3] drm/omap: Add wide display support using multiple overlays

Tomi Valkeinen tomi.valkeinen at ti.com
Thu Aug 2 10:09:52 UTC 2018


Hi Benoit,

On 29/06/18 20:02, Benoit Parrot wrote:
> In the case where we need to support wide-display using more than one
> overlay to achieve the needed display resolution, we need to be able to
> dynamically assign overlays to planes instead of having the overlays
> being statically mapped to planes.
> 
> This also means that on occasion where the number of requested planes
> exceeds the numbers of overlays required to display them then a failure
> would be returned for the plane that cannot be handled at that time. It
> is up to user space to make sure the H/W resource are not
> over-subscribed.

This is not a trivial patch, I think it needs much more explanation in
the desc on how the patch solves this issue and what it changes.

I have some small comments below here and there, but overall, I feel
it's rather difficult to review, and I really think this should be split
into multiple smaller patches. Some ideas on the patches it might be
split to:

- add plane state
- add global state
- add code which manages plane-id -> hw plane id
- add dual plane support

> Signed-off-by: Benoit Parrot <bparrot at ti.com>
> ---
>  drivers/gpu/drm/omapdrm/Makefile       |   1 +
>  drivers/gpu/drm/omapdrm/omap_drv.c     | 119 ++++++++++-
>  drivers/gpu/drm/omapdrm/omap_drv.h     |  15 +-
>  drivers/gpu/drm/omapdrm/omap_fb.c      |  33 ++-
>  drivers/gpu/drm/omapdrm/omap_fb.h      |   4 +-
>  drivers/gpu/drm/omapdrm/omap_overlay.c | 366 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/omapdrm/omap_overlay.h |  80 +++++++
>  drivers/gpu/drm/omapdrm/omap_plane.c   | 322 ++++++++++++++++++++++++-----
>  drivers/gpu/drm/omapdrm/omap_plane.h   |  20 ++
>  9 files changed, 892 insertions(+), 68 deletions(-)
>  create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.c
>  create mode 100644 drivers/gpu/drm/omapdrm/omap_overlay.h
> 
> diff --git a/drivers/gpu/drm/omapdrm/Makefile b/drivers/gpu/drm/omapdrm/Makefile
> index f115253115c5..800dfd035360 100644
> --- a/drivers/gpu/drm/omapdrm/Makefile
> +++ b/drivers/gpu/drm/omapdrm/Makefile
> @@ -12,6 +12,7 @@ omapdrm-y := omap_drv.o \
>  	omap_debugfs.o \
>  	omap_crtc.o \
>  	omap_plane.o \
> +	omap_overlay.o \
>  	omap_encoder.o \
>  	omap_connector.o \
>  	omap_fb.o \
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
> index ef3b0e3571ec..f0a5c3dab471 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.c
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.c
> @@ -16,11 +16,7 @@
>   */
>  
>  #include <linux/sys_soc.h>
> -
> -#include <drm/drm_atomic.h>
> -#include <drm/drm_atomic_helper.h>
> -#include <drm/drm_crtc_helper.h>
> -#include <drm/drm_fb_helper.h>
> +#include <linux/sort.h>
>  
>  #include "omap_dmm_tiler.h"
>  #include "omap_drv.h"
> @@ -113,9 +109,100 @@ static void omap_atomic_commit_tail(struct drm_atomic_state *old_state)
>  
>  	drm_atomic_helper_cleanup_planes(dev, old_state);
>  
> +	omap_overlay_disable_unassigned(old_state);
> +
>  	priv->dispc_ops->runtime_put(priv->dispc);
>  }
>  
> +static int drm_atomic_state_normalized_zpos_cmp(const void *a, const void *b)
> +{
> +	const struct drm_plane_state *sa = *(struct drm_plane_state **)a;
> +	const struct drm_plane_state *sb = *(struct drm_plane_state **)b;
> +
> +	if (sa->normalized_zpos != sb->normalized_zpos)
> +		return sa->normalized_zpos - sb->normalized_zpos;
> +	else
> +		return sa->plane->base.id - sb->plane->base.id;
> +}
> +
> +static int omap_atomic_update_normalize_zpos(struct drm_device *dev,
> +					     struct drm_atomic_state *state)
> +{
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *old_state, *new_state;
> +	struct drm_plane *plane;
> +	int i, n, inc;
> +	int total_planes = dev->mode_config.num_total_plane;
> +	struct drm_plane_state **states;
> +	int ret = 0;
> +
> +	states = kmalloc_array(total_planes, sizeof(*states), GFP_KERNEL);
> +	if (!states)
> +		return -ENOMEM;
> +
> +	for_each_oldnew_crtc_in_state(state, crtc, old_state, new_state, i) {
> +		if (old_state->plane_mask == new_state->plane_mask &&
> +		    !new_state->zpos_changed)
> +			continue;
> +
> +		/* Reset plane increment and index value for every crtc */
> +		n = 0;
> +
> +		/*
> +		 * Normalization process might create new states for planes
> +		 * which normalized_zpos has to be recalculated.
> +		 */
> +		drm_for_each_plane_mask(plane, dev, new_state->plane_mask) {
> +			struct drm_plane_state *plane_state =
> +				drm_atomic_get_plane_state(new_state->state,
> +							   plane);
> +			if (IS_ERR(plane_state)) {
> +				ret = PTR_ERR(plane_state);
> +				goto done;
> +			}
> +			states[n++] = plane_state;
> +		}
> +
> +		sort(states, n, sizeof(*states),
> +		     drm_atomic_state_normalized_zpos_cmp, NULL);
> +
> +		for (i = 0, inc = 0; i < n; i++) {
> +			plane = states[i]->plane;
> +
> +			states[i]->normalized_zpos = i + inc;
> +			DRM_DEBUG_ATOMIC("[PLANE:%d:%s] updated normalized zpos value %d\n",
> +					 plane->base.id, plane->name,
> +					 states[i]->normalized_zpos);
> +
> +			if (is_omap_plane_dual_overlay(states[i]))
> +				inc++;
> +		}
> +		new_state->zpos_changed = true;
> +	}
> +
> +done:
> +	kfree(states);
> +	return ret;
> +}
> +
> +static int omap_atomic_check(struct drm_device *dev,
> +			     struct drm_atomic_state *state)
> +{
> +	int ret;
> +
> +	ret = drm_atomic_helper_check(dev, state);
> +	if (ret)
> +		return ret;
> +
> +	if (dev->mode_config.normalize_zpos) {
> +		ret = omap_atomic_update_normalize_zpos(dev, state);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs = {
>  	.atomic_commit_tail = omap_atomic_commit_tail,
>  };
> @@ -123,7 +210,7 @@ static const struct drm_mode_config_helper_funcs omap_mode_config_helper_funcs =
>  static const struct drm_mode_config_funcs omap_mode_config_funcs = {
>  	.fb_create = omap_framebuffer_create,
>  	.output_poll_changed = drm_fb_helper_output_poll_changed,
> -	.atomic_check = drm_atomic_helper_check,
> +	.atomic_check = omap_atomic_check,
>  	.atomic_commit = drm_atomic_helper_commit,
>  };
>  
> @@ -296,7 +383,7 @@ static int omap_modeset_init(struct drm_device *dev)
>  			return -EINVAL;
>  
>  		plane = omap_plane_init(dev, plane_idx, DRM_PLANE_TYPE_OVERLAY,
> -			plane_crtc_mask);
> +					plane_crtc_mask);
>  		if (IS_ERR(plane))
>  			return PTR_ERR(plane);
>  
> @@ -560,10 +647,18 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
>  
>  	omap_gem_init(ddev);
>  
> +	ret = omap_global_obj_init(priv);
> +	if (ret)
> +		goto err_free_drm_dev;
> +
> +	ret = omap_hwoverlays_init(priv);
> +	if (ret)
> +		goto err_free_priv_obj;
> +
>  	ret = omap_modeset_init(ddev);
>  	if (ret) {
>  		dev_err(priv->dev, "omap_modeset_init failed: ret=%d\n", ret);
> -		goto err_free_drm_dev;
> +		goto err_free_overlays;
>  	}
>  
>  	/* Initialize vblank handling, start with all CRTCs disabled. */
> @@ -577,7 +672,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
>  		drm_crtc_vblank_off(priv->crtcs[i]);
>  
>  	omap_fbdev_init(ddev);
> -

As this is a big patch already, try not to make any extra cleanups that
are not needed.

>  	drm_kms_helper_poll_init(ddev);
>  	omap_modeset_enable_external_hpd();
>  
> @@ -599,6 +693,10 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
>  err_cleanup_modeset:
>  	drm_mode_config_cleanup(ddev);
>  	omap_drm_irq_uninstall(ddev);
> +err_free_overlays:
> +	omap_hwoverlays_destroy(priv);
> +err_free_priv_obj:
> +	omap_global_obj_fini(priv);
>  err_free_drm_dev:
>  	omap_gem_deinit(ddev);
>  	drm_dev_unref(ddev);
> @@ -632,6 +730,9 @@ static void omapdrm_cleanup(struct omap_drm_private *priv)
>  
>  	drm_dev_unref(ddev);
>  
> +	omap_hwoverlays_destroy(priv);
> +	omap_global_obj_fini(priv);
> +
>  	destroy_workqueue(priv->wq);
>  
>  	omap_disconnect_dssdevs();
> diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
> index 6eaee4df4559..eb71ea8decee 100644
> --- a/drivers/gpu/drm/omapdrm/omap_drv.h
> +++ b/drivers/gpu/drm/omapdrm/omap_drv.h
> @@ -23,7 +23,10 @@
>  #include <linux/workqueue.h>
>  
>  #include <drm/drmP.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
>  #include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
>  #include <drm/drm_gem.h>
>  #include <drm/omap_drm.h>
>  
> @@ -37,6 +40,7 @@
>  #include "omap_gem.h"
>  #include "omap_irq.h"
>  #include "omap_plane.h"
> +#include "omap_overlay.h"
>  
>  #define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
>  #define VERB(fmt, ...) if (0) DRM_DEBUG(fmt, ##__VA_ARGS__) /* verbose debug */
> @@ -66,6 +70,16 @@ struct omap_drm_private {
>  	unsigned int num_connectors;
>  	struct drm_connector *connectors[8];
>  
> +	unsigned int num_ovls;
> +	struct omap_hw_overlay *overlays[8];
> +
> +        /*
> +         * Global private object state, Do not access directly, use
> +         * omap_global_get_state()
> +         */
> +        struct drm_modeset_lock glob_state_lock;
> +        struct drm_private_obj glob_state;
> +

You're using space indentation here.

>  	struct drm_fb_helper *fbdev;
>  
>  	struct workqueue_struct *wq;
> @@ -91,7 +105,6 @@ struct omap_drm_private {
>  	unsigned int max_bandwidth;
>  };
>  
> -
>  int omap_debugfs_init(struct drm_minor *minor);
>  
>  #endif /* __OMAPDRM_DRV_H__ */
> diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
> index 5fd22ca73913..b9573c163117 100644
> --- a/drivers/gpu/drm/omapdrm/omap_fb.c
> +++ b/drivers/gpu/drm/omapdrm/omap_fb.c
> @@ -153,7 +153,9 @@ static u32 drm_rotation_to_tiler(unsigned int drm_rot)
>  /* update ovl info for scanout, handles cases of multi-planar fb's, etc.
>   */
>  void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
> -		struct drm_plane_state *state, struct omap_overlay_info *info)
> +		struct drm_plane_state *state,
> +		struct omap_overlay_info *info,
> +		struct omap_overlay_info *r_info)
>  {
>  	struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
>  	const struct drm_format_info *format = omap_fb->format;
> @@ -206,7 +208,8 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
>  		info->rotation_type = OMAP_DSS_ROT_TILER;
>  		info->rotation = state->rotation ?: DRM_MODE_ROTATE_0;
>  		/* Note: stride in TILER units, not pixels */
> -		info->screen_width  = omap_gem_tiled_stride(plane->bo, orient);
> +		info->screen_width  =
> +				omap_gem_tiled_stride(plane->bo, orient);
>  	} else {
>  		switch (state->rotation & DRM_MODE_ROTATE_MASK) {
>  		case 0:
> @@ -221,10 +224,10 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
>  			break;
>  		}
>  
> -		info->paddr         = get_linear_addr(plane, format, 0, x, y);
> +		info->paddr = get_linear_addr(plane, format, 0, x, y);
>  		info->rotation_type = OMAP_DSS_ROT_NONE;
> -		info->rotation      = DRM_MODE_ROTATE_0;
> -		info->screen_width  = plane->pitch;
> +		info->rotation = DRM_MODE_ROTATE_0;
> +		info->screen_width = plane->pitch;

These are also extra changes. There are other similar ones.

>  	}
>  
>  	/* convert to pixels: */
> @@ -238,11 +241,29 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
>  			omap_gem_rotated_dma_addr(plane->bo, orient, x/2, y/2,
>  						  &info->p_uv_addr);
>  		} else {
> -			info->p_uv_addr = get_linear_addr(plane, format, 1, x, y);
> +			info->p_uv_addr =
> +				get_linear_addr(plane, format, 1, x, y);
>  		}
>  	} else {
>  		info->p_uv_addr = 0;
>  	}
> +
> +	if (r_info) {
> +		info->width /= 2;
> +		info->out_width /= 2;
> +
> +		*r_info = *info;
> +
> +		r_info->pos_x = info->pos_x + info->out_width;
> +
> +		r_info->paddr =	get_linear_addr(&omap_fb->planes[0], format, 0,
> +						x + info->width, y);
> +		if (fb->format->format == DRM_FORMAT_NV12) {
> +			r_info->p_uv_addr =
> +				get_linear_addr(&omap_fb->planes[1], format, 1,
> +						x + info->width, y);
> +		}
> +	}
>  }
>  
>  /* pin, prepare for scanout: */
> diff --git a/drivers/gpu/drm/omapdrm/omap_fb.h b/drivers/gpu/drm/omapdrm/omap_fb.h
> index 94ad5f9e4404..8c116c1aac0d 100644
> --- a/drivers/gpu/drm/omapdrm/omap_fb.h
> +++ b/drivers/gpu/drm/omapdrm/omap_fb.h
> @@ -37,7 +37,9 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
>  int omap_framebuffer_pin(struct drm_framebuffer *fb);
>  void omap_framebuffer_unpin(struct drm_framebuffer *fb);
>  void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
> -		struct drm_plane_state *state, struct omap_overlay_info *info);
> +		struct drm_plane_state *state,
> +		struct omap_overlay_info *info,
> +		struct omap_overlay_info *r_info);
>  struct drm_connector *omap_framebuffer_get_next_connector(
>  		struct drm_framebuffer *fb, struct drm_connector *from);
>  bool omap_framebuffer_supports_rotation(struct drm_framebuffer *fb);
> diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.c b/drivers/gpu/drm/omapdrm/omap_overlay.c
> new file mode 100644
> index 000000000000..0a1327c31b69
> --- /dev/null
> +++ b/drivers/gpu/drm/omapdrm/omap_overlay.c
> @@ -0,0 +1,366 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
> + * Author: Benoit Parrot, <bparrot at ti.com>
> + */
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "omap_dmm_tiler.h"
> +#include "omap_drv.h"
> +
> +/*
> + * overlay funcs
> + */
> +static void __maybe_unused
> +omap_overlay_atomic_print_state(struct drm_printer *p,
> +				const struct omap_global_state *state,
> +				struct omap_drm_private *priv)
> +{
> +	int i;
> +
> +	drm_printf(p, "\tomap_global_state=%p\n", state);
> +	if (state) {
> +		for (i = 0; i < priv->num_ovls; i++) {
> +			struct drm_plane *plane =
> +				state->overlay.hwoverlay_to_plane[i];
> +
> +			drm_printf(p, "\t\t[%d] plane=%p\n", i, plane);
> +			if (plane)
> +				drm_printf(p, "\t\t\t plane=%s\n", plane->name);
> +		}
> +	}
> +}
> +
> +/* Global/shared object state funcs */
> +
> +/*
> + * This is a helper that returns the private state currently in operation.
> + * Note that this would return the "old_state" if called in the atomic check
> + * path, and the "new_state" after the atomic swap has been done.
> + */
> +static struct omap_global_state *
> +omap_get_existing_global_state(struct omap_drm_private *priv)
> +{
> +	return to_omap_global_state(priv->glob_state.state);
> +}
> +
> +/*
> + * This acquires the modeset lock set aside for global state, creates
> + * a new duplicated private object state.
> + */
> +static struct omap_global_state *__must_check
> +omap_get_global_state(struct drm_atomic_state *s)
> +{
> +	struct omap_drm_private *priv = s->dev->dev_private;
> +	struct drm_private_state *priv_state;
> +	int ret;
> +
> +	while (1) {
> +		ret = drm_modeset_lock(&priv->glob_state_lock, s->acquire_ctx);
> +		if (ret != -EDEADLK)
> +			break;
> +
> +		drm_modeset_backoff(s->acquire_ctx);
> +	}
> +
> +	if (ret)
> +		return ERR_PTR(ret);
> +
> +	priv_state = drm_atomic_get_private_obj_state(s, &priv->glob_state);
> +	if (IS_ERR(priv_state))
> +		return ERR_CAST(priv_state);
> +
> +	return to_omap_global_state(priv_state);
> +}
> +
> +static struct drm_private_state *
> +omap_global_duplicate_state(struct drm_private_obj *obj)
> +{
> +	struct omap_global_state *state;
> +
> +	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return NULL;
> +
> +	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
> +
> +	return &state->base;
> +}
> +
> +static void omap_global_destroy_state(struct drm_private_obj *obj,
> +				      struct drm_private_state *state)
> +{
> +	struct omap_global_state *omap_state = to_omap_global_state(state);
> +
> +	kfree(omap_state);
> +}
> +
> +static const struct drm_private_state_funcs omap_global_state_funcs = {
> +	.atomic_duplicate_state = omap_global_duplicate_state,
> +	.atomic_destroy_state = omap_global_destroy_state,
> +};
> +
> +int omap_global_obj_init(struct omap_drm_private *priv)
> +{
> +	struct omap_global_state *state;
> +
> +	drm_modeset_lock_init(&priv->glob_state_lock);
> +
> +	state = kzalloc(sizeof(*state), GFP_KERNEL);
> +	if (!state)
> +		return -ENOMEM;
> +
> +	drm_atomic_private_obj_init(&priv->glob_state,
> +				    &state->base,
> +				    &omap_global_state_funcs);
> +	return 0;
> +}
> +
> +void omap_global_obj_fini(struct omap_drm_private *priv)
> +{
> +	drm_atomic_private_obj_fini(&priv->glob_state);
> +	drm_modeset_lock_fini(&priv->glob_state_lock);
> +}
> +
> +static struct omap_hw_overlay *
> +omap_plane_find_free_overlay(struct drm_device *dev,
> +			     struct omap_hw_overlay_state *new_state,
> +			     u32 caps, u32 fourcc, u32 crtc_mask)
> +{
> +	struct omap_drm_private *priv = dev->dev_private;
> +	const struct dispc_ops *ops = priv->dispc_ops;
> +	int i;
> +
> +	DBG("caps: %x fourcc: %x crtc: %x\n", caps, fourcc, crtc_mask);
> +
> +	for (i = 0; i < priv->num_ovls; i++) {
> +		struct omap_hw_overlay *cur = priv->overlays[i];
> +	
> +		DBG("%d: id: %d cur->caps: %x cur->crtc: %x\n",
> +		    cur->idx, cur->overlay_id, cur->caps, cur->possible_crtcs);
> +
> +		/* skip if already in-use */
> +		if (new_state->hwoverlay_to_plane[cur->idx])
> +			continue;
> +
> +		/* check if allowed on crtc */
> +		if (!(cur->possible_crtcs & crtc_mask))
> +			continue;
> +
> +		/* skip if doesn't support some required caps: */
> +		if (caps & ~cur->caps)
> +			continue;
> +
> +		/* check supported format */
> +		if (!ops->ovl_color_mode_supported(priv->dispc,
> +						   cur->overlay_id,
> +						   fourcc))
> +			continue;
> +
> +		return cur;
> +	}
> +
> +	DBG("no match\n");
> +	return NULL;
> +}
> +
> +int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
> +			u32 caps, u32 fourcc, u32 crtc_mask,
> +			struct omap_hw_overlay **overlay,
> +			struct omap_hw_overlay **r_overlay)
> +{
> +	struct omap_drm_private *priv = s->dev->dev_private;
> +	struct omap_global_state *new_global_state, *old_global_state;
> +	struct omap_hw_overlay_state *old_state, *new_state;
> +	struct omap_hw_overlay *ovl, *r_ovl;
> +
> +	new_global_state = omap_get_global_state(s);
> +	if (IS_ERR(new_global_state))
> +		return PTR_ERR(new_global_state);
> +
> +	/*
> +	 * grab old_state after omap_get_global_state(),
> +	 * since now we hold lock:
> +	 */
> +	old_global_state = omap_get_existing_global_state(priv);
> +	DBG("new_global_state: %p old_global_state: %p should be different (%d)",
> +	    new_global_state, old_global_state, new_global_state != old_global_state);
> +
> +	old_state = &old_global_state->overlay;
> +	new_state = &new_global_state->overlay;
> +
> +	if (!*overlay) {
> +		ovl = omap_plane_find_free_overlay(s->dev, new_state,
> +						   caps, fourcc, crtc_mask);
> +		if (!ovl)
> +			return -ENOMEM;
> +
> +		new_state->hwoverlay_to_plane[ovl->idx] = plane;
> +		*overlay = ovl;
> +
> +		if (r_overlay) {
> +			r_ovl = omap_plane_find_free_overlay(s->dev, new_state,
> +							     caps, fourcc,
> +							     crtc_mask);
> +			if (!r_ovl) {
> +				new_state->hwoverlay_to_plane[ovl->idx] = NULL;
> +				*overlay = NULL;
> +				return -ENOMEM;
> +			}
> +
> +			new_state->hwoverlay_to_plane[r_ovl->idx] = plane;
> +			*r_overlay = r_ovl;
> +		}
> +
> +
> +		DBG("%s: assign to plane %s for caps %x",
> +		    (*overlay)->name, plane->name, caps);
> +
> +		if (r_overlay) {
> +			DBG("%s: assign to right of plane %s for caps %x",
> +			    (*r_overlay)->name, plane->name, caps);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +void omap_overlay_release(struct drm_atomic_state *s,
> +			  struct omap_hw_overlay *overlay)
> +{
> +	struct omap_global_state *state = omap_get_global_state(s);
> +	struct omap_hw_overlay_state *new_state = &state->overlay;
> +
> +	if (!overlay)
> +		return;
> +
> +	if (WARN_ON(!new_state->hwoverlay_to_plane[overlay->idx]))
> +		return;
> +
> +	DBG("%s: release from plane %s", overlay->name,
> +	    new_state->hwoverlay_to_plane[overlay->idx]->name);
> +
> +	new_state->hwoverlay_to_plane[overlay->idx] = NULL;
> +}
> +
> +/*
> + * This is called only from omap_atomic_commit_tail()
> + * as a cleanup step to make sure hw overlay which are no longer
> + * are disabled.
> + *
> + * I was originally taking the glob_state_lock here by calling
> + * omap_get_global_state(s) but doing so here was causing all kind
> + * lock related warnings, for instance:
> + *  WARNING: CPU: 0 PID: 68 at drivers/gpu/drm/drm_modeset_lock.c:241
> + * and
> + *  WARNING: CPU: 0 PID: 68 at drivers/gpu/drm/drm_modeset_lock.c:244
> + * As well as also generating these:
> + *  ==================================
> + *  WARNING: Nested lock was not taken
> + *  4.18.0-rc2-00055-g5d51e5159b0a #24 Tainted: G        W
> + *  ----------------------------------
> + *  kworker/u2:3/66 is trying to lock:
> + *  51abea2e (crtc_ww_class_mutex){+.+.}, at: drm_modeset_lock+0xd0/0x140
> + *
> + *  but this task is not holding:
> + *  �21
> + *
> + * The only thing that worked so far was to stop trying to take that lock
> + * in this particular case. It might the real solution but I would like
> + * to sure.
> + */
> +void omap_overlay_disable_unassigned(struct drm_atomic_state *s)
> +{
> +	struct omap_drm_private *priv = s->dev->dev_private;
> +	struct omap_hw_overlay_state *new_state;
> +	struct omap_global_state *old_state;
> +	int i;
> +
> +	old_state = omap_get_existing_global_state(priv);
> +	new_state = &old_state->overlay;
> +
> +	for (i = 0; i < priv->num_ovls; i++) {
> +		struct omap_hw_overlay *cur = priv->overlays[i];
> +
> +		if (!new_state->hwoverlay_to_plane[cur->idx]) {
> +			priv->dispc_ops->ovl_enable(priv->dispc,
> +						    cur->overlay_id,
> +						    false);
> +
> +			/*
> +			 * Since we are disabling this overlay in this
> +			 * atomic cycle we can reset the avalaible crtcs
> +			 * it can be used on
> +			 */
> +			cur->possible_crtcs = (1 << priv->num_crtcs) - 1;
> +		}
> +	}
> +}
> +
> +void omap_overlay_destroy(struct omap_hw_overlay *overlay)
> +{
> +	kfree(overlay);
> +}
> +
> +static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
> +						 enum omap_overlay_caps caps)
> +{
> +	struct omap_hw_overlay *overlay;
> +
> +	overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
> +	if (!overlay)
> +		return ERR_PTR(-ENOMEM);
> +
> +	overlay->name = overlay2name(overlay_id);
> +	overlay->overlay_id = overlay_id;
> +	overlay->caps = caps;
> +	/* 
> +	 * When this is called priv->num_crtcs is not known yet.
> +	 * Use a safe mask value to start with, it will get updated to the
> +	 * proper value after the first use.
> +	 */
> +	overlay->possible_crtcs = 0xff;
> +
> +	return overlay;
> +}
> +
> +int omap_hwoverlays_init(struct omap_drm_private *priv)
> +{
> +	static const enum omap_plane_id overlays[] = {
> +			OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
> +			OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
> +	};
> +	u32 num_overlays = priv->dispc_ops->get_num_ovls(priv->dispc);
> +	enum omap_overlay_caps caps;
> +	int i, ret;
> +
> +	for (i = 0; i < num_overlays; i++) {
> +		struct omap_hw_overlay *overlay;
> +
> +		caps = priv->dispc_ops->ovl_get_caps(priv->dispc, overlays[i]);
> +		overlay = omap_overlay_init(overlays[i], caps);
> +		if (IS_ERR(overlay)) {
> +			ret = PTR_ERR(overlay);
> +			dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
> +				overlay2name(i), ret);
> +			return ret;
> +		}
> +		overlay->idx = priv->num_ovls;
> +		priv->overlays[priv->num_ovls++] = overlay;
> +	}
> +
> +	return 0;
> +}
> +
> +void omap_hwoverlays_destroy(struct omap_drm_private *priv)
> +{
> +	int i;
> +
> +	for (i = 0; i < priv->num_ovls; i++) {
> +		omap_overlay_destroy(priv->overlays[i]);
> +		priv->overlays[i] = NULL;
> +	}
> +}
> diff --git a/drivers/gpu/drm/omapdrm/omap_overlay.h b/drivers/gpu/drm/omapdrm/omap_overlay.h
> new file mode 100644
> index 000000000000..ed94a260ba10
> --- /dev/null
> +++ b/drivers/gpu/drm/omapdrm/omap_overlay.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2018 Texas Instruments Incorporated -  http://www.ti.com/
> + * Author: Benoit Parrot, <bparrot at ti.com>
> + */
> +
> +#ifndef __OMAPDRM_OVERLAY_H__
> +#define __OMAPDRM_OVERLAY_H__
> +
> +#include <linux/types.h>
> + 
> +enum drm_plane_type;
> +
> +struct drm_device;
> +struct drm_mode_object;
> +struct drm_plane;
> +
> +/* Used to associate a HW overlay/plane to a plane */
> +struct omap_hw_overlay {
> +	int idx;
> +
> +	const char *name;
> +	enum omap_plane_id overlay_id;
> +
> +	enum omap_overlay_caps caps;
> +	/*
> +	 * The CRTC(s) this overlay is currently allowed on.
> +	 * When the overlay is unused and was not assigned to any crtc then
> +	 * this will be the equal to the plane possible_crtcs otherwise it
> +	 * will be the current crtc this overlay is displayed on.
> +	 * When clearing the overlay to plane assignemnt while going through
> +	 * an atomic_check sequence we need to remember which crtc the overlay
> +	 * was on as we do not want to create flicker. We want to be able to
> +	 * reassign the overlay to the same crtc it was previously on.
> +	 */
> +	u32 possible_crtcs;
> +	/* Reference to the associated drm_plane */
> +	struct drm_plane *plane;
> +};
> +
> +/* global atomic state of assignment between pipes and planes: */
> +struct omap_hw_overlay_state {
> +	struct drm_plane *hwoverlay_to_plane[8];
> +};
> +
> +/* Global private object state for tracking resources that are shared across
> + * multiple kms objects (planes/crtcs/etc).
> + */

This doesn't follow the kernel comment style.

> +#define to_omap_global_state(x) container_of(x, struct omap_global_state, base)
> +struct omap_global_state {
> +	struct drm_private_state base;
> +
> +	struct drm_atomic_state *state;
> +
> +	struct omap_hw_overlay_state overlay;
> +};
> +
> +static inline const char *overlay2name(enum omap_plane_id id)
> +{
> +	static const char *name[] = {
> +		[OMAP_DSS_GFX] = "gfx",
> +		[OMAP_DSS_VIDEO1] = "vid1",
> +		[OMAP_DSS_VIDEO2] = "vid2",
> +		[OMAP_DSS_VIDEO3] = "vid3",
> +	};
> +	return name[id];
> +}
> +
> +int omap_hwoverlays_init(struct omap_drm_private *priv);
> +void omap_global_obj_fini(struct omap_drm_private *priv);
> +void omap_hwoverlays_destroy(struct omap_drm_private *priv);
> +int omap_global_obj_init(struct omap_drm_private *priv);
> +int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
> +			u32 caps, u32 fourcc, u32 crtc_mask,
> +			struct omap_hw_overlay **overlay,
> +			struct omap_hw_overlay **r_overlay);
> +void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay);
> +void omap_overlay_disable_unassigned(struct drm_atomic_state *s);
> +
> +#endif /* __OMAPDRM_OVERLAY_H__ */
> diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
> index 161233cbc9a0..01f1da155994 100644
> --- a/drivers/gpu/drm/omapdrm/omap_plane.c
> +++ b/drivers/gpu/drm/omapdrm/omap_plane.c
> @@ -30,10 +30,12 @@
>  
>  struct omap_plane {
>  	struct drm_plane base;
> -	enum omap_plane_id id;
> +	enum omap_plane_id default_id;
>  	const char *name;
>  };
>  
> +static const char *plane_id_to_name[];
> +
>  static int omap_plane_prepare_fb(struct drm_plane *plane,
>  				 struct drm_plane_state *new_state)
>  {
> @@ -50,15 +52,26 @@ static void omap_plane_cleanup_fb(struct drm_plane *plane,
>  		omap_framebuffer_unpin(old_state->fb);
>  }
>  
> +static bool plane_enabled(struct drm_plane_state *state)
> +{
> +	return state->visible;
> +}
> +
>  static void omap_plane_atomic_update(struct drm_plane *plane,
>  				     struct drm_plane_state *old_state)
>  {
>  	struct omap_drm_private *priv = plane->dev->dev_private;
>  	struct omap_plane *omap_plane = to_omap_plane(plane);
>  	struct drm_plane_state *state = plane->state;
> -	struct omap_overlay_info info;
> +	struct omap_plane_state *omap_state = to_omap_plane_state(state);
> +	struct omap_overlay_info info, r_info;
> +	enum omap_plane_id ovl_id, r_ovl_id;
>  	int ret;
> +	bool dual_plane = !!omap_state->r_overlay;
>  
> +	ovl_id = omap_state->overlay->overlay_id;
> +	DBG("[PLANE:%d:%s] overlay_id: %d\n", plane->base.id, plane->name,
> +	    ovl_id);
>  	DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb);
>  
>  	memset(&info, 0, sizeof(info));
> @@ -67,75 +80,231 @@ static void omap_plane_atomic_update(struct drm_plane *plane,
>  	info.global_alpha = 0xff;
>  	info.zorder = state->normalized_zpos;
>  
> +	r_info = info;
> +
>  	/* update scanout: */
> -	omap_framebuffer_update_scanout(state->fb, state, &info);
> +	omap_framebuffer_update_scanout(state->fb, state, &info,
> +					dual_plane ? &r_info : NULL);
>  
> -	DBG("%dx%d -> %dx%d (%d)", info.width, info.height,
> -			info.out_width, info.out_height,
> -			info.screen_width);
> +	DBG("%s: %dx%d -> %dx%d (%d)",
> +	    overlay2name(ovl_id), info.width, info.height,
> +	    info.out_width, info.out_height, info.screen_width);
>  	DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
> -			&info.paddr, &info.p_uv_addr);
> +	    &info.paddr, &info.p_uv_addr);
> +
> +	if (dual_plane) {
> +		r_ovl_id = omap_state->r_overlay->overlay_id;
> +		/*
> +		 * If the current plane uses 2 hw planes the very next
> +		 * zorder is used by the r_overlay so we just use the
> +		 * main overlay zorder + 1
> +		 */
> +		r_info.zorder = info.zorder + 1;
> +
> +		DBG("%s: %dx%d -> %dx%d (%d)",
> +		    overlay2name(r_ovl_id), r_info.width, r_info.height,
> +		    r_info.out_width, r_info.out_height, r_info.screen_width);
> +		DBG("%d,%d %pad %pad", r_info.pos_x, r_info.pos_y,
> +		    &r_info.paddr, &r_info.p_uv_addr);
> +	}
>  
>  	/* and finally, update omapdss: */
> -	ret = priv->dispc_ops->ovl_setup(priv->dispc, omap_plane->id, &info,
> +	ret = priv->dispc_ops->ovl_setup(priv->dispc, ovl_id, &info,
>  			      omap_crtc_timings(state->crtc), false,
>  			      omap_crtc_channel(state->crtc));
>  	if (ret) {
> -		dev_err(plane->dev->dev, "Failed to setup plane %s\n",
> +		dev_err(plane->dev->dev, "Failed to setup plane1 %s\n",
>  			omap_plane->name);
> -		priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false);
> +		priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, false);
>  		return;
>  	}
>  
> -	priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, true);
> +	priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, true);
> +
> +	if (dual_plane) {
> +		ret = priv->dispc_ops->ovl_setup(priv->dispc, r_ovl_id, &r_info,
> +				      omap_crtc_timings(state->crtc), false,
> +				      omap_crtc_channel(state->crtc));
> +		if (ret) {
> +			dev_err(plane->dev->dev, "Failed to setup plane2 %s\n",
> +				omap_plane->name);
> +			priv->dispc_ops->ovl_enable(priv->dispc, r_ovl_id, false);
> +			priv->dispc_ops->ovl_enable(priv->dispc, ovl_id, false);
> +			return;
> +		}
> +
> +		priv->dispc_ops->ovl_enable(priv->dispc, r_ovl_id, true);
> +	}
>  }
>  
>  static void omap_plane_atomic_disable(struct drm_plane *plane,
>  				      struct drm_plane_state *old_state)
>  {
>  	struct omap_drm_private *priv = plane->dev->dev_private;
> -	struct omap_plane *omap_plane = to_omap_plane(plane);
> +	struct omap_plane_state *omap_state = to_omap_plane_state(old_state);
> +	bool dual_plane = !!omap_state->r_overlay;
> +
> +	DBG("%s: check (overlay %p r_overlay %p)", plane->name,
> +	    omap_state->overlay, omap_state->r_overlay);
> +
> +	if (!omap_state->overlay)
> +		return;
>  
>  	plane->state->rotation = DRM_MODE_ROTATE_0;
>  	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
> -			   ? 0 : omap_plane->id;
> -
> -	priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false);
> +			   ? 0 : omap_state->overlay->overlay_id;
> +
> +	priv->dispc_ops->ovl_enable(priv->dispc, omap_state->overlay->overlay_id, false);
> +	omap_overlay_release(old_state->state, omap_state->overlay);
> +	omap_state->overlay = NULL;
> +	if (dual_plane) {
> +		priv->dispc_ops->ovl_enable(priv->dispc, omap_state->r_overlay->overlay_id, false);
> +		omap_overlay_release(old_state->state, omap_state->r_overlay);
> +		omap_state->r_overlay = NULL;
> +	}
>  }
>  
> +#define FRAC_16_16(mult, div)    (((mult) << 16) / (div))
>  static int omap_plane_atomic_check(struct drm_plane *plane,
>  				   struct drm_plane_state *state)
>  {
> +	struct omap_drm_private *priv = plane->dev->dev_private;
> +	struct drm_crtc *crtc;	
>  	struct drm_crtc_state *crtc_state;
> +	struct drm_plane_state *old_state = plane->state;
> +	struct omap_plane_state *omap_state = to_omap_plane_state(state);
> +	const struct dispc_ops *ops = priv->dispc_ops;
> +	u16 width, height;
> +	u32 crtc_mask;
> +	u32 fourcc;
> +	u32 caps = 0;
> +	bool new_hw_overlay = false;
> +	bool new_r_hw_overlay = false;
> +	bool out_of_bounds = false;
> +	int min_scale, max_scale;
> +	u32 max_width, max_height;
> +	int ret;
>  
> -	if (!state->fb)
> -		return 0;
> +	DBG("%s: check (%d -> %d)", plane->name,
> +	    plane_enabled(old_state), plane_enabled(state));
> +
> +	priv->dispc_ops->ovl_get_max_size(priv->dispc, &width, &height);
> +	max_width = width << 16;
> +	max_height = height << 16;
>  
> -	/* crtc should only be NULL when disabling (i.e., !state->fb) */
> -	if (WARN_ON(!state->crtc))
> +	crtc = state->crtc ? state->crtc : plane->state->crtc;
> +	if (!crtc)
>  		return 0;
>  
> -	crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
> +	crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
>  	/* we should have a crtc state if the plane is attached to a crtc */
>  	if (WARN_ON(!crtc_state))
>  		return 0;
>  
> -	if (!crtc_state->enable)
> -		return 0;
> +	/* Make sure source dimensions are within bounds. */
> +	if (state->src_h > max_height)
> +		out_of_bounds = true;
>  
> -	if (state->crtc_x < 0 || state->crtc_y < 0)
> -		return -EINVAL;
> +	if (state->src_w > max_width) {
> +		if (state->src_w <= (2 * max_width))
> +			new_r_hw_overlay = true;
> +		else
> +			out_of_bounds = true;
> +	}
>  
> -	if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay)
> -		return -EINVAL;
> +	if (out_of_bounds) {
> +		struct drm_rect src = drm_plane_state_src(state);
> +		DBG("Invalid source size "DRM_RECT_FP_FMT,
> +		    DRM_RECT_FP_ARG(&src));
> +		return -ERANGE;
> +	}
>  
> -	if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)
> -		return -EINVAL;
> +	min_scale = FRAC_16_16(1, 4);
> +	max_scale = FRAC_16_16(8, 1);
> +
> +	ret = drm_atomic_helper_check_plane_state(state, crtc_state,
> +						  min_scale, max_scale,
> +						  true, true);
> +	if (ret)
> +		return ret;
>  
>  	if (state->rotation != DRM_MODE_ROTATE_0 &&
>  	    !omap_framebuffer_supports_rotation(state->fb))
>  		return -EINVAL;
>  
> +	if (plane_enabled(state)) {
> +		if ((state->src_w >> 16) != state->crtc_w ||
> +		    (state->src_h >> 16) != state->crtc_h)
> +			caps |= OMAP_DSS_OVL_CAP_SCALE;
> +
> +		fourcc = state->fb->format->format;
> +		crtc_mask = drm_crtc_mask(state->crtc);
> +
> +		/* (re)allocate hw overlay if we don't have one or caps-mismatch: */
> +		if (!omap_state->overlay || (caps & ~omap_state->overlay->caps)) {
> +			new_hw_overlay = true;
> +		} else {
> +			/* check if allowed on crtc */
> +			if (!(omap_state->overlay->possible_crtcs & crtc_mask))
> +				new_hw_overlay = true;
> +
> +			/* check supported format */
> +			if (!ops->ovl_color_mode_supported(priv->dispc,
> +						omap_state->overlay->overlay_id,
> +						fourcc))
> +				new_hw_overlay = true;
> +		}
> +		/* 
> +		 * check if we need two overlays and only have 1 or
> +		 * if we had 2 overlays but will only need 1
> +		 */ 
> +		if ((new_r_hw_overlay && !omap_state->r_overlay) ||
> +		    (!new_r_hw_overlay && omap_state->r_overlay))
> +			new_hw_overlay = true;
> +
> +		if (new_hw_overlay) {
> +			struct omap_hw_overlay *old_ovl = 
> +						omap_state->overlay;
> +			struct omap_hw_overlay *old_r_ovl = 
> +						omap_state->r_overlay;
> +			struct omap_hw_overlay *new_ovl = NULL;
> +			struct omap_hw_overlay *new_r_ovl = NULL;
> +
> +			omap_overlay_release(state->state, old_ovl);
> +			omap_overlay_release(state->state, old_r_ovl);
> +
> +			ret = omap_overlay_assign(state->state, plane, caps,
> +						  fourcc, crtc_mask, &new_ovl,
> +						  new_r_hw_overlay ?
> +						  &new_r_ovl : NULL);
> +			if (ret) {
> +				DBG("%s: failed to assign hw_overlay(s)!",
> +				    plane->name);
> +				omap_state->overlay = NULL;
> +				omap_state->r_overlay = NULL;
> +				return ret;
> +			}
> +
> +			omap_state->overlay = new_ovl;
> +			if (new_r_hw_overlay)
> +				omap_state->r_overlay = new_r_ovl;
> +			else
> +				omap_state->r_overlay = NULL;
> +		}
> +	} else {
> +		omap_overlay_release(state->state, omap_state->overlay);
> +		omap_overlay_release(state->state, omap_state->r_overlay);
> +		omap_state->overlay = NULL;
> +		omap_state->r_overlay = NULL;
> +	}
> +
> +	if (omap_state->overlay)
> +		DBG("plane: %s overlay_id: %d", plane->name,
> +		    omap_state->overlay->overlay_id);
> +	if (omap_state->r_overlay)
> +		DBG("plane: %s r_overlay_id: %d", plane->name,
> +		    omap_state->r_overlay->overlay_id);
> +
>  	return 0;
>  }
>  
> @@ -182,20 +351,77 @@ void omap_plane_install_properties(struct drm_plane *plane,
>  	drm_object_attach_property(obj, priv->zorder_prop, 0);
>  }
>  
> +/* Add duplicate and destroy state helper */
> +static struct drm_plane_state *
> +omap_plane_atomic_duplicate_state(struct drm_plane *plane)
> +{
> +	struct omap_plane_state *state;
> +	struct omap_plane_state *copy;
> +
> +	if (WARN_ON(!plane->state))
> +		return NULL;
> +
> +	state = to_omap_plane_state(plane->state);
> +	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
> +	if (copy == NULL)
> +		return NULL;
> +
> +	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
> +
> +	return &copy->base;
> +}
> +
> +static void omap_plane_atomic_destroy_state(struct drm_plane *plane,
> +					    struct drm_plane_state *state)
> +{
> +	__drm_atomic_helper_plane_destroy_state(state);
> +	kfree(to_omap_plane_state(state));
> +}
> +
>  static void omap_plane_reset(struct drm_plane *plane)
>  {
>  	struct omap_plane *omap_plane = to_omap_plane(plane);
> +	struct omap_plane_state *omap_state;
> +
> +	if (plane->state)
> +		omap_plane_atomic_destroy_state(plane, plane->state);
>  
> -	drm_atomic_helper_plane_reset(plane);
> -	if (!plane->state)
> +	omap_state = kzalloc(sizeof(*omap_state), GFP_KERNEL);
> +	if (!omap_state)
>  		return;
>  
> +	omap_state->base.plane = plane;
> +	plane->state = &omap_state->base;
> +	plane->state->plane = plane;
> +	plane->state->rotation = DRM_MODE_ROTATE_0;
>  	/*
>  	 * Set the zpos default depending on whether we are a primary or overlay
>  	 * plane.
>  	 */
>  	plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
> -			   ? 0 : omap_plane->id;
> +			   ? 0 : omap_plane->default_id;
> +}
> +
> +static void omap_plane_atomic_print_state(struct drm_printer *p,
> +		const struct drm_plane_state *state)
> +{
> +	struct omap_plane_state *omap_state = to_omap_plane_state(state);
> +
> +	drm_printf(p, "\toverlay=%p\n", omap_state->overlay);
> +	if (omap_state->overlay) {
> +		drm_printf(p, "\t\tidx=%d\n", omap_state->overlay->idx);
> +		drm_printf(p, "\t\toverlay_id=%d\n", omap_state->overlay->overlay_id);
> +		drm_printf(p, "\t\tcaps=0x%x\n", omap_state->overlay->caps);
> +		drm_printf(p, "\t\tpossible_crtcs=0x%x\n", omap_state->overlay->possible_crtcs);
> +	}
> +
> +	drm_printf(p, "\tr_overlay=%p\n", omap_state->r_overlay);
> +	if (omap_state->r_overlay) {
> +		drm_printf(p, "\t\tidx=%d\n", omap_state->r_overlay->idx);
> +		drm_printf(p, "\t\toverlay_id=%d\n", omap_state->r_overlay->overlay_id);
> +		drm_printf(p, "\t\tcaps=0x%x\n", omap_state->r_overlay->caps);
> +		drm_printf(p, "\t\tpossible_crtcs=0x%x\n", omap_state->r_overlay->possible_crtcs);
> +	}
>  }
>  
>  static int omap_plane_atomic_set_property(struct drm_plane *plane,
> @@ -233,10 +459,11 @@ static const struct drm_plane_funcs omap_plane_funcs = {
>  	.disable_plane = drm_atomic_helper_disable_plane,
>  	.reset = omap_plane_reset,
>  	.destroy = omap_plane_destroy,
> -	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> -	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +	.atomic_duplicate_state = omap_plane_atomic_duplicate_state,
> +	.atomic_destroy_state = omap_plane_atomic_destroy_state,
>  	.atomic_set_property = omap_plane_atomic_set_property,
>  	.atomic_get_property = omap_plane_atomic_get_property,
> +	.atomic_print_state = omap_plane_atomic_print_state,
>  };
>  
>  static const char *plane_id_to_name[] = {
> @@ -246,14 +473,6 @@ static const char *plane_id_to_name[] = {
>  	[OMAP_DSS_VIDEO3] = "vid3",
>  };
>  
> -static const enum omap_plane_id plane_idx_to_id[] = {
> -	OMAP_DSS_GFX,
> -	OMAP_DSS_VIDEO1,
> -	OMAP_DSS_VIDEO2,
> -	OMAP_DSS_VIDEO3,
> -};
> -
> -/* initialize plane */
>  struct drm_plane *omap_plane_init(struct drm_device *dev,
>  		int idx, enum drm_plane_type type,
>  		u32 possible_crtcs)
> @@ -262,27 +481,28 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
>  	unsigned int num_planes = priv->dispc_ops->get_num_ovls(priv->dispc);
>  	struct drm_plane *plane;
>  	struct omap_plane *omap_plane;
> -	enum omap_plane_id id;
>  	int ret;
>  	u32 nformats;
>  	const u32 *formats;
>  
> -	if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id)))
> +	if (WARN_ON(idx >= num_planes))
>  		return ERR_PTR(-EINVAL);
>  
> -	id = plane_idx_to_id[idx];
> -
> -	DBG("%s: type=%d", plane_id_to_name[id], type);
> -
>  	omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
>  	if (!omap_plane)
>  		return ERR_PTR(-ENOMEM);
>  
> -	formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc, id);
> +	omap_plane->default_id = idx;
> +	omap_plane->name = plane_id_to_name[idx];
> +
> +	DBG("%s: type=%d", omap_plane->name, type);
> +	DBG("	omap_plane->default_id: %d", omap_plane->default_id);
> +	DBG("	crtc_mask: 0x%04x", possible_crtcs);
> +
> +	formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc,
> +						       omap_plane->default_id);
>  	for (nformats = 0; formats[nformats]; ++nformats)
>  		;
> -	omap_plane->id = id;
> -	omap_plane->name = plane_id_to_name[id];
>  
>  	plane = &omap_plane->base;
>  
> @@ -301,7 +521,7 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
>  
>  error:
>  	dev_err(dev->dev, "%s(): could not create plane: %s\n",
> -		__func__, plane_id_to_name[id]);
> +		__func__, omap_plane->name);
>  
>  	kfree(omap_plane);
>  	return NULL;
> diff --git a/drivers/gpu/drm/omapdrm/omap_plane.h b/drivers/gpu/drm/omapdrm/omap_plane.h
> index dc5e82ad061d..9000f45a9b65 100644
> --- a/drivers/gpu/drm/omapdrm/omap_plane.h
> +++ b/drivers/gpu/drm/omapdrm/omap_plane.h
> @@ -28,10 +28,30 @@ struct drm_device;
>  struct drm_mode_object;
>  struct drm_plane;
>  
> +/*
> + * Atomic plane state. Subclasses the base drm_plane_state in order to
> + * track assigned overlay and hw specific state.
> + */
> +struct omap_plane_state {
> +	struct drm_plane_state base;
> +
> +	struct omap_hw_overlay *overlay;
> +	struct omap_hw_overlay *r_overlay;  /* right overlay */
> +};
> +#define to_omap_plane_state(x) \
> +		container_of(x, struct omap_plane_state, base)
> +
>  struct drm_plane *omap_plane_init(struct drm_device *dev,
>  		int idx, enum drm_plane_type type,
>  		u32 possible_crtcs);
>  void omap_plane_install_properties(struct drm_plane *plane,
>  		struct drm_mode_object *obj);
>  
> +static inline bool is_omap_plane_dual_overlay(struct drm_plane_state *state)
> +{
> +	struct omap_plane_state *omap_state = to_omap_plane_state(state);
> +
> +	return !!omap_state->r_overlay;
> +}
> +
>  #endif /* __OMAPDRM_PLANE_H__ */
> 

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki


More information about the dri-devel mailing list