root/drivers/gpu/drm/sun4i/sun8i_vi_layer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun8i_vi_layer_enable
  2. sun8i_vi_layer_update_coord
  3. sun8i_vi_layer_update_formats
  4. sun8i_vi_layer_update_buffer
  5. sun8i_vi_layer_atomic_check
  6. sun8i_vi_layer_atomic_disable
  7. sun8i_vi_layer_atomic_update
  8. sun8i_vi_layer_init_one

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
   4  */
   5 
   6 #include <drm/drm_atomic.h>
   7 #include <drm/drm_atomic_helper.h>
   8 #include <drm/drm_crtc.h>
   9 #include <drm/drm_fb_cma_helper.h>
  10 #include <drm/drm_gem_cma_helper.h>
  11 #include <drm/drm_gem_framebuffer_helper.h>
  12 #include <drm/drm_plane_helper.h>
  13 #include <drm/drm_probe_helper.h>
  14 
  15 #include "sun8i_vi_layer.h"
  16 #include "sun8i_mixer.h"
  17 #include "sun8i_vi_scaler.h"
  18 
  19 static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
  20                                   int overlay, bool enable, unsigned int zpos,
  21                                   unsigned int old_zpos)
  22 {
  23         u32 val, bld_base, ch_base;
  24 
  25         bld_base = sun8i_blender_base(mixer);
  26         ch_base = sun8i_channel_base(mixer, channel);
  27 
  28         DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
  29                          enable ? "En" : "Dis", channel, overlay);
  30 
  31         if (enable)
  32                 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
  33         else
  34                 val = 0;
  35 
  36         regmap_update_bits(mixer->engine.regs,
  37                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
  38                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
  39 
  40         if (!enable || zpos != old_zpos) {
  41                 regmap_update_bits(mixer->engine.regs,
  42                                    SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
  43                                    SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
  44                                    0);
  45 
  46                 regmap_update_bits(mixer->engine.regs,
  47                                    SUN8I_MIXER_BLEND_ROUTE(bld_base),
  48                                    SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
  49                                    0);
  50         }
  51 
  52         if (enable) {
  53                 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
  54 
  55                 regmap_update_bits(mixer->engine.regs,
  56                                    SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
  57                                    val, val);
  58 
  59                 val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
  60 
  61                 regmap_update_bits(mixer->engine.regs,
  62                                    SUN8I_MIXER_BLEND_ROUTE(bld_base),
  63                                    SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
  64                                    val);
  65         }
  66 }
  67 
  68 static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
  69                                        int overlay, struct drm_plane *plane,
  70                                        unsigned int zpos)
  71 {
  72         struct drm_plane_state *state = plane->state;
  73         const struct drm_format_info *format = state->fb->format;
  74         u32 src_w, src_h, dst_w, dst_h;
  75         u32 bld_base, ch_base;
  76         u32 outsize, insize;
  77         u32 hphase, vphase;
  78         u32 hn = 0, hm = 0;
  79         u32 vn = 0, vm = 0;
  80         bool subsampled;
  81 
  82         DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
  83                          channel, overlay);
  84 
  85         bld_base = sun8i_blender_base(mixer);
  86         ch_base = sun8i_channel_base(mixer, channel);
  87 
  88         src_w = drm_rect_width(&state->src) >> 16;
  89         src_h = drm_rect_height(&state->src) >> 16;
  90         dst_w = drm_rect_width(&state->dst);
  91         dst_h = drm_rect_height(&state->dst);
  92 
  93         hphase = state->src.x1 & 0xffff;
  94         vphase = state->src.y1 & 0xffff;
  95 
  96         /* make coordinates dividable by subsampling factor */
  97         if (format->hsub > 1) {
  98                 int mask, remainder;
  99 
 100                 mask = format->hsub - 1;
 101                 remainder = (state->src.x1 >> 16) & mask;
 102                 src_w = (src_w + remainder) & ~mask;
 103                 hphase += remainder << 16;
 104         }
 105 
 106         if (format->vsub > 1) {
 107                 int mask, remainder;
 108 
 109                 mask = format->vsub - 1;
 110                 remainder = (state->src.y1 >> 16) & mask;
 111                 src_h = (src_h + remainder) & ~mask;
 112                 vphase += remainder << 16;
 113         }
 114 
 115         insize = SUN8I_MIXER_SIZE(src_w, src_h);
 116         outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
 117 
 118         /* Set height and width */
 119         DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
 120                          (state->src.x1 >> 16) & ~(format->hsub - 1),
 121                          (state->src.y1 >> 16) & ~(format->vsub - 1));
 122         DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
 123         regmap_write(mixer->engine.regs,
 124                      SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
 125                      insize);
 126         regmap_write(mixer->engine.regs,
 127                      SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
 128                      insize);
 129 
 130         /*
 131          * Scaler must be enabled for subsampled formats, so it scales
 132          * chroma to same size as luma.
 133          */
 134         subsampled = format->hsub > 1 || format->vsub > 1;
 135 
 136         if (insize != outsize || subsampled || hphase || vphase) {
 137                 unsigned int scanline, required;
 138                 struct drm_display_mode *mode;
 139                 u32 hscale, vscale, fps;
 140                 u64 ability;
 141 
 142                 DRM_DEBUG_DRIVER("HW scaling is enabled\n");
 143 
 144                 mode = &plane->state->crtc->state->mode;
 145                 fps = (mode->clock * 1000) / (mode->vtotal * mode->htotal);
 146                 ability = clk_get_rate(mixer->mod_clk);
 147                 /* BSP algorithm assumes 80% efficiency of VI scaler unit */
 148                 ability *= 80;
 149                 do_div(ability, mode->vdisplay * fps * max(src_w, dst_w));
 150 
 151                 required = src_h * 100 / dst_h;
 152 
 153                 if (ability < required) {
 154                         DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
 155                         vm = src_h;
 156                         vn = (u32)ability * dst_h / 100;
 157                         src_h = vn;
 158                 }
 159 
 160                 /* it seems that every RGB scaler has buffer for 2048 pixels */
 161                 scanline = subsampled ? mixer->cfg->scanline_yuv : 2048;
 162 
 163                 if (src_w > scanline) {
 164                         DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
 165                         hm = src_w;
 166                         hn = scanline;
 167                         src_w = hn;
 168                 }
 169 
 170                 hscale = (src_w << 16) / dst_w;
 171                 vscale = (src_h << 16) / dst_h;
 172 
 173                 sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
 174                                       dst_h, hscale, vscale, hphase, vphase,
 175                                       format);
 176                 sun8i_vi_scaler_enable(mixer, channel, true);
 177         } else {
 178                 DRM_DEBUG_DRIVER("HW scaling is not needed\n");
 179                 sun8i_vi_scaler_enable(mixer, channel, false);
 180         }
 181 
 182         regmap_write(mixer->engine.regs,
 183                      SUN8I_MIXER_CHAN_VI_HDS_Y(ch_base),
 184                      SUN8I_MIXER_CHAN_VI_DS_N(hn) |
 185                      SUN8I_MIXER_CHAN_VI_DS_M(hm));
 186         regmap_write(mixer->engine.regs,
 187                      SUN8I_MIXER_CHAN_VI_HDS_UV(ch_base),
 188                      SUN8I_MIXER_CHAN_VI_DS_N(hn) |
 189                      SUN8I_MIXER_CHAN_VI_DS_M(hm));
 190         regmap_write(mixer->engine.regs,
 191                      SUN8I_MIXER_CHAN_VI_VDS_Y(ch_base),
 192                      SUN8I_MIXER_CHAN_VI_DS_N(vn) |
 193                      SUN8I_MIXER_CHAN_VI_DS_M(vm));
 194         regmap_write(mixer->engine.regs,
 195                      SUN8I_MIXER_CHAN_VI_VDS_UV(ch_base),
 196                      SUN8I_MIXER_CHAN_VI_DS_N(vn) |
 197                      SUN8I_MIXER_CHAN_VI_DS_M(vm));
 198 
 199         /* Set base coordinates */
 200         DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
 201                          state->dst.x1, state->dst.y1);
 202         DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
 203         regmap_write(mixer->engine.regs,
 204                      SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
 205                      SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
 206         regmap_write(mixer->engine.regs,
 207                      SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
 208                      outsize);
 209 
 210         return 0;
 211 }
 212 
 213 static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
 214                                          int overlay, struct drm_plane *plane)
 215 {
 216         struct drm_plane_state *state = plane->state;
 217         const struct de2_fmt_info *fmt_info;
 218         u32 val, ch_base;
 219 
 220         ch_base = sun8i_channel_base(mixer, channel);
 221 
 222         fmt_info = sun8i_mixer_format_info(state->fb->format->format);
 223         if (!fmt_info) {
 224                 DRM_DEBUG_DRIVER("Invalid format\n");
 225                 return -EINVAL;
 226         }
 227 
 228         val = fmt_info->de2_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
 229         regmap_update_bits(mixer->engine.regs,
 230                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
 231                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
 232 
 233         if (fmt_info->csc != SUN8I_CSC_MODE_OFF) {
 234                 sun8i_csc_set_ccsc_coefficients(mixer, channel, fmt_info->csc,
 235                                                 state->color_encoding,
 236                                                 state->color_range);
 237                 sun8i_csc_enable_ccsc(mixer, channel, true);
 238         } else {
 239                 sun8i_csc_enable_ccsc(mixer, channel, false);
 240         }
 241 
 242         if (fmt_info->rgb)
 243                 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
 244         else
 245                 val = 0;
 246 
 247         regmap_update_bits(mixer->engine.regs,
 248                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
 249                            SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
 250 
 251         /* It seems that YUV formats use global alpha setting. */
 252         if (mixer->cfg->is_de3)
 253                 regmap_update_bits(mixer->engine.regs,
 254                                    SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
 255                                                                   overlay),
 256                                    SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK,
 257                                    SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff));
 258 
 259         return 0;
 260 }
 261 
 262 static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
 263                                         int overlay, struct drm_plane *plane)
 264 {
 265         struct drm_plane_state *state = plane->state;
 266         struct drm_framebuffer *fb = state->fb;
 267         const struct drm_format_info *format = fb->format;
 268         struct drm_gem_cma_object *gem;
 269         u32 dx, dy, src_x, src_y;
 270         dma_addr_t paddr;
 271         u32 ch_base;
 272         int i;
 273 
 274         ch_base = sun8i_channel_base(mixer, channel);
 275 
 276         /* Adjust x and y to be dividable by subsampling factor */
 277         src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
 278         src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
 279 
 280         for (i = 0; i < format->num_planes; i++) {
 281                 /* Get the physical address of the buffer in memory */
 282                 gem = drm_fb_cma_get_gem_obj(fb, i);
 283 
 284                 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
 285 
 286                 /* Compute the start of the displayed memory */
 287                 paddr = gem->paddr + fb->offsets[i];
 288 
 289                 dx = src_x;
 290                 dy = src_y;
 291 
 292                 if (i > 0) {
 293                         dx /= format->hsub;
 294                         dy /= format->vsub;
 295                 }
 296 
 297                 /* Fixup framebuffer address for src coordinates */
 298                 paddr += dx * format->cpp[i];
 299                 paddr += dy * fb->pitches[i];
 300 
 301                 /* Set the line width */
 302                 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
 303                                  i + 1, fb->pitches[i]);
 304                 regmap_write(mixer->engine.regs,
 305                              SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
 306                                                              overlay, i),
 307                              fb->pitches[i]);
 308 
 309                 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
 310                                  i + 1, &paddr);
 311 
 312                 regmap_write(mixer->engine.regs,
 313                              SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
 314                                                                  overlay, i),
 315                              lower_32_bits(paddr));
 316         }
 317 
 318         return 0;
 319 }
 320 
 321 static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
 322                                        struct drm_plane_state *state)
 323 {
 324         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
 325         struct drm_crtc *crtc = state->crtc;
 326         struct drm_crtc_state *crtc_state;
 327         int min_scale, max_scale;
 328 
 329         if (!crtc)
 330                 return 0;
 331 
 332         crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
 333         if (WARN_ON(!crtc_state))
 334                 return -EINVAL;
 335 
 336         min_scale = DRM_PLANE_HELPER_NO_SCALING;
 337         max_scale = DRM_PLANE_HELPER_NO_SCALING;
 338 
 339         if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
 340                 min_scale = SUN8I_VI_SCALER_SCALE_MIN;
 341                 max_scale = SUN8I_VI_SCALER_SCALE_MAX;
 342         }
 343 
 344         return drm_atomic_helper_check_plane_state(state, crtc_state,
 345                                                    min_scale, max_scale,
 346                                                    true, true);
 347 }
 348 
 349 static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
 350                                           struct drm_plane_state *old_state)
 351 {
 352         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
 353         unsigned int old_zpos = old_state->normalized_zpos;
 354         struct sun8i_mixer *mixer = layer->mixer;
 355 
 356         sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
 357                               old_zpos);
 358 }
 359 
 360 static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
 361                                          struct drm_plane_state *old_state)
 362 {
 363         struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
 364         unsigned int zpos = plane->state->normalized_zpos;
 365         unsigned int old_zpos = old_state->normalized_zpos;
 366         struct sun8i_mixer *mixer = layer->mixer;
 367 
 368         if (!plane->state->visible) {
 369                 sun8i_vi_layer_enable(mixer, layer->channel,
 370                                       layer->overlay, false, 0, old_zpos);
 371                 return;
 372         }
 373 
 374         sun8i_vi_layer_update_coord(mixer, layer->channel,
 375                                     layer->overlay, plane, zpos);
 376         sun8i_vi_layer_update_formats(mixer, layer->channel,
 377                                       layer->overlay, plane);
 378         sun8i_vi_layer_update_buffer(mixer, layer->channel,
 379                                      layer->overlay, plane);
 380         sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
 381                               true, zpos, old_zpos);
 382 }
 383 
 384 static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
 385         .prepare_fb     = drm_gem_fb_prepare_fb,
 386         .atomic_check   = sun8i_vi_layer_atomic_check,
 387         .atomic_disable = sun8i_vi_layer_atomic_disable,
 388         .atomic_update  = sun8i_vi_layer_atomic_update,
 389 };
 390 
 391 static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
 392         .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
 393         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
 394         .destroy                = drm_plane_cleanup,
 395         .disable_plane          = drm_atomic_helper_disable_plane,
 396         .reset                  = drm_atomic_helper_plane_reset,
 397         .update_plane           = drm_atomic_helper_update_plane,
 398 };
 399 
 400 /*
 401  * While DE2 VI layer supports same RGB formats as UI layer, alpha
 402  * channel is ignored. This structure lists all unique variants
 403  * where alpha channel is replaced with "don't care" (X) channel.
 404  */
 405 static const u32 sun8i_vi_layer_formats[] = {
 406         DRM_FORMAT_BGR565,
 407         DRM_FORMAT_BGR888,
 408         DRM_FORMAT_BGRX4444,
 409         DRM_FORMAT_BGRX5551,
 410         DRM_FORMAT_BGRX8888,
 411         DRM_FORMAT_RGB565,
 412         DRM_FORMAT_RGB888,
 413         DRM_FORMAT_RGBX4444,
 414         DRM_FORMAT_RGBX5551,
 415         DRM_FORMAT_RGBX8888,
 416         DRM_FORMAT_XBGR1555,
 417         DRM_FORMAT_XBGR4444,
 418         DRM_FORMAT_XBGR8888,
 419         DRM_FORMAT_XRGB1555,
 420         DRM_FORMAT_XRGB4444,
 421         DRM_FORMAT_XRGB8888,
 422 
 423         DRM_FORMAT_NV16,
 424         DRM_FORMAT_NV12,
 425         DRM_FORMAT_NV21,
 426         DRM_FORMAT_NV61,
 427         DRM_FORMAT_UYVY,
 428         DRM_FORMAT_VYUY,
 429         DRM_FORMAT_YUYV,
 430         DRM_FORMAT_YVYU,
 431         DRM_FORMAT_YUV411,
 432         DRM_FORMAT_YUV420,
 433         DRM_FORMAT_YUV422,
 434         DRM_FORMAT_YVU411,
 435         DRM_FORMAT_YVU420,
 436         DRM_FORMAT_YVU422,
 437 };
 438 
 439 static const u32 sun8i_vi_layer_de3_formats[] = {
 440         DRM_FORMAT_ABGR1555,
 441         DRM_FORMAT_ABGR2101010,
 442         DRM_FORMAT_ABGR4444,
 443         DRM_FORMAT_ABGR8888,
 444         DRM_FORMAT_ARGB1555,
 445         DRM_FORMAT_ARGB2101010,
 446         DRM_FORMAT_ARGB4444,
 447         DRM_FORMAT_ARGB8888,
 448         DRM_FORMAT_BGR565,
 449         DRM_FORMAT_BGR888,
 450         DRM_FORMAT_BGRA1010102,
 451         DRM_FORMAT_BGRA5551,
 452         DRM_FORMAT_BGRA4444,
 453         DRM_FORMAT_BGRA8888,
 454         DRM_FORMAT_BGRX8888,
 455         DRM_FORMAT_RGB565,
 456         DRM_FORMAT_RGB888,
 457         DRM_FORMAT_RGBA1010102,
 458         DRM_FORMAT_RGBA4444,
 459         DRM_FORMAT_RGBA5551,
 460         DRM_FORMAT_RGBA8888,
 461         DRM_FORMAT_RGBX8888,
 462         DRM_FORMAT_XBGR8888,
 463         DRM_FORMAT_XRGB8888,
 464 
 465         DRM_FORMAT_NV16,
 466         DRM_FORMAT_NV12,
 467         DRM_FORMAT_NV21,
 468         DRM_FORMAT_NV61,
 469         DRM_FORMAT_P010,
 470         DRM_FORMAT_P210,
 471         DRM_FORMAT_UYVY,
 472         DRM_FORMAT_VYUY,
 473         DRM_FORMAT_YUYV,
 474         DRM_FORMAT_YVYU,
 475         DRM_FORMAT_YUV411,
 476         DRM_FORMAT_YUV420,
 477         DRM_FORMAT_YUV422,
 478         DRM_FORMAT_YVU411,
 479         DRM_FORMAT_YVU420,
 480         DRM_FORMAT_YVU422,
 481 };
 482 
 483 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
 484                                                struct sun8i_mixer *mixer,
 485                                                int index)
 486 {
 487         u32 supported_encodings, supported_ranges;
 488         unsigned int plane_cnt, format_count;
 489         struct sun8i_vi_layer *layer;
 490         const u32 *formats;
 491         int ret;
 492 
 493         layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
 494         if (!layer)
 495                 return ERR_PTR(-ENOMEM);
 496 
 497         if (mixer->cfg->is_de3) {
 498                 formats = sun8i_vi_layer_de3_formats;
 499                 format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
 500         } else {
 501                 formats = sun8i_vi_layer_formats;
 502                 format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
 503         }
 504 
 505         /* possible crtcs are set later */
 506         ret = drm_universal_plane_init(drm, &layer->plane, 0,
 507                                        &sun8i_vi_layer_funcs,
 508                                        formats, format_count,
 509                                        NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
 510         if (ret) {
 511                 dev_err(drm->dev, "Couldn't initialize layer\n");
 512                 return ERR_PTR(ret);
 513         }
 514 
 515         plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
 516 
 517         ret = drm_plane_create_zpos_property(&layer->plane, index,
 518                                              0, plane_cnt - 1);
 519         if (ret) {
 520                 dev_err(drm->dev, "Couldn't add zpos property\n");
 521                 return ERR_PTR(ret);
 522         }
 523 
 524         supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
 525                               BIT(DRM_COLOR_YCBCR_BT709);
 526 
 527         supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
 528                            BIT(DRM_COLOR_YCBCR_FULL_RANGE);
 529 
 530         ret = drm_plane_create_color_properties(&layer->plane,
 531                                                 supported_encodings,
 532                                                 supported_ranges,
 533                                                 DRM_COLOR_YCBCR_BT709,
 534                                                 DRM_COLOR_YCBCR_LIMITED_RANGE);
 535         if (ret) {
 536                 dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
 537                 return ERR_PTR(ret);
 538         }
 539 
 540         drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
 541         layer->mixer = mixer;
 542         layer->channel = index;
 543         layer->overlay = 0;
 544 
 545         return layer;
 546 }

/* [<][>][^][v][top][bottom][index][help] */