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