linux/drivers/gpu/drm/armada/armada_overlay.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2012 Russell King
   4 *  Rewritten from the dovefb driver, and Armada510 manuals.
   5 */
   6
   7#include <drm/armada_drm.h>
   8#include <drm/drm_atomic.h>
   9#include <drm/drm_atomic_helper.h>
  10#include <drm/drm_atomic_uapi.h>
  11#include <drm/drm_fourcc.h>
  12#include <drm/drm_plane_helper.h>
  13
  14#include "armada_crtc.h"
  15#include "armada_drm.h"
  16#include "armada_fb.h"
  17#include "armada_gem.h"
  18#include "armada_hw.h"
  19#include "armada_ioctlP.h"
  20#include "armada_plane.h"
  21#include "armada_trace.h"
  22
  23#define DEFAULT_BRIGHTNESS      0
  24#define DEFAULT_CONTRAST        0x4000
  25#define DEFAULT_SATURATION      0x4000
  26#define DEFAULT_ENCODING        DRM_COLOR_YCBCR_BT601
  27
  28struct armada_overlay_state {
  29        struct armada_plane_state base;
  30        u32 colorkey_yr;
  31        u32 colorkey_ug;
  32        u32 colorkey_vb;
  33        u32 colorkey_mode;
  34        u32 colorkey_enable;
  35        s16 brightness;
  36        u16 contrast;
  37        u16 saturation;
  38};
  39#define drm_to_overlay_state(s) \
  40        container_of(s, struct armada_overlay_state, base.base)
  41
  42static inline u32 armada_spu_contrast(struct drm_plane_state *state)
  43{
  44        return drm_to_overlay_state(state)->brightness << 16 |
  45               drm_to_overlay_state(state)->contrast;
  46}
  47
  48static inline u32 armada_spu_saturation(struct drm_plane_state *state)
  49{
  50        /* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */
  51        return drm_to_overlay_state(state)->saturation << 16;
  52}
  53
  54static inline u32 armada_csc(struct drm_plane_state *state)
  55{
  56        /*
  57         * The CFG_CSC_RGB_* settings control the output of the colour space
  58         * converter, setting the range of output values it produces.  Since
  59         * we will be blending with the full-range graphics, we need to
  60         * produce full-range RGB output from the conversion.
  61         */
  62        return CFG_CSC_RGB_COMPUTER |
  63               (state->color_encoding == DRM_COLOR_YCBCR_BT709 ?
  64                        CFG_CSC_YUV_CCIR709 : CFG_CSC_YUV_CCIR601);
  65}
  66
  67/* === Plane support === */
  68static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
  69        struct drm_atomic_state *state)
  70{
  71        struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
  72                                                                           plane);
  73        struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
  74                                                                           plane);
  75        struct armada_crtc *dcrtc;
  76        struct armada_regs *regs;
  77        unsigned int idx;
  78        u32 cfg, cfg_mask, val;
  79
  80        DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
  81
  82        if (!new_state->fb || WARN_ON(!new_state->crtc))
  83                return;
  84
  85        DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
  86                plane->base.id, plane->name,
  87                new_state->crtc->base.id, new_state->crtc->name,
  88                new_state->fb->base.id,
  89                old_state->visible, new_state->visible);
  90
  91        dcrtc = drm_to_armada_crtc(new_state->crtc);
  92        regs = dcrtc->regs + dcrtc->regs_idx;
  93
  94        idx = 0;
  95        if (!old_state->visible && new_state->visible)
  96                armada_reg_queue_mod(regs, idx,
  97                                     0, CFG_PDWN16x66 | CFG_PDWN32x66,
  98                                     LCD_SPU_SRAM_PARA1);
  99        val = armada_src_hw(new_state);
 100        if (armada_src_hw(old_state) != val)
 101                armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN);
 102        val = armada_dst_yx(new_state);
 103        if (armada_dst_yx(old_state) != val)
 104                armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN);
 105        val = armada_dst_hw(new_state);
 106        if (armada_dst_hw(old_state) != val)
 107                armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);
 108        /* FIXME: overlay on an interlaced display */
 109        if (old_state->src.x1 != new_state->src.x1 ||
 110            old_state->src.y1 != new_state->src.y1 ||
 111            old_state->fb != new_state->fb ||
 112            new_state->crtc->state->mode_changed) {
 113                const struct drm_format_info *format;
 114                u16 src_x;
 115
 116                armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),
 117                                     LCD_SPU_DMA_START_ADDR_Y0);
 118                armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 1),
 119                                     LCD_SPU_DMA_START_ADDR_U0);
 120                armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 2),
 121                                     LCD_SPU_DMA_START_ADDR_V0);
 122                armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),
 123                                     LCD_SPU_DMA_START_ADDR_Y1);
 124                armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 1),
 125                                     LCD_SPU_DMA_START_ADDR_U1);
 126                armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 2),
 127                                     LCD_SPU_DMA_START_ADDR_V1);
 128
 129                val = armada_pitch(new_state, 0) << 16 | armada_pitch(new_state,
 130                                                                      0);
 131                armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC);
 132                val = armada_pitch(new_state, 1) << 16 | armada_pitch(new_state,
 133                                                                      2);
 134                armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);
 135
 136                cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |
 137                      CFG_DMA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod) |
 138                      CFG_CBSH_ENA;
 139                if (new_state->visible)
 140                        cfg |= CFG_DMA_ENA;
 141
 142                /*
 143                 * Shifting a YUV packed format image by one pixel causes the
 144                 * U/V planes to swap.  Compensate for it by also toggling
 145                 * the UV swap.
 146                 */
 147                format = new_state->fb->format;
 148                src_x = new_state->src.x1 >> 16;
 149                if (format->num_planes == 1 && src_x & (format->hsub - 1))
 150                        cfg ^= CFG_DMA_MOD(CFG_SWAPUV);
 151                if (to_armada_plane_state(new_state)->interlace)
 152                        cfg |= CFG_DMA_FTOGGLE;
 153                cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |
 154                           CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |
 155                                       CFG_SWAPYU | CFG_YUV2RGB) |
 156                           CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE |
 157                           CFG_DMA_ENA;
 158        } else if (old_state->visible != new_state->visible) {
 159                cfg = new_state->visible ? CFG_DMA_ENA : 0;
 160                cfg_mask = CFG_DMA_ENA;
 161        } else {
 162                cfg = cfg_mask = 0;
 163        }
 164        if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||
 165            drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {
 166                cfg_mask |= CFG_DMA_HSMOOTH;
 167                if (drm_rect_width(&new_state->src) >> 16 !=
 168                    drm_rect_width(&new_state->dst))
 169                        cfg |= CFG_DMA_HSMOOTH;
 170        }
 171
 172        if (cfg_mask)
 173                armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
 174                                     LCD_SPU_DMA_CTRL0);
 175
 176        val = armada_spu_contrast(new_state);
 177        if ((!old_state->visible && new_state->visible) ||
 178            armada_spu_contrast(old_state) != val)
 179                armada_reg_queue_set(regs, idx, val, LCD_SPU_CONTRAST);
 180        val = armada_spu_saturation(new_state);
 181        if ((!old_state->visible && new_state->visible) ||
 182            armada_spu_saturation(old_state) != val)
 183                armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION);
 184        if (!old_state->visible && new_state->visible)
 185                armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE);
 186        val = armada_csc(new_state);
 187        if ((!old_state->visible && new_state->visible) ||
 188            armada_csc(old_state) != val)
 189                armada_reg_queue_mod(regs, idx, val, CFG_CSC_MASK,
 190                                     LCD_SPU_IOPAD_CONTROL);
 191        val = drm_to_overlay_state(new_state)->colorkey_yr;
 192        if ((!old_state->visible && new_state->visible) ||
 193            drm_to_overlay_state(old_state)->colorkey_yr != val)
 194                armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_Y);
 195        val = drm_to_overlay_state(new_state)->colorkey_ug;
 196        if ((!old_state->visible && new_state->visible) ||
 197            drm_to_overlay_state(old_state)->colorkey_ug != val)
 198                armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_U);
 199        val = drm_to_overlay_state(new_state)->colorkey_vb;
 200        if ((!old_state->visible && new_state->visible) ||
 201            drm_to_overlay_state(old_state)->colorkey_vb != val)
 202                armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_V);
 203        val = drm_to_overlay_state(new_state)->colorkey_mode;
 204        if ((!old_state->visible && new_state->visible) ||
 205            drm_to_overlay_state(old_state)->colorkey_mode != val)
 206                armada_reg_queue_mod(regs, idx, val, CFG_CKMODE_MASK |
 207                                     CFG_ALPHAM_MASK | CFG_ALPHA_MASK,
 208                                     LCD_SPU_DMA_CTRL1);
 209        val = drm_to_overlay_state(new_state)->colorkey_enable;
 210        if (((!old_state->visible && new_state->visible) ||
 211             drm_to_overlay_state(old_state)->colorkey_enable != val) &&
 212            dcrtc->variant->has_spu_adv_reg)
 213                armada_reg_queue_mod(regs, idx, val, ADV_GRACOLORKEY |
 214                                     ADV_VIDCOLORKEY, LCD_SPU_ADV_REG);
 215
 216        dcrtc->regs_idx += idx;
 217}
 218
 219static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane,
 220        struct drm_atomic_state *state)
 221{
 222        struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
 223                                                                           plane);
 224        struct armada_crtc *dcrtc;
 225        struct armada_regs *regs;
 226        unsigned int idx = 0;
 227
 228        DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
 229
 230        if (!old_state->crtc)
 231                return;
 232
 233        DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
 234                plane->base.id, plane->name,
 235                old_state->crtc->base.id, old_state->crtc->name,
 236                old_state->fb->base.id);
 237
 238        dcrtc = drm_to_armada_crtc(old_state->crtc);
 239        regs = dcrtc->regs + dcrtc->regs_idx;
 240
 241        /* Disable plane and power down the YUV FIFOs */
 242        armada_reg_queue_mod(regs, idx, 0, CFG_DMA_ENA, LCD_SPU_DMA_CTRL0);
 243        armada_reg_queue_mod(regs, idx, CFG_PDWN16x66 | CFG_PDWN32x66, 0,
 244                             LCD_SPU_SRAM_PARA1);
 245
 246        dcrtc->regs_idx += idx;
 247}
 248
 249static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = {
 250        .atomic_check   = armada_drm_plane_atomic_check,
 251        .atomic_update  = armada_drm_overlay_plane_atomic_update,
 252        .atomic_disable = armada_drm_overlay_plane_atomic_disable,
 253};
 254
 255static int
 256armada_overlay_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
 257        struct drm_framebuffer *fb,
 258        int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h,
 259        uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
 260        struct drm_modeset_acquire_ctx *ctx)
 261{
 262        struct drm_atomic_state *state;
 263        struct drm_plane_state *plane_state;
 264        int ret = 0;
 265
 266        trace_armada_ovl_plane_update(plane, crtc, fb,
 267                                 crtc_x, crtc_y, crtc_w, crtc_h,
 268                                 src_x, src_y, src_w, src_h);
 269
 270        state = drm_atomic_state_alloc(plane->dev);
 271        if (!state)
 272                return -ENOMEM;
 273
 274        state->acquire_ctx = ctx;
 275        plane_state = drm_atomic_get_plane_state(state, plane);
 276        if (IS_ERR(plane_state)) {
 277                ret = PTR_ERR(plane_state);
 278                goto fail;
 279        }
 280
 281        ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
 282        if (ret != 0)
 283                goto fail;
 284
 285        drm_atomic_set_fb_for_plane(plane_state, fb);
 286        plane_state->crtc_x = crtc_x;
 287        plane_state->crtc_y = crtc_y;
 288        plane_state->crtc_h = crtc_h;
 289        plane_state->crtc_w = crtc_w;
 290        plane_state->src_x = src_x;
 291        plane_state->src_y = src_y;
 292        plane_state->src_h = src_h;
 293        plane_state->src_w = src_w;
 294
 295        ret = drm_atomic_nonblocking_commit(state);
 296fail:
 297        drm_atomic_state_put(state);
 298        return ret;
 299}
 300
 301static void armada_ovl_plane_destroy(struct drm_plane *plane)
 302{
 303        drm_plane_cleanup(plane);
 304        kfree(plane);
 305}
 306
 307static void armada_overlay_reset(struct drm_plane *plane)
 308{
 309        struct armada_overlay_state *state;
 310
 311        if (plane->state)
 312                __drm_atomic_helper_plane_destroy_state(plane->state);
 313        kfree(plane->state);
 314        plane->state = NULL;
 315
 316        state = kzalloc(sizeof(*state), GFP_KERNEL);
 317        if (state) {
 318                state->colorkey_yr = 0xfefefe00;
 319                state->colorkey_ug = 0x01010100;
 320                state->colorkey_vb = 0x01010100;
 321                state->colorkey_mode = CFG_CKMODE(CKMODE_RGB) |
 322                                       CFG_ALPHAM_GRA | CFG_ALPHA(0);
 323                state->colorkey_enable = ADV_GRACOLORKEY;
 324                state->brightness = DEFAULT_BRIGHTNESS;
 325                state->contrast = DEFAULT_CONTRAST;
 326                state->saturation = DEFAULT_SATURATION;
 327                __drm_atomic_helper_plane_reset(plane, &state->base.base);
 328                state->base.base.color_encoding = DEFAULT_ENCODING;
 329                state->base.base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
 330        }
 331}
 332
 333static struct drm_plane_state *
 334armada_overlay_duplicate_state(struct drm_plane *plane)
 335{
 336        struct armada_overlay_state *state;
 337
 338        if (WARN_ON(!plane->state))
 339                return NULL;
 340
 341        state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
 342        if (state)
 343                __drm_atomic_helper_plane_duplicate_state(plane,
 344                                                          &state->base.base);
 345        return &state->base.base;
 346}
 347
 348static int armada_overlay_set_property(struct drm_plane *plane,
 349        struct drm_plane_state *state, struct drm_property *property,
 350        uint64_t val)
 351{
 352        struct armada_private *priv = drm_to_armada_dev(plane->dev);
 353
 354#define K2R(val) (((val) >> 0) & 0xff)
 355#define K2G(val) (((val) >> 8) & 0xff)
 356#define K2B(val) (((val) >> 16) & 0xff)
 357        if (property == priv->colorkey_prop) {
 358#define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8)
 359                drm_to_overlay_state(state)->colorkey_yr = CCC(K2R(val));
 360                drm_to_overlay_state(state)->colorkey_ug = CCC(K2G(val));
 361                drm_to_overlay_state(state)->colorkey_vb = CCC(K2B(val));
 362#undef CCC
 363        } else if (property == priv->colorkey_min_prop) {
 364                drm_to_overlay_state(state)->colorkey_yr &= ~0x00ff0000;
 365                drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 16;
 366                drm_to_overlay_state(state)->colorkey_ug &= ~0x00ff0000;
 367                drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 16;
 368                drm_to_overlay_state(state)->colorkey_vb &= ~0x00ff0000;
 369                drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 16;
 370        } else if (property == priv->colorkey_max_prop) {
 371                drm_to_overlay_state(state)->colorkey_yr &= ~0xff000000;
 372                drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 24;
 373                drm_to_overlay_state(state)->colorkey_ug &= ~0xff000000;
 374                drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 24;
 375                drm_to_overlay_state(state)->colorkey_vb &= ~0xff000000;
 376                drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 24;
 377        } else if (property == priv->colorkey_val_prop) {
 378                drm_to_overlay_state(state)->colorkey_yr &= ~0x0000ff00;
 379                drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 8;
 380                drm_to_overlay_state(state)->colorkey_ug &= ~0x0000ff00;
 381                drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 8;
 382                drm_to_overlay_state(state)->colorkey_vb &= ~0x0000ff00;
 383                drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 8;
 384        } else if (property == priv->colorkey_alpha_prop) {
 385                drm_to_overlay_state(state)->colorkey_yr &= ~0x000000ff;
 386                drm_to_overlay_state(state)->colorkey_yr |= K2R(val);
 387                drm_to_overlay_state(state)->colorkey_ug &= ~0x000000ff;
 388                drm_to_overlay_state(state)->colorkey_ug |= K2G(val);
 389                drm_to_overlay_state(state)->colorkey_vb &= ~0x000000ff;
 390                drm_to_overlay_state(state)->colorkey_vb |= K2B(val);
 391        } else if (property == priv->colorkey_mode_prop) {
 392                if (val == CKMODE_DISABLE) {
 393                        drm_to_overlay_state(state)->colorkey_mode =
 394                                CFG_CKMODE(CKMODE_DISABLE) |
 395                                CFG_ALPHAM_CFG | CFG_ALPHA(255);
 396                        drm_to_overlay_state(state)->colorkey_enable = 0;
 397                } else {
 398                        drm_to_overlay_state(state)->colorkey_mode =
 399                                CFG_CKMODE(val) |
 400                                CFG_ALPHAM_GRA | CFG_ALPHA(0);
 401                        drm_to_overlay_state(state)->colorkey_enable =
 402                                ADV_GRACOLORKEY;
 403                }
 404        } else if (property == priv->brightness_prop) {
 405                drm_to_overlay_state(state)->brightness = val - 256;
 406        } else if (property == priv->contrast_prop) {
 407                drm_to_overlay_state(state)->contrast = val;
 408        } else if (property == priv->saturation_prop) {
 409                drm_to_overlay_state(state)->saturation = val;
 410        } else {
 411                return -EINVAL;
 412        }
 413        return 0;
 414}
 415
 416static int armada_overlay_get_property(struct drm_plane *plane,
 417        const struct drm_plane_state *state, struct drm_property *property,
 418        uint64_t *val)
 419{
 420        struct armada_private *priv = drm_to_armada_dev(plane->dev);
 421
 422#define C2K(c,s)        (((c) >> (s)) & 0xff)
 423#define R2BGR(r,g,b,s)  (C2K(r,s) << 0 | C2K(g,s) << 8 | C2K(b,s) << 16)
 424        if (property == priv->colorkey_prop) {
 425                /* Do best-efforts here for this property */
 426                *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
 427                             drm_to_overlay_state(state)->colorkey_ug,
 428                             drm_to_overlay_state(state)->colorkey_vb, 16);
 429                /* If min != max, or min != val, error out */
 430                if (*val != R2BGR(drm_to_overlay_state(state)->colorkey_yr,
 431                                  drm_to_overlay_state(state)->colorkey_ug,
 432                                  drm_to_overlay_state(state)->colorkey_vb, 24) ||
 433                    *val != R2BGR(drm_to_overlay_state(state)->colorkey_yr,
 434                                  drm_to_overlay_state(state)->colorkey_ug,
 435                                  drm_to_overlay_state(state)->colorkey_vb, 8))
 436                        return -EINVAL;
 437        } else if (property == priv->colorkey_min_prop) {
 438                *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
 439                             drm_to_overlay_state(state)->colorkey_ug,
 440                             drm_to_overlay_state(state)->colorkey_vb, 16);
 441        } else if (property == priv->colorkey_max_prop) {
 442                *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
 443                             drm_to_overlay_state(state)->colorkey_ug,
 444                             drm_to_overlay_state(state)->colorkey_vb, 24);
 445        } else if (property == priv->colorkey_val_prop) {
 446                *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
 447                             drm_to_overlay_state(state)->colorkey_ug,
 448                             drm_to_overlay_state(state)->colorkey_vb, 8);
 449        } else if (property == priv->colorkey_alpha_prop) {
 450                *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
 451                             drm_to_overlay_state(state)->colorkey_ug,
 452                             drm_to_overlay_state(state)->colorkey_vb, 0);
 453        } else if (property == priv->colorkey_mode_prop) {
 454                *val = (drm_to_overlay_state(state)->colorkey_mode &
 455                        CFG_CKMODE_MASK) >> ffs(CFG_CKMODE_MASK);
 456        } else if (property == priv->brightness_prop) {
 457                *val = drm_to_overlay_state(state)->brightness + 256;
 458        } else if (property == priv->contrast_prop) {
 459                *val = drm_to_overlay_state(state)->contrast;
 460        } else if (property == priv->saturation_prop) {
 461                *val = drm_to_overlay_state(state)->saturation;
 462        } else {
 463                return -EINVAL;
 464        }
 465        return 0;
 466}
 467
 468static const struct drm_plane_funcs armada_ovl_plane_funcs = {
 469        .update_plane   = armada_overlay_plane_update,
 470        .disable_plane  = drm_atomic_helper_disable_plane,
 471        .destroy        = armada_ovl_plane_destroy,
 472        .reset          = armada_overlay_reset,
 473        .atomic_duplicate_state = armada_overlay_duplicate_state,
 474        .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
 475        .atomic_set_property = armada_overlay_set_property,
 476        .atomic_get_property = armada_overlay_get_property,
 477};
 478
 479static const uint32_t armada_ovl_formats[] = {
 480        DRM_FORMAT_UYVY,
 481        DRM_FORMAT_YUYV,
 482        DRM_FORMAT_YUV420,
 483        DRM_FORMAT_YVU420,
 484        DRM_FORMAT_YUV422,
 485        DRM_FORMAT_YVU422,
 486        DRM_FORMAT_VYUY,
 487        DRM_FORMAT_YVYU,
 488        DRM_FORMAT_ARGB8888,
 489        DRM_FORMAT_ABGR8888,
 490        DRM_FORMAT_XRGB8888,
 491        DRM_FORMAT_XBGR8888,
 492        DRM_FORMAT_RGB888,
 493        DRM_FORMAT_BGR888,
 494        DRM_FORMAT_ARGB1555,
 495        DRM_FORMAT_ABGR1555,
 496        DRM_FORMAT_RGB565,
 497        DRM_FORMAT_BGR565,
 498};
 499
 500static const struct drm_prop_enum_list armada_drm_colorkey_enum_list[] = {
 501        { CKMODE_DISABLE, "disabled" },
 502        { CKMODE_Y,       "Y component" },
 503        { CKMODE_U,       "U component" },
 504        { CKMODE_V,       "V component" },
 505        { CKMODE_RGB,     "RGB" },
 506        { CKMODE_R,       "R component" },
 507        { CKMODE_G,       "G component" },
 508        { CKMODE_B,       "B component" },
 509};
 510
 511static int armada_overlay_create_properties(struct drm_device *dev)
 512{
 513        struct armada_private *priv = drm_to_armada_dev(dev);
 514
 515        if (priv->colorkey_prop)
 516                return 0;
 517
 518        priv->colorkey_prop = drm_property_create_range(dev, 0,
 519                                "colorkey", 0, 0xffffff);
 520        priv->colorkey_min_prop = drm_property_create_range(dev, 0,
 521                                "colorkey_min", 0, 0xffffff);
 522        priv->colorkey_max_prop = drm_property_create_range(dev, 0,
 523                                "colorkey_max", 0, 0xffffff);
 524        priv->colorkey_val_prop = drm_property_create_range(dev, 0,
 525                                "colorkey_val", 0, 0xffffff);
 526        priv->colorkey_alpha_prop = drm_property_create_range(dev, 0,
 527                                "colorkey_alpha", 0, 0xffffff);
 528        priv->colorkey_mode_prop = drm_property_create_enum(dev, 0,
 529                                "colorkey_mode",
 530                                armada_drm_colorkey_enum_list,
 531                                ARRAY_SIZE(armada_drm_colorkey_enum_list));
 532        priv->brightness_prop = drm_property_create_range(dev, 0,
 533                                "brightness", 0, 256 + 255);
 534        priv->contrast_prop = drm_property_create_range(dev, 0,
 535                                "contrast", 0, 0x7fff);
 536        priv->saturation_prop = drm_property_create_range(dev, 0,
 537                                "saturation", 0, 0x7fff);
 538
 539        if (!priv->colorkey_prop)
 540                return -ENOMEM;
 541
 542        return 0;
 543}
 544
 545int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
 546{
 547        struct armada_private *priv = drm_to_armada_dev(dev);
 548        struct drm_mode_object *mobj;
 549        struct drm_plane *overlay;
 550        int ret;
 551
 552        ret = armada_overlay_create_properties(dev);
 553        if (ret)
 554                return ret;
 555
 556        overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
 557        if (!overlay)
 558                return -ENOMEM;
 559
 560        drm_plane_helper_add(overlay, &armada_overlay_plane_helper_funcs);
 561
 562        ret = drm_universal_plane_init(dev, overlay, crtcs,
 563                                       &armada_ovl_plane_funcs,
 564                                       armada_ovl_formats,
 565                                       ARRAY_SIZE(armada_ovl_formats),
 566                                       NULL,
 567                                       DRM_PLANE_TYPE_OVERLAY, NULL);
 568        if (ret) {
 569                kfree(overlay);
 570                return ret;
 571        }
 572
 573        mobj = &overlay->base;
 574        drm_object_attach_property(mobj, priv->colorkey_prop,
 575                                   0x0101fe);
 576        drm_object_attach_property(mobj, priv->colorkey_min_prop,
 577                                   0x0101fe);
 578        drm_object_attach_property(mobj, priv->colorkey_max_prop,
 579                                   0x0101fe);
 580        drm_object_attach_property(mobj, priv->colorkey_val_prop,
 581                                   0x0101fe);
 582        drm_object_attach_property(mobj, priv->colorkey_alpha_prop,
 583                                   0x000000);
 584        drm_object_attach_property(mobj, priv->colorkey_mode_prop,
 585                                   CKMODE_RGB);
 586        drm_object_attach_property(mobj, priv->brightness_prop,
 587                                   256 + DEFAULT_BRIGHTNESS);
 588        drm_object_attach_property(mobj, priv->contrast_prop,
 589                                   DEFAULT_CONTRAST);
 590        drm_object_attach_property(mobj, priv->saturation_prop,
 591                                   DEFAULT_SATURATION);
 592
 593        ret = drm_plane_create_color_properties(overlay,
 594                                                BIT(DRM_COLOR_YCBCR_BT601) |
 595                                                BIT(DRM_COLOR_YCBCR_BT709),
 596                                                BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
 597                                                DEFAULT_ENCODING,
 598                                                DRM_COLOR_YCBCR_LIMITED_RANGE);
 599
 600        return ret;
 601}
 602