linux/drivers/gpu/drm/rcar-du/rcar_du_plane.c
<<
>>
Prefs
   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 = dev->dev_private;
 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                rcar_du_plane_setup_scanout(rgrp, state);
 554
 555        if (state->source == RCAR_DU_PLANE_VSPD1) {
 556                unsigned int vspd1_sink = rgrp->index ? 2 : 0;
 557
 558                if (rcdu->vspd1_sink != vspd1_sink) {
 559                        rcdu->vspd1_sink = vspd1_sink;
 560                        rcar_du_set_dpad0_vsp1_routing(rcdu);
 561                }
 562        }
 563}
 564
 565int __rcar_du_plane_atomic_check(struct drm_plane *plane,
 566                                 struct drm_plane_state *state,
 567                                 const struct rcar_du_format_info **format)
 568{
 569        struct drm_device *dev = plane->dev;
 570        struct drm_crtc_state *crtc_state;
 571        int ret;
 572
 573        if (!state->crtc) {
 574                /*
 575                 * The visible field is not reset by the DRM core but only
 576                 * updated by drm_plane_helper_check_state(), set it manually.
 577                 */
 578                state->visible = false;
 579                *format = NULL;
 580                return 0;
 581        }
 582
 583        crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
 584        if (IS_ERR(crtc_state))
 585                return PTR_ERR(crtc_state);
 586
 587        ret = drm_atomic_helper_check_plane_state(state, crtc_state,
 588                                                  DRM_PLANE_HELPER_NO_SCALING,
 589                                                  DRM_PLANE_HELPER_NO_SCALING,
 590                                                  true, true);
 591        if (ret < 0)
 592                return ret;
 593
 594        if (!state->visible) {
 595                *format = NULL;
 596                return 0;
 597        }
 598
 599        *format = rcar_du_format_info(state->fb->format->format);
 600        if (*format == NULL) {
 601                dev_dbg(dev->dev, "%s: unsupported format %08x\n", __func__,
 602                        state->fb->format->format);
 603                return -EINVAL;
 604        }
 605
 606        return 0;
 607}
 608
 609static int rcar_du_plane_atomic_check(struct drm_plane *plane,
 610                                      struct drm_plane_state *state)
 611{
 612        struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
 613
 614        return __rcar_du_plane_atomic_check(plane, state, &rstate->format);
 615}
 616
 617static void rcar_du_plane_atomic_update(struct drm_plane *plane,
 618                                        struct drm_plane_state *old_state)
 619{
 620        struct rcar_du_plane *rplane = to_rcar_plane(plane);
 621        struct rcar_du_plane_state *old_rstate;
 622        struct rcar_du_plane_state *new_rstate;
 623
 624        if (!plane->state->visible)
 625                return;
 626
 627        rcar_du_plane_setup(rplane);
 628
 629        /*
 630         * Check whether the source has changed from memory to live source or
 631         * from live source to memory. The source has been configured by the
 632         * VSPS bit in the PnDDCR4 register. Although the datasheet states that
 633         * the bit is updated during vertical blanking, it seems that updates
 634         * only occur when the DU group is held in reset through the DSYSR.DRES
 635         * bit. We thus need to restart the group if the source changes.
 636         */
 637        old_rstate = to_rcar_plane_state(old_state);
 638        new_rstate = to_rcar_plane_state(plane->state);
 639
 640        if ((old_rstate->source == RCAR_DU_PLANE_MEMORY) !=
 641            (new_rstate->source == RCAR_DU_PLANE_MEMORY))
 642                rplane->group->need_restart = true;
 643}
 644
 645static const struct drm_plane_helper_funcs rcar_du_plane_helper_funcs = {
 646        .atomic_check = rcar_du_plane_atomic_check,
 647        .atomic_update = rcar_du_plane_atomic_update,
 648};
 649
 650static struct drm_plane_state *
 651rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
 652{
 653        struct rcar_du_plane_state *state;
 654        struct rcar_du_plane_state *copy;
 655
 656        if (WARN_ON(!plane->state))
 657                return NULL;
 658
 659        state = to_rcar_plane_state(plane->state);
 660        copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
 661        if (copy == NULL)
 662                return NULL;
 663
 664        __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
 665
 666        return &copy->state;
 667}
 668
 669static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
 670                                               struct drm_plane_state *state)
 671{
 672        __drm_atomic_helper_plane_destroy_state(state);
 673        kfree(to_rcar_plane_state(state));
 674}
 675
 676static void rcar_du_plane_reset(struct drm_plane *plane)
 677{
 678        struct rcar_du_plane_state *state;
 679
 680        if (plane->state) {
 681                rcar_du_plane_atomic_destroy_state(plane, plane->state);
 682                plane->state = NULL;
 683        }
 684
 685        state = kzalloc(sizeof(*state), GFP_KERNEL);
 686        if (state == NULL)
 687                return;
 688
 689        __drm_atomic_helper_plane_reset(plane, &state->state);
 690
 691        state->hwindex = -1;
 692        state->source = RCAR_DU_PLANE_MEMORY;
 693        state->colorkey = RCAR_DU_COLORKEY_NONE;
 694        state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
 695}
 696
 697static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
 698                                             struct drm_plane_state *state,
 699                                             struct drm_property *property,
 700                                             uint64_t val)
 701{
 702        struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
 703        struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
 704
 705        if (property == rcdu->props.colorkey)
 706                rstate->colorkey = val;
 707        else
 708                return -EINVAL;
 709
 710        return 0;
 711}
 712
 713static int rcar_du_plane_atomic_get_property(struct drm_plane *plane,
 714        const struct drm_plane_state *state, struct drm_property *property,
 715        uint64_t *val)
 716{
 717        const struct rcar_du_plane_state *rstate =
 718                container_of(state, const struct rcar_du_plane_state, state);
 719        struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
 720
 721        if (property == rcdu->props.colorkey)
 722                *val = rstate->colorkey;
 723        else
 724                return -EINVAL;
 725
 726        return 0;
 727}
 728
 729static const struct drm_plane_funcs rcar_du_plane_funcs = {
 730        .update_plane = drm_atomic_helper_update_plane,
 731        .disable_plane = drm_atomic_helper_disable_plane,
 732        .reset = rcar_du_plane_reset,
 733        .destroy = drm_plane_cleanup,
 734        .atomic_duplicate_state = rcar_du_plane_atomic_duplicate_state,
 735        .atomic_destroy_state = rcar_du_plane_atomic_destroy_state,
 736        .atomic_set_property = rcar_du_plane_atomic_set_property,
 737        .atomic_get_property = rcar_du_plane_atomic_get_property,
 738};
 739
 740static const uint32_t formats[] = {
 741        DRM_FORMAT_RGB565,
 742        DRM_FORMAT_ARGB1555,
 743        DRM_FORMAT_XRGB1555,
 744        DRM_FORMAT_XRGB8888,
 745        DRM_FORMAT_ARGB8888,
 746        DRM_FORMAT_UYVY,
 747        DRM_FORMAT_YUYV,
 748        DRM_FORMAT_NV12,
 749        DRM_FORMAT_NV21,
 750        DRM_FORMAT_NV16,
 751};
 752
 753int rcar_du_planes_init(struct rcar_du_group *rgrp)
 754{
 755        struct rcar_du_device *rcdu = rgrp->dev;
 756        unsigned int crtcs;
 757        unsigned int i;
 758        int ret;
 759
 760         /*
 761          * Create one primary plane per CRTC in this group and seven overlay
 762          * planes.
 763          */
 764        rgrp->num_planes = rgrp->num_crtcs + 7;
 765
 766        crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
 767
 768        for (i = 0; i < rgrp->num_planes; ++i) {
 769                enum drm_plane_type type = i < rgrp->num_crtcs
 770                                         ? DRM_PLANE_TYPE_PRIMARY
 771                                         : DRM_PLANE_TYPE_OVERLAY;
 772                struct rcar_du_plane *plane = &rgrp->planes[i];
 773
 774                plane->group = rgrp;
 775
 776                ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
 777                                               &rcar_du_plane_funcs, formats,
 778                                               ARRAY_SIZE(formats),
 779                                               NULL, type, NULL);
 780                if (ret < 0)
 781                        return ret;
 782
 783                drm_plane_helper_add(&plane->plane,
 784                                     &rcar_du_plane_helper_funcs);
 785
 786                drm_plane_create_alpha_property(&plane->plane);
 787
 788                if (type == DRM_PLANE_TYPE_PRIMARY) {
 789                        drm_plane_create_zpos_immutable_property(&plane->plane,
 790                                                                 0);
 791                } else {
 792                        drm_object_attach_property(&plane->plane.base,
 793                                                   rcdu->props.colorkey,
 794                                                   RCAR_DU_COLORKEY_NONE);
 795                        drm_plane_create_zpos_property(&plane->plane, 1, 1, 7);
 796                }
 797        }
 798
 799        return 0;
 800}
 801