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