linux/drivers/gpu/drm/omapdrm/omap_plane.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
   4 * Author: Rob Clark <rob.clark@linaro.org>
   5 */
   6
   7#include <drm/drm_atomic.h>
   8#include <drm/drm_atomic_helper.h>
   9#include <drm/drm_plane_helper.h>
  10
  11#include "omap_dmm_tiler.h"
  12#include "omap_drv.h"
  13
  14/*
  15 * plane funcs
  16 */
  17
  18#define to_omap_plane(x) container_of(x, struct omap_plane, base)
  19
  20struct omap_plane {
  21        struct drm_plane base;
  22        enum omap_plane_id id;
  23        const char *name;
  24};
  25
  26static int omap_plane_prepare_fb(struct drm_plane *plane,
  27                                 struct drm_plane_state *new_state)
  28{
  29        if (!new_state->fb)
  30                return 0;
  31
  32        return omap_framebuffer_pin(new_state->fb);
  33}
  34
  35static void omap_plane_cleanup_fb(struct drm_plane *plane,
  36                                  struct drm_plane_state *old_state)
  37{
  38        if (old_state->fb)
  39                omap_framebuffer_unpin(old_state->fb);
  40}
  41
  42static void omap_plane_atomic_update(struct drm_plane *plane,
  43                                     struct drm_plane_state *old_state)
  44{
  45        struct omap_drm_private *priv = plane->dev->dev_private;
  46        struct omap_plane *omap_plane = to_omap_plane(plane);
  47        struct drm_plane_state *state = plane->state;
  48        struct omap_overlay_info info;
  49        int ret;
  50
  51        DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb);
  52
  53        memset(&info, 0, sizeof(info));
  54        info.rotation_type = OMAP_DSS_ROT_NONE;
  55        info.rotation = DRM_MODE_ROTATE_0;
  56        info.global_alpha = state->alpha >> 8;
  57        info.zorder = state->normalized_zpos;
  58        if (state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
  59                info.pre_mult_alpha = 1;
  60        else
  61                info.pre_mult_alpha = 0;
  62
  63        /* update scanout: */
  64        omap_framebuffer_update_scanout(state->fb, state, &info);
  65
  66        DBG("%dx%d -> %dx%d (%d)", info.width, info.height,
  67                        info.out_width, info.out_height,
  68                        info.screen_width);
  69        DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
  70                        &info.paddr, &info.p_uv_addr);
  71
  72        /* and finally, update omapdss: */
  73        ret = priv->dispc_ops->ovl_setup(priv->dispc, omap_plane->id, &info,
  74                              omap_crtc_timings(state->crtc), false,
  75                              omap_crtc_channel(state->crtc));
  76        if (ret) {
  77                dev_err(plane->dev->dev, "Failed to setup plane %s\n",
  78                        omap_plane->name);
  79                priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false);
  80                return;
  81        }
  82
  83        priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, true);
  84}
  85
  86static void omap_plane_atomic_disable(struct drm_plane *plane,
  87                                      struct drm_plane_state *old_state)
  88{
  89        struct omap_drm_private *priv = plane->dev->dev_private;
  90        struct omap_plane *omap_plane = to_omap_plane(plane);
  91
  92        plane->state->rotation = DRM_MODE_ROTATE_0;
  93        plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
  94                           ? 0 : omap_plane->id;
  95
  96        priv->dispc_ops->ovl_enable(priv->dispc, omap_plane->id, false);
  97}
  98
  99static int omap_plane_atomic_check(struct drm_plane *plane,
 100                                   struct drm_plane_state *state)
 101{
 102        struct drm_crtc_state *crtc_state;
 103
 104        if (!state->fb)
 105                return 0;
 106
 107        /* crtc should only be NULL when disabling (i.e., !state->fb) */
 108        if (WARN_ON(!state->crtc))
 109                return 0;
 110
 111        crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
 112        /* we should have a crtc state if the plane is attached to a crtc */
 113        if (WARN_ON(!crtc_state))
 114                return 0;
 115
 116        if (!crtc_state->enable)
 117                return 0;
 118
 119        if (state->crtc_x < 0 || state->crtc_y < 0)
 120                return -EINVAL;
 121
 122        if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay)
 123                return -EINVAL;
 124
 125        if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)
 126                return -EINVAL;
 127
 128        if (state->rotation != DRM_MODE_ROTATE_0 &&
 129            !omap_framebuffer_supports_rotation(state->fb))
 130                return -EINVAL;
 131
 132        return 0;
 133}
 134
 135static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
 136        .prepare_fb = omap_plane_prepare_fb,
 137        .cleanup_fb = omap_plane_cleanup_fb,
 138        .atomic_check = omap_plane_atomic_check,
 139        .atomic_update = omap_plane_atomic_update,
 140        .atomic_disable = omap_plane_atomic_disable,
 141};
 142
 143static void omap_plane_destroy(struct drm_plane *plane)
 144{
 145        struct omap_plane *omap_plane = to_omap_plane(plane);
 146
 147        DBG("%s", omap_plane->name);
 148
 149        drm_plane_cleanup(plane);
 150
 151        kfree(omap_plane);
 152}
 153
 154/* helper to install properties which are common to planes and crtcs */
 155void omap_plane_install_properties(struct drm_plane *plane,
 156                struct drm_mode_object *obj)
 157{
 158        struct drm_device *dev = plane->dev;
 159        struct omap_drm_private *priv = dev->dev_private;
 160
 161        if (priv->has_dmm) {
 162                if (!plane->rotation_property)
 163                        drm_plane_create_rotation_property(plane,
 164                                                           DRM_MODE_ROTATE_0,
 165                                                           DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
 166                                                           DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
 167                                                           DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
 168
 169                /* Attach the rotation property also to the crtc object */
 170                if (plane->rotation_property && obj != &plane->base)
 171                        drm_object_attach_property(obj, plane->rotation_property,
 172                                                   DRM_MODE_ROTATE_0);
 173        }
 174
 175        drm_object_attach_property(obj, priv->zorder_prop, 0);
 176}
 177
 178static void omap_plane_reset(struct drm_plane *plane)
 179{
 180        struct omap_plane *omap_plane = to_omap_plane(plane);
 181
 182        drm_atomic_helper_plane_reset(plane);
 183        if (!plane->state)
 184                return;
 185
 186        /*
 187         * Set the zpos default depending on whether we are a primary or overlay
 188         * plane.
 189         */
 190        plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
 191                           ? 0 : omap_plane->id;
 192}
 193
 194static int omap_plane_atomic_set_property(struct drm_plane *plane,
 195                                          struct drm_plane_state *state,
 196                                          struct drm_property *property,
 197                                          u64 val)
 198{
 199        struct omap_drm_private *priv = plane->dev->dev_private;
 200
 201        if (property == priv->zorder_prop)
 202                state->zpos = val;
 203        else
 204                return -EINVAL;
 205
 206        return 0;
 207}
 208
 209static int omap_plane_atomic_get_property(struct drm_plane *plane,
 210                                          const struct drm_plane_state *state,
 211                                          struct drm_property *property,
 212                                          u64 *val)
 213{
 214        struct omap_drm_private *priv = plane->dev->dev_private;
 215
 216        if (property == priv->zorder_prop)
 217                *val = state->zpos;
 218        else
 219                return -EINVAL;
 220
 221        return 0;
 222}
 223
 224static const struct drm_plane_funcs omap_plane_funcs = {
 225        .update_plane = drm_atomic_helper_update_plane,
 226        .disable_plane = drm_atomic_helper_disable_plane,
 227        .reset = omap_plane_reset,
 228        .destroy = omap_plane_destroy,
 229        .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 230        .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
 231        .atomic_set_property = omap_plane_atomic_set_property,
 232        .atomic_get_property = omap_plane_atomic_get_property,
 233};
 234
 235static const char *plane_id_to_name[] = {
 236        [OMAP_DSS_GFX] = "gfx",
 237        [OMAP_DSS_VIDEO1] = "vid1",
 238        [OMAP_DSS_VIDEO2] = "vid2",
 239        [OMAP_DSS_VIDEO3] = "vid3",
 240};
 241
 242static const enum omap_plane_id plane_idx_to_id[] = {
 243        OMAP_DSS_GFX,
 244        OMAP_DSS_VIDEO1,
 245        OMAP_DSS_VIDEO2,
 246        OMAP_DSS_VIDEO3,
 247};
 248
 249/* initialize plane */
 250struct drm_plane *omap_plane_init(struct drm_device *dev,
 251                int idx, enum drm_plane_type type,
 252                u32 possible_crtcs)
 253{
 254        struct omap_drm_private *priv = dev->dev_private;
 255        unsigned int num_planes = priv->dispc_ops->get_num_ovls(priv->dispc);
 256        struct drm_plane *plane;
 257        struct omap_plane *omap_plane;
 258        enum omap_plane_id id;
 259        int ret;
 260        u32 nformats;
 261        const u32 *formats;
 262
 263        if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id)))
 264                return ERR_PTR(-EINVAL);
 265
 266        id = plane_idx_to_id[idx];
 267
 268        DBG("%s: type=%d", plane_id_to_name[id], type);
 269
 270        omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
 271        if (!omap_plane)
 272                return ERR_PTR(-ENOMEM);
 273
 274        formats = priv->dispc_ops->ovl_get_color_modes(priv->dispc, id);
 275        for (nformats = 0; formats[nformats]; ++nformats)
 276                ;
 277        omap_plane->id = id;
 278        omap_plane->name = plane_id_to_name[id];
 279
 280        plane = &omap_plane->base;
 281
 282        ret = drm_universal_plane_init(dev, plane, possible_crtcs,
 283                                       &omap_plane_funcs, formats,
 284                                       nformats, NULL, type, NULL);
 285        if (ret < 0)
 286                goto error;
 287
 288        drm_plane_helper_add(plane, &omap_plane_helper_funcs);
 289
 290        omap_plane_install_properties(plane, &plane->base);
 291        drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1);
 292        drm_plane_create_alpha_property(plane);
 293        drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) |
 294                                             BIT(DRM_MODE_BLEND_COVERAGE));
 295
 296        return plane;
 297
 298error:
 299        dev_err(dev->dev, "%s(): could not create plane: %s\n",
 300                __func__, plane_id_to_name[id]);
 301
 302        kfree(omap_plane);
 303        return NULL;
 304}
 305