Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2012 Russell King
0004  *  Rewritten from the dovefb driver, and Armada510 manuals.
0005  */
0006 
0007 #include <drm/armada_drm.h>
0008 #include <drm/drm_atomic.h>
0009 #include <drm/drm_atomic_helper.h>
0010 #include <drm/drm_atomic_uapi.h>
0011 #include <drm/drm_fourcc.h>
0012 #include <drm/drm_plane_helper.h>
0013 
0014 #include "armada_crtc.h"
0015 #include "armada_drm.h"
0016 #include "armada_fb.h"
0017 #include "armada_gem.h"
0018 #include "armada_hw.h"
0019 #include "armada_ioctlP.h"
0020 #include "armada_plane.h"
0021 #include "armada_trace.h"
0022 
0023 #define DEFAULT_BRIGHTNESS  0
0024 #define DEFAULT_CONTRAST    0x4000
0025 #define DEFAULT_SATURATION  0x4000
0026 #define DEFAULT_ENCODING    DRM_COLOR_YCBCR_BT601
0027 
0028 struct armada_overlay_state {
0029     struct armada_plane_state base;
0030     u32 colorkey_yr;
0031     u32 colorkey_ug;
0032     u32 colorkey_vb;
0033     u32 colorkey_mode;
0034     u32 colorkey_enable;
0035     s16 brightness;
0036     u16 contrast;
0037     u16 saturation;
0038 };
0039 #define drm_to_overlay_state(s) \
0040     container_of(s, struct armada_overlay_state, base.base)
0041 
0042 static inline u32 armada_spu_contrast(struct drm_plane_state *state)
0043 {
0044     return drm_to_overlay_state(state)->brightness << 16 |
0045            drm_to_overlay_state(state)->contrast;
0046 }
0047 
0048 static inline u32 armada_spu_saturation(struct drm_plane_state *state)
0049 {
0050     /* Docs say 15:0, but it seems to actually be 31:16 on Armada 510 */
0051     return drm_to_overlay_state(state)->saturation << 16;
0052 }
0053 
0054 static inline u32 armada_csc(struct drm_plane_state *state)
0055 {
0056     /*
0057      * The CFG_CSC_RGB_* settings control the output of the colour space
0058      * converter, setting the range of output values it produces.  Since
0059      * we will be blending with the full-range graphics, we need to
0060      * produce full-range RGB output from the conversion.
0061      */
0062     return CFG_CSC_RGB_COMPUTER |
0063            (state->color_encoding == DRM_COLOR_YCBCR_BT709 ?
0064             CFG_CSC_YUV_CCIR709 : CFG_CSC_YUV_CCIR601);
0065 }
0066 
0067 /* === Plane support === */
0068 static void armada_drm_overlay_plane_atomic_update(struct drm_plane *plane,
0069     struct drm_atomic_state *state)
0070 {
0071     struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0072                                        plane);
0073     struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0074                                        plane);
0075     struct armada_crtc *dcrtc;
0076     struct armada_regs *regs;
0077     unsigned int idx;
0078     u32 cfg, cfg_mask, val;
0079 
0080     DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
0081 
0082     if (!new_state->fb || WARN_ON(!new_state->crtc))
0083         return;
0084 
0085     DRM_DEBUG_KMS("[PLANE:%d:%s] is on [CRTC:%d:%s] with [FB:%d] visible %u->%u\n",
0086         plane->base.id, plane->name,
0087         new_state->crtc->base.id, new_state->crtc->name,
0088         new_state->fb->base.id,
0089         old_state->visible, new_state->visible);
0090 
0091     dcrtc = drm_to_armada_crtc(new_state->crtc);
0092     regs = dcrtc->regs + dcrtc->regs_idx;
0093 
0094     idx = 0;
0095     if (!old_state->visible && new_state->visible)
0096         armada_reg_queue_mod(regs, idx,
0097                      0, CFG_PDWN16x66 | CFG_PDWN32x66,
0098                      LCD_SPU_SRAM_PARA1);
0099     val = armada_src_hw(new_state);
0100     if (armada_src_hw(old_state) != val)
0101         armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_HPXL_VLN);
0102     val = armada_dst_yx(new_state);
0103     if (armada_dst_yx(old_state) != val)
0104         armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_OVSA_HPXL_VLN);
0105     val = armada_dst_hw(new_state);
0106     if (armada_dst_hw(old_state) != val)
0107         armada_reg_queue_set(regs, idx, val, LCD_SPU_DZM_HPXL_VLN);
0108     /* FIXME: overlay on an interlaced display */
0109     if (old_state->src.x1 != new_state->src.x1 ||
0110         old_state->src.y1 != new_state->src.y1 ||
0111         old_state->fb != new_state->fb ||
0112         new_state->crtc->state->mode_changed) {
0113         const struct drm_format_info *format;
0114         u16 src_x;
0115 
0116         armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 0),
0117                      LCD_SPU_DMA_START_ADDR_Y0);
0118         armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 1),
0119                      LCD_SPU_DMA_START_ADDR_U0);
0120         armada_reg_queue_set(regs, idx, armada_addr(new_state, 0, 2),
0121                      LCD_SPU_DMA_START_ADDR_V0);
0122         armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 0),
0123                      LCD_SPU_DMA_START_ADDR_Y1);
0124         armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 1),
0125                      LCD_SPU_DMA_START_ADDR_U1);
0126         armada_reg_queue_set(regs, idx, armada_addr(new_state, 1, 2),
0127                      LCD_SPU_DMA_START_ADDR_V1);
0128 
0129         val = armada_pitch(new_state, 0) << 16 | armada_pitch(new_state,
0130                                       0);
0131         armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_YC);
0132         val = armada_pitch(new_state, 1) << 16 | armada_pitch(new_state,
0133                                       2);
0134         armada_reg_queue_set(regs, idx, val, LCD_SPU_DMA_PITCH_UV);
0135 
0136         cfg = CFG_DMA_FMT(drm_fb_to_armada_fb(new_state->fb)->fmt) |
0137               CFG_DMA_MOD(drm_fb_to_armada_fb(new_state->fb)->mod) |
0138               CFG_CBSH_ENA;
0139         if (new_state->visible)
0140             cfg |= CFG_DMA_ENA;
0141 
0142         /*
0143          * Shifting a YUV packed format image by one pixel causes the
0144          * U/V planes to swap.  Compensate for it by also toggling
0145          * the UV swap.
0146          */
0147         format = new_state->fb->format;
0148         src_x = new_state->src.x1 >> 16;
0149         if (format->num_planes == 1 && src_x & (format->hsub - 1))
0150             cfg ^= CFG_DMA_MOD(CFG_SWAPUV);
0151         if (to_armada_plane_state(new_state)->interlace)
0152             cfg |= CFG_DMA_FTOGGLE;
0153         cfg_mask = CFG_CBSH_ENA | CFG_DMAFORMAT |
0154                CFG_DMA_MOD(CFG_SWAPRB | CFG_SWAPUV |
0155                        CFG_SWAPYU | CFG_YUV2RGB) |
0156                CFG_DMA_FTOGGLE | CFG_DMA_TSTMODE |
0157                CFG_DMA_ENA;
0158     } else if (old_state->visible != new_state->visible) {
0159         cfg = new_state->visible ? CFG_DMA_ENA : 0;
0160         cfg_mask = CFG_DMA_ENA;
0161     } else {
0162         cfg = cfg_mask = 0;
0163     }
0164     if (drm_rect_width(&old_state->src) != drm_rect_width(&new_state->src) ||
0165         drm_rect_width(&old_state->dst) != drm_rect_width(&new_state->dst)) {
0166         cfg_mask |= CFG_DMA_HSMOOTH;
0167         if (drm_rect_width(&new_state->src) >> 16 !=
0168             drm_rect_width(&new_state->dst))
0169             cfg |= CFG_DMA_HSMOOTH;
0170     }
0171 
0172     if (cfg_mask)
0173         armada_reg_queue_mod(regs, idx, cfg, cfg_mask,
0174                      LCD_SPU_DMA_CTRL0);
0175 
0176     val = armada_spu_contrast(new_state);
0177     if ((!old_state->visible && new_state->visible) ||
0178         armada_spu_contrast(old_state) != val)
0179         armada_reg_queue_set(regs, idx, val, LCD_SPU_CONTRAST);
0180     val = armada_spu_saturation(new_state);
0181     if ((!old_state->visible && new_state->visible) ||
0182         armada_spu_saturation(old_state) != val)
0183         armada_reg_queue_set(regs, idx, val, LCD_SPU_SATURATION);
0184     if (!old_state->visible && new_state->visible)
0185         armada_reg_queue_set(regs, idx, 0x00002000, LCD_SPU_CBSH_HUE);
0186     val = armada_csc(new_state);
0187     if ((!old_state->visible && new_state->visible) ||
0188         armada_csc(old_state) != val)
0189         armada_reg_queue_mod(regs, idx, val, CFG_CSC_MASK,
0190                      LCD_SPU_IOPAD_CONTROL);
0191     val = drm_to_overlay_state(new_state)->colorkey_yr;
0192     if ((!old_state->visible && new_state->visible) ||
0193         drm_to_overlay_state(old_state)->colorkey_yr != val)
0194         armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_Y);
0195     val = drm_to_overlay_state(new_state)->colorkey_ug;
0196     if ((!old_state->visible && new_state->visible) ||
0197         drm_to_overlay_state(old_state)->colorkey_ug != val)
0198         armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_U);
0199     val = drm_to_overlay_state(new_state)->colorkey_vb;
0200     if ((!old_state->visible && new_state->visible) ||
0201         drm_to_overlay_state(old_state)->colorkey_vb != val)
0202         armada_reg_queue_set(regs, idx, val, LCD_SPU_COLORKEY_V);
0203     val = drm_to_overlay_state(new_state)->colorkey_mode;
0204     if ((!old_state->visible && new_state->visible) ||
0205         drm_to_overlay_state(old_state)->colorkey_mode != val)
0206         armada_reg_queue_mod(regs, idx, val, CFG_CKMODE_MASK |
0207                      CFG_ALPHAM_MASK | CFG_ALPHA_MASK,
0208                      LCD_SPU_DMA_CTRL1);
0209     val = drm_to_overlay_state(new_state)->colorkey_enable;
0210     if (((!old_state->visible && new_state->visible) ||
0211          drm_to_overlay_state(old_state)->colorkey_enable != val) &&
0212         dcrtc->variant->has_spu_adv_reg)
0213         armada_reg_queue_mod(regs, idx, val, ADV_GRACOLORKEY |
0214                      ADV_VIDCOLORKEY, LCD_SPU_ADV_REG);
0215 
0216     dcrtc->regs_idx += idx;
0217 }
0218 
0219 static void armada_drm_overlay_plane_atomic_disable(struct drm_plane *plane,
0220     struct drm_atomic_state *state)
0221 {
0222     struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0223                                        plane);
0224     struct armada_crtc *dcrtc;
0225     struct armada_regs *regs;
0226     unsigned int idx = 0;
0227 
0228     DRM_DEBUG_KMS("[PLANE:%d:%s]\n", plane->base.id, plane->name);
0229 
0230     if (!old_state->crtc)
0231         return;
0232 
0233     DRM_DEBUG_KMS("[PLANE:%d:%s] was on [CRTC:%d:%s] with [FB:%d]\n",
0234         plane->base.id, plane->name,
0235         old_state->crtc->base.id, old_state->crtc->name,
0236         old_state->fb->base.id);
0237 
0238     dcrtc = drm_to_armada_crtc(old_state->crtc);
0239     regs = dcrtc->regs + dcrtc->regs_idx;
0240 
0241     /* Disable plane and power down the YUV FIFOs */
0242     armada_reg_queue_mod(regs, idx, 0, CFG_DMA_ENA, LCD_SPU_DMA_CTRL0);
0243     armada_reg_queue_mod(regs, idx, CFG_PDWN16x66 | CFG_PDWN32x66, 0,
0244                  LCD_SPU_SRAM_PARA1);
0245 
0246     dcrtc->regs_idx += idx;
0247 }
0248 
0249 static const struct drm_plane_helper_funcs armada_overlay_plane_helper_funcs = {
0250     .atomic_check   = armada_drm_plane_atomic_check,
0251     .atomic_update  = armada_drm_overlay_plane_atomic_update,
0252     .atomic_disable = armada_drm_overlay_plane_atomic_disable,
0253 };
0254 
0255 static int
0256 armada_overlay_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
0257     struct drm_framebuffer *fb,
0258     int crtc_x, int crtc_y, unsigned crtc_w, unsigned crtc_h,
0259     uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h,
0260     struct drm_modeset_acquire_ctx *ctx)
0261 {
0262     struct drm_atomic_state *state;
0263     struct drm_plane_state *plane_state;
0264     int ret = 0;
0265 
0266     trace_armada_ovl_plane_update(plane, crtc, fb,
0267                  crtc_x, crtc_y, crtc_w, crtc_h,
0268                  src_x, src_y, src_w, src_h);
0269 
0270     state = drm_atomic_state_alloc(plane->dev);
0271     if (!state)
0272         return -ENOMEM;
0273 
0274     state->acquire_ctx = ctx;
0275     plane_state = drm_atomic_get_plane_state(state, plane);
0276     if (IS_ERR(plane_state)) {
0277         ret = PTR_ERR(plane_state);
0278         goto fail;
0279     }
0280 
0281     ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
0282     if (ret != 0)
0283         goto fail;
0284 
0285     drm_atomic_set_fb_for_plane(plane_state, fb);
0286     plane_state->crtc_x = crtc_x;
0287     plane_state->crtc_y = crtc_y;
0288     plane_state->crtc_h = crtc_h;
0289     plane_state->crtc_w = crtc_w;
0290     plane_state->src_x = src_x;
0291     plane_state->src_y = src_y;
0292     plane_state->src_h = src_h;
0293     plane_state->src_w = src_w;
0294 
0295     ret = drm_atomic_nonblocking_commit(state);
0296 fail:
0297     drm_atomic_state_put(state);
0298     return ret;
0299 }
0300 
0301 static void armada_ovl_plane_destroy(struct drm_plane *plane)
0302 {
0303     drm_plane_cleanup(plane);
0304     kfree(plane);
0305 }
0306 
0307 static void armada_overlay_reset(struct drm_plane *plane)
0308 {
0309     struct armada_overlay_state *state;
0310 
0311     if (plane->state)
0312         __drm_atomic_helper_plane_destroy_state(plane->state);
0313     kfree(plane->state);
0314     plane->state = NULL;
0315 
0316     state = kzalloc(sizeof(*state), GFP_KERNEL);
0317     if (state) {
0318         state->colorkey_yr = 0xfefefe00;
0319         state->colorkey_ug = 0x01010100;
0320         state->colorkey_vb = 0x01010100;
0321         state->colorkey_mode = CFG_CKMODE(CKMODE_RGB) |
0322                        CFG_ALPHAM_GRA | CFG_ALPHA(0);
0323         state->colorkey_enable = ADV_GRACOLORKEY;
0324         state->brightness = DEFAULT_BRIGHTNESS;
0325         state->contrast = DEFAULT_CONTRAST;
0326         state->saturation = DEFAULT_SATURATION;
0327         __drm_atomic_helper_plane_reset(plane, &state->base.base);
0328         state->base.base.color_encoding = DEFAULT_ENCODING;
0329         state->base.base.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
0330     }
0331 }
0332 
0333 static struct drm_plane_state *
0334 armada_overlay_duplicate_state(struct drm_plane *plane)
0335 {
0336     struct armada_overlay_state *state;
0337 
0338     if (WARN_ON(!plane->state))
0339         return NULL;
0340 
0341     state = kmemdup(plane->state, sizeof(*state), GFP_KERNEL);
0342     if (state)
0343         __drm_atomic_helper_plane_duplicate_state(plane,
0344                               &state->base.base);
0345     return &state->base.base;
0346 }
0347 
0348 static int armada_overlay_set_property(struct drm_plane *plane,
0349     struct drm_plane_state *state, struct drm_property *property,
0350     uint64_t val)
0351 {
0352     struct armada_private *priv = drm_to_armada_dev(plane->dev);
0353 
0354 #define K2R(val) (((val) >> 0) & 0xff)
0355 #define K2G(val) (((val) >> 8) & 0xff)
0356 #define K2B(val) (((val) >> 16) & 0xff)
0357     if (property == priv->colorkey_prop) {
0358 #define CCC(v) ((v) << 24 | (v) << 16 | (v) << 8)
0359         drm_to_overlay_state(state)->colorkey_yr = CCC(K2R(val));
0360         drm_to_overlay_state(state)->colorkey_ug = CCC(K2G(val));
0361         drm_to_overlay_state(state)->colorkey_vb = CCC(K2B(val));
0362 #undef CCC
0363     } else if (property == priv->colorkey_min_prop) {
0364         drm_to_overlay_state(state)->colorkey_yr &= ~0x00ff0000;
0365         drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 16;
0366         drm_to_overlay_state(state)->colorkey_ug &= ~0x00ff0000;
0367         drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 16;
0368         drm_to_overlay_state(state)->colorkey_vb &= ~0x00ff0000;
0369         drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 16;
0370     } else if (property == priv->colorkey_max_prop) {
0371         drm_to_overlay_state(state)->colorkey_yr &= ~0xff000000;
0372         drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 24;
0373         drm_to_overlay_state(state)->colorkey_ug &= ~0xff000000;
0374         drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 24;
0375         drm_to_overlay_state(state)->colorkey_vb &= ~0xff000000;
0376         drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 24;
0377     } else if (property == priv->colorkey_val_prop) {
0378         drm_to_overlay_state(state)->colorkey_yr &= ~0x0000ff00;
0379         drm_to_overlay_state(state)->colorkey_yr |= K2R(val) << 8;
0380         drm_to_overlay_state(state)->colorkey_ug &= ~0x0000ff00;
0381         drm_to_overlay_state(state)->colorkey_ug |= K2G(val) << 8;
0382         drm_to_overlay_state(state)->colorkey_vb &= ~0x0000ff00;
0383         drm_to_overlay_state(state)->colorkey_vb |= K2B(val) << 8;
0384     } else if (property == priv->colorkey_alpha_prop) {
0385         drm_to_overlay_state(state)->colorkey_yr &= ~0x000000ff;
0386         drm_to_overlay_state(state)->colorkey_yr |= K2R(val);
0387         drm_to_overlay_state(state)->colorkey_ug &= ~0x000000ff;
0388         drm_to_overlay_state(state)->colorkey_ug |= K2G(val);
0389         drm_to_overlay_state(state)->colorkey_vb &= ~0x000000ff;
0390         drm_to_overlay_state(state)->colorkey_vb |= K2B(val);
0391     } else if (property == priv->colorkey_mode_prop) {
0392         if (val == CKMODE_DISABLE) {
0393             drm_to_overlay_state(state)->colorkey_mode =
0394                 CFG_CKMODE(CKMODE_DISABLE) |
0395                 CFG_ALPHAM_CFG | CFG_ALPHA(255);
0396             drm_to_overlay_state(state)->colorkey_enable = 0;
0397         } else {
0398             drm_to_overlay_state(state)->colorkey_mode =
0399                 CFG_CKMODE(val) |
0400                 CFG_ALPHAM_GRA | CFG_ALPHA(0);
0401             drm_to_overlay_state(state)->colorkey_enable =
0402                 ADV_GRACOLORKEY;
0403         }
0404     } else if (property == priv->brightness_prop) {
0405         drm_to_overlay_state(state)->brightness = val - 256;
0406     } else if (property == priv->contrast_prop) {
0407         drm_to_overlay_state(state)->contrast = val;
0408     } else if (property == priv->saturation_prop) {
0409         drm_to_overlay_state(state)->saturation = val;
0410     } else {
0411         return -EINVAL;
0412     }
0413     return 0;
0414 }
0415 
0416 static int armada_overlay_get_property(struct drm_plane *plane,
0417     const struct drm_plane_state *state, struct drm_property *property,
0418     uint64_t *val)
0419 {
0420     struct armada_private *priv = drm_to_armada_dev(plane->dev);
0421 
0422 #define C2K(c,s)    (((c) >> (s)) & 0xff)
0423 #define R2BGR(r,g,b,s)  (C2K(r,s) << 0 | C2K(g,s) << 8 | C2K(b,s) << 16)
0424     if (property == priv->colorkey_prop) {
0425         /* Do best-efforts here for this property */
0426         *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
0427                  drm_to_overlay_state(state)->colorkey_ug,
0428                  drm_to_overlay_state(state)->colorkey_vb, 16);
0429         /* If min != max, or min != val, error out */
0430         if (*val != R2BGR(drm_to_overlay_state(state)->colorkey_yr,
0431                   drm_to_overlay_state(state)->colorkey_ug,
0432                   drm_to_overlay_state(state)->colorkey_vb, 24) ||
0433             *val != R2BGR(drm_to_overlay_state(state)->colorkey_yr,
0434                   drm_to_overlay_state(state)->colorkey_ug,
0435                   drm_to_overlay_state(state)->colorkey_vb, 8))
0436             return -EINVAL;
0437     } else if (property == priv->colorkey_min_prop) {
0438         *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
0439                  drm_to_overlay_state(state)->colorkey_ug,
0440                  drm_to_overlay_state(state)->colorkey_vb, 16);
0441     } else if (property == priv->colorkey_max_prop) {
0442         *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
0443                  drm_to_overlay_state(state)->colorkey_ug,
0444                  drm_to_overlay_state(state)->colorkey_vb, 24);
0445     } else if (property == priv->colorkey_val_prop) {
0446         *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
0447                  drm_to_overlay_state(state)->colorkey_ug,
0448                  drm_to_overlay_state(state)->colorkey_vb, 8);
0449     } else if (property == priv->colorkey_alpha_prop) {
0450         *val = R2BGR(drm_to_overlay_state(state)->colorkey_yr,
0451                  drm_to_overlay_state(state)->colorkey_ug,
0452                  drm_to_overlay_state(state)->colorkey_vb, 0);
0453     } else if (property == priv->colorkey_mode_prop) {
0454         *val = (drm_to_overlay_state(state)->colorkey_mode &
0455             CFG_CKMODE_MASK) >> ffs(CFG_CKMODE_MASK);
0456     } else if (property == priv->brightness_prop) {
0457         *val = drm_to_overlay_state(state)->brightness + 256;
0458     } else if (property == priv->contrast_prop) {
0459         *val = drm_to_overlay_state(state)->contrast;
0460     } else if (property == priv->saturation_prop) {
0461         *val = drm_to_overlay_state(state)->saturation;
0462     } else {
0463         return -EINVAL;
0464     }
0465     return 0;
0466 }
0467 
0468 static const struct drm_plane_funcs armada_ovl_plane_funcs = {
0469     .update_plane   = armada_overlay_plane_update,
0470     .disable_plane  = drm_atomic_helper_disable_plane,
0471     .destroy    = armada_ovl_plane_destroy,
0472     .reset      = armada_overlay_reset,
0473     .atomic_duplicate_state = armada_overlay_duplicate_state,
0474     .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
0475     .atomic_set_property = armada_overlay_set_property,
0476     .atomic_get_property = armada_overlay_get_property,
0477 };
0478 
0479 static const uint32_t armada_ovl_formats[] = {
0480     DRM_FORMAT_UYVY,
0481     DRM_FORMAT_YUYV,
0482     DRM_FORMAT_YUV420,
0483     DRM_FORMAT_YVU420,
0484     DRM_FORMAT_YUV422,
0485     DRM_FORMAT_YVU422,
0486     DRM_FORMAT_VYUY,
0487     DRM_FORMAT_YVYU,
0488     DRM_FORMAT_ARGB8888,
0489     DRM_FORMAT_ABGR8888,
0490     DRM_FORMAT_XRGB8888,
0491     DRM_FORMAT_XBGR8888,
0492     DRM_FORMAT_RGB888,
0493     DRM_FORMAT_BGR888,
0494     DRM_FORMAT_ARGB1555,
0495     DRM_FORMAT_ABGR1555,
0496     DRM_FORMAT_RGB565,
0497     DRM_FORMAT_BGR565,
0498 };
0499 
0500 static const struct drm_prop_enum_list armada_drm_colorkey_enum_list[] = {
0501     { CKMODE_DISABLE, "disabled" },
0502     { CKMODE_Y,       "Y component" },
0503     { CKMODE_U,       "U component" },
0504     { CKMODE_V,       "V component" },
0505     { CKMODE_RGB,     "RGB" },
0506     { CKMODE_R,       "R component" },
0507     { CKMODE_G,       "G component" },
0508     { CKMODE_B,       "B component" },
0509 };
0510 
0511 static int armada_overlay_create_properties(struct drm_device *dev)
0512 {
0513     struct armada_private *priv = drm_to_armada_dev(dev);
0514 
0515     if (priv->colorkey_prop)
0516         return 0;
0517 
0518     priv->colorkey_prop = drm_property_create_range(dev, 0,
0519                 "colorkey", 0, 0xffffff);
0520     priv->colorkey_min_prop = drm_property_create_range(dev, 0,
0521                 "colorkey_min", 0, 0xffffff);
0522     priv->colorkey_max_prop = drm_property_create_range(dev, 0,
0523                 "colorkey_max", 0, 0xffffff);
0524     priv->colorkey_val_prop = drm_property_create_range(dev, 0,
0525                 "colorkey_val", 0, 0xffffff);
0526     priv->colorkey_alpha_prop = drm_property_create_range(dev, 0,
0527                 "colorkey_alpha", 0, 0xffffff);
0528     priv->colorkey_mode_prop = drm_property_create_enum(dev, 0,
0529                 "colorkey_mode",
0530                 armada_drm_colorkey_enum_list,
0531                 ARRAY_SIZE(armada_drm_colorkey_enum_list));
0532     priv->brightness_prop = drm_property_create_range(dev, 0,
0533                 "brightness", 0, 256 + 255);
0534     priv->contrast_prop = drm_property_create_range(dev, 0,
0535                 "contrast", 0, 0x7fff);
0536     priv->saturation_prop = drm_property_create_range(dev, 0,
0537                 "saturation", 0, 0x7fff);
0538 
0539     if (!priv->colorkey_prop)
0540         return -ENOMEM;
0541 
0542     return 0;
0543 }
0544 
0545 int armada_overlay_plane_create(struct drm_device *dev, unsigned long crtcs)
0546 {
0547     struct armada_private *priv = drm_to_armada_dev(dev);
0548     struct drm_mode_object *mobj;
0549     struct drm_plane *overlay;
0550     int ret;
0551 
0552     ret = armada_overlay_create_properties(dev);
0553     if (ret)
0554         return ret;
0555 
0556     overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
0557     if (!overlay)
0558         return -ENOMEM;
0559 
0560     drm_plane_helper_add(overlay, &armada_overlay_plane_helper_funcs);
0561 
0562     ret = drm_universal_plane_init(dev, overlay, crtcs,
0563                        &armada_ovl_plane_funcs,
0564                        armada_ovl_formats,
0565                        ARRAY_SIZE(armada_ovl_formats),
0566                        NULL,
0567                        DRM_PLANE_TYPE_OVERLAY, NULL);
0568     if (ret) {
0569         kfree(overlay);
0570         return ret;
0571     }
0572 
0573     mobj = &overlay->base;
0574     drm_object_attach_property(mobj, priv->colorkey_prop,
0575                    0x0101fe);
0576     drm_object_attach_property(mobj, priv->colorkey_min_prop,
0577                    0x0101fe);
0578     drm_object_attach_property(mobj, priv->colorkey_max_prop,
0579                    0x0101fe);
0580     drm_object_attach_property(mobj, priv->colorkey_val_prop,
0581                    0x0101fe);
0582     drm_object_attach_property(mobj, priv->colorkey_alpha_prop,
0583                    0x000000);
0584     drm_object_attach_property(mobj, priv->colorkey_mode_prop,
0585                    CKMODE_RGB);
0586     drm_object_attach_property(mobj, priv->brightness_prop,
0587                    256 + DEFAULT_BRIGHTNESS);
0588     drm_object_attach_property(mobj, priv->contrast_prop,
0589                    DEFAULT_CONTRAST);
0590     drm_object_attach_property(mobj, priv->saturation_prop,
0591                    DEFAULT_SATURATION);
0592 
0593     ret = drm_plane_create_color_properties(overlay,
0594                         BIT(DRM_COLOR_YCBCR_BT601) |
0595                         BIT(DRM_COLOR_YCBCR_BT709),
0596                         BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
0597                         DEFAULT_ENCODING,
0598                         DRM_COLOR_YCBCR_LIMITED_RANGE);
0599 
0600     return ret;
0601 }