cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sun8i_vi_layer.c (17341B)


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