Merge tag 'printk-for-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/printk...
[linux-2.6-microblaze.git] / drivers / gpu / drm / sun4i / sun8i_vi_layer.c
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
20 static 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
69 static 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
99 static 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
244 static 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
260 static 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
304 static 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
363 static 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
395 static 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
408 static 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
438 static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
439         .prepare_fb     = drm_gem_plane_helper_prepare_fb,
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 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
538                                                struct sun8i_mixer *mixer,
539                                                int index)
540 {
541         u32 supported_encodings, supported_ranges;
542         unsigned int plane_cnt, format_count;
543         struct sun8i_vi_layer *layer;
544         const u32 *formats;
545         int ret;
546
547         layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
548         if (!layer)
549                 return ERR_PTR(-ENOMEM);
550
551         if (mixer->cfg->is_de3) {
552                 formats = sun8i_vi_layer_de3_formats;
553                 format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
554         } else {
555                 formats = sun8i_vi_layer_formats;
556                 format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
557         }
558
559         /* possible crtcs are set later */
560         ret = drm_universal_plane_init(drm, &layer->plane, 0,
561                                        &sun8i_vi_layer_funcs,
562                                        formats, format_count,
563                                        NULL, DRM_PLANE_TYPE_OVERLAY, NULL);
564         if (ret) {
565                 dev_err(drm->dev, "Couldn't initialize layer\n");
566                 return ERR_PTR(ret);
567         }
568
569         plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
570
571         if (mixer->cfg->vi_num == 1 || mixer->cfg->is_de3) {
572                 ret = drm_plane_create_alpha_property(&layer->plane);
573                 if (ret) {
574                         dev_err(drm->dev, "Couldn't add alpha property\n");
575                         return ERR_PTR(ret);
576                 }
577         }
578
579         ret = drm_plane_create_zpos_property(&layer->plane, index,
580                                              0, plane_cnt - 1);
581         if (ret) {
582                 dev_err(drm->dev, "Couldn't add zpos property\n");
583                 return ERR_PTR(ret);
584         }
585
586         supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
587                               BIT(DRM_COLOR_YCBCR_BT709);
588         if (mixer->cfg->is_de3)
589                 supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020);
590
591         supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
592                            BIT(DRM_COLOR_YCBCR_FULL_RANGE);
593
594         ret = drm_plane_create_color_properties(&layer->plane,
595                                                 supported_encodings,
596                                                 supported_ranges,
597                                                 DRM_COLOR_YCBCR_BT709,
598                                                 DRM_COLOR_YCBCR_LIMITED_RANGE);
599         if (ret) {
600                 dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
601                 return ERR_PTR(ret);
602         }
603
604         drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
605         layer->mixer = mixer;
606         layer->channel = index;
607         layer->overlay = 0;
608
609         return layer;
610 }