0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <drm/drm_atomic.h>
0011 #include <drm/drm_atomic_helper.h>
0012 #include <drm/drm_blend.h>
0013 #include <drm/drm_crtc.h>
0014 #include <drm/drm_device.h>
0015 #include <drm/drm_fb_cma_helper.h>
0016 #include <drm/drm_fourcc.h>
0017 #include <drm/drm_framebuffer.h>
0018 #include <drm/drm_gem_cma_helper.h>
0019 #include <drm/drm_plane_helper.h>
0020
0021 #include "rcar_du_drv.h"
0022 #include "rcar_du_group.h"
0023 #include "rcar_du_kms.h"
0024 #include "rcar_du_plane.h"
0025 #include "rcar_du_regs.h"
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 static bool rcar_du_plane_needs_realloc(
0052 const struct rcar_du_plane_state *old_state,
0053 const struct rcar_du_plane_state *new_state)
0054 {
0055
0056
0057
0058
0059
0060 if (!old_state->format ||
0061 old_state->format->planes != new_state->format->planes)
0062 return true;
0063
0064
0065 if (old_state->source != new_state->source)
0066 return true;
0067
0068 return false;
0069 }
0070
0071 static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state)
0072 {
0073 unsigned int mask;
0074
0075 if (state->hwindex == -1)
0076 return 0;
0077
0078 mask = 1 << state->hwindex;
0079 if (state->format->planes == 2)
0080 mask |= 1 << ((state->hwindex + 1) % 8);
0081
0082 return mask;
0083 }
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 static int rcar_du_plane_hwalloc(struct rcar_du_plane *plane,
0098 struct rcar_du_plane_state *state,
0099 unsigned int free)
0100 {
0101 unsigned int num_planes = state->format->planes;
0102 int fixed = -1;
0103 int i;
0104
0105 if (state->source == RCAR_DU_PLANE_VSPD0) {
0106
0107 if (plane->group->index != 0)
0108 return -EINVAL;
0109
0110 fixed = 0;
0111 } else if (state->source == RCAR_DU_PLANE_VSPD1) {
0112
0113 fixed = plane->group->index == 0 ? 1 : 0;
0114 }
0115
0116 if (fixed >= 0)
0117 return free & (1 << fixed) ? fixed : -EBUSY;
0118
0119 for (i = RCAR_DU_NUM_HW_PLANES - 1; i >= 0; --i) {
0120 if (!(free & (1 << i)))
0121 continue;
0122
0123 if (num_planes == 1 || free & (1 << ((i + 1) % 8)))
0124 break;
0125 }
0126
0127 return i < 0 ? -EBUSY : i;
0128 }
0129
0130 int rcar_du_atomic_check_planes(struct drm_device *dev,
0131 struct drm_atomic_state *state)
0132 {
0133 struct rcar_du_device *rcdu = to_rcar_du_device(dev);
0134 unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, };
0135 unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, };
0136 bool needs_realloc = false;
0137 unsigned int groups = 0;
0138 unsigned int i;
0139 struct drm_plane *drm_plane;
0140 struct drm_plane_state *old_drm_plane_state;
0141 struct drm_plane_state *new_drm_plane_state;
0142
0143
0144 for_each_oldnew_plane_in_state(state, drm_plane, old_drm_plane_state,
0145 new_drm_plane_state, i) {
0146 struct rcar_du_plane_state *old_plane_state;
0147 struct rcar_du_plane_state *new_plane_state;
0148 struct rcar_du_plane *plane;
0149 unsigned int index;
0150
0151 plane = to_rcar_plane(drm_plane);
0152 old_plane_state = to_rcar_plane_state(old_drm_plane_state);
0153 new_plane_state = to_rcar_plane_state(new_drm_plane_state);
0154
0155 dev_dbg(rcdu->dev, "%s: checking plane (%u,%tu)\n", __func__,
0156 plane->group->index, plane - plane->group->planes);
0157
0158
0159
0160
0161
0162
0163 if (!new_plane_state->format) {
0164 dev_dbg(rcdu->dev, "%s: plane is being disabled\n",
0165 __func__);
0166 index = plane - plane->group->planes;
0167 group_freed_planes[plane->group->index] |= 1 << index;
0168 new_plane_state->hwindex = -1;
0169 continue;
0170 }
0171
0172
0173
0174
0175
0176 if (rcar_du_plane_needs_realloc(old_plane_state, new_plane_state)) {
0177 dev_dbg(rcdu->dev, "%s: plane needs reallocation\n",
0178 __func__);
0179 groups |= 1 << plane->group->index;
0180 needs_realloc = true;
0181
0182 index = plane - plane->group->planes;
0183 group_freed_planes[plane->group->index] |= 1 << index;
0184 new_plane_state->hwindex = -1;
0185 }
0186 }
0187
0188 if (!needs_realloc)
0189 return 0;
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200 while (groups) {
0201 unsigned int index = ffs(groups) - 1;
0202 struct rcar_du_group *group = &rcdu->groups[index];
0203 unsigned int used_planes = 0;
0204
0205 dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n",
0206 __func__, index);
0207
0208 for (i = 0; i < group->num_planes; ++i) {
0209 struct rcar_du_plane *plane = &group->planes[i];
0210 struct rcar_du_plane_state *new_plane_state;
0211 struct drm_plane_state *s;
0212
0213 s = drm_atomic_get_plane_state(state, &plane->plane);
0214 if (IS_ERR(s))
0215 return PTR_ERR(s);
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225 if (group_freed_planes[index] & (1 << i)) {
0226 dev_dbg(rcdu->dev,
0227 "%s: plane (%u,%tu) has been freed, skipping\n",
0228 __func__, plane->group->index,
0229 plane - plane->group->planes);
0230 continue;
0231 }
0232
0233 new_plane_state = to_rcar_plane_state(s);
0234 used_planes |= rcar_du_plane_hwmask(new_plane_state);
0235
0236 dev_dbg(rcdu->dev,
0237 "%s: plane (%u,%tu) uses %u hwplanes (index %d)\n",
0238 __func__, plane->group->index,
0239 plane - plane->group->planes,
0240 new_plane_state->format ?
0241 new_plane_state->format->planes : 0,
0242 new_plane_state->hwindex);
0243 }
0244
0245 group_free_planes[index] = 0xff & ~used_planes;
0246 groups &= ~(1 << index);
0247
0248 dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n",
0249 __func__, index, group_free_planes[index]);
0250 }
0251
0252
0253 for_each_oldnew_plane_in_state(state, drm_plane, old_drm_plane_state,
0254 new_drm_plane_state, i) {
0255 struct rcar_du_plane_state *old_plane_state;
0256 struct rcar_du_plane_state *new_plane_state;
0257 struct rcar_du_plane *plane;
0258 unsigned int crtc_planes;
0259 unsigned int free;
0260 int idx;
0261
0262 plane = to_rcar_plane(drm_plane);
0263 old_plane_state = to_rcar_plane_state(old_drm_plane_state);
0264 new_plane_state = to_rcar_plane_state(new_drm_plane_state);
0265
0266 dev_dbg(rcdu->dev, "%s: allocating plane (%u,%tu)\n", __func__,
0267 plane->group->index, plane - plane->group->planes);
0268
0269
0270
0271
0272
0273 if (!new_plane_state->format ||
0274 !rcar_du_plane_needs_realloc(old_plane_state, new_plane_state))
0275 continue;
0276
0277
0278
0279
0280
0281
0282
0283 crtc_planes = to_rcar_crtc(new_plane_state->state.crtc)->index % 2
0284 ? plane->group->dptsr_planes
0285 : ~plane->group->dptsr_planes;
0286 free = group_free_planes[plane->group->index];
0287
0288 idx = rcar_du_plane_hwalloc(plane, new_plane_state,
0289 free & crtc_planes);
0290 if (idx < 0)
0291 idx = rcar_du_plane_hwalloc(plane, new_plane_state,
0292 free);
0293 if (idx < 0) {
0294 dev_dbg(rcdu->dev, "%s: no available hardware plane\n",
0295 __func__);
0296 return idx;
0297 }
0298
0299 dev_dbg(rcdu->dev, "%s: allocated %u hwplanes (index %u)\n",
0300 __func__, new_plane_state->format->planes, idx);
0301
0302 new_plane_state->hwindex = idx;
0303
0304 group_free_planes[plane->group->index] &=
0305 ~rcar_du_plane_hwmask(new_plane_state);
0306
0307 dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n",
0308 __func__, plane->group->index,
0309 group_free_planes[plane->group->index]);
0310 }
0311
0312 return 0;
0313 }
0314
0315
0316
0317
0318
0319 #define RCAR_DU_COLORKEY_NONE (0 << 24)
0320 #define RCAR_DU_COLORKEY_SOURCE (1 << 24)
0321 #define RCAR_DU_COLORKEY_MASK (1 << 24)
0322
0323 static void rcar_du_plane_write(struct rcar_du_group *rgrp,
0324 unsigned int index, u32 reg, u32 data)
0325 {
0326 rcar_du_write(rgrp->dev, rgrp->mmio_offset + index * PLANE_OFF + reg,
0327 data);
0328 }
0329
0330 static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp,
0331 const struct rcar_du_plane_state *state)
0332 {
0333 unsigned int src_x = state->state.src.x1 >> 16;
0334 unsigned int src_y = state->state.src.y1 >> 16;
0335 unsigned int index = state->hwindex;
0336 unsigned int pitch;
0337 bool interlaced;
0338 u32 dma[2];
0339
0340 interlaced = state->state.crtc->state->adjusted_mode.flags
0341 & DRM_MODE_FLAG_INTERLACE;
0342
0343 if (state->source == RCAR_DU_PLANE_MEMORY) {
0344 struct drm_framebuffer *fb = state->state.fb;
0345 struct drm_gem_cma_object *gem;
0346 unsigned int i;
0347
0348 if (state->format->planes == 2)
0349 pitch = fb->pitches[0];
0350 else
0351 pitch = fb->pitches[0] * 8 / state->format->bpp;
0352
0353 for (i = 0; i < state->format->planes; ++i) {
0354 gem = drm_fb_cma_get_gem_obj(fb, i);
0355 dma[i] = gem->paddr + fb->offsets[i];
0356 }
0357 } else {
0358 pitch = drm_rect_width(&state->state.src) >> 16;
0359 dma[0] = 0;
0360 dma[1] = 0;
0361 }
0362
0363
0364
0365
0366
0367 rcar_du_plane_write(rgrp, index, PnMWR,
0368 (interlaced && state->format->bpp == 32) ?
0369 pitch * 2 : pitch);
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384 rcar_du_plane_write(rgrp, index, PnSPXR, src_x);
0385 rcar_du_plane_write(rgrp, index, PnSPYR, src_y *
0386 (!interlaced && state->format->bpp == 32 ? 2 : 1));
0387
0388 rcar_du_plane_write(rgrp, index, PnDSA0R, dma[0]);
0389
0390 if (state->format->planes == 2) {
0391 index = (index + 1) % 8;
0392
0393 rcar_du_plane_write(rgrp, index, PnMWR, pitch);
0394
0395 rcar_du_plane_write(rgrp, index, PnSPXR, src_x);
0396 rcar_du_plane_write(rgrp, index, PnSPYR, src_y *
0397 (state->format->bpp == 16 ? 2 : 1) / 2);
0398
0399 rcar_du_plane_write(rgrp, index, PnDSA0R, dma[1]);
0400 }
0401 }
0402
0403 static void rcar_du_plane_setup_mode(struct rcar_du_group *rgrp,
0404 unsigned int index,
0405 const struct rcar_du_plane_state *state)
0406 {
0407 u32 colorkey;
0408 u32 pnmr;
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420 if (state->format->fourcc != DRM_FORMAT_XRGB1555)
0421 rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0);
0422 else
0423 rcar_du_plane_write(rgrp, index, PnALPHAR,
0424 PnALPHAR_ABIT_X | state->state.alpha >> 8);
0425
0426 pnmr = PnMR_BM_MD | state->format->pnmr;
0427
0428
0429
0430
0431
0432
0433 if ((state->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE)
0434 pnmr |= PnMR_SPIM_TP_OFF;
0435
0436
0437 if (state->format->fourcc == DRM_FORMAT_YUYV)
0438 pnmr |= PnMR_YCDF_YUYV;
0439
0440 rcar_du_plane_write(rgrp, index, PnMR, pnmr);
0441
0442 switch (state->format->fourcc) {
0443 case DRM_FORMAT_RGB565:
0444 colorkey = ((state->colorkey & 0xf80000) >> 8)
0445 | ((state->colorkey & 0x00fc00) >> 5)
0446 | ((state->colorkey & 0x0000f8) >> 3);
0447 rcar_du_plane_write(rgrp, index, PnTC2R, colorkey);
0448 break;
0449
0450 case DRM_FORMAT_ARGB1555:
0451 case DRM_FORMAT_XRGB1555:
0452 colorkey = ((state->colorkey & 0xf80000) >> 9)
0453 | ((state->colorkey & 0x00f800) >> 6)
0454 | ((state->colorkey & 0x0000f8) >> 3);
0455 rcar_du_plane_write(rgrp, index, PnTC2R, colorkey);
0456 break;
0457
0458 case DRM_FORMAT_XRGB8888:
0459 case DRM_FORMAT_ARGB8888:
0460 rcar_du_plane_write(rgrp, index, PnTC3R,
0461 PnTC3R_CODE | (state->colorkey & 0xffffff));
0462 break;
0463 }
0464 }
0465
0466 static void rcar_du_plane_setup_format_gen2(struct rcar_du_group *rgrp,
0467 unsigned int index,
0468 const struct rcar_du_plane_state *state)
0469 {
0470 u32 ddcr2 = PnDDCR2_CODE;
0471 u32 ddcr4;
0472
0473
0474
0475
0476
0477
0478
0479
0480 rcar_du_plane_setup_mode(rgrp, index, state);
0481
0482 if (state->format->planes == 2) {
0483 if (state->hwindex != index) {
0484 if (state->format->fourcc == DRM_FORMAT_NV12 ||
0485 state->format->fourcc == DRM_FORMAT_NV21)
0486 ddcr2 |= PnDDCR2_Y420;
0487
0488 if (state->format->fourcc == DRM_FORMAT_NV21)
0489 ddcr2 |= PnDDCR2_NV21;
0490
0491 ddcr2 |= PnDDCR2_DIVU;
0492 } else {
0493 ddcr2 |= PnDDCR2_DIVY;
0494 }
0495 }
0496
0497 rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2);
0498
0499 ddcr4 = state->format->edf | PnDDCR4_CODE;
0500 if (state->source != RCAR_DU_PLANE_MEMORY)
0501 ddcr4 |= PnDDCR4_VSPS;
0502
0503 rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4);
0504 }
0505
0506 static void rcar_du_plane_setup_format_gen3(struct rcar_du_group *rgrp,
0507 unsigned int index,
0508 const struct rcar_du_plane_state *state)
0509 {
0510 rcar_du_plane_write(rgrp, index, PnMR,
0511 PnMR_SPIM_TP_OFF | state->format->pnmr);
0512
0513 rcar_du_plane_write(rgrp, index, PnDDCR4,
0514 state->format->edf | PnDDCR4_CODE);
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526 rcar_du_plane_write(rgrp, index, PnALPHAR, 0);
0527 }
0528
0529 static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp,
0530 unsigned int index,
0531 const struct rcar_du_plane_state *state)
0532 {
0533 struct rcar_du_device *rcdu = rgrp->dev;
0534 const struct drm_rect *dst = &state->state.dst;
0535
0536 if (rcdu->info->gen < 3)
0537 rcar_du_plane_setup_format_gen2(rgrp, index, state);
0538 else
0539 rcar_du_plane_setup_format_gen3(rgrp, index, state);
0540
0541
0542 rcar_du_plane_write(rgrp, index, PnDSXR, drm_rect_width(dst));
0543 rcar_du_plane_write(rgrp, index, PnDSYR, drm_rect_height(dst));
0544 rcar_du_plane_write(rgrp, index, PnDPXR, dst->x1);
0545 rcar_du_plane_write(rgrp, index, PnDPYR, dst->y1);
0546
0547 if (rcdu->info->gen < 3) {
0548
0549 rcar_du_plane_write(rgrp, index, PnWASPR, 0);
0550 rcar_du_plane_write(rgrp, index, PnWAMWR, 4095);
0551 rcar_du_plane_write(rgrp, index, PnBTR, 0);
0552 rcar_du_plane_write(rgrp, index, PnMLR, 0);
0553 }
0554 }
0555
0556 void __rcar_du_plane_setup(struct rcar_du_group *rgrp,
0557 const struct rcar_du_plane_state *state)
0558 {
0559 struct rcar_du_device *rcdu = rgrp->dev;
0560
0561 rcar_du_plane_setup_format(rgrp, state->hwindex, state);
0562 if (state->format->planes == 2)
0563 rcar_du_plane_setup_format(rgrp, (state->hwindex + 1) % 8,
0564 state);
0565
0566 if (rcdu->info->gen >= 3)
0567 return;
0568
0569 rcar_du_plane_setup_scanout(rgrp, state);
0570
0571 if (state->source == RCAR_DU_PLANE_VSPD1) {
0572 unsigned int vspd1_sink = rgrp->index ? 2 : 0;
0573
0574 if (rcdu->vspd1_sink != vspd1_sink) {
0575 rcdu->vspd1_sink = vspd1_sink;
0576 rcar_du_set_dpad0_vsp1_routing(rcdu);
0577
0578
0579
0580
0581
0582 rgrp->need_restart = true;
0583 }
0584 }
0585 }
0586
0587 int __rcar_du_plane_atomic_check(struct drm_plane *plane,
0588 struct drm_plane_state *state,
0589 const struct rcar_du_format_info **format)
0590 {
0591 struct drm_device *dev = plane->dev;
0592 struct drm_crtc_state *crtc_state;
0593 int ret;
0594
0595 if (!state->crtc) {
0596
0597
0598
0599
0600 state->visible = false;
0601 *format = NULL;
0602 return 0;
0603 }
0604
0605 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
0606 if (IS_ERR(crtc_state))
0607 return PTR_ERR(crtc_state);
0608
0609 ret = drm_atomic_helper_check_plane_state(state, crtc_state,
0610 DRM_PLANE_HELPER_NO_SCALING,
0611 DRM_PLANE_HELPER_NO_SCALING,
0612 true, true);
0613 if (ret < 0)
0614 return ret;
0615
0616 if (!state->visible) {
0617 *format = NULL;
0618 return 0;
0619 }
0620
0621 *format = rcar_du_format_info(state->fb->format->format);
0622 if (*format == NULL) {
0623 dev_dbg(dev->dev, "%s: unsupported format %08x\n", __func__,
0624 state->fb->format->format);
0625 return -EINVAL;
0626 }
0627
0628 return 0;
0629 }
0630
0631 static int rcar_du_plane_atomic_check(struct drm_plane *plane,
0632 struct drm_atomic_state *state)
0633 {
0634 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
0635 plane);
0636 struct rcar_du_plane_state *rstate = to_rcar_plane_state(new_plane_state);
0637
0638 return __rcar_du_plane_atomic_check(plane, new_plane_state,
0639 &rstate->format);
0640 }
0641
0642 static void rcar_du_plane_atomic_update(struct drm_plane *plane,
0643 struct drm_atomic_state *state)
0644 {
0645 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
0646 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
0647 struct rcar_du_plane *rplane = to_rcar_plane(plane);
0648 struct rcar_du_plane_state *old_rstate;
0649 struct rcar_du_plane_state *new_rstate;
0650
0651 if (!new_state->visible)
0652 return;
0653
0654 rcar_du_plane_setup(rplane);
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664 old_rstate = to_rcar_plane_state(old_state);
0665 new_rstate = to_rcar_plane_state(new_state);
0666
0667 if ((old_rstate->source == RCAR_DU_PLANE_MEMORY) !=
0668 (new_rstate->source == RCAR_DU_PLANE_MEMORY))
0669 rplane->group->need_restart = true;
0670 }
0671
0672 static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = {
0673 .atomic_check = rcar_du_plane_atomic_check,
0674 .atomic_update = rcar_du_plane_atomic_update,
0675 };
0676
0677 static struct drm_plane_state *
0678 rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
0679 {
0680 struct rcar_du_plane_state *state;
0681 struct rcar_du_plane_state *copy;
0682
0683 if (WARN_ON(!plane->state))
0684 return NULL;
0685
0686 state = to_rcar_plane_state(plane->state);
0687 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
0688 if (copy == NULL)
0689 return NULL;
0690
0691 __drm_atomic_helper_plane_duplicate_state(plane, ©->state);
0692
0693 return ©->state;
0694 }
0695
0696 static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
0697 struct drm_plane_state *state)
0698 {
0699 __drm_atomic_helper_plane_destroy_state(state);
0700 kfree(to_rcar_plane_state(state));
0701 }
0702
0703 static void rcar_du_plane_reset(struct drm_plane *plane)
0704 {
0705 struct rcar_du_plane_state *state;
0706
0707 if (plane->state) {
0708 rcar_du_plane_atomic_destroy_state(plane, plane->state);
0709 plane->state = NULL;
0710 }
0711
0712 state = kzalloc(sizeof(*state), GFP_KERNEL);
0713 if (state == NULL)
0714 return;
0715
0716 __drm_atomic_helper_plane_reset(plane, &state->state);
0717
0718 state->hwindex = -1;
0719 state->source = RCAR_DU_PLANE_MEMORY;
0720 state->colorkey = RCAR_DU_COLORKEY_NONE;
0721 }
0722
0723 static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
0724 struct drm_plane_state *state,
0725 struct drm_property *property,
0726 uint64_t val)
0727 {
0728 struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
0729 struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
0730
0731 if (property == rcdu->props.colorkey)
0732 rstate->colorkey = val;
0733 else
0734 return -EINVAL;
0735
0736 return 0;
0737 }
0738
0739 static int rcar_du_plane_atomic_get_property(struct drm_plane *plane,
0740 const struct drm_plane_state *state, struct drm_property *property,
0741 uint64_t *val)
0742 {
0743 const struct rcar_du_plane_state *rstate =
0744 container_of(state, const struct rcar_du_plane_state, state);
0745 struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
0746
0747 if (property == rcdu->props.colorkey)
0748 *val = rstate->colorkey;
0749 else
0750 return -EINVAL;
0751
0752 return 0;
0753 }
0754
0755 static const struct drm_plane_funcs rcar_du_plane_funcs = {
0756 .update_plane = drm_atomic_helper_update_plane,
0757 .disable_plane = drm_atomic_helper_disable_plane,
0758 .reset = rcar_du_plane_reset,
0759 .destroy = drm_plane_cleanup,
0760 .atomic_duplicate_state = rcar_du_plane_atomic_duplicate_state,
0761 .atomic_destroy_state = rcar_du_plane_atomic_destroy_state,
0762 .atomic_set_property = rcar_du_plane_atomic_set_property,
0763 .atomic_get_property = rcar_du_plane_atomic_get_property,
0764 };
0765
0766 static const uint32_t formats[] = {
0767 DRM_FORMAT_RGB565,
0768 DRM_FORMAT_ARGB1555,
0769 DRM_FORMAT_XRGB1555,
0770 DRM_FORMAT_XRGB8888,
0771 DRM_FORMAT_ARGB8888,
0772 DRM_FORMAT_UYVY,
0773 DRM_FORMAT_YUYV,
0774 DRM_FORMAT_NV12,
0775 DRM_FORMAT_NV21,
0776 DRM_FORMAT_NV16,
0777 };
0778
0779 int rcar_du_planes_init(struct rcar_du_group *rgrp)
0780 {
0781 struct rcar_du_device *rcdu = rgrp->dev;
0782 unsigned int crtcs;
0783 unsigned int i;
0784 int ret;
0785
0786
0787
0788
0789
0790 rgrp->num_planes = rgrp->num_crtcs + 7;
0791
0792 crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
0793
0794 for (i = 0; i < rgrp->num_planes; ++i) {
0795 enum drm_plane_type type = i < rgrp->num_crtcs
0796 ? DRM_PLANE_TYPE_PRIMARY
0797 : DRM_PLANE_TYPE_OVERLAY;
0798 struct rcar_du_plane *plane = &rgrp->planes[i];
0799
0800 plane->group = rgrp;
0801
0802 ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane,
0803 crtcs, &rcar_du_plane_funcs,
0804 formats, ARRAY_SIZE(formats),
0805 NULL, type, NULL);
0806 if (ret < 0)
0807 return ret;
0808
0809 drm_plane_helper_add(&plane->plane,
0810 &rcar_du_plane_helper_funcs);
0811
0812 drm_plane_create_alpha_property(&plane->plane);
0813
0814 if (type == DRM_PLANE_TYPE_PRIMARY) {
0815 drm_plane_create_zpos_immutable_property(&plane->plane,
0816 0);
0817 } else {
0818 drm_object_attach_property(&plane->plane.base,
0819 rcdu->props.colorkey,
0820 RCAR_DU_COLORKEY_NONE);
0821 drm_plane_create_zpos_property(&plane->plane, 1, 1, 7);
0822 }
0823 }
0824
0825 return 0;
0826 }