0001
0002
0003
0004
0005
0006 #include <drm/drm_atomic.h>
0007 #include <drm/drm_atomic_helper.h>
0008 #include <drm/drm_blend.h>
0009 #include <drm/drm_crtc.h>
0010 #include <drm/drm_fb_cma_helper.h>
0011 #include <drm/drm_framebuffer.h>
0012 #include <drm/drm_gem_atomic_helper.h>
0013 #include <drm/drm_gem_cma_helper.h>
0014 #include <drm/drm_plane_helper.h>
0015 #include <drm/drm_probe_helper.h>
0016
0017 #include "sun8i_csc.h"
0018 #include "sun8i_mixer.h"
0019 #include "sun8i_vi_layer.h"
0020 #include "sun8i_vi_scaler.h"
0021
0022 static void sun8i_vi_layer_enable(struct sun8i_mixer *mixer, int channel,
0023 int overlay, bool enable, unsigned int zpos,
0024 unsigned int old_zpos)
0025 {
0026 u32 val, bld_base, ch_base;
0027
0028 bld_base = sun8i_blender_base(mixer);
0029 ch_base = sun8i_channel_base(mixer, channel);
0030
0031 DRM_DEBUG_DRIVER("%sabling VI channel %d overlay %d\n",
0032 enable ? "En" : "Dis", channel, overlay);
0033
0034 if (enable)
0035 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
0036 else
0037 val = 0;
0038
0039 regmap_update_bits(mixer->engine.regs,
0040 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
0041 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN, val);
0042
0043 if (!enable || zpos != old_zpos) {
0044 regmap_update_bits(mixer->engine.regs,
0045 SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
0046 SUN8I_MIXER_BLEND_PIPE_CTL_EN(old_zpos),
0047 0);
0048
0049 regmap_update_bits(mixer->engine.regs,
0050 SUN8I_MIXER_BLEND_ROUTE(bld_base),
0051 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(old_zpos),
0052 0);
0053 }
0054
0055 if (enable) {
0056 val = SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
0057
0058 regmap_update_bits(mixer->engine.regs,
0059 SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
0060 val, val);
0061
0062 val = channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
0063
0064 regmap_update_bits(mixer->engine.regs,
0065 SUN8I_MIXER_BLEND_ROUTE(bld_base),
0066 SUN8I_MIXER_BLEND_ROUTE_PIPE_MSK(zpos),
0067 val);
0068 }
0069 }
0070
0071 static void sun8i_vi_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
0072 int overlay, struct drm_plane *plane)
0073 {
0074 u32 mask, val, ch_base;
0075
0076 ch_base = sun8i_channel_base(mixer, channel);
0077
0078 if (mixer->cfg->is_de3) {
0079 mask = SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MASK |
0080 SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_MASK;
0081 val = SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA
0082 (plane->state->alpha >> 8);
0083
0084 val |= (plane->state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
0085 SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_PIXEL :
0086 SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_COMBINED;
0087
0088 regmap_update_bits(mixer->engine.regs,
0089 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
0090 overlay),
0091 mask, val);
0092 } else if (mixer->cfg->vi_num == 1) {
0093 regmap_update_bits(mixer->engine.regs,
0094 SUN8I_MIXER_FCC_GLOBAL_ALPHA_REG,
0095 SUN8I_MIXER_FCC_GLOBAL_ALPHA_MASK,
0096 SUN8I_MIXER_FCC_GLOBAL_ALPHA
0097 (plane->state->alpha >> 8));
0098 }
0099 }
0100
0101 static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
0102 int overlay, struct drm_plane *plane,
0103 unsigned int zpos)
0104 {
0105 struct drm_plane_state *state = plane->state;
0106 const struct drm_format_info *format = state->fb->format;
0107 u32 src_w, src_h, dst_w, dst_h;
0108 u32 bld_base, ch_base;
0109 u32 outsize, insize;
0110 u32 hphase, vphase;
0111 u32 hn = 0, hm = 0;
0112 u32 vn = 0, vm = 0;
0113 bool subsampled;
0114
0115 DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
0116 channel, overlay);
0117
0118 bld_base = sun8i_blender_base(mixer);
0119 ch_base = sun8i_channel_base(mixer, channel);
0120
0121 src_w = drm_rect_width(&state->src) >> 16;
0122 src_h = drm_rect_height(&state->src) >> 16;
0123 dst_w = drm_rect_width(&state->dst);
0124 dst_h = drm_rect_height(&state->dst);
0125
0126 hphase = state->src.x1 & 0xffff;
0127 vphase = state->src.y1 & 0xffff;
0128
0129
0130 if (format->hsub > 1) {
0131 int mask, remainder;
0132
0133 mask = format->hsub - 1;
0134 remainder = (state->src.x1 >> 16) & mask;
0135 src_w = (src_w + remainder) & ~mask;
0136 hphase += remainder << 16;
0137 }
0138
0139 if (format->vsub > 1) {
0140 int mask, remainder;
0141
0142 mask = format->vsub - 1;
0143 remainder = (state->src.y1 >> 16) & mask;
0144 src_h = (src_h + remainder) & ~mask;
0145 vphase += remainder << 16;
0146 }
0147
0148 insize = SUN8I_MIXER_SIZE(src_w, src_h);
0149 outsize = SUN8I_MIXER_SIZE(dst_w, dst_h);
0150
0151
0152 DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
0153 (state->src.x1 >> 16) & ~(format->hsub - 1),
0154 (state->src.y1 >> 16) & ~(format->vsub - 1));
0155 DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
0156 regmap_write(mixer->engine.regs,
0157 SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
0158 insize);
0159 regmap_write(mixer->engine.regs,
0160 SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
0161 insize);
0162
0163
0164
0165
0166
0167 subsampled = format->hsub > 1 || format->vsub > 1;
0168
0169 if (insize != outsize || subsampled || hphase || vphase) {
0170 unsigned int scanline, required;
0171 struct drm_display_mode *mode;
0172 u32 hscale, vscale, fps;
0173 u64 ability;
0174
0175 DRM_DEBUG_DRIVER("HW scaling is enabled\n");
0176
0177 mode = &plane->state->crtc->state->mode;
0178 fps = (mode->clock * 1000) / (mode->vtotal * mode->htotal);
0179 ability = clk_get_rate(mixer->mod_clk);
0180
0181 ability *= 80;
0182 do_div(ability, mode->vdisplay * fps * max(src_w, dst_w));
0183
0184 required = src_h * 100 / dst_h;
0185
0186 if (ability < required) {
0187 DRM_DEBUG_DRIVER("Using vertical coarse scaling\n");
0188 vm = src_h;
0189 vn = (u32)ability * dst_h / 100;
0190 src_h = vn;
0191 }
0192
0193
0194 scanline = subsampled ? mixer->cfg->scanline_yuv : 2048;
0195
0196 if (src_w > scanline) {
0197 DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
0198 hm = src_w;
0199 hn = scanline;
0200 src_w = hn;
0201 }
0202
0203 hscale = (src_w << 16) / dst_w;
0204 vscale = (src_h << 16) / dst_h;
0205
0206 sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
0207 dst_h, hscale, vscale, hphase, vphase,
0208 format);
0209 sun8i_vi_scaler_enable(mixer, channel, true);
0210 } else {
0211 DRM_DEBUG_DRIVER("HW scaling is not needed\n");
0212 sun8i_vi_scaler_enable(mixer, channel, false);
0213 }
0214
0215 regmap_write(mixer->engine.regs,
0216 SUN8I_MIXER_CHAN_VI_HDS_Y(ch_base),
0217 SUN8I_MIXER_CHAN_VI_DS_N(hn) |
0218 SUN8I_MIXER_CHAN_VI_DS_M(hm));
0219 regmap_write(mixer->engine.regs,
0220 SUN8I_MIXER_CHAN_VI_HDS_UV(ch_base),
0221 SUN8I_MIXER_CHAN_VI_DS_N(hn) |
0222 SUN8I_MIXER_CHAN_VI_DS_M(hm));
0223 regmap_write(mixer->engine.regs,
0224 SUN8I_MIXER_CHAN_VI_VDS_Y(ch_base),
0225 SUN8I_MIXER_CHAN_VI_DS_N(vn) |
0226 SUN8I_MIXER_CHAN_VI_DS_M(vm));
0227 regmap_write(mixer->engine.regs,
0228 SUN8I_MIXER_CHAN_VI_VDS_UV(ch_base),
0229 SUN8I_MIXER_CHAN_VI_DS_N(vn) |
0230 SUN8I_MIXER_CHAN_VI_DS_M(vm));
0231
0232
0233 DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
0234 state->dst.x1, state->dst.y1);
0235 DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
0236 regmap_write(mixer->engine.regs,
0237 SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
0238 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
0239 regmap_write(mixer->engine.regs,
0240 SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
0241 outsize);
0242
0243 return 0;
0244 }
0245
0246 static u32 sun8i_vi_layer_get_csc_mode(const struct drm_format_info *format)
0247 {
0248 if (!format->is_yuv)
0249 return SUN8I_CSC_MODE_OFF;
0250
0251 switch (format->format) {
0252 case DRM_FORMAT_YVU411:
0253 case DRM_FORMAT_YVU420:
0254 case DRM_FORMAT_YVU422:
0255 case DRM_FORMAT_YVU444:
0256 return SUN8I_CSC_MODE_YVU2RGB;
0257 default:
0258 return SUN8I_CSC_MODE_YUV2RGB;
0259 }
0260 }
0261
0262 static int sun8i_vi_layer_update_formats(struct sun8i_mixer *mixer, int channel,
0263 int overlay, struct drm_plane *plane)
0264 {
0265 struct drm_plane_state *state = plane->state;
0266 u32 val, ch_base, csc_mode, hw_fmt;
0267 const struct drm_format_info *fmt;
0268 int ret;
0269
0270 ch_base = sun8i_channel_base(mixer, channel);
0271
0272 fmt = state->fb->format;
0273 ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
0274 if (ret) {
0275 DRM_DEBUG_DRIVER("Invalid format\n");
0276 return ret;
0277 }
0278
0279 val = hw_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
0280 regmap_update_bits(mixer->engine.regs,
0281 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
0282 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_MASK, val);
0283
0284 csc_mode = sun8i_vi_layer_get_csc_mode(fmt);
0285 if (csc_mode != SUN8I_CSC_MODE_OFF) {
0286 sun8i_csc_set_ccsc_coefficients(mixer, channel, csc_mode,
0287 state->color_encoding,
0288 state->color_range);
0289 sun8i_csc_enable_ccsc(mixer, channel, true);
0290 } else {
0291 sun8i_csc_enable_ccsc(mixer, channel, false);
0292 }
0293
0294 if (!fmt->is_yuv)
0295 val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
0296 else
0297 val = 0;
0298
0299 regmap_update_bits(mixer->engine.regs,
0300 SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
0301 SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
0302
0303 return 0;
0304 }
0305
0306 static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
0307 int overlay, struct drm_plane *plane)
0308 {
0309 struct drm_plane_state *state = plane->state;
0310 struct drm_framebuffer *fb = state->fb;
0311 const struct drm_format_info *format = fb->format;
0312 struct drm_gem_cma_object *gem;
0313 u32 dx, dy, src_x, src_y;
0314 dma_addr_t paddr;
0315 u32 ch_base;
0316 int i;
0317
0318 ch_base = sun8i_channel_base(mixer, channel);
0319
0320
0321 src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
0322 src_y = (state->src.y1 >> 16) & ~(format->vsub - 1);
0323
0324 for (i = 0; i < format->num_planes; i++) {
0325
0326 gem = drm_fb_cma_get_gem_obj(fb, i);
0327
0328 DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
0329
0330
0331 paddr = gem->paddr + fb->offsets[i];
0332
0333 dx = src_x;
0334 dy = src_y;
0335
0336 if (i > 0) {
0337 dx /= format->hsub;
0338 dy /= format->vsub;
0339 }
0340
0341
0342 paddr += dx * format->cpp[i];
0343 paddr += dy * fb->pitches[i];
0344
0345
0346 DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
0347 i + 1, fb->pitches[i]);
0348 regmap_write(mixer->engine.regs,
0349 SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
0350 overlay, i),
0351 fb->pitches[i]);
0352
0353 DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
0354 i + 1, &paddr);
0355
0356 regmap_write(mixer->engine.regs,
0357 SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
0358 overlay, i),
0359 lower_32_bits(paddr));
0360 }
0361
0362 return 0;
0363 }
0364
0365 static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
0366 struct drm_atomic_state *state)
0367 {
0368 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0369 plane);
0370 struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
0371 struct drm_crtc *crtc = new_plane_state->crtc;
0372 struct drm_crtc_state *crtc_state;
0373 int min_scale, max_scale;
0374
0375 if (!crtc)
0376 return 0;
0377
0378 crtc_state = drm_atomic_get_existing_crtc_state(state,
0379 crtc);
0380 if (WARN_ON(!crtc_state))
0381 return -EINVAL;
0382
0383 min_scale = DRM_PLANE_HELPER_NO_SCALING;
0384 max_scale = DRM_PLANE_HELPER_NO_SCALING;
0385
0386 if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
0387 min_scale = SUN8I_VI_SCALER_SCALE_MIN;
0388 max_scale = SUN8I_VI_SCALER_SCALE_MAX;
0389 }
0390
0391 return drm_atomic_helper_check_plane_state(new_plane_state,
0392 crtc_state,
0393 min_scale, max_scale,
0394 true, true);
0395 }
0396
0397 static void sun8i_vi_layer_atomic_disable(struct drm_plane *plane,
0398 struct drm_atomic_state *state)
0399 {
0400 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0401 plane);
0402 struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
0403 unsigned int old_zpos = old_state->normalized_zpos;
0404 struct sun8i_mixer *mixer = layer->mixer;
0405
0406 sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay, false, 0,
0407 old_zpos);
0408 }
0409
0410 static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
0411 struct drm_atomic_state *state)
0412 {
0413 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
0414 plane);
0415 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
0416 plane);
0417 struct sun8i_vi_layer *layer = plane_to_sun8i_vi_layer(plane);
0418 unsigned int zpos = new_state->normalized_zpos;
0419 unsigned int old_zpos = old_state->normalized_zpos;
0420 struct sun8i_mixer *mixer = layer->mixer;
0421
0422 if (!new_state->visible) {
0423 sun8i_vi_layer_enable(mixer, layer->channel,
0424 layer->overlay, false, 0, old_zpos);
0425 return;
0426 }
0427
0428 sun8i_vi_layer_update_coord(mixer, layer->channel,
0429 layer->overlay, plane, zpos);
0430 sun8i_vi_layer_update_alpha(mixer, layer->channel,
0431 layer->overlay, plane);
0432 sun8i_vi_layer_update_formats(mixer, layer->channel,
0433 layer->overlay, plane);
0434 sun8i_vi_layer_update_buffer(mixer, layer->channel,
0435 layer->overlay, plane);
0436 sun8i_vi_layer_enable(mixer, layer->channel, layer->overlay,
0437 true, zpos, old_zpos);
0438 }
0439
0440 static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
0441 .atomic_check = sun8i_vi_layer_atomic_check,
0442 .atomic_disable = sun8i_vi_layer_atomic_disable,
0443 .atomic_update = sun8i_vi_layer_atomic_update,
0444 };
0445
0446 static const struct drm_plane_funcs sun8i_vi_layer_funcs = {
0447 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
0448 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
0449 .destroy = drm_plane_cleanup,
0450 .disable_plane = drm_atomic_helper_disable_plane,
0451 .reset = drm_atomic_helper_plane_reset,
0452 .update_plane = drm_atomic_helper_update_plane,
0453 };
0454
0455
0456
0457
0458
0459
0460 static const u32 sun8i_vi_layer_formats[] = {
0461 DRM_FORMAT_BGR565,
0462 DRM_FORMAT_BGR888,
0463 DRM_FORMAT_BGRX4444,
0464 DRM_FORMAT_BGRX5551,
0465 DRM_FORMAT_BGRX8888,
0466 DRM_FORMAT_RGB565,
0467 DRM_FORMAT_RGB888,
0468 DRM_FORMAT_RGBX4444,
0469 DRM_FORMAT_RGBX5551,
0470 DRM_FORMAT_RGBX8888,
0471 DRM_FORMAT_XBGR1555,
0472 DRM_FORMAT_XBGR4444,
0473 DRM_FORMAT_XBGR8888,
0474 DRM_FORMAT_XRGB1555,
0475 DRM_FORMAT_XRGB4444,
0476 DRM_FORMAT_XRGB8888,
0477
0478 DRM_FORMAT_NV16,
0479 DRM_FORMAT_NV12,
0480 DRM_FORMAT_NV21,
0481 DRM_FORMAT_NV61,
0482 DRM_FORMAT_UYVY,
0483 DRM_FORMAT_VYUY,
0484 DRM_FORMAT_YUYV,
0485 DRM_FORMAT_YVYU,
0486 DRM_FORMAT_YUV411,
0487 DRM_FORMAT_YUV420,
0488 DRM_FORMAT_YUV422,
0489 DRM_FORMAT_YVU411,
0490 DRM_FORMAT_YVU420,
0491 DRM_FORMAT_YVU422,
0492 };
0493
0494 static const u32 sun8i_vi_layer_de3_formats[] = {
0495 DRM_FORMAT_ABGR1555,
0496 DRM_FORMAT_ABGR2101010,
0497 DRM_FORMAT_ABGR4444,
0498 DRM_FORMAT_ABGR8888,
0499 DRM_FORMAT_ARGB1555,
0500 DRM_FORMAT_ARGB2101010,
0501 DRM_FORMAT_ARGB4444,
0502 DRM_FORMAT_ARGB8888,
0503 DRM_FORMAT_BGR565,
0504 DRM_FORMAT_BGR888,
0505 DRM_FORMAT_BGRA1010102,
0506 DRM_FORMAT_BGRA5551,
0507 DRM_FORMAT_BGRA4444,
0508 DRM_FORMAT_BGRA8888,
0509 DRM_FORMAT_BGRX8888,
0510 DRM_FORMAT_RGB565,
0511 DRM_FORMAT_RGB888,
0512 DRM_FORMAT_RGBA1010102,
0513 DRM_FORMAT_RGBA4444,
0514 DRM_FORMAT_RGBA5551,
0515 DRM_FORMAT_RGBA8888,
0516 DRM_FORMAT_RGBX8888,
0517 DRM_FORMAT_XBGR8888,
0518 DRM_FORMAT_XRGB8888,
0519
0520 DRM_FORMAT_NV16,
0521 DRM_FORMAT_NV12,
0522 DRM_FORMAT_NV21,
0523 DRM_FORMAT_NV61,
0524 DRM_FORMAT_P010,
0525 DRM_FORMAT_P210,
0526 DRM_FORMAT_UYVY,
0527 DRM_FORMAT_VYUY,
0528 DRM_FORMAT_YUYV,
0529 DRM_FORMAT_YVYU,
0530 DRM_FORMAT_YUV411,
0531 DRM_FORMAT_YUV420,
0532 DRM_FORMAT_YUV422,
0533 DRM_FORMAT_YVU411,
0534 DRM_FORMAT_YVU420,
0535 DRM_FORMAT_YVU422,
0536 };
0537
0538 static const uint64_t sun8i_layer_modifiers[] = {
0539 DRM_FORMAT_MOD_LINEAR,
0540 DRM_FORMAT_MOD_INVALID
0541 };
0542
0543 struct sun8i_vi_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
0544 struct sun8i_mixer *mixer,
0545 int index)
0546 {
0547 enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
0548 u32 supported_encodings, supported_ranges;
0549 unsigned int plane_cnt, format_count;
0550 struct sun8i_vi_layer *layer;
0551 const u32 *formats;
0552 int ret;
0553
0554 layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
0555 if (!layer)
0556 return ERR_PTR(-ENOMEM);
0557
0558 if (mixer->cfg->is_de3) {
0559 formats = sun8i_vi_layer_de3_formats;
0560 format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
0561 } else {
0562 formats = sun8i_vi_layer_formats;
0563 format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
0564 }
0565
0566 if (!mixer->cfg->ui_num && index == 0)
0567 type = DRM_PLANE_TYPE_PRIMARY;
0568
0569
0570 ret = drm_universal_plane_init(drm, &layer->plane, 0,
0571 &sun8i_vi_layer_funcs,
0572 formats, format_count,
0573 sun8i_layer_modifiers,
0574 type, NULL);
0575 if (ret) {
0576 dev_err(drm->dev, "Couldn't initialize layer\n");
0577 return ERR_PTR(ret);
0578 }
0579
0580 plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
0581
0582 if (mixer->cfg->vi_num == 1 || mixer->cfg->is_de3) {
0583 ret = drm_plane_create_alpha_property(&layer->plane);
0584 if (ret) {
0585 dev_err(drm->dev, "Couldn't add alpha property\n");
0586 return ERR_PTR(ret);
0587 }
0588 }
0589
0590 ret = drm_plane_create_zpos_property(&layer->plane, index,
0591 0, plane_cnt - 1);
0592 if (ret) {
0593 dev_err(drm->dev, "Couldn't add zpos property\n");
0594 return ERR_PTR(ret);
0595 }
0596
0597 supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
0598 BIT(DRM_COLOR_YCBCR_BT709);
0599 if (mixer->cfg->is_de3)
0600 supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020);
0601
0602 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
0603 BIT(DRM_COLOR_YCBCR_FULL_RANGE);
0604
0605 ret = drm_plane_create_color_properties(&layer->plane,
0606 supported_encodings,
0607 supported_ranges,
0608 DRM_COLOR_YCBCR_BT709,
0609 DRM_COLOR_YCBCR_LIMITED_RANGE);
0610 if (ret) {
0611 dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
0612 return ERR_PTR(ret);
0613 }
0614
0615 drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
0616 layer->mixer = mixer;
0617 layer->channel = index;
0618 layer->overlay = 0;
0619
0620 return layer;
0621 }