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