1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * R-Car Display Unit Planes 4 * 5 * Copyright (C) 2013-2015 Renesas Electronics Corporation 6 * 7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) 8 */ 9 10 #include <drm/drm_atomic.h> 11 #include <drm/drm_atomic_helper.h> 12 #include <drm/drm_blend.h> 13 #include <drm/drm_crtc.h> 14 #include <drm/drm_device.h> 15 #include <drm/drm_fb_dma_helper.h> 16 #include <drm/drm_fourcc.h> 17 #include <drm/drm_framebuffer.h> 18 #include <drm/drm_gem_dma_helper.h> 19 20 #include "rcar_du_drv.h" 21 #include "rcar_du_group.h" 22 #include "rcar_du_kms.h" 23 #include "rcar_du_plane.h" 24 #include "rcar_du_regs.h" 25 26 /* ----------------------------------------------------------------------------- 27 * Atomic hardware plane allocator 28 * 29 * The hardware plane allocator is solely based on the atomic plane states 30 * without keeping any external state to avoid races between .atomic_check() 31 * and .atomic_commit(). 32 * 33 * The core idea is to avoid using a free planes bitmask that would need to be 34 * shared between check and commit handlers with a collective knowledge based on 35 * the allocated hardware plane(s) for each KMS plane. The allocator then loops 36 * over all plane states to compute the free planes bitmask, allocates hardware 37 * planes based on that bitmask, and stores the result back in the plane states. 38 * 39 * For this to work we need to access the current state of planes not touched by 40 * the atomic update. To ensure that it won't be modified, we need to lock all 41 * planes using drm_atomic_get_plane_state(). This effectively serializes atomic 42 * updates from .atomic_check() up to completion (when swapping the states if 43 * the check step has succeeded) or rollback (when freeing the states if the 44 * check step has failed). 45 * 46 * Allocation is performed in the .atomic_check() handler and applied 47 * automatically when the core swaps the old and new states. 48 */ 49 50 static bool rcar_du_plane_needs_realloc( 51 const struct rcar_du_plane_state *old_state, 52 const struct rcar_du_plane_state *new_state) 53 { 54 /* 55 * Lowering the number of planes doesn't strictly require reallocation 56 * as the extra hardware plane will be freed when committing, but doing 57 * so could lead to more fragmentation. 58 */ 59 if (!old_state->format || 60 old_state->format->planes != new_state->format->planes) 61 return true; 62 63 /* Reallocate hardware planes if the source has changed. */ 64 if (old_state->source != new_state->source) 65 return true; 66 67 return false; 68 } 69 70 static unsigned int rcar_du_plane_hwmask(struct rcar_du_plane_state *state) 71 { 72 unsigned int mask; 73 74 if (state->hwindex == -1) 75 return 0; 76 77 mask = 1 << state->hwindex; 78 if (state->format->planes == 2) 79 mask |= 1 << ((state->hwindex + 1) % 8); 80 81 return mask; 82 } 83 84 /* 85 * The R8A7790 DU can source frames directly from the VSP1 devices VSPD0 and 86 * VSPD1. VSPD0 feeds DU0/1 plane 0, and VSPD1 feeds either DU2 plane 0 or 87 * DU0/1 plane 1. 88 * 89 * Allocate the correct fixed plane when sourcing frames from VSPD0 or VSPD1, 90 * and allocate planes in reverse index order otherwise to ensure maximum 91 * availability of planes 0 and 1. 92 * 93 * The caller is responsible for ensuring that the requested source is 94 * compatible with the DU revision. 95 */ 96 static int rcar_du_plane_hwalloc(struct rcar_du_plane *plane, 97 struct rcar_du_plane_state *state, 98 unsigned int free) 99 { 100 unsigned int num_planes = state->format->planes; 101 int fixed = -1; 102 int i; 103 104 if (state->source == RCAR_DU_PLANE_VSPD0) { 105 /* VSPD0 feeds plane 0 on DU0/1. */ 106 if (plane->group->index != 0) 107 return -EINVAL; 108 109 fixed = 0; 110 } else if (state->source == RCAR_DU_PLANE_VSPD1) { 111 /* VSPD1 feeds plane 1 on DU0/1 or plane 0 on DU2. */ 112 fixed = plane->group->index == 0 ? 1 : 0; 113 } 114 115 if (fixed >= 0) 116 return free & (1 << fixed) ? fixed : -EBUSY; 117 118 for (i = RCAR_DU_NUM_HW_PLANES - 1; i >= 0; --i) { 119 if (!(free & (1 << i))) 120 continue; 121 122 if (num_planes == 1 || free & (1 << ((i + 1) % 8))) 123 break; 124 } 125 126 return i < 0 ? -EBUSY : i; 127 } 128 129 int rcar_du_atomic_check_planes(struct drm_device *dev, 130 struct drm_atomic_state *state) 131 { 132 struct rcar_du_device *rcdu = to_rcar_du_device(dev); 133 unsigned int group_freed_planes[RCAR_DU_MAX_GROUPS] = { 0, }; 134 unsigned int group_free_planes[RCAR_DU_MAX_GROUPS] = { 0, }; 135 bool needs_realloc = false; 136 unsigned int groups = 0; 137 unsigned int i; 138 struct drm_plane *drm_plane; 139 struct drm_plane_state *old_drm_plane_state; 140 struct drm_plane_state *new_drm_plane_state; 141 142 /* Check if hardware planes need to be reallocated. */ 143 for_each_oldnew_plane_in_state(state, drm_plane, old_drm_plane_state, 144 new_drm_plane_state, i) { 145 struct rcar_du_plane_state *old_plane_state; 146 struct rcar_du_plane_state *new_plane_state; 147 struct rcar_du_plane *plane; 148 unsigned int index; 149 150 plane = to_rcar_plane(drm_plane); 151 old_plane_state = to_rcar_plane_state(old_drm_plane_state); 152 new_plane_state = to_rcar_plane_state(new_drm_plane_state); 153 154 dev_dbg(rcdu->dev, "%s: checking plane (%u,%tu)\n", __func__, 155 plane->group->index, plane - plane->group->planes); 156 157 /* 158 * If the plane is being disabled we don't need to go through 159 * the full reallocation procedure. Just mark the hardware 160 * plane(s) as freed. 161 */ 162 if (!new_plane_state->format) { 163 dev_dbg(rcdu->dev, "%s: plane is being disabled\n", 164 __func__); 165 index = plane - plane->group->planes; 166 group_freed_planes[plane->group->index] |= 1 << index; 167 new_plane_state->hwindex = -1; 168 continue; 169 } 170 171 /* 172 * If the plane needs to be reallocated mark it as such, and 173 * mark the hardware plane(s) as free. 174 */ 175 if (rcar_du_plane_needs_realloc(old_plane_state, new_plane_state)) { 176 dev_dbg(rcdu->dev, "%s: plane needs reallocation\n", 177 __func__); 178 groups |= 1 << plane->group->index; 179 needs_realloc = true; 180 181 index = plane - plane->group->planes; 182 group_freed_planes[plane->group->index] |= 1 << index; 183 new_plane_state->hwindex = -1; 184 } 185 } 186 187 if (!needs_realloc) 188 return 0; 189 190 /* 191 * Grab all plane states for the groups that need reallocation to ensure 192 * locking and avoid racy updates. This serializes the update operation, 193 * but there's not much we can do about it as that's the hardware 194 * design. 195 * 196 * Compute the used planes mask for each group at the same time to avoid 197 * looping over the planes separately later. 198 */ 199 while (groups) { 200 unsigned int index = ffs(groups) - 1; 201 struct rcar_du_group *group = &rcdu->groups[index]; 202 unsigned int used_planes = 0; 203 204 dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n", 205 __func__, index); 206 207 for (i = 0; i < group->num_planes; ++i) { 208 struct rcar_du_plane *plane = &group->planes[i]; 209 struct rcar_du_plane_state *new_plane_state; 210 struct drm_plane_state *s; 211 212 s = drm_atomic_get_plane_state(state, &plane->plane); 213 if (IS_ERR(s)) 214 return PTR_ERR(s); 215 216 /* 217 * If the plane has been freed in the above loop its 218 * hardware planes must not be added to the used planes 219 * bitmask. However, the current state doesn't reflect 220 * the free state yet, as we've modified the new state 221 * above. Use the local freed planes list to check for 222 * that condition instead. 223 */ 224 if (group_freed_planes[index] & (1 << i)) { 225 dev_dbg(rcdu->dev, 226 "%s: plane (%u,%tu) has been freed, skipping\n", 227 __func__, plane->group->index, 228 plane - plane->group->planes); 229 continue; 230 } 231 232 new_plane_state = to_rcar_plane_state(s); 233 used_planes |= rcar_du_plane_hwmask(new_plane_state); 234 235 dev_dbg(rcdu->dev, 236 "%s: plane (%u,%tu) uses %u hwplanes (index %d)\n", 237 __func__, plane->group->index, 238 plane - plane->group->planes, 239 new_plane_state->format ? 240 new_plane_state->format->planes : 0, 241 new_plane_state->hwindex); 242 } 243 244 group_free_planes[index] = 0xff & ~used_planes; 245 groups &= ~(1 << index); 246 247 dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n", 248 __func__, index, group_free_planes[index]); 249 } 250 251 /* Reallocate hardware planes for each plane that needs it. */ 252 for_each_oldnew_plane_in_state(state, drm_plane, old_drm_plane_state, 253 new_drm_plane_state, i) { 254 struct rcar_du_plane_state *old_plane_state; 255 struct rcar_du_plane_state *new_plane_state; 256 struct rcar_du_plane *plane; 257 unsigned int crtc_planes; 258 unsigned int free; 259 int idx; 260 261 plane = to_rcar_plane(drm_plane); 262 old_plane_state = to_rcar_plane_state(old_drm_plane_state); 263 new_plane_state = to_rcar_plane_state(new_drm_plane_state); 264 265 dev_dbg(rcdu->dev, "%s: allocating plane (%u,%tu)\n", __func__, 266 plane->group->index, plane - plane->group->planes); 267 268 /* 269 * Skip planes that are being disabled or don't need to be 270 * reallocated. 271 */ 272 if (!new_plane_state->format || 273 !rcar_du_plane_needs_realloc(old_plane_state, new_plane_state)) 274 continue; 275 276 /* 277 * Try to allocate the plane from the free planes currently 278 * associated with the target CRTC to avoid restarting the CRTC 279 * group and thus minimize flicker. If it fails fall back to 280 * allocating from all free planes. 281 */ 282 crtc_planes = to_rcar_crtc(new_plane_state->state.crtc)->index % 2 283 ? plane->group->dptsr_planes 284 : ~plane->group->dptsr_planes; 285 free = group_free_planes[plane->group->index]; 286 287 idx = rcar_du_plane_hwalloc(plane, new_plane_state, 288 free & crtc_planes); 289 if (idx < 0) 290 idx = rcar_du_plane_hwalloc(plane, new_plane_state, 291 free); 292 if (idx < 0) { 293 dev_dbg(rcdu->dev, "%s: no available hardware plane\n", 294 __func__); 295 return idx; 296 } 297 298 dev_dbg(rcdu->dev, "%s: allocated %u hwplanes (index %u)\n", 299 __func__, new_plane_state->format->planes, idx); 300 301 new_plane_state->hwindex = idx; 302 303 group_free_planes[plane->group->index] &= 304 ~rcar_du_plane_hwmask(new_plane_state); 305 306 dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n", 307 __func__, plane->group->index, 308 group_free_planes[plane->group->index]); 309 } 310 311 return 0; 312 } 313 314 /* ----------------------------------------------------------------------------- 315 * Plane Setup 316 */ 317 318 #define RCAR_DU_COLORKEY_NONE (0 << 24) 319 #define RCAR_DU_COLORKEY_SOURCE (1 << 24) 320 #define RCAR_DU_COLORKEY_MASK (1 << 24) 321 322 static void rcar_du_plane_write(struct rcar_du_group *rgrp, 323 unsigned int index, u32 reg, u32 data) 324 { 325 rcar_du_write(rgrp->dev, rgrp->mmio_offset + index * PLANE_OFF + reg, 326 data); 327 } 328 329 static void rcar_du_plane_setup_scanout(struct rcar_du_group *rgrp, 330 const struct rcar_du_plane_state *state) 331 { 332 unsigned int src_x = state->state.src.x1 >> 16; 333 unsigned int src_y = state->state.src.y1 >> 16; 334 unsigned int index = state->hwindex; 335 unsigned int pitch; 336 bool interlaced; 337 u32 dma[2]; 338 339 interlaced = state->state.crtc->state->adjusted_mode.flags 340 & DRM_MODE_FLAG_INTERLACE; 341 342 if (state->source == RCAR_DU_PLANE_MEMORY) { 343 struct drm_framebuffer *fb = state->state.fb; 344 struct drm_gem_dma_object *gem; 345 unsigned int i; 346 347 if (state->format->planes == 2) 348 pitch = fb->pitches[0]; 349 else 350 pitch = fb->pitches[0] * 8 / state->format->bpp; 351 352 for (i = 0; i < state->format->planes; ++i) { 353 gem = drm_fb_dma_get_gem_obj(fb, i); 354 dma[i] = gem->dma_addr + fb->offsets[i]; 355 } 356 } else { 357 pitch = drm_rect_width(&state->state.src) >> 16; 358 dma[0] = 0; 359 dma[1] = 0; 360 } 361 362 /* 363 * Memory pitch (expressed in pixels). Must be doubled for interlaced 364 * operation with 32bpp formats. 365 */ 366 rcar_du_plane_write(rgrp, index, PnMWR, 367 (interlaced && state->format->bpp == 32) ? 368 pitch * 2 : pitch); 369 370 /* 371 * The Y position is expressed in raster line units and must be doubled 372 * for 32bpp formats, according to the R8A7790 datasheet. No mention of 373 * doubling the Y position is found in the R8A7779 datasheet, but the 374 * rule seems to apply there as well. 375 * 376 * Despite not being documented, doubling seem not to be needed when 377 * operating in interlaced mode. 378 * 379 * Similarly, for the second plane, NV12 and NV21 formats seem to 380 * require a halved Y position value, in both progressive and interlaced 381 * modes. 382 */ 383 rcar_du_plane_write(rgrp, index, PnSPXR, src_x); 384 rcar_du_plane_write(rgrp, index, PnSPYR, src_y * 385 (!interlaced && state->format->bpp == 32 ? 2 : 1)); 386 387 rcar_du_plane_write(rgrp, index, PnDSA0R, dma[0]); 388 389 if (state->format->planes == 2) { 390 index = (index + 1) % 8; 391 392 rcar_du_plane_write(rgrp, index, PnMWR, pitch); 393 394 rcar_du_plane_write(rgrp, index, PnSPXR, src_x); 395 rcar_du_plane_write(rgrp, index, PnSPYR, src_y * 396 (state->format->bpp == 16 ? 2 : 1) / 2); 397 398 rcar_du_plane_write(rgrp, index, PnDSA0R, dma[1]); 399 } 400 } 401 402 static void rcar_du_plane_setup_mode(struct rcar_du_group *rgrp, 403 unsigned int index, 404 const struct rcar_du_plane_state *state) 405 { 406 u32 colorkey; 407 u32 pnmr; 408 409 /* 410 * The PnALPHAR register controls alpha-blending in 16bpp formats 411 * (ARGB1555 and XRGB1555). 412 * 413 * For ARGB, set the alpha value to 0, and enable alpha-blending when 414 * the A bit is 0. This maps A=0 to alpha=0 and A=1 to alpha=255. 415 * 416 * For XRGB, set the alpha value to the plane-wide alpha value and 417 * enable alpha-blending regardless of the X bit value. 418 */ 419 if (state->format->fourcc != DRM_FORMAT_XRGB1555) 420 rcar_du_plane_write(rgrp, index, PnALPHAR, PnALPHAR_ABIT_0); 421 else 422 rcar_du_plane_write(rgrp, index, PnALPHAR, 423 PnALPHAR_ABIT_X | state->state.alpha >> 8); 424 425 pnmr = PnMR_BM_MD | state->format->pnmr; 426 427 /* 428 * Disable color keying when requested. YUV formats have the 429 * PnMR_SPIM_TP_OFF bit set in their pnmr field, disabling color keying 430 * automatically. 431 */ 432 if ((state->colorkey & RCAR_DU_COLORKEY_MASK) == RCAR_DU_COLORKEY_NONE) 433 pnmr |= PnMR_SPIM_TP_OFF; 434 435 /* For packed YUV formats we need to select the U/V order. */ 436 if (state->format->fourcc == DRM_FORMAT_YUYV) 437 pnmr |= PnMR_YCDF_YUYV; 438 439 rcar_du_plane_write(rgrp, index, PnMR, pnmr); 440 441 switch (state->format->fourcc) { 442 case DRM_FORMAT_RGB565: 443 colorkey = ((state->colorkey & 0xf80000) >> 8) 444 | ((state->colorkey & 0x00fc00) >> 5) 445 | ((state->colorkey & 0x0000f8) >> 3); 446 rcar_du_plane_write(rgrp, index, PnTC2R, colorkey); 447 break; 448 449 case DRM_FORMAT_ARGB1555: 450 case DRM_FORMAT_XRGB1555: 451 colorkey = ((state->colorkey & 0xf80000) >> 9) 452 | ((state->colorkey & 0x00f800) >> 6) 453 | ((state->colorkey & 0x0000f8) >> 3); 454 rcar_du_plane_write(rgrp, index, PnTC2R, colorkey); 455 break; 456 457 case DRM_FORMAT_XRGB8888: 458 case DRM_FORMAT_ARGB8888: 459 rcar_du_plane_write(rgrp, index, PnTC3R, 460 PnTC3R_CODE | (state->colorkey & 0xffffff)); 461 break; 462 } 463 } 464 465 static void rcar_du_plane_setup_format_gen2(struct rcar_du_group *rgrp, 466 unsigned int index, 467 const struct rcar_du_plane_state *state) 468 { 469 u32 ddcr2 = PnDDCR2_CODE; 470 u32 ddcr4; 471 472 /* 473 * Data format 474 * 475 * The data format is selected by the DDDF field in PnMR and the EDF 476 * field in DDCR4. 477 */ 478 479 rcar_du_plane_setup_mode(rgrp, index, state); 480 481 if (state->format->planes == 2) { 482 if (state->hwindex != index) { 483 if (state->format->fourcc == DRM_FORMAT_NV12 || 484 state->format->fourcc == DRM_FORMAT_NV21) 485 ddcr2 |= PnDDCR2_Y420; 486 487 if (state->format->fourcc == DRM_FORMAT_NV21) 488 ddcr2 |= PnDDCR2_NV21; 489 490 ddcr2 |= PnDDCR2_DIVU; 491 } else { 492 ddcr2 |= PnDDCR2_DIVY; 493 } 494 } 495 496 rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); 497 498 ddcr4 = state->format->edf | PnDDCR4_CODE; 499 if (state->source != RCAR_DU_PLANE_MEMORY) 500 ddcr4 |= PnDDCR4_VSPS; 501 502 rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); 503 } 504 505 static void rcar_du_plane_setup_format_gen3(struct rcar_du_group *rgrp, 506 unsigned int index, 507 const struct rcar_du_plane_state *state) 508 { 509 struct rcar_du_device *rcdu = rgrp->dev; 510 u32 pnmr = state->format->pnmr | PnMR_SPIM_TP_OFF; 511 512 if (rcdu->info->features & RCAR_DU_FEATURE_NO_BLENDING) { 513 /* No blending. ALP and EOR are not supported. */ 514 pnmr &= ~(PnMR_SPIM_ALP | PnMR_SPIM_EOR); 515 } 516 517 rcar_du_plane_write(rgrp, index, PnMR, pnmr); 518 519 rcar_du_plane_write(rgrp, index, PnDDCR4, 520 state->format->edf | PnDDCR4_CODE); 521 522 /* 523 * On Gen3, some DU channels have two planes, each being wired to a 524 * separate VSPD instance. The DU can then blend two planes. While 525 * this feature isn't used by the driver, issues related to alpha 526 * blending (such as incorrect colors or planes being invisible) may 527 * still occur if the PnALPHAR register has a stale value. Set the 528 * register to 0 to avoid this. 529 */ 530 531 rcar_du_plane_write(rgrp, index, PnALPHAR, 0); 532 } 533 534 static void rcar_du_plane_setup_format(struct rcar_du_group *rgrp, 535 unsigned int index, 536 const struct rcar_du_plane_state *state) 537 { 538 struct rcar_du_device *rcdu = rgrp->dev; 539 const struct drm_rect *dst = &state->state.dst; 540 541 if (rcdu->info->gen < 3) 542 rcar_du_plane_setup_format_gen2(rgrp, index, state); 543 else 544 rcar_du_plane_setup_format_gen3(rgrp, index, state); 545 546 /* Destination position and size */ 547 rcar_du_plane_write(rgrp, index, PnDSXR, drm_rect_width(dst)); 548 rcar_du_plane_write(rgrp, index, PnDSYR, drm_rect_height(dst)); 549 rcar_du_plane_write(rgrp, index, PnDPXR, dst->x1); 550 rcar_du_plane_write(rgrp, index, PnDPYR, dst->y1); 551 552 if (rcdu->info->gen < 3) { 553 /* Wrap-around and blinking, disabled */ 554 rcar_du_plane_write(rgrp, index, PnWASPR, 0); 555 rcar_du_plane_write(rgrp, index, PnWAMWR, 4095); 556 rcar_du_plane_write(rgrp, index, PnBTR, 0); 557 rcar_du_plane_write(rgrp, index, PnMLR, 0); 558 } 559 } 560 561 void __rcar_du_plane_setup(struct rcar_du_group *rgrp, 562 const struct rcar_du_plane_state *state) 563 { 564 struct rcar_du_device *rcdu = rgrp->dev; 565 566 rcar_du_plane_setup_format(rgrp, state->hwindex, state); 567 if (state->format->planes == 2) 568 rcar_du_plane_setup_format(rgrp, (state->hwindex + 1) % 8, 569 state); 570 571 if (rcdu->info->gen >= 3) 572 return; 573 574 rcar_du_plane_setup_scanout(rgrp, state); 575 576 if (state->source == RCAR_DU_PLANE_VSPD1) { 577 unsigned int vspd1_sink = rgrp->index ? 2 : 0; 578 579 if (rcdu->vspd1_sink != vspd1_sink) { 580 rcdu->vspd1_sink = vspd1_sink; 581 rcar_du_set_dpad0_vsp1_routing(rcdu); 582 583 /* 584 * Changes to the VSP1 sink take effect on DRES and thus 585 * need a restart of the group. 586 */ 587 rgrp->need_restart = true; 588 } 589 } 590 } 591 592 int __rcar_du_plane_atomic_check(struct drm_plane *plane, 593 struct drm_plane_state *state, 594 const struct rcar_du_format_info **format) 595 { 596 struct drm_device *dev = plane->dev; 597 struct drm_crtc_state *crtc_state; 598 int ret; 599 600 if (!state->crtc) { 601 /* 602 * The visible field is not reset by the DRM core but only 603 * updated by drm_plane_helper_check_state(), set it manually. 604 */ 605 state->visible = false; 606 *format = NULL; 607 return 0; 608 } 609 610 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); 611 if (IS_ERR(crtc_state)) 612 return PTR_ERR(crtc_state); 613 614 ret = drm_atomic_helper_check_plane_state(state, crtc_state, 615 DRM_PLANE_NO_SCALING, 616 DRM_PLANE_NO_SCALING, 617 true, true); 618 if (ret < 0) 619 return ret; 620 621 if (!state->visible) { 622 *format = NULL; 623 return 0; 624 } 625 626 *format = rcar_du_format_info(state->fb->format->format); 627 if (*format == NULL) { 628 dev_dbg(dev->dev, "%s: unsupported format %p4cc\n", __func__, 629 &state->fb->format->format); 630 return -EINVAL; 631 } 632 633 return 0; 634 } 635 636 static int rcar_du_plane_atomic_check(struct drm_plane *plane, 637 struct drm_atomic_state *state) 638 { 639 struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state, 640 plane); 641 struct rcar_du_plane_state *rstate = to_rcar_plane_state(new_plane_state); 642 643 return __rcar_du_plane_atomic_check(plane, new_plane_state, 644 &rstate->format); 645 } 646 647 static void rcar_du_plane_atomic_update(struct drm_plane *plane, 648 struct drm_atomic_state *state) 649 { 650 struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); 651 struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); 652 struct rcar_du_plane *rplane = to_rcar_plane(plane); 653 struct rcar_du_plane_state *old_rstate; 654 struct rcar_du_plane_state *new_rstate; 655 656 if (!new_state->visible) 657 return; 658 659 rcar_du_plane_setup(rplane); 660 661 /* 662 * Check whether the source has changed from memory to live source or 663 * from live source to memory. The source has been configured by the 664 * VSPS bit in the PnDDCR4 register. Although the datasheet states that 665 * the bit is updated during vertical blanking, it seems that updates 666 * only occur when the DU group is held in reset through the DSYSR.DRES 667 * bit. We thus need to restart the group if the source changes. 668 */ 669 old_rstate = to_rcar_plane_state(old_state); 670 new_rstate = to_rcar_plane_state(new_state); 671 672 if ((old_rstate->source == RCAR_DU_PLANE_MEMORY) != 673 (new_rstate->source == RCAR_DU_PLANE_MEMORY)) 674 rplane->group->need_restart = true; 675 } 676 677 static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = { 678 .atomic_check = rcar_du_plane_atomic_check, 679 .atomic_update = rcar_du_plane_atomic_update, 680 }; 681 682 static struct drm_plane_state * 683 rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane) 684 { 685 struct rcar_du_plane_state *state; 686 struct rcar_du_plane_state *copy; 687 688 if (WARN_ON(!plane->state)) 689 return NULL; 690 691 state = to_rcar_plane_state(plane->state); 692 copy = kmemdup(state, sizeof(*state), GFP_KERNEL); 693 if (copy == NULL) 694 return NULL; 695 696 __drm_atomic_helper_plane_duplicate_state(plane, ©->state); 697 698 return ©->state; 699 } 700 701 static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane, 702 struct drm_plane_state *state) 703 { 704 __drm_atomic_helper_plane_destroy_state(state); 705 kfree(to_rcar_plane_state(state)); 706 } 707 708 static void rcar_du_plane_reset(struct drm_plane *plane) 709 { 710 struct rcar_du_plane_state *state; 711 712 if (plane->state) { 713 rcar_du_plane_atomic_destroy_state(plane, plane->state); 714 plane->state = NULL; 715 } 716 717 state = kzalloc(sizeof(*state), GFP_KERNEL); 718 if (state == NULL) 719 return; 720 721 __drm_atomic_helper_plane_reset(plane, &state->state); 722 723 state->hwindex = -1; 724 state->source = RCAR_DU_PLANE_MEMORY; 725 state->colorkey = RCAR_DU_COLORKEY_NONE; 726 } 727 728 static int rcar_du_plane_atomic_set_property(struct drm_plane *plane, 729 struct drm_plane_state *state, 730 struct drm_property *property, 731 uint64_t val) 732 { 733 struct rcar_du_plane_state *rstate = to_rcar_plane_state(state); 734 struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev; 735 736 if (property == rcdu->props.colorkey) 737 rstate->colorkey = val; 738 else 739 return -EINVAL; 740 741 return 0; 742 } 743 744 static int rcar_du_plane_atomic_get_property(struct drm_plane *plane, 745 const struct drm_plane_state *state, struct drm_property *property, 746 uint64_t *val) 747 { 748 const struct rcar_du_plane_state *rstate = 749 container_of(state, const struct rcar_du_plane_state, state); 750 struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev; 751 752 if (property == rcdu->props.colorkey) 753 *val = rstate->colorkey; 754 else 755 return -EINVAL; 756 757 return 0; 758 } 759 760 static const struct drm_plane_funcs rcar_du_plane_funcs = { 761 .update_plane = drm_atomic_helper_update_plane, 762 .disable_plane = drm_atomic_helper_disable_plane, 763 .reset = rcar_du_plane_reset, 764 .destroy = drm_plane_cleanup, 765 .atomic_duplicate_state = rcar_du_plane_atomic_duplicate_state, 766 .atomic_destroy_state = rcar_du_plane_atomic_destroy_state, 767 .atomic_set_property = rcar_du_plane_atomic_set_property, 768 .atomic_get_property = rcar_du_plane_atomic_get_property, 769 }; 770 771 static const uint32_t formats[] = { 772 DRM_FORMAT_RGB565, 773 DRM_FORMAT_ARGB1555, 774 DRM_FORMAT_XRGB1555, 775 DRM_FORMAT_XRGB8888, 776 DRM_FORMAT_ARGB8888, 777 DRM_FORMAT_UYVY, 778 DRM_FORMAT_YUYV, 779 DRM_FORMAT_NV12, 780 DRM_FORMAT_NV21, 781 DRM_FORMAT_NV16, 782 }; 783 784 int rcar_du_planes_init(struct rcar_du_group *rgrp) 785 { 786 struct rcar_du_device *rcdu = rgrp->dev; 787 unsigned int crtcs; 788 unsigned int i; 789 int ret; 790 791 /* 792 * Create one primary plane per CRTC in this group and seven overlay 793 * planes. 794 */ 795 rgrp->num_planes = rgrp->num_crtcs + 7; 796 797 crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index)); 798 799 for (i = 0; i < rgrp->num_planes; ++i) { 800 enum drm_plane_type type = i < rgrp->num_crtcs 801 ? DRM_PLANE_TYPE_PRIMARY 802 : DRM_PLANE_TYPE_OVERLAY; 803 struct rcar_du_plane *plane = &rgrp->planes[i]; 804 805 plane->group = rgrp; 806 807 ret = drm_universal_plane_init(&rcdu->ddev, &plane->plane, 808 crtcs, &rcar_du_plane_funcs, 809 formats, ARRAY_SIZE(formats), 810 NULL, type, NULL); 811 if (ret < 0) 812 return ret; 813 814 drm_plane_helper_add(&plane->plane, 815 &rcar_du_plane_helper_funcs); 816 817 drm_plane_create_alpha_property(&plane->plane); 818 819 if (type == DRM_PLANE_TYPE_PRIMARY) { 820 drm_plane_create_zpos_immutable_property(&plane->plane, 821 0); 822 } else { 823 drm_object_attach_property(&plane->plane.base, 824 rcdu->props.colorkey, 825 RCAR_DU_COLORKEY_NONE); 826 drm_plane_create_zpos_property(&plane->plane, 1, 1, 7); 827 } 828 } 829 830 return 0; 831 } 832