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 <[email protected]>
> ---
>  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, <[email protected]>
> + */
> +
> +#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, <[email protected]>
> + */
> +
> +#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
_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to