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

zynqmp_disp.c (46983B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * ZynqMP Display Controller Driver
      4 *
      5 * Copyright (C) 2017 - 2020 Xilinx, Inc.
      6 *
      7 * Authors:
      8 * - Hyun Woo Kwon <hyun.kwon@xilinx.com>
      9 * - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
     10 */
     11
     12#include <drm/drm_atomic.h>
     13#include <drm/drm_atomic_helper.h>
     14#include <drm/drm_atomic_uapi.h>
     15#include <drm/drm_crtc.h>
     16#include <drm/drm_device.h>
     17#include <drm/drm_fb_cma_helper.h>
     18#include <drm/drm_fourcc.h>
     19#include <drm/drm_framebuffer.h>
     20#include <drm/drm_managed.h>
     21#include <drm/drm_plane.h>
     22#include <drm/drm_plane_helper.h>
     23#include <drm/drm_vblank.h>
     24
     25#include <linux/clk.h>
     26#include <linux/delay.h>
     27#include <linux/dma/xilinx_dpdma.h>
     28#include <linux/dma-mapping.h>
     29#include <linux/dmaengine.h>
     30#include <linux/module.h>
     31#include <linux/of.h>
     32#include <linux/platform_device.h>
     33#include <linux/pm_runtime.h>
     34#include <linux/spinlock.h>
     35
     36#include "zynqmp_disp.h"
     37#include "zynqmp_disp_regs.h"
     38#include "zynqmp_dp.h"
     39#include "zynqmp_dpsub.h"
     40
     41/*
     42 * Overview
     43 * --------
     44 *
     45 * The display controller part of ZynqMP DP subsystem, made of the Audio/Video
     46 * Buffer Manager, the Video Rendering Pipeline (blender) and the Audio Mixer.
     47 *
     48 *              +------------------------------------------------------------+
     49 * +--------+   | +----------------+     +-----------+                       |
     50 * | DPDMA  | --->|                | --> |   Video   | Video +-------------+ |
     51 * | 4x vid |   | |                |     | Rendering | -+--> |             | |   +------+
     52 * | 2x aud |   | |  Audio/Video   | --> | Pipeline  |  |    | DisplayPort |---> | PHY0 |
     53 * +--------+   | | Buffer Manager |     +-----------+  |    |   Source    | |   +------+
     54 *              | |    and STC     |     +-----------+  |    | Controller  | |   +------+
     55 * Live Video --->|                | --> |   Audio   | Audio |             |---> | PHY1 |
     56 *              | |                |     |   Mixer   | --+-> |             | |   +------+
     57 * Live Audio --->|                | --> |           |  ||   +-------------+ |
     58 *              | +----------------+     +-----------+  ||                   |
     59 *              +---------------------------------------||-------------------+
     60 *                                                      vv
     61 *                                                Blended Video and
     62 *                                                Mixed Audio to PL
     63 *
     64 * Only non-live input from the DPDMA and output to the DisplayPort Source
     65 * Controller are currently supported. Interface with the programmable logic
     66 * for live streams is not implemented.
     67 *
     68 * The display controller code creates planes for the DPDMA video and graphics
     69 * layers, and a CRTC for the Video Rendering Pipeline.
     70 */
     71
     72#define ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS		4
     73#define ZYNQMP_DISP_AV_BUF_NUM_BUFFERS			6
     74
     75#define ZYNQMP_DISP_NUM_LAYERS				2
     76#define ZYNQMP_DISP_MAX_NUM_SUB_PLANES			3
     77
     78/**
     79 * struct zynqmp_disp_format - Display subsystem format information
     80 * @drm_fmt: DRM format (4CC)
     81 * @buf_fmt: AV buffer format
     82 * @bus_fmt: Media bus formats (live formats)
     83 * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats
     84 * @sf: Scaling factors for color components
     85 */
     86struct zynqmp_disp_format {
     87	u32 drm_fmt;
     88	u32 buf_fmt;
     89	u32 bus_fmt;
     90	bool swap;
     91	const u32 *sf;
     92};
     93
     94/**
     95 * enum zynqmp_disp_layer_id - Layer identifier
     96 * @ZYNQMP_DISP_LAYER_VID: Video layer
     97 * @ZYNQMP_DISP_LAYER_GFX: Graphics layer
     98 */
     99enum zynqmp_disp_layer_id {
    100	ZYNQMP_DISP_LAYER_VID,
    101	ZYNQMP_DISP_LAYER_GFX
    102};
    103
    104/**
    105 * enum zynqmp_disp_layer_mode - Layer mode
    106 * @ZYNQMP_DISP_LAYER_NONLIVE: non-live (memory) mode
    107 * @ZYNQMP_DISP_LAYER_LIVE: live (stream) mode
    108 */
    109enum zynqmp_disp_layer_mode {
    110	ZYNQMP_DISP_LAYER_NONLIVE,
    111	ZYNQMP_DISP_LAYER_LIVE
    112};
    113
    114/**
    115 * struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer
    116 * @chan: DMA channel
    117 * @xt: Interleaved DMA descriptor template
    118 * @sgl: Data chunk for dma_interleaved_template
    119 */
    120struct zynqmp_disp_layer_dma {
    121	struct dma_chan *chan;
    122	struct dma_interleaved_template xt;
    123	struct data_chunk sgl;
    124};
    125
    126/**
    127 * struct zynqmp_disp_layer_info - Static layer information
    128 * @formats: Array of supported formats
    129 * @num_formats: Number of formats in @formats array
    130 * @num_channels: Number of DMA channels
    131 */
    132struct zynqmp_disp_layer_info {
    133	const struct zynqmp_disp_format *formats;
    134	unsigned int num_formats;
    135	unsigned int num_channels;
    136};
    137
    138/**
    139 * struct zynqmp_disp_layer - Display layer (DRM plane)
    140 * @plane: DRM plane
    141 * @id: Layer ID
    142 * @disp: Back pointer to struct zynqmp_disp
    143 * @info: Static layer information
    144 * @dmas: DMA channels
    145 * @disp_fmt: Current format information
    146 * @drm_fmt: Current DRM format information
    147 * @mode: Current operation mode
    148 */
    149struct zynqmp_disp_layer {
    150	struct drm_plane plane;
    151	enum zynqmp_disp_layer_id id;
    152	struct zynqmp_disp *disp;
    153	const struct zynqmp_disp_layer_info *info;
    154
    155	struct zynqmp_disp_layer_dma dmas[ZYNQMP_DISP_MAX_NUM_SUB_PLANES];
    156
    157	const struct zynqmp_disp_format *disp_fmt;
    158	const struct drm_format_info *drm_fmt;
    159	enum zynqmp_disp_layer_mode mode;
    160};
    161
    162/**
    163 * struct zynqmp_disp - Display controller
    164 * @dev: Device structure
    165 * @drm: DRM core
    166 * @dpsub: Display subsystem
    167 * @crtc: DRM CRTC
    168 * @blend.base: Register I/O base address for the blender
    169 * @avbuf.base: Register I/O base address for the audio/video buffer manager
    170 * @audio.base: Registers I/O base address for the audio mixer
    171 * @audio.clk: Audio clock
    172 * @audio.clk_from_ps: True of the audio clock comes from PS, false from PL
    173 * @layers: Layers (planes)
    174 * @event: Pending vblank event request
    175 * @pclk: Pixel clock
    176 * @pclk_from_ps: True of the video clock comes from PS, false from PL
    177 */
    178struct zynqmp_disp {
    179	struct device *dev;
    180	struct drm_device *drm;
    181	struct zynqmp_dpsub *dpsub;
    182
    183	struct drm_crtc crtc;
    184
    185	struct {
    186		void __iomem *base;
    187	} blend;
    188	struct {
    189		void __iomem *base;
    190	} avbuf;
    191	struct {
    192		void __iomem *base;
    193		struct clk *clk;
    194		bool clk_from_ps;
    195	} audio;
    196
    197	struct zynqmp_disp_layer layers[ZYNQMP_DISP_NUM_LAYERS];
    198
    199	struct drm_pending_vblank_event *event;
    200
    201	struct clk *pclk;
    202	bool pclk_from_ps;
    203};
    204
    205/* -----------------------------------------------------------------------------
    206 * Audio/Video Buffer Manager
    207 */
    208
    209static const u32 scaling_factors_444[] = {
    210	ZYNQMP_DISP_AV_BUF_4BIT_SF,
    211	ZYNQMP_DISP_AV_BUF_4BIT_SF,
    212	ZYNQMP_DISP_AV_BUF_4BIT_SF,
    213};
    214
    215static const u32 scaling_factors_555[] = {
    216	ZYNQMP_DISP_AV_BUF_5BIT_SF,
    217	ZYNQMP_DISP_AV_BUF_5BIT_SF,
    218	ZYNQMP_DISP_AV_BUF_5BIT_SF,
    219};
    220
    221static const u32 scaling_factors_565[] = {
    222	ZYNQMP_DISP_AV_BUF_5BIT_SF,
    223	ZYNQMP_DISP_AV_BUF_6BIT_SF,
    224	ZYNQMP_DISP_AV_BUF_5BIT_SF,
    225};
    226
    227static const u32 scaling_factors_888[] = {
    228	ZYNQMP_DISP_AV_BUF_8BIT_SF,
    229	ZYNQMP_DISP_AV_BUF_8BIT_SF,
    230	ZYNQMP_DISP_AV_BUF_8BIT_SF,
    231};
    232
    233static const u32 scaling_factors_101010[] = {
    234	ZYNQMP_DISP_AV_BUF_10BIT_SF,
    235	ZYNQMP_DISP_AV_BUF_10BIT_SF,
    236	ZYNQMP_DISP_AV_BUF_10BIT_SF,
    237};
    238
    239/* List of video layer formats */
    240static const struct zynqmp_disp_format avbuf_vid_fmts[] = {
    241	{
    242		.drm_fmt	= DRM_FORMAT_VYUY,
    243		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY,
    244		.swap		= true,
    245		.sf		= scaling_factors_888,
    246	}, {
    247		.drm_fmt	= DRM_FORMAT_UYVY,
    248		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY,
    249		.swap		= false,
    250		.sf		= scaling_factors_888,
    251	}, {
    252		.drm_fmt	= DRM_FORMAT_YUYV,
    253		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV,
    254		.swap		= false,
    255		.sf		= scaling_factors_888,
    256	}, {
    257		.drm_fmt	= DRM_FORMAT_YVYU,
    258		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV,
    259		.swap		= true,
    260		.sf		= scaling_factors_888,
    261	}, {
    262		.drm_fmt	= DRM_FORMAT_YUV422,
    263		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16,
    264		.swap		= false,
    265		.sf		= scaling_factors_888,
    266	}, {
    267		.drm_fmt	= DRM_FORMAT_YVU422,
    268		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16,
    269		.swap		= true,
    270		.sf		= scaling_factors_888,
    271	}, {
    272		.drm_fmt	= DRM_FORMAT_YUV444,
    273		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24,
    274		.swap		= false,
    275		.sf		= scaling_factors_888,
    276	}, {
    277		.drm_fmt	= DRM_FORMAT_YVU444,
    278		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24,
    279		.swap		= true,
    280		.sf		= scaling_factors_888,
    281	}, {
    282		.drm_fmt	= DRM_FORMAT_NV16,
    283		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI,
    284		.swap		= false,
    285		.sf		= scaling_factors_888,
    286	}, {
    287		.drm_fmt	= DRM_FORMAT_NV61,
    288		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI,
    289		.swap		= true,
    290		.sf		= scaling_factors_888,
    291	}, {
    292		.drm_fmt	= DRM_FORMAT_BGR888,
    293		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888,
    294		.swap		= false,
    295		.sf		= scaling_factors_888,
    296	}, {
    297		.drm_fmt	= DRM_FORMAT_RGB888,
    298		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888,
    299		.swap		= true,
    300		.sf		= scaling_factors_888,
    301	}, {
    302		.drm_fmt	= DRM_FORMAT_XBGR8888,
    303		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880,
    304		.swap		= false,
    305		.sf		= scaling_factors_888,
    306	}, {
    307		.drm_fmt	= DRM_FORMAT_XRGB8888,
    308		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880,
    309		.swap		= true,
    310		.sf		= scaling_factors_888,
    311	}, {
    312		.drm_fmt	= DRM_FORMAT_XBGR2101010,
    313		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10,
    314		.swap		= false,
    315		.sf		= scaling_factors_101010,
    316	}, {
    317		.drm_fmt	= DRM_FORMAT_XRGB2101010,
    318		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10,
    319		.swap		= true,
    320		.sf		= scaling_factors_101010,
    321	}, {
    322		.drm_fmt	= DRM_FORMAT_YUV420,
    323		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420,
    324		.swap		= false,
    325		.sf		= scaling_factors_888,
    326	}, {
    327		.drm_fmt	= DRM_FORMAT_YVU420,
    328		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420,
    329		.swap		= true,
    330		.sf		= scaling_factors_888,
    331	}, {
    332		.drm_fmt	= DRM_FORMAT_NV12,
    333		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420,
    334		.swap		= false,
    335		.sf		= scaling_factors_888,
    336	}, {
    337		.drm_fmt	= DRM_FORMAT_NV21,
    338		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420,
    339		.swap		= true,
    340		.sf		= scaling_factors_888,
    341	},
    342};
    343
    344/* List of graphics layer formats */
    345static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {
    346	{
    347		.drm_fmt	= DRM_FORMAT_ABGR8888,
    348		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888,
    349		.swap		= false,
    350		.sf		= scaling_factors_888,
    351	}, {
    352		.drm_fmt	= DRM_FORMAT_ARGB8888,
    353		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888,
    354		.swap		= true,
    355		.sf		= scaling_factors_888,
    356	}, {
    357		.drm_fmt	= DRM_FORMAT_RGBA8888,
    358		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888,
    359		.swap		= false,
    360		.sf		= scaling_factors_888,
    361	}, {
    362		.drm_fmt	= DRM_FORMAT_BGRA8888,
    363		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888,
    364		.swap		= true,
    365		.sf		= scaling_factors_888,
    366	}, {
    367		.drm_fmt	= DRM_FORMAT_BGR888,
    368		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB888,
    369		.swap		= false,
    370		.sf		= scaling_factors_888,
    371	}, {
    372		.drm_fmt	= DRM_FORMAT_RGB888,
    373		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_BGR888,
    374		.swap		= false,
    375		.sf		= scaling_factors_888,
    376	}, {
    377		.drm_fmt	= DRM_FORMAT_RGBA5551,
    378		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551,
    379		.swap		= false,
    380		.sf		= scaling_factors_555,
    381	}, {
    382		.drm_fmt	= DRM_FORMAT_BGRA5551,
    383		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551,
    384		.swap		= true,
    385		.sf		= scaling_factors_555,
    386	}, {
    387		.drm_fmt	= DRM_FORMAT_RGBA4444,
    388		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444,
    389		.swap		= false,
    390		.sf		= scaling_factors_444,
    391	}, {
    392		.drm_fmt	= DRM_FORMAT_BGRA4444,
    393		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444,
    394		.swap		= true,
    395		.sf		= scaling_factors_444,
    396	}, {
    397		.drm_fmt	= DRM_FORMAT_RGB565,
    398		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565,
    399		.swap		= false,
    400		.sf		= scaling_factors_565,
    401	}, {
    402		.drm_fmt	= DRM_FORMAT_BGR565,
    403		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565,
    404		.swap		= true,
    405		.sf		= scaling_factors_565,
    406	},
    407};
    408
    409static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)
    410{
    411	return readl(disp->avbuf.base + reg);
    412}
    413
    414static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val)
    415{
    416	writel(val, disp->avbuf.base + reg);
    417}
    418
    419static bool zynqmp_disp_layer_is_gfx(const struct zynqmp_disp_layer *layer)
    420{
    421	return layer->id == ZYNQMP_DISP_LAYER_GFX;
    422}
    423
    424static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer)
    425{
    426	return layer->id == ZYNQMP_DISP_LAYER_VID;
    427}
    428
    429/**
    430 * zynqmp_disp_avbuf_set_format - Set the input format for a layer
    431 * @disp: Display controller
    432 * @layer: The layer
    433 * @fmt: The format information
    434 *
    435 * Set the video buffer manager format for @layer to @fmt.
    436 */
    437static void zynqmp_disp_avbuf_set_format(struct zynqmp_disp *disp,
    438					 struct zynqmp_disp_layer *layer,
    439					 const struct zynqmp_disp_format *fmt)
    440{
    441	unsigned int i;
    442	u32 val;
    443
    444	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);
    445	val &= zynqmp_disp_layer_is_video(layer)
    446	    ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK
    447	    : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;
    448	val |= fmt->buf_fmt;
    449	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_FMT, val);
    450
    451	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; i++) {
    452		unsigned int reg = zynqmp_disp_layer_is_video(layer)
    453				 ? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)
    454				 : ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);
    455
    456		zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);
    457	}
    458}
    459
    460/**
    461 * zynqmp_disp_avbuf_set_clocks_sources - Set the clocks sources
    462 * @disp: Display controller
    463 * @video_from_ps: True if the video clock originates from the PS
    464 * @audio_from_ps: True if the audio clock originates from the PS
    465 * @timings_internal: True if video timings are generated internally
    466 *
    467 * Set the source for the video and audio clocks, as well as for the video
    468 * timings. Clocks can originate from the PS or PL, and timings can be
    469 * generated internally or externally.
    470 */
    471static void
    472zynqmp_disp_avbuf_set_clocks_sources(struct zynqmp_disp *disp,
    473				     bool video_from_ps, bool audio_from_ps,
    474				     bool timings_internal)
    475{
    476	u32 val = 0;
    477
    478	if (video_from_ps)
    479		val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_FROM_PS;
    480	if (audio_from_ps)
    481		val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_AUD_FROM_PS;
    482	if (timings_internal)
    483		val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING;
    484
    485	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CLK_SRC, val);
    486}
    487
    488/**
    489 * zynqmp_disp_avbuf_enable_channels - Enable buffer channels
    490 * @disp: Display controller
    491 *
    492 * Enable all (video and audio) buffer channels.
    493 */
    494static void zynqmp_disp_avbuf_enable_channels(struct zynqmp_disp *disp)
    495{
    496	unsigned int i;
    497	u32 val;
    498
    499	val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |
    500	      (ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_MAX <<
    501	       ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT);
    502
    503	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS; i++)
    504		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),
    505					val);
    506
    507	val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |
    508	      (ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_AUD_MAX <<
    509	       ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT);
    510
    511	for (; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++)
    512		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),
    513					val);
    514}
    515
    516/**
    517 * zynqmp_disp_avbuf_disable_channels - Disable buffer channels
    518 * @disp: Display controller
    519 *
    520 * Disable all (video and audio) buffer channels.
    521 */
    522static void zynqmp_disp_avbuf_disable_channels(struct zynqmp_disp *disp)
    523{
    524	unsigned int i;
    525
    526	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++)
    527		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),
    528					ZYNQMP_DISP_AV_BUF_CHBUF_FLUSH);
    529}
    530
    531/**
    532 * zynqmp_disp_avbuf_enable_audio - Enable audio
    533 * @disp: Display controller
    534 *
    535 * Enable all audio buffers with a non-live (memory) source.
    536 */
    537static void zynqmp_disp_avbuf_enable_audio(struct zynqmp_disp *disp)
    538{
    539	u32 val;
    540
    541	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
    542	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK;
    543	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MEM;
    544	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN;
    545	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
    546}
    547
    548/**
    549 * zynqmp_disp_avbuf_disable_audio - Disable audio
    550 * @disp: Display controller
    551 *
    552 * Disable all audio buffers.
    553 */
    554static void zynqmp_disp_avbuf_disable_audio(struct zynqmp_disp *disp)
    555{
    556	u32 val;
    557
    558	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
    559	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK;
    560	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_DISABLE;
    561	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN;
    562	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
    563}
    564
    565/**
    566 * zynqmp_disp_avbuf_enable_video - Enable a video layer
    567 * @disp: Display controller
    568 * @layer: The layer
    569 * @mode: Operating mode of layer
    570 *
    571 * Enable the video/graphics buffer for @layer.
    572 */
    573static void zynqmp_disp_avbuf_enable_video(struct zynqmp_disp *disp,
    574					   struct zynqmp_disp_layer *layer,
    575					   enum zynqmp_disp_layer_mode mode)
    576{
    577	u32 val;
    578
    579	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
    580	if (zynqmp_disp_layer_is_video(layer)) {
    581		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;
    582		if (mode == ZYNQMP_DISP_LAYER_NONLIVE)
    583			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM;
    584		else
    585			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_LIVE;
    586	} else {
    587		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK;
    588		val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM;
    589		if (mode == ZYNQMP_DISP_LAYER_NONLIVE)
    590			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM;
    591		else
    592			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE;
    593	}
    594	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
    595}
    596
    597/**
    598 * zynqmp_disp_avbuf_disable_video - Disable a video layer
    599 * @disp: Display controller
    600 * @layer: The layer
    601 *
    602 * Disable the video/graphics buffer for @layer.
    603 */
    604static void zynqmp_disp_avbuf_disable_video(struct zynqmp_disp *disp,
    605					    struct zynqmp_disp_layer *layer)
    606{
    607	u32 val;
    608
    609	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);
    610	if (zynqmp_disp_layer_is_video(layer)) {
    611		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;
    612		val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_NONE;
    613	} else {
    614		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK;
    615		val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_DISABLE;
    616	}
    617	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);
    618}
    619
    620/**
    621 * zynqmp_disp_avbuf_enable - Enable the video pipe
    622 * @disp: Display controller
    623 *
    624 * De-assert the video pipe reset.
    625 */
    626static void zynqmp_disp_avbuf_enable(struct zynqmp_disp *disp)
    627{
    628	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG, 0);
    629}
    630
    631/**
    632 * zynqmp_disp_avbuf_disable - Disable the video pipe
    633 * @disp: Display controller
    634 *
    635 * Assert the video pipe reset.
    636 */
    637static void zynqmp_disp_avbuf_disable(struct zynqmp_disp *disp)
    638{
    639	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG,
    640				ZYNQMP_DISP_AV_BUF_SRST_REG_VID_RST);
    641}
    642
    643/* -----------------------------------------------------------------------------
    644 * Blender (Video Pipeline)
    645 */
    646
    647static void zynqmp_disp_blend_write(struct zynqmp_disp *disp, int reg, u32 val)
    648{
    649	writel(val, disp->blend.base + reg);
    650}
    651
    652/*
    653 * Colorspace conversion matrices.
    654 *
    655 * Hardcode RGB <-> YUV conversion to full-range SDTV for now.
    656 */
    657static const u16 csc_zero_matrix[] = {
    658	0x0,    0x0,    0x0,
    659	0x0,    0x0,    0x0,
    660	0x0,    0x0,    0x0
    661};
    662
    663static const u16 csc_identity_matrix[] = {
    664	0x1000, 0x0,    0x0,
    665	0x0,    0x1000, 0x0,
    666	0x0,    0x0,    0x1000
    667};
    668
    669static const u32 csc_zero_offsets[] = {
    670	0, 0, 0
    671};
    672
    673static const u16 csc_rgb_to_sdtv_matrix[] = {
    674	0x4c9,  0x864,  0x1d3,
    675	0x7d4d, 0x7ab3, 0x800,
    676	0x800,  0x794d, 0x7eb3
    677};
    678
    679static const u32 csc_rgb_to_sdtv_offsets[] = {
    680	0x0, 0x8000000, 0x8000000
    681};
    682
    683static const u16 csc_sdtv_to_rgb_matrix[] = {
    684	0x1000, 0x166f, 0x0,
    685	0x1000, 0x7483, 0x7a7f,
    686	0x1000, 0x0,    0x1c5a
    687};
    688
    689static const u32 csc_sdtv_to_rgb_offsets[] = {
    690	0x0, 0x1800, 0x1800
    691};
    692
    693/**
    694 * zynqmp_disp_blend_set_output_format - Set the output format of the blender
    695 * @disp: Display controller
    696 * @format: Output format
    697 *
    698 * Set the output format of the blender to @format.
    699 */
    700static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp *disp,
    701						enum zynqmp_dpsub_format format)
    702{
    703	static const unsigned int blend_output_fmts[] = {
    704		[ZYNQMP_DPSUB_FORMAT_RGB] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB,
    705		[ZYNQMP_DPSUB_FORMAT_YCRCB444] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR444,
    706		[ZYNQMP_DPSUB_FORMAT_YCRCB422] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR422
    707					       | ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_EN_DOWNSAMPLE,
    708		[ZYNQMP_DPSUB_FORMAT_YONLY] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YONLY,
    709	};
    710
    711	u32 fmt = blend_output_fmts[format];
    712	const u16 *coeffs;
    713	const u32 *offsets;
    714	unsigned int i;
    715
    716	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT, fmt);
    717	if (fmt == ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB) {
    718		coeffs = csc_identity_matrix;
    719		offsets = csc_zero_offsets;
    720	} else {
    721		coeffs = csc_rgb_to_sdtv_matrix;
    722		offsets = csc_rgb_to_sdtv_offsets;
    723	}
    724
    725	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i++)
    726		zynqmp_disp_blend_write(disp,
    727					ZYNQMP_DISP_V_BLEND_RGB2YCBCR_COEFF(i),
    728					coeffs[i]);
    729
    730	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++)
    731		zynqmp_disp_blend_write(disp,
    732					ZYNQMP_DISP_V_BLEND_OUTCSC_OFFSET(i),
    733					offsets[i]);
    734}
    735
    736/**
    737 * zynqmp_disp_blend_set_bg_color - Set the background color
    738 * @disp: Display controller
    739 * @rcr: Red/Cr color component
    740 * @gy: Green/Y color component
    741 * @bcb: Blue/Cb color component
    742 *
    743 * Set the background color to (@rcr, @gy, @bcb), corresponding to the R, G and
    744 * B or Cr, Y and Cb components respectively depending on the selected output
    745 * format.
    746 */
    747static void zynqmp_disp_blend_set_bg_color(struct zynqmp_disp *disp,
    748					   u32 rcr, u32 gy, u32 bcb)
    749{
    750	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_0, rcr);
    751	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_1, gy);
    752	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_2, bcb);
    753}
    754
    755/**
    756 * zynqmp_disp_blend_set_global_alpha - Configure global alpha blending
    757 * @disp: Display controller
    758 * @enable: True to enable global alpha blending
    759 * @alpha: Global alpha value (ignored if @enabled is false)
    760 */
    761static void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp,
    762					       bool enable, u32 alpha)
    763{
    764	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA,
    765				ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE(alpha) |
    766				(enable ? ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_EN : 0));
    767}
    768
    769/**
    770 * zynqmp_disp_blend_layer_set_csc - Configure colorspace conversion for layer
    771 * @disp: Display controller
    772 * @layer: The layer
    773 * @coeffs: Colorspace conversion matrix
    774 * @offsets: Colorspace conversion offsets
    775 *
    776 * Configure the input colorspace conversion matrix and offsets for the @layer.
    777 * Columns of the matrix are automatically swapped based on the input format to
    778 * handle RGB and YCrCb components permutations.
    779 */
    780static void zynqmp_disp_blend_layer_set_csc(struct zynqmp_disp *disp,
    781					    struct zynqmp_disp_layer *layer,
    782					    const u16 *coeffs,
    783					    const u32 *offsets)
    784{
    785	unsigned int swap[3] = { 0, 1, 2 };
    786	unsigned int reg;
    787	unsigned int i;
    788
    789	if (layer->disp_fmt->swap) {
    790		if (layer->drm_fmt->is_yuv) {
    791			/* Swap U and V. */
    792			swap[1] = 2;
    793			swap[2] = 1;
    794		} else {
    795			/* Swap R and B. */
    796			swap[0] = 2;
    797			swap[2] = 0;
    798		}
    799	}
    800
    801	if (zynqmp_disp_layer_is_video(layer))
    802		reg = ZYNQMP_DISP_V_BLEND_IN1CSC_COEFF(0);
    803	else
    804		reg = ZYNQMP_DISP_V_BLEND_IN2CSC_COEFF(0);
    805
    806	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i += 3, reg += 12) {
    807		zynqmp_disp_blend_write(disp, reg + 0, coeffs[i + swap[0]]);
    808		zynqmp_disp_blend_write(disp, reg + 4, coeffs[i + swap[1]]);
    809		zynqmp_disp_blend_write(disp, reg + 8, coeffs[i + swap[2]]);
    810	}
    811
    812	if (zynqmp_disp_layer_is_video(layer))
    813		reg = ZYNQMP_DISP_V_BLEND_IN1CSC_OFFSET(0);
    814	else
    815		reg = ZYNQMP_DISP_V_BLEND_IN2CSC_OFFSET(0);
    816
    817	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++)
    818		zynqmp_disp_blend_write(disp, reg + i * 4, offsets[i]);
    819}
    820
    821/**
    822 * zynqmp_disp_blend_layer_enable - Enable a layer
    823 * @disp: Display controller
    824 * @layer: The layer
    825 */
    826static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp *disp,
    827					   struct zynqmp_disp_layer *layer)
    828{
    829	const u16 *coeffs;
    830	const u32 *offsets;
    831	u32 val;
    832
    833	val = (layer->drm_fmt->is_yuv ?
    834	       0 : ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_RGB) |
    835	      (layer->drm_fmt->hsub > 1 ?
    836	       ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_EN_US : 0);
    837
    838	zynqmp_disp_blend_write(disp,
    839				ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),
    840				val);
    841
    842	if (layer->drm_fmt->is_yuv) {
    843		coeffs = csc_sdtv_to_rgb_matrix;
    844		offsets = csc_sdtv_to_rgb_offsets;
    845	} else {
    846		coeffs = csc_identity_matrix;
    847		offsets = csc_zero_offsets;
    848	}
    849
    850	zynqmp_disp_blend_layer_set_csc(disp, layer, coeffs, offsets);
    851}
    852
    853/**
    854 * zynqmp_disp_blend_layer_disable - Disable a layer
    855 * @disp: Display controller
    856 * @layer: The layer
    857 */
    858static void zynqmp_disp_blend_layer_disable(struct zynqmp_disp *disp,
    859					    struct zynqmp_disp_layer *layer)
    860{
    861	zynqmp_disp_blend_write(disp,
    862				ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),
    863				0);
    864
    865	zynqmp_disp_blend_layer_set_csc(disp, layer, csc_zero_matrix,
    866					csc_zero_offsets);
    867}
    868
    869/* -----------------------------------------------------------------------------
    870 * Audio Mixer
    871 */
    872
    873static void zynqmp_disp_audio_write(struct zynqmp_disp *disp, int reg, u32 val)
    874{
    875	writel(val, disp->audio.base + reg);
    876}
    877
    878/**
    879 * zynqmp_disp_audio_enable - Enable the audio mixer
    880 * @disp: Display controller
    881 *
    882 * Enable the audio mixer by de-asserting the soft reset. The audio state is set to
    883 * default values by the reset, set the default mixer volume explicitly.
    884 */
    885static void zynqmp_disp_audio_enable(struct zynqmp_disp *disp)
    886{
    887	/* Clear the audio soft reset register as it's an non-reset flop. */
    888	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET, 0);
    889	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_MIXER_VOLUME,
    890				ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE);
    891}
    892
    893/**
    894 * zynqmp_disp_audio_disable - Disable the audio mixer
    895 * @disp: Display controller
    896 *
    897 * Disable the audio mixer by asserting its soft reset.
    898 */
    899static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)
    900{
    901	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET,
    902				ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST);
    903}
    904
    905static void zynqmp_disp_audio_init(struct zynqmp_disp *disp)
    906{
    907	/* Try the live PL audio clock. */
    908	disp->audio.clk = devm_clk_get(disp->dev, "dp_live_audio_aclk");
    909	if (!IS_ERR(disp->audio.clk)) {
    910		disp->audio.clk_from_ps = false;
    911		return;
    912	}
    913
    914	/* If the live PL audio clock is not valid, fall back to PS clock. */
    915	disp->audio.clk = devm_clk_get(disp->dev, "dp_aud_clk");
    916	if (!IS_ERR(disp->audio.clk)) {
    917		disp->audio.clk_from_ps = true;
    918		return;
    919	}
    920
    921	dev_err(disp->dev, "audio disabled due to missing clock\n");
    922}
    923
    924/* -----------------------------------------------------------------------------
    925 * ZynqMP Display external functions for zynqmp_dp
    926 */
    927
    928/**
    929 * zynqmp_disp_handle_vblank - Handle the vblank event
    930 * @disp: Display controller
    931 *
    932 * This function handles the vblank interrupt, and sends an event to
    933 * CRTC object. This will be called by the DP vblank interrupt handler.
    934 */
    935void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp)
    936{
    937	struct drm_crtc *crtc = &disp->crtc;
    938
    939	drm_crtc_handle_vblank(crtc);
    940}
    941
    942/**
    943 * zynqmp_disp_audio_enabled - If the audio is enabled
    944 * @disp: Display controller
    945 *
    946 * Return if the audio is enabled depending on the audio clock.
    947 *
    948 * Return: true if audio is enabled, or false.
    949 */
    950bool zynqmp_disp_audio_enabled(struct zynqmp_disp *disp)
    951{
    952	return !!disp->audio.clk;
    953}
    954
    955/**
    956 * zynqmp_disp_get_audio_clk_rate - Get the current audio clock rate
    957 * @disp: Display controller
    958 *
    959 * Return: the current audio clock rate.
    960 */
    961unsigned int zynqmp_disp_get_audio_clk_rate(struct zynqmp_disp *disp)
    962{
    963	if (zynqmp_disp_audio_enabled(disp))
    964		return 0;
    965	return clk_get_rate(disp->audio.clk);
    966}
    967
    968/**
    969 * zynqmp_disp_get_crtc_mask - Return the CRTC bit mask
    970 * @disp: Display controller
    971 *
    972 * Return: the crtc mask of the zyqnmp_disp CRTC.
    973 */
    974uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp)
    975{
    976	return drm_crtc_mask(&disp->crtc);
    977}
    978
    979/* -----------------------------------------------------------------------------
    980 * ZynqMP Display Layer & DRM Plane
    981 */
    982
    983/**
    984 * zynqmp_disp_layer_find_format - Find format information for a DRM format
    985 * @layer: The layer
    986 * @drm_fmt: DRM format to search
    987 *
    988 * Search display subsystem format information corresponding to the given DRM
    989 * format @drm_fmt for the @layer, and return a pointer to the format
    990 * descriptor.
    991 *
    992 * Return: A pointer to the format descriptor if found, NULL otherwise
    993 */
    994static const struct zynqmp_disp_format *
    995zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer,
    996			      u32 drm_fmt)
    997{
    998	unsigned int i;
    999
   1000	for (i = 0; i < layer->info->num_formats; i++) {
   1001		if (layer->info->formats[i].drm_fmt == drm_fmt)
   1002			return &layer->info->formats[i];
   1003	}
   1004
   1005	return NULL;
   1006}
   1007
   1008/**
   1009 * zynqmp_disp_layer_enable - Enable a layer
   1010 * @layer: The layer
   1011 *
   1012 * Enable the @layer in the audio/video buffer manager and the blender. DMA
   1013 * channels are started separately by zynqmp_disp_layer_update().
   1014 */
   1015static void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)
   1016{
   1017	zynqmp_disp_avbuf_enable_video(layer->disp, layer,
   1018				       ZYNQMP_DISP_LAYER_NONLIVE);
   1019	zynqmp_disp_blend_layer_enable(layer->disp, layer);
   1020
   1021	layer->mode = ZYNQMP_DISP_LAYER_NONLIVE;
   1022}
   1023
   1024/**
   1025 * zynqmp_disp_layer_disable - Disable the layer
   1026 * @layer: The layer
   1027 *
   1028 * Disable the layer by stopping its DMA channels and disabling it in the
   1029 * audio/video buffer manager and the blender.
   1030 */
   1031static void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer)
   1032{
   1033	unsigned int i;
   1034
   1035	for (i = 0; i < layer->drm_fmt->num_planes; i++)
   1036		dmaengine_terminate_sync(layer->dmas[i].chan);
   1037
   1038	zynqmp_disp_avbuf_disable_video(layer->disp, layer);
   1039	zynqmp_disp_blend_layer_disable(layer->disp, layer);
   1040}
   1041
   1042/**
   1043 * zynqmp_disp_layer_set_format - Set the layer format
   1044 * @layer: The layer
   1045 * @state: The plane state
   1046 *
   1047 * Set the format for @layer based on @state->fb->format. The layer must be
   1048 * disabled.
   1049 */
   1050static void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,
   1051					 struct drm_plane_state *state)
   1052{
   1053	const struct drm_format_info *info = state->fb->format;
   1054	unsigned int i;
   1055
   1056	layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format);
   1057	layer->drm_fmt = info;
   1058
   1059	zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);
   1060
   1061	/*
   1062	 * Set pconfig for each DMA channel to indicate they're part of a
   1063	 * video group.
   1064	 */
   1065	for (i = 0; i < info->num_planes; i++) {
   1066		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
   1067		struct xilinx_dpdma_peripheral_config pconfig = {
   1068			.video_group = true,
   1069		};
   1070		struct dma_slave_config config = {
   1071			.direction = DMA_MEM_TO_DEV,
   1072			.peripheral_config = &pconfig,
   1073			.peripheral_size = sizeof(pconfig),
   1074		};
   1075
   1076		dmaengine_slave_config(dma->chan, &config);
   1077	}
   1078}
   1079
   1080/**
   1081 * zynqmp_disp_layer_update - Update the layer framebuffer
   1082 * @layer: The layer
   1083 * @state: The plane state
   1084 *
   1085 * Update the framebuffer for the layer by issuing a new DMA engine transaction
   1086 * for the new framebuffer.
   1087 *
   1088 * Return: 0 on success, or the DMA descriptor failure error otherwise
   1089 */
   1090static int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,
   1091				    struct drm_plane_state *state)
   1092{
   1093	const struct drm_format_info *info = layer->drm_fmt;
   1094	unsigned int i;
   1095
   1096	for (i = 0; i < layer->drm_fmt->num_planes; i++) {
   1097		unsigned int width = state->crtc_w / (i ? info->hsub : 1);
   1098		unsigned int height = state->crtc_h / (i ? info->vsub : 1);
   1099		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
   1100		struct dma_async_tx_descriptor *desc;
   1101		dma_addr_t paddr;
   1102
   1103		paddr = drm_fb_cma_get_gem_addr(state->fb, state, i);
   1104
   1105		dma->xt.numf = height;
   1106		dma->sgl.size = width * info->cpp[i];
   1107		dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size;
   1108		dma->xt.src_start = paddr;
   1109		dma->xt.frame_size = 1;
   1110		dma->xt.dir = DMA_MEM_TO_DEV;
   1111		dma->xt.src_sgl = true;
   1112		dma->xt.dst_sgl = false;
   1113
   1114		desc = dmaengine_prep_interleaved_dma(dma->chan, &dma->xt,
   1115						      DMA_CTRL_ACK |
   1116						      DMA_PREP_REPEAT |
   1117						      DMA_PREP_LOAD_EOT);
   1118		if (!desc) {
   1119			dev_err(layer->disp->dev,
   1120				"failed to prepare DMA descriptor\n");
   1121			return -ENOMEM;
   1122		}
   1123
   1124		dmaengine_submit(desc);
   1125		dma_async_issue_pending(dma->chan);
   1126	}
   1127
   1128	return 0;
   1129}
   1130
   1131static inline struct zynqmp_disp_layer *plane_to_layer(struct drm_plane *plane)
   1132{
   1133	return container_of(plane, struct zynqmp_disp_layer, plane);
   1134}
   1135
   1136static int
   1137zynqmp_disp_plane_atomic_check(struct drm_plane *plane,
   1138			       struct drm_atomic_state *state)
   1139{
   1140	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
   1141										 plane);
   1142	struct drm_crtc_state *crtc_state;
   1143
   1144	if (!new_plane_state->crtc)
   1145		return 0;
   1146
   1147	crtc_state = drm_atomic_get_crtc_state(state, new_plane_state->crtc);
   1148	if (IS_ERR(crtc_state))
   1149		return PTR_ERR(crtc_state);
   1150
   1151	return drm_atomic_helper_check_plane_state(new_plane_state,
   1152						   crtc_state,
   1153						   DRM_PLANE_HELPER_NO_SCALING,
   1154						   DRM_PLANE_HELPER_NO_SCALING,
   1155						   false, false);
   1156}
   1157
   1158static void
   1159zynqmp_disp_plane_atomic_disable(struct drm_plane *plane,
   1160				 struct drm_atomic_state *state)
   1161{
   1162	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
   1163									   plane);
   1164	struct zynqmp_disp_layer *layer = plane_to_layer(plane);
   1165
   1166	if (!old_state->fb)
   1167		return;
   1168
   1169	zynqmp_disp_layer_disable(layer);
   1170
   1171	if (zynqmp_disp_layer_is_gfx(layer))
   1172		zynqmp_disp_blend_set_global_alpha(layer->disp, false,
   1173						   plane->state->alpha >> 8);
   1174}
   1175
   1176static void
   1177zynqmp_disp_plane_atomic_update(struct drm_plane *plane,
   1178				struct drm_atomic_state *state)
   1179{
   1180	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
   1181	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
   1182	struct zynqmp_disp_layer *layer = plane_to_layer(plane);
   1183	bool format_changed = false;
   1184
   1185	if (!old_state->fb ||
   1186	    old_state->fb->format->format != new_state->fb->format->format)
   1187		format_changed = true;
   1188
   1189	/*
   1190	 * If the format has changed (including going from a previously
   1191	 * disabled state to any format), reconfigure the format. Disable the
   1192	 * plane first if needed.
   1193	 */
   1194	if (format_changed) {
   1195		if (old_state->fb)
   1196			zynqmp_disp_layer_disable(layer);
   1197
   1198		zynqmp_disp_layer_set_format(layer, new_state);
   1199	}
   1200
   1201	zynqmp_disp_layer_update(layer, new_state);
   1202
   1203	if (zynqmp_disp_layer_is_gfx(layer))
   1204		zynqmp_disp_blend_set_global_alpha(layer->disp, true,
   1205						   plane->state->alpha >> 8);
   1206
   1207	/* Enable or re-enable the plane is the format has changed. */
   1208	if (format_changed)
   1209		zynqmp_disp_layer_enable(layer);
   1210}
   1211
   1212static const struct drm_plane_helper_funcs zynqmp_disp_plane_helper_funcs = {
   1213	.atomic_check		= zynqmp_disp_plane_atomic_check,
   1214	.atomic_update		= zynqmp_disp_plane_atomic_update,
   1215	.atomic_disable		= zynqmp_disp_plane_atomic_disable,
   1216};
   1217
   1218static const struct drm_plane_funcs zynqmp_disp_plane_funcs = {
   1219	.update_plane		= drm_atomic_helper_update_plane,
   1220	.disable_plane		= drm_atomic_helper_disable_plane,
   1221	.destroy		= drm_plane_cleanup,
   1222	.reset			= drm_atomic_helper_plane_reset,
   1223	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
   1224	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
   1225};
   1226
   1227static int zynqmp_disp_create_planes(struct zynqmp_disp *disp)
   1228{
   1229	unsigned int i, j;
   1230	int ret;
   1231
   1232	for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++) {
   1233		struct zynqmp_disp_layer *layer = &disp->layers[i];
   1234		enum drm_plane_type type;
   1235		u32 *drm_formats;
   1236
   1237		drm_formats = drmm_kcalloc(disp->drm, sizeof(*drm_formats),
   1238					   layer->info->num_formats,
   1239					   GFP_KERNEL);
   1240		if (!drm_formats)
   1241			return -ENOMEM;
   1242
   1243		for (j = 0; j < layer->info->num_formats; ++j)
   1244			drm_formats[j] = layer->info->formats[j].drm_fmt;
   1245
   1246		/* Graphics layer is primary, and video layer is overlay. */
   1247		type = zynqmp_disp_layer_is_video(layer)
   1248		     ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY;
   1249		ret = drm_universal_plane_init(disp->drm, &layer->plane, 0,
   1250					       &zynqmp_disp_plane_funcs,
   1251					       drm_formats,
   1252					       layer->info->num_formats,
   1253					       NULL, type, NULL);
   1254		if (ret)
   1255			return ret;
   1256
   1257		drm_plane_helper_add(&layer->plane,
   1258				     &zynqmp_disp_plane_helper_funcs);
   1259
   1260		drm_plane_create_zpos_immutable_property(&layer->plane, i);
   1261		if (zynqmp_disp_layer_is_gfx(layer))
   1262			drm_plane_create_alpha_property(&layer->plane);
   1263	}
   1264
   1265	return 0;
   1266}
   1267
   1268/**
   1269 * zynqmp_disp_layer_release_dma - Release DMA channels for a layer
   1270 * @disp: Display controller
   1271 * @layer: The layer
   1272 *
   1273 * Release the DMA channels associated with @layer.
   1274 */
   1275static void zynqmp_disp_layer_release_dma(struct zynqmp_disp *disp,
   1276					  struct zynqmp_disp_layer *layer)
   1277{
   1278	unsigned int i;
   1279
   1280	if (!layer->info)
   1281		return;
   1282
   1283	for (i = 0; i < layer->info->num_channels; i++) {
   1284		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
   1285
   1286		if (!dma->chan)
   1287			continue;
   1288
   1289		/* Make sure the channel is terminated before release. */
   1290		dmaengine_terminate_sync(dma->chan);
   1291		dma_release_channel(dma->chan);
   1292	}
   1293}
   1294
   1295/**
   1296 * zynqmp_disp_destroy_layers - Destroy all layers
   1297 * @disp: Display controller
   1298 */
   1299static void zynqmp_disp_destroy_layers(struct zynqmp_disp *disp)
   1300{
   1301	unsigned int i;
   1302
   1303	for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++)
   1304		zynqmp_disp_layer_release_dma(disp, &disp->layers[i]);
   1305}
   1306
   1307/**
   1308 * zynqmp_disp_layer_request_dma - Request DMA channels for a layer
   1309 * @disp: Display controller
   1310 * @layer: The layer
   1311 *
   1312 * Request all DMA engine channels needed by @layer.
   1313 *
   1314 * Return: 0 on success, or the DMA channel request error otherwise
   1315 */
   1316static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp,
   1317					 struct zynqmp_disp_layer *layer)
   1318{
   1319	static const char * const dma_names[] = { "vid", "gfx" };
   1320	unsigned int i;
   1321	int ret;
   1322
   1323	for (i = 0; i < layer->info->num_channels; i++) {
   1324		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];
   1325		char dma_channel_name[16];
   1326
   1327		snprintf(dma_channel_name, sizeof(dma_channel_name),
   1328			 "%s%u", dma_names[layer->id], i);
   1329		dma->chan = dma_request_chan(disp->dev, dma_channel_name);
   1330		if (IS_ERR(dma->chan)) {
   1331			dev_err(disp->dev, "failed to request dma channel\n");
   1332			ret = PTR_ERR(dma->chan);
   1333			dma->chan = NULL;
   1334			return ret;
   1335		}
   1336	}
   1337
   1338	return 0;
   1339}
   1340
   1341/**
   1342 * zynqmp_disp_create_layers - Create and initialize all layers
   1343 * @disp: Display controller
   1344 *
   1345 * Return: 0 on success, or the DMA channel request error otherwise
   1346 */
   1347static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)
   1348{
   1349	static const struct zynqmp_disp_layer_info layer_info[] = {
   1350		[ZYNQMP_DISP_LAYER_VID] = {
   1351			.formats = avbuf_vid_fmts,
   1352			.num_formats = ARRAY_SIZE(avbuf_vid_fmts),
   1353			.num_channels = 3,
   1354		},
   1355		[ZYNQMP_DISP_LAYER_GFX] = {
   1356			.formats = avbuf_gfx_fmts,
   1357			.num_formats = ARRAY_SIZE(avbuf_gfx_fmts),
   1358			.num_channels = 1,
   1359		},
   1360	};
   1361
   1362	unsigned int i;
   1363	int ret;
   1364
   1365	for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++) {
   1366		struct zynqmp_disp_layer *layer = &disp->layers[i];
   1367
   1368		layer->id = i;
   1369		layer->disp = disp;
   1370		layer->info = &layer_info[i];
   1371
   1372		ret = zynqmp_disp_layer_request_dma(disp, layer);
   1373		if (ret)
   1374			goto err;
   1375	}
   1376
   1377	return 0;
   1378
   1379err:
   1380	zynqmp_disp_destroy_layers(disp);
   1381	return ret;
   1382}
   1383
   1384/* -----------------------------------------------------------------------------
   1385 * ZynqMP Display & DRM CRTC
   1386 */
   1387
   1388/**
   1389 * zynqmp_disp_enable - Enable the display controller
   1390 * @disp: Display controller
   1391 */
   1392static void zynqmp_disp_enable(struct zynqmp_disp *disp)
   1393{
   1394	zynqmp_disp_avbuf_enable(disp);
   1395	/* Choose clock source based on the DT clock handle. */
   1396	zynqmp_disp_avbuf_set_clocks_sources(disp, disp->pclk_from_ps,
   1397					     disp->audio.clk_from_ps, true);
   1398	zynqmp_disp_avbuf_enable_channels(disp);
   1399	zynqmp_disp_avbuf_enable_audio(disp);
   1400
   1401	zynqmp_disp_audio_enable(disp);
   1402}
   1403
   1404/**
   1405 * zynqmp_disp_disable - Disable the display controller
   1406 * @disp: Display controller
   1407 */
   1408static void zynqmp_disp_disable(struct zynqmp_disp *disp)
   1409{
   1410	zynqmp_disp_audio_disable(disp);
   1411
   1412	zynqmp_disp_avbuf_disable_audio(disp);
   1413	zynqmp_disp_avbuf_disable_channels(disp);
   1414	zynqmp_disp_avbuf_disable(disp);
   1415}
   1416
   1417static inline struct zynqmp_disp *crtc_to_disp(struct drm_crtc *crtc)
   1418{
   1419	return container_of(crtc, struct zynqmp_disp, crtc);
   1420}
   1421
   1422static int zynqmp_disp_crtc_setup_clock(struct drm_crtc *crtc,
   1423					struct drm_display_mode *adjusted_mode)
   1424{
   1425	struct zynqmp_disp *disp = crtc_to_disp(crtc);
   1426	unsigned long mode_clock = adjusted_mode->clock * 1000;
   1427	unsigned long rate;
   1428	long diff;
   1429	int ret;
   1430
   1431	ret = clk_set_rate(disp->pclk, mode_clock);
   1432	if (ret) {
   1433		dev_err(disp->dev, "failed to set a pixel clock\n");
   1434		return ret;
   1435	}
   1436
   1437	rate = clk_get_rate(disp->pclk);
   1438	diff = rate - mode_clock;
   1439	if (abs(diff) > mode_clock / 20)
   1440		dev_info(disp->dev,
   1441			 "requested pixel rate: %lu actual rate: %lu\n",
   1442			 mode_clock, rate);
   1443	else
   1444		dev_dbg(disp->dev,
   1445			"requested pixel rate: %lu actual rate: %lu\n",
   1446			mode_clock, rate);
   1447
   1448	return 0;
   1449}
   1450
   1451static void
   1452zynqmp_disp_crtc_atomic_enable(struct drm_crtc *crtc,
   1453			       struct drm_atomic_state *state)
   1454{
   1455	struct zynqmp_disp *disp = crtc_to_disp(crtc);
   1456	struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode;
   1457	int ret, vrefresh;
   1458
   1459	pm_runtime_get_sync(disp->dev);
   1460
   1461	zynqmp_disp_crtc_setup_clock(crtc, adjusted_mode);
   1462
   1463	ret = clk_prepare_enable(disp->pclk);
   1464	if (ret) {
   1465		dev_err(disp->dev, "failed to enable a pixel clock\n");
   1466		pm_runtime_put_sync(disp->dev);
   1467		return;
   1468	}
   1469
   1470	zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB);
   1471	zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0);
   1472
   1473	zynqmp_disp_enable(disp);
   1474
   1475	/* Delay of 3 vblank intervals for timing gen to be stable */
   1476	vrefresh = (adjusted_mode->clock * 1000) /
   1477		   (adjusted_mode->vtotal * adjusted_mode->htotal);
   1478	msleep(3 * 1000 / vrefresh);
   1479}
   1480
   1481static void
   1482zynqmp_disp_crtc_atomic_disable(struct drm_crtc *crtc,
   1483				struct drm_atomic_state *state)
   1484{
   1485	struct zynqmp_disp *disp = crtc_to_disp(crtc);
   1486	struct drm_plane_state *old_plane_state;
   1487
   1488	/*
   1489	 * Disable the plane if active. The old plane state can be NULL in the
   1490	 * .shutdown() path if the plane is already disabled, skip
   1491	 * zynqmp_disp_plane_atomic_disable() in that case.
   1492	 */
   1493	old_plane_state = drm_atomic_get_old_plane_state(state, crtc->primary);
   1494	if (old_plane_state)
   1495		zynqmp_disp_plane_atomic_disable(crtc->primary, state);
   1496
   1497	zynqmp_disp_disable(disp);
   1498
   1499	drm_crtc_vblank_off(&disp->crtc);
   1500
   1501	spin_lock_irq(&crtc->dev->event_lock);
   1502	if (crtc->state->event) {
   1503		drm_crtc_send_vblank_event(crtc, crtc->state->event);
   1504		crtc->state->event = NULL;
   1505	}
   1506	spin_unlock_irq(&crtc->dev->event_lock);
   1507
   1508	clk_disable_unprepare(disp->pclk);
   1509	pm_runtime_put_sync(disp->dev);
   1510}
   1511
   1512static int zynqmp_disp_crtc_atomic_check(struct drm_crtc *crtc,
   1513					 struct drm_atomic_state *state)
   1514{
   1515	return drm_atomic_add_affected_planes(state, crtc);
   1516}
   1517
   1518static void
   1519zynqmp_disp_crtc_atomic_begin(struct drm_crtc *crtc,
   1520			      struct drm_atomic_state *state)
   1521{
   1522	drm_crtc_vblank_on(crtc);
   1523}
   1524
   1525static void
   1526zynqmp_disp_crtc_atomic_flush(struct drm_crtc *crtc,
   1527			      struct drm_atomic_state *state)
   1528{
   1529	if (crtc->state->event) {
   1530		struct drm_pending_vblank_event *event;
   1531
   1532		/* Consume the flip_done event from atomic helper. */
   1533		event = crtc->state->event;
   1534		crtc->state->event = NULL;
   1535
   1536		event->pipe = drm_crtc_index(crtc);
   1537
   1538		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
   1539
   1540		spin_lock_irq(&crtc->dev->event_lock);
   1541		drm_crtc_arm_vblank_event(crtc, event);
   1542		spin_unlock_irq(&crtc->dev->event_lock);
   1543	}
   1544}
   1545
   1546static const struct drm_crtc_helper_funcs zynqmp_disp_crtc_helper_funcs = {
   1547	.atomic_enable	= zynqmp_disp_crtc_atomic_enable,
   1548	.atomic_disable	= zynqmp_disp_crtc_atomic_disable,
   1549	.atomic_check	= zynqmp_disp_crtc_atomic_check,
   1550	.atomic_begin	= zynqmp_disp_crtc_atomic_begin,
   1551	.atomic_flush	= zynqmp_disp_crtc_atomic_flush,
   1552};
   1553
   1554static int zynqmp_disp_crtc_enable_vblank(struct drm_crtc *crtc)
   1555{
   1556	struct zynqmp_disp *disp = crtc_to_disp(crtc);
   1557
   1558	zynqmp_dp_enable_vblank(disp->dpsub->dp);
   1559
   1560	return 0;
   1561}
   1562
   1563static void zynqmp_disp_crtc_disable_vblank(struct drm_crtc *crtc)
   1564{
   1565	struct zynqmp_disp *disp = crtc_to_disp(crtc);
   1566
   1567	zynqmp_dp_disable_vblank(disp->dpsub->dp);
   1568}
   1569
   1570static const struct drm_crtc_funcs zynqmp_disp_crtc_funcs = {
   1571	.destroy		= drm_crtc_cleanup,
   1572	.set_config		= drm_atomic_helper_set_config,
   1573	.page_flip		= drm_atomic_helper_page_flip,
   1574	.reset			= drm_atomic_helper_crtc_reset,
   1575	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,
   1576	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
   1577	.enable_vblank		= zynqmp_disp_crtc_enable_vblank,
   1578	.disable_vblank		= zynqmp_disp_crtc_disable_vblank,
   1579};
   1580
   1581static int zynqmp_disp_create_crtc(struct zynqmp_disp *disp)
   1582{
   1583	struct drm_plane *plane = &disp->layers[ZYNQMP_DISP_LAYER_GFX].plane;
   1584	int ret;
   1585
   1586	ret = drm_crtc_init_with_planes(disp->drm, &disp->crtc, plane,
   1587					NULL, &zynqmp_disp_crtc_funcs, NULL);
   1588	if (ret < 0)
   1589		return ret;
   1590
   1591	drm_crtc_helper_add(&disp->crtc, &zynqmp_disp_crtc_helper_funcs);
   1592
   1593	/* Start with vertical blanking interrupt reporting disabled. */
   1594	drm_crtc_vblank_off(&disp->crtc);
   1595
   1596	return 0;
   1597}
   1598
   1599static void zynqmp_disp_map_crtc_to_plane(struct zynqmp_disp *disp)
   1600{
   1601	u32 possible_crtcs = drm_crtc_mask(&disp->crtc);
   1602	unsigned int i;
   1603
   1604	for (i = 0; i < ZYNQMP_DISP_NUM_LAYERS; i++)
   1605		disp->layers[i].plane.possible_crtcs = possible_crtcs;
   1606}
   1607
   1608/* -----------------------------------------------------------------------------
   1609 * Initialization & Cleanup
   1610 */
   1611
   1612int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub)
   1613{
   1614	struct zynqmp_disp *disp = dpsub->disp;
   1615	int ret;
   1616
   1617	ret = zynqmp_disp_create_planes(disp);
   1618	if (ret)
   1619		return ret;
   1620
   1621	ret = zynqmp_disp_create_crtc(disp);
   1622	if (ret < 0)
   1623		return ret;
   1624
   1625	zynqmp_disp_map_crtc_to_plane(disp);
   1626
   1627	return 0;
   1628}
   1629
   1630int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm)
   1631{
   1632	struct platform_device *pdev = to_platform_device(dpsub->dev);
   1633	struct zynqmp_disp *disp;
   1634	struct zynqmp_disp_layer *layer;
   1635	struct resource *res;
   1636	int ret;
   1637
   1638	disp = drmm_kzalloc(drm, sizeof(*disp), GFP_KERNEL);
   1639	if (!disp)
   1640		return -ENOMEM;
   1641
   1642	disp->dev = &pdev->dev;
   1643	disp->dpsub = dpsub;
   1644	disp->drm = drm;
   1645
   1646	dpsub->disp = disp;
   1647
   1648	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "blend");
   1649	disp->blend.base = devm_ioremap_resource(disp->dev, res);
   1650	if (IS_ERR(disp->blend.base))
   1651		return PTR_ERR(disp->blend.base);
   1652
   1653	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "av_buf");
   1654	disp->avbuf.base = devm_ioremap_resource(disp->dev, res);
   1655	if (IS_ERR(disp->avbuf.base))
   1656		return PTR_ERR(disp->avbuf.base);
   1657
   1658	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud");
   1659	disp->audio.base = devm_ioremap_resource(disp->dev, res);
   1660	if (IS_ERR(disp->audio.base))
   1661		return PTR_ERR(disp->audio.base);
   1662
   1663	/* Try the live PL video clock */
   1664	disp->pclk = devm_clk_get(disp->dev, "dp_live_video_in_clk");
   1665	if (!IS_ERR(disp->pclk))
   1666		disp->pclk_from_ps = false;
   1667	else if (PTR_ERR(disp->pclk) == -EPROBE_DEFER)
   1668		return PTR_ERR(disp->pclk);
   1669
   1670	/* If the live PL video clock is not valid, fall back to PS clock */
   1671	if (IS_ERR_OR_NULL(disp->pclk)) {
   1672		disp->pclk = devm_clk_get(disp->dev, "dp_vtc_pixel_clk_in");
   1673		if (IS_ERR(disp->pclk)) {
   1674			dev_err(disp->dev, "failed to init any video clock\n");
   1675			return PTR_ERR(disp->pclk);
   1676		}
   1677		disp->pclk_from_ps = true;
   1678	}
   1679
   1680	zynqmp_disp_audio_init(disp);
   1681
   1682	ret = zynqmp_disp_create_layers(disp);
   1683	if (ret)
   1684		return ret;
   1685
   1686	layer = &disp->layers[ZYNQMP_DISP_LAYER_VID];
   1687	dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align;
   1688
   1689	return 0;
   1690}
   1691
   1692void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub)
   1693{
   1694	struct zynqmp_disp *disp = dpsub->disp;
   1695
   1696	zynqmp_disp_destroy_layers(disp);
   1697}