[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, ©->base);
> +
> + return ©->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