cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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, &copy->state);
    678
    679	return &copy->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}