sun8i_vi_layer.c 15.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2 3 4 5 6 7 8 9 10
/*
 * Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
 */

#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fb_cma_helper.h>
#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_csc.h"
16
#include "sun8i_mixer.h"
17
#include "sun8i_vi_layer.h"
18
#include "sun8i_vi_scaler.h"
19 20

static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
21 22
				  int overlay, bool enable, unsigned int zpos,
				  unsigned int old_zpos)
23
{
24 25 26 27
	u32 val, bld_base, ch_base;

	bld_base = sun8i_blender_base(mixer);
	ch_base = sun8i_channel_base(mixer, channel);
28 29 30 31 32 33 34 35 36 37

	DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
			 enable ? "En" : "Dis", channel, overlay);

	if (enable)
		val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
	else
		val = 0;

	regmap_update_bits(mixer->engine.regs,
38
			   SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
39 40
			   SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);

41 42
	if (!enable || zpos != old_zpos) {
		regmap_update_bits(mixer->engine.regs,
43
				   SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
44 45 46 47
				   SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
				   0);

		regmap_update_bits(mixer->engine.regs,
48
				   SUN8I_MIXER_BLEND_ROUTE(bld_base),
49 50 51 52
				   SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
				   0);
	}

53 54
	if (enable) {
		val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
55

56
		regmap_update_bits(mixer->engine.regs,
57 58
				   SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
				   val, val);
59 60 61 62

		val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);

		regmap_update_bits(mixer->engine.regs,
63
				   SUN8I_MIXER_BLEND_ROUTE(bld_base),
64 65 66
				   SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
				   val);
	}
67 68 69
}

static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
70 71
				       int overlay, struct drm_plane *plane,
				       unsigned int zpos)
72 73
{
	struct drm_plane_state *state = plane->state;
74
	const struct drm_format_info *format = state->fb->format;
75
	u32 src_w, src_h, dst_w, dst_h;
76
	u32 bld_base, ch_base;
77 78
	u32 outsize, insize;
	u32 hphase, vphase;
79 80
	u32 hn = 0, hm = 0;
	u32 vn = 0, vm = 0;
81
	bool subsampled;
82 83 84

	DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
			 channel, overlay);
85

86 87 88
	bld_base = sun8i_blender_base(mixer);
	ch_base = sun8i_channel_base(mixer, channel);

89 90 91 92 93 94 95 96
	src_w = drm_rect_width(&state->src) >> 16;
	src_h = drm_rect_height(&state->src) >> 16;
	dst_w = drm_rect_width(&state->dst);
	dst_h = drm_rect_height(&state->dst);

	hphase = state->src.x1 & 0xffff;
	vphase = state->src.y1 & 0xffff;

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
	/* make coordinates dividable by subsampling factor */
	if (format->hsub > 1) {
		int mask, remainder;

		mask = format->hsub - 1;
		remainder = (state->src.x1 >> 16) & mask;
		src_w = (src_w + remainder) & ~mask;
		hphase += remainder << 16;
	}

	if (format->vsub > 1) {
		int mask, remainder;

		mask = format->vsub - 1;
		remainder = (state->src.y1 >> 16) & mask;
		src_h = (src_h + remainder) & ~mask;
		vphase += remainder << 16;
	}

116 117
	insize = SUN8I_MIXER_SIZE(src_w, src_h);
	outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
118 119

	/* Set height and width */
120
	DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
121 122
			 (state->src.x1 >> 16) & ~(format->hsub - 1),
			 (state->src.y1 >> 16) & ~(format->vsub - 1));
123
	DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
124
	regmap_write(mixer->engine.regs,
125
		     SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
126
		     insize);
127
	regmap_write(mixer->engine.regs,
128
		     SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
129 130
		     insize);

131 132 133 134 135 136 137
	/*
	 * Scaler must be enabled for subsampled formats, so it scales
	 * chroma to same size as luma.
	 */
	subsampled = format->hsub > 1 || format->vsub > 1;

	if (insize != outsize || subsampled || hphase || vphase) {
138 139 140 141
		unsigned int scanline, required;
		struct drm_display_mode *mode;
		u32 hscale, vscale, fps;
		u64 ability;
142 143 144

		DRM_DEBUG_DRIVER("HW scaling is enabled\n");

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
		mode = &plane->state->crtc->state->mode;
		fps = (mode->clock * 1000) / (mode->vtotal * mode->htotal);
		ability = clk_get_rate(mixer->mod_clk);
		/* BSP algorithm assumes 80% efficiency of VI scaler unit */
		ability *= 80;
		do_div(ability, mode->vdisplay * fps * max(src_w, dst_w));

		required = src_h * 100 / dst_h;

		if (ability < required) {
			DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
			vm = src_h;
			vn = (u32)ability * dst_h / 100;
			src_h = vn;
		}

		/* it seems that every RGB scaler has buffer for 2048 pixels */
		scanline = subsampled ? mixer->cfg->scanline_yuv : 2048;

		if (src_w > scanline) {
			DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
			hm = src_w;
			hn = scanline;
			src_w = hn;
		}

		hscale = (src_w << 16) / dst_w;
		vscale = (src_h << 16) / dst_h;
173 174

		sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
175 176
				      dst_h, hscale, vscale, hphase, vphase,
				      format);
177 178 179 180 181
		sun8i_vi_scaler_enable(mixer, channel, true);
	} else {
		DRM_DEBUG_DRIVER("HW scaling is not needed\n");
		sun8i_vi_scaler_enable(mixer, channel, false);
	}
182

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
	regmap_write(mixer->engine.regs,
		     SUN8I_MIXER_CHAN_VI_HDS_Y(ch_base),
		     SUN8I_MIXER_CHAN_VI_DS_N(hn) |
		     SUN8I_MIXER_CHAN_VI_DS_M(hm));
	regmap_write(mixer->engine.regs,
		     SUN8I_MIXER_CHAN_VI_HDS_UV(ch_base),
		     SUN8I_MIXER_CHAN_VI_DS_N(hn) |
		     SUN8I_MIXER_CHAN_VI_DS_M(hm));
	regmap_write(mixer->engine.regs,
		     SUN8I_MIXER_CHAN_VI_VDS_Y(ch_base),
		     SUN8I_MIXER_CHAN_VI_DS_N(vn) |
		     SUN8I_MIXER_CHAN_VI_DS_M(vm));
	regmap_write(mixer->engine.regs,
		     SUN8I_MIXER_CHAN_VI_VDS_UV(ch_base),
		     SUN8I_MIXER_CHAN_VI_DS_N(vn) |
		     SUN8I_MIXER_CHAN_VI_DS_M(vm));

200
	/* Set base coordinates */
201
	DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
202
			 state->dst.x1, state->dst.y1);
203
	DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
204
	regmap_write(mixer->engine.regs,
205
		     SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
206 207
		     SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
	regmap_write(mixer->engine.regs,
208
		     SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
209
		     outsize);
210 211 212 213

	return 0;
}

J
Jernej Skrabec 已提交
214
static u32 sun8i_vi_layer_get_csc_mode(const struct drm_format_info *format)
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
{
	if (!format->is_yuv)
		return SUN8I_CSC_MODE_OFF;

	switch (format->format) {
	case DRM_FORMAT_YVU411:
	case DRM_FORMAT_YVU420:
	case DRM_FORMAT_YVU422:
	case DRM_FORMAT_YVU444:
		return SUN8I_CSC_MODE_YVU2RGB;
	default:
		return SUN8I_CSC_MODE_YUV2RGB;
	}
}

230 231 232 233
static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
					 int overlay, struct drm_plane *plane)
{
	struct drm_plane_state *state = plane->state;
234
	u32 val, ch_base, csc_mode, hw_fmt;
235
	const struct drm_format_info *fmt;
236
	int ret;
237 238

	ch_base = sun8i_channel_base(mixer, channel);
239

240
	fmt = state->fb->format;
241 242
	ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
	if (ret) {
243
		DRM_DEBUG_DRIVER("Invalid format\n");
244
		return ret;
245 246
	}

247
	val = hw_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
248
	regmap_update_bits(mixer->engine.regs,
249
			   SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
250 251
			   SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);

252 253 254
	csc_mode = sun8i_vi_layer_get_csc_mode(fmt);
	if (csc_mode != SUN8I_CSC_MODE_OFF) {
		sun8i_csc_set_ccsc_coefficients(mixer, channel, csc_mode,
255 256
						state->color_encoding,
						state->color_range);
257 258 259 260 261
		sun8i_csc_enable_ccsc(mixer, channel, true);
	} else {
		sun8i_csc_enable_ccsc(mixer, channel, false);
	}

262
	if (!fmt->is_yuv)
263 264 265 266 267
		val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
	else
		val = 0;

	regmap_update_bits(mixer->engine.regs,
268
			   SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
269
			   SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
270

271 272 273 274 275 276 277 278
	/* It seems that YUV formats use global alpha setting. */
	if (mixer->cfg->is_de3)
		regmap_update_bits(mixer->engine.regs,
				   SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
								  overlay),
				   SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK,
				   SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(0xff));

279 280 281 282 283 284 285 286
	return 0;
}

static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
					int overlay, struct drm_plane *plane)
{
	struct drm_plane_state *state = plane->state;
	struct drm_framebuffer *fb = state->fb;
287
	const struct drm_format_info *format = fb->format;
288
	struct drm_gem_cma_object *gem;
289
	u32 dx, dy, src_x, src_y;
290
	dma_addr_t paddr;
291
	u32 ch_base;
292
	int i;
293

294 295
	ch_base = sun8i_channel_base(mixer, channel);

296 297 298
	/* Adjust x and y to be dividable by subsampling factor */
	src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
	src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
299

300 301 302
	for (i = 0; i < format->num_planes; i++) {
		/* Get the physical address of the buffer in memory */
		gem = drm_fb_cma_get_gem_obj(fb, i);
303

304
		DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
305

306 307
		/* Compute the start of the displayed memory */
		paddr = gem->paddr + fb->offsets[i];
308

309 310
		dx = src_x;
		dy = src_y;
311

312 313 314 315
		if (i > 0) {
			dx /= format->hsub;
			dy /= format->vsub;
		}
316

317 318 319 320 321 322 323 324
		/* Fixup framebuffer address for src coordinates */
		paddr += dx * format->cpp[i];
		paddr += dy * fb->pitches[i];

		/* Set the line width */
		DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
				 i + 1, fb->pitches[i]);
		regmap_write(mixer->engine.regs,
325
			     SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
326
							     overlay, i),
327
			     fb->pitches[i]);
328 329 330 331 332

		DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
				 i + 1, &paddr);

		regmap_write(mixer->engine.regs,
333
			     SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
334
								 overlay, i),
335
			     lower_32_bits(paddr));
336
	}
337 338 339 340 341 342 343

	return 0;
}

static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
				       struct drm_plane_state *state)
{
344
	struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
345 346
	struct drm_crtc *crtc = state->crtc;
	struct drm_crtc_state *crtc_state;
347
	int min_scale, max_scale;
348 349 350 351 352 353 354 355

	if (!crtc)
		return 0;

	crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc);
	if (WARN_ON(!crtc_state))
		return -EINVAL;

356 357 358
	min_scale = DRM_PLANE_HELPER_NO_SCALING;
	max_scale = DRM_PLANE_HELPER_NO_SCALING;

359 360 361 362 363
	if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
		min_scale = SUN8I_VI_SCALER_SCALE_MIN;
		max_scale = SUN8I_VI_SCALER_SCALE_MAX;
	}

364
	return drm_atomic_helper_check_plane_state(state, crtc_state,
365
						   min_scale, max_scale,
366 367 368 369 370 371 372
						   true, true);
}

static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
					  struct drm_plane_state *old_state)
{
	struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
373
	unsigned int old_zpos = old_state->normalized_zpos;
374 375
	struct sun8i_mixer *mixer = layer->mixer;

376 377
	sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
			      old_zpos);
378 379 380 381 382 383
}

static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
					 struct drm_plane_state *old_state)
{
	struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
384
	unsigned int zpos = plane->state->normalized_zpos;
385
	unsigned int old_zpos = old_state->normalized_zpos;
386 387 388 389
	struct sun8i_mixer *mixer = layer->mixer;

	if (!plane->state->visible) {
		sun8i_vi_layer_enable(mixer, layer->channel,
390
				      layer->overlay, false, 0, old_zpos);
391 392 393 394
		return;
	}

	sun8i_vi_layer_update_coord(mixer, layer->channel,
395
				    layer->overlay, plane, zpos);
396 397 398 399
	sun8i_vi_layer_update_formats(mixer, layer->channel,
				      layer->overlay, plane);
	sun8i_vi_layer_update_buffer(mixer, layer->channel,
				     layer->overlay, plane);
400
	sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
401
			      true, zpos, old_zpos);
402 403 404
}

static struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
405
	.prepare_fb	= drm_gem_fb_prepare_fb,
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
	.atomic_check	= sun8i_vi_layer_atomic_check,
	.atomic_disable	= sun8i_vi_layer_atomic_disable,
	.atomic_update	= sun8i_vi_layer_atomic_update,
};

static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
	.destroy		= drm_plane_cleanup,
	.disable_plane		= drm_atomic_helper_disable_plane,
	.reset			= drm_atomic_helper_plane_reset,
	.update_plane		= drm_atomic_helper_update_plane,
};

/*
421 422 423
 * While DE2 VI layer supports same RGB formats as UI layer, alpha
 * channel is ignored. This structure lists all unique variants
 * where alpha channel is replaced with "don't care" (X) channel.
424 425 426 427
 */
static const u32 sun8i_vi_layer_formats[] = {
	DRM_FORMAT_BGR565,
	DRM_FORMAT_BGR888,
428 429
	DRM_FORMAT_BGRX4444,
	DRM_FORMAT_BGRX5551,
430 431 432
	DRM_FORMAT_BGRX8888,
	DRM_FORMAT_RGB565,
	DRM_FORMAT_RGB888,
433 434
	DRM_FORMAT_RGBX4444,
	DRM_FORMAT_RGBX5551,
435
	DRM_FORMAT_RGBX8888,
436 437
	DRM_FORMAT_XBGR1555,
	DRM_FORMAT_XBGR4444,
438
	DRM_FORMAT_XBGR8888,
439 440
	DRM_FORMAT_XRGB1555,
	DRM_FORMAT_XRGB4444,
441
	DRM_FORMAT_XRGB8888,
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456

	DRM_FORMAT_NV16,
	DRM_FORMAT_NV12,
	DRM_FORMAT_NV21,
	DRM_FORMAT_NV61,
	DRM_FORMAT_UYVY,
	DRM_FORMAT_VYUY,
	DRM_FORMAT_YUYV,
	DRM_FORMAT_YVYU,
	DRM_FORMAT_YUV411,
	DRM_FORMAT_YUV420,
	DRM_FORMAT_YUV422,
	DRM_FORMAT_YVU411,
	DRM_FORMAT_YVU420,
	DRM_FORMAT_YVU422,
457 458
};

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
static const u32 sun8i_vi_layer_de3_formats[] = {
	DRM_FORMAT_ABGR1555,
	DRM_FORMAT_ABGR2101010,
	DRM_FORMAT_ABGR4444,
	DRM_FORMAT_ABGR8888,
	DRM_FORMAT_ARGB1555,
	DRM_FORMAT_ARGB2101010,
	DRM_FORMAT_ARGB4444,
	DRM_FORMAT_ARGB8888,
	DRM_FORMAT_BGR565,
	DRM_FORMAT_BGR888,
	DRM_FORMAT_BGRA1010102,
	DRM_FORMAT_BGRA5551,
	DRM_FORMAT_BGRA4444,
	DRM_FORMAT_BGRA8888,
	DRM_FORMAT_BGRX8888,
	DRM_FORMAT_RGB565,
	DRM_FORMAT_RGB888,
	DRM_FORMAT_RGBA1010102,
	DRM_FORMAT_RGBA4444,
	DRM_FORMAT_RGBA5551,
	DRM_FORMAT_RGBA8888,
	DRM_FORMAT_RGBX8888,
	DRM_FORMAT_XBGR8888,
	DRM_FORMAT_XRGB8888,

	DRM_FORMAT_NV16,
	DRM_FORMAT_NV12,
	DRM_FORMAT_NV21,
	DRM_FORMAT_NV61,
	DRM_FORMAT_P010,
	DRM_FORMAT_P210,
	DRM_FORMAT_UYVY,
	DRM_FORMAT_VYUY,
	DRM_FORMAT_YUYV,
	DRM_FORMAT_YVYU,
	DRM_FORMAT_YUV411,
	DRM_FORMAT_YUV420,
	DRM_FORMAT_YUV422,
	DRM_FORMAT_YVU411,
	DRM_FORMAT_YVU420,
	DRM_FORMAT_YVU422,
};

503 504 505 506
struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
					       struct sun8i_mixer *mixer,
					       int index)
{
507
	u32 supported_encodings, supported_ranges;
508
	unsigned int plane_cnt, format_count;
509
	struct sun8i_vi_layer *layer;
510
	const u32 *formats;
511 512 513 514 515 516
	int ret;

	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
	if (!layer)
		return ERR_PTR(-ENOMEM);

517 518 519 520 521 522 523 524
	if (mixer->cfg->is_de3) {
		formats = sun8i_vi_layer_de3_formats;
		format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
	} else {
		formats = sun8i_vi_layer_formats;
		format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
	}

525 526 527
	/* possible crtcs are set later */
	ret = drm_universal_plane_init(drm, &layer->plane, 0,
				       &sun8i_vi_layer_funcs,
528
				       formats, format_count,
529 530 531 532 533 534
				       NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
	if (ret) {
		dev_err(drm->dev, "Couldn't initialize layer\n");
		return ERR_PTR(ret);
	}

535 536 537 538
	plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;

	ret = drm_plane_create_zpos_property(&layer->plane, index,
					     0, plane_cnt - 1);
539 540 541 542 543
	if (ret) {
		dev_err(drm->dev, "Couldn't add zpos property\n");
		return ERR_PTR(ret);
	}

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
	supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
			      BIT(DRM_COLOR_YCBCR_BT709);

	supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
			   BIT(DRM_COLOR_YCBCR_FULL_RANGE);

	ret = drm_plane_create_color_properties(&layer->plane,
						supported_encodings,
						supported_ranges,
						DRM_COLOR_YCBCR_BT709,
						DRM_COLOR_YCBCR_LIMITED_RANGE);
	if (ret) {
		dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
		return ERR_PTR(ret);
	}

560 561 562 563 564 565 566
	drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
	layer->mixer = mixer;
	layer->channel = index;
	layer->overlay = 0;

	return layer;
}