brintos

brintos / linux-shallow public Read only

0
0
Text · 39.4 KiB · 9368acf Raw
1453 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * ZynqMP Display Controller Driver4 *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_fb_dma_helper.h>13#include <drm/drm_fourcc.h>14#include <drm/drm_framebuffer.h>15#include <drm/drm_plane.h>16 17#include <linux/clk.h>18#include <linux/dma/xilinx_dpdma.h>19#include <linux/dma-mapping.h>20#include <linux/dmaengine.h>21#include <linux/media-bus-format.h>22#include <linux/module.h>23#include <linux/of.h>24#include <linux/platform_device.h>25#include <linux/slab.h>26 27#include "zynqmp_disp.h"28#include "zynqmp_disp_regs.h"29#include "zynqmp_dp.h"30#include "zynqmp_dpsub.h"31 32/*33 * Overview34 * --------35 *36 * The display controller part of ZynqMP DP subsystem, made of the Audio/Video37 * Buffer Manager, the Video Rendering Pipeline (blender) and the Audio Mixer.38 *39 *              +------------------------------------------------------------+40 * +--------+   | +----------------+     +-----------+                       |41 * | DPDMA  | --->|                | --> |   Video   | Video +-------------+ |42 * | 4x vid |   | |                |     | Rendering | -+--> |             | |   +------+43 * | 2x aud |   | |  Audio/Video   | --> | Pipeline  |  |    | DisplayPort |---> | PHY0 |44 * +--------+   | | Buffer Manager |     +-----------+  |    |   Source    | |   +------+45 *              | |    and STC     |     +-----------+  |    | Controller  | |   +------+46 * Live Video --->|                | --> |   Audio   | Audio |             |---> | PHY1 |47 *              | |                |     |   Mixer   | --+-> |             | |   +------+48 * Live Audio --->|                | --> |           |  ||   +-------------+ |49 *              | +----------------+     +-----------+  ||                   |50 *              +---------------------------------------||-------------------+51 *                                                      vv52 *                                                Blended Video and53 *                                                Mixed Audio to PL54 *55 * Only non-live input from the DPDMA and output to the DisplayPort Source56 * Controller are currently supported. Interface with the programmable logic57 * for live streams is not implemented.58 *59 * The display controller code creates planes for the DPDMA video and graphics60 * layers, and a CRTC for the Video Rendering Pipeline.61 */62 63#define ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS		464#define ZYNQMP_DISP_AV_BUF_NUM_BUFFERS			665 66#define ZYNQMP_DISP_MAX_NUM_SUB_PLANES			367 68/**69 * enum zynqmp_dpsub_layer_mode - Layer mode70 * @ZYNQMP_DPSUB_LAYER_NONLIVE: non-live (memory) mode71 * @ZYNQMP_DPSUB_LAYER_LIVE: live (stream) mode72 */73enum zynqmp_dpsub_layer_mode {74	ZYNQMP_DPSUB_LAYER_NONLIVE,75	ZYNQMP_DPSUB_LAYER_LIVE,76};77 78/**79 * struct zynqmp_disp_format - Display subsystem format information80 * @drm_fmt: DRM format (4CC)81 * @bus_fmt: Media bus format82 * @buf_fmt: AV buffer format83 * @swap: Flag to swap R & B for RGB formats, and U & V for YUV formats84 * @sf: Scaling factors for color components85 */86struct zynqmp_disp_format {87	u32 drm_fmt;88	u32 bus_fmt;89	u32 buf_fmt;90	bool swap;91	const u32 *sf;92};93 94/**95 * struct zynqmp_disp_layer_dma - DMA channel for one data plane of a layer96 * @chan: DMA channel97 * @xt: Interleaved DMA descriptor template98 * @sgl: Data chunk for dma_interleaved_template99 */100struct zynqmp_disp_layer_dma {101	struct dma_chan *chan;102	struct dma_interleaved_template xt;103	struct data_chunk sgl;104};105 106/**107 * struct zynqmp_disp_layer_info - Static layer information108 * @formats: Array of supported formats109 * @num_formats: Number of formats in @formats array110 * @num_channels: Number of DMA channels111 */112struct zynqmp_disp_layer_info {113	const struct zynqmp_disp_format *formats;114	unsigned int num_formats;115	unsigned int num_channels;116};117 118/**119 * struct zynqmp_disp_layer - Display layer120 * @id: Layer ID121 * @disp: Back pointer to struct zynqmp_disp122 * @info: Static layer information123 * @dmas: DMA channels124 * @disp_fmt: Current format information125 * @drm_fmt: Current DRM format information126 * @mode: Current operation mode127 */128struct zynqmp_disp_layer {129	enum zynqmp_dpsub_layer_id id;130	struct zynqmp_disp *disp;131	const struct zynqmp_disp_layer_info *info;132 133	struct zynqmp_disp_layer_dma dmas[ZYNQMP_DISP_MAX_NUM_SUB_PLANES];134 135	const struct zynqmp_disp_format *disp_fmt;136	const struct drm_format_info *drm_fmt;137	enum zynqmp_dpsub_layer_mode mode;138};139 140/**141 * struct zynqmp_disp - Display controller142 * @dev: Device structure143 * @dpsub: Display subsystem144 * @blend: Register I/O base address for the blender145 * @avbuf: Register I/O base address for the audio/video buffer manager146 * @audio: Registers I/O base address for the audio mixer147 * @layers: Layers (planes)148 */149struct zynqmp_disp {150	struct device *dev;151	struct zynqmp_dpsub *dpsub;152 153	void __iomem *blend;154	void __iomem *avbuf;155	void __iomem *audio;156 157	struct zynqmp_disp_layer layers[ZYNQMP_DPSUB_NUM_LAYERS];158};159 160/* -----------------------------------------------------------------------------161 * Audio/Video Buffer Manager162 */163 164static const u32 scaling_factors_444[] = {165	ZYNQMP_DISP_AV_BUF_4BIT_SF,166	ZYNQMP_DISP_AV_BUF_4BIT_SF,167	ZYNQMP_DISP_AV_BUF_4BIT_SF,168};169 170static const u32 scaling_factors_555[] = {171	ZYNQMP_DISP_AV_BUF_5BIT_SF,172	ZYNQMP_DISP_AV_BUF_5BIT_SF,173	ZYNQMP_DISP_AV_BUF_5BIT_SF,174};175 176static const u32 scaling_factors_565[] = {177	ZYNQMP_DISP_AV_BUF_5BIT_SF,178	ZYNQMP_DISP_AV_BUF_6BIT_SF,179	ZYNQMP_DISP_AV_BUF_5BIT_SF,180};181 182static const u32 scaling_factors_666[] = {183	ZYNQMP_DISP_AV_BUF_6BIT_SF,184	ZYNQMP_DISP_AV_BUF_6BIT_SF,185	ZYNQMP_DISP_AV_BUF_6BIT_SF,186};187 188static const u32 scaling_factors_888[] = {189	ZYNQMP_DISP_AV_BUF_8BIT_SF,190	ZYNQMP_DISP_AV_BUF_8BIT_SF,191	ZYNQMP_DISP_AV_BUF_8BIT_SF,192};193 194static const u32 scaling_factors_101010[] = {195	ZYNQMP_DISP_AV_BUF_10BIT_SF,196	ZYNQMP_DISP_AV_BUF_10BIT_SF,197	ZYNQMP_DISP_AV_BUF_10BIT_SF,198};199 200/* List of video layer formats */201static const struct zynqmp_disp_format avbuf_vid_fmts[] = {202	{203		.drm_fmt	= DRM_FORMAT_VYUY,204		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY,205		.swap		= true,206		.sf		= scaling_factors_888,207	}, {208		.drm_fmt	= DRM_FORMAT_UYVY,209		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY,210		.swap		= false,211		.sf		= scaling_factors_888,212	}, {213		.drm_fmt	= DRM_FORMAT_YUYV,214		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV,215		.swap		= false,216		.sf		= scaling_factors_888,217	}, {218		.drm_fmt	= DRM_FORMAT_YVYU,219		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV,220		.swap		= true,221		.sf		= scaling_factors_888,222	}, {223		.drm_fmt	= DRM_FORMAT_YUV422,224		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16,225		.swap		= false,226		.sf		= scaling_factors_888,227	}, {228		.drm_fmt	= DRM_FORMAT_YVU422,229		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16,230		.swap		= true,231		.sf		= scaling_factors_888,232	}, {233		.drm_fmt	= DRM_FORMAT_YUV444,234		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24,235		.swap		= false,236		.sf		= scaling_factors_888,237	}, {238		.drm_fmt	= DRM_FORMAT_YVU444,239		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24,240		.swap		= true,241		.sf		= scaling_factors_888,242	}, {243		.drm_fmt	= DRM_FORMAT_NV16,244		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI,245		.swap		= false,246		.sf		= scaling_factors_888,247	}, {248		.drm_fmt	= DRM_FORMAT_NV61,249		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI,250		.swap		= true,251		.sf		= scaling_factors_888,252	}, {253		.drm_fmt	= DRM_FORMAT_BGR888,254		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888,255		.swap		= false,256		.sf		= scaling_factors_888,257	}, {258		.drm_fmt	= DRM_FORMAT_RGB888,259		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888,260		.swap		= true,261		.sf		= scaling_factors_888,262	}, {263		.drm_fmt	= DRM_FORMAT_XBGR8888,264		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880,265		.swap		= false,266		.sf		= scaling_factors_888,267	}, {268		.drm_fmt	= DRM_FORMAT_XRGB8888,269		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880,270		.swap		= true,271		.sf		= scaling_factors_888,272	}, {273		.drm_fmt	= DRM_FORMAT_XBGR2101010,274		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10,275		.swap		= false,276		.sf		= scaling_factors_101010,277	}, {278		.drm_fmt	= DRM_FORMAT_XRGB2101010,279		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10,280		.swap		= true,281		.sf		= scaling_factors_101010,282	}, {283		.drm_fmt	= DRM_FORMAT_YUV420,284		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420,285		.swap		= false,286		.sf		= scaling_factors_888,287	}, {288		.drm_fmt	= DRM_FORMAT_YVU420,289		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420,290		.swap		= true,291		.sf		= scaling_factors_888,292	}, {293		.drm_fmt	= DRM_FORMAT_NV12,294		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420,295		.swap		= false,296		.sf		= scaling_factors_888,297	}, {298		.drm_fmt	= DRM_FORMAT_NV21,299		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420,300		.swap		= true,301		.sf		= scaling_factors_888,302	},303};304 305/* List of graphics layer formats */306static const struct zynqmp_disp_format avbuf_gfx_fmts[] = {307	{308		.drm_fmt	= DRM_FORMAT_ABGR8888,309		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888,310		.swap		= false,311		.sf		= scaling_factors_888,312	}, {313		.drm_fmt	= DRM_FORMAT_ARGB8888,314		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888,315		.swap		= true,316		.sf		= scaling_factors_888,317	}, {318		.drm_fmt	= DRM_FORMAT_RGBA8888,319		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888,320		.swap		= false,321		.sf		= scaling_factors_888,322	}, {323		.drm_fmt	= DRM_FORMAT_BGRA8888,324		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888,325		.swap		= true,326		.sf		= scaling_factors_888,327	}, {328		.drm_fmt	= DRM_FORMAT_BGR888,329		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB888,330		.swap		= false,331		.sf		= scaling_factors_888,332	}, {333		.drm_fmt	= DRM_FORMAT_RGB888,334		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_BGR888,335		.swap		= false,336		.sf		= scaling_factors_888,337	}, {338		.drm_fmt	= DRM_FORMAT_RGBA5551,339		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551,340		.swap		= false,341		.sf		= scaling_factors_555,342	}, {343		.drm_fmt	= DRM_FORMAT_BGRA5551,344		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551,345		.swap		= true,346		.sf		= scaling_factors_555,347	}, {348		.drm_fmt	= DRM_FORMAT_RGBA4444,349		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444,350		.swap		= false,351		.sf		= scaling_factors_444,352	}, {353		.drm_fmt	= DRM_FORMAT_BGRA4444,354		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444,355		.swap		= true,356		.sf		= scaling_factors_444,357	}, {358		.drm_fmt	= DRM_FORMAT_RGB565,359		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565,360		.swap		= false,361		.sf		= scaling_factors_565,362	}, {363		.drm_fmt	= DRM_FORMAT_BGR565,364		.buf_fmt	= ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565,365		.swap		= true,366		.sf		= scaling_factors_565,367	},368};369 370/* List of live video layer formats */371static const struct zynqmp_disp_format avbuf_live_fmts[] = {372	{373		.drm_fmt	= DRM_FORMAT_RGB565,374		.bus_fmt	= MEDIA_BUS_FMT_RGB666_1X18,375		.buf_fmt	= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_6 |376				  ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,377		.sf		= scaling_factors_666,378	}, {379		.drm_fmt	= DRM_FORMAT_RGB888,380		.bus_fmt	= MEDIA_BUS_FMT_RGB888_1X24,381		.buf_fmt	= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |382				  ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB,383		.sf		= scaling_factors_888,384	}, {385		.drm_fmt	= DRM_FORMAT_YUV422,386		.bus_fmt	= MEDIA_BUS_FMT_UYVY8_1X16,387		.buf_fmt	= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |388				  ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,389		.sf		= scaling_factors_888,390	}, {391		.drm_fmt	= DRM_FORMAT_YUV444,392		.bus_fmt	= MEDIA_BUS_FMT_VUY8_1X24,393		.buf_fmt	= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 |394				  ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444,395		.sf		= scaling_factors_888,396	}, {397		.drm_fmt	= DRM_FORMAT_P210,398		.bus_fmt	= MEDIA_BUS_FMT_UYVY10_1X20,399		.buf_fmt	= ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10 |400				  ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422,401		.sf		= scaling_factors_101010,402	},403};404 405static u32 zynqmp_disp_avbuf_read(struct zynqmp_disp *disp, int reg)406{407	return readl(disp->avbuf + reg);408}409 410static void zynqmp_disp_avbuf_write(struct zynqmp_disp *disp, int reg, u32 val)411{412	writel(val, disp->avbuf + reg);413}414 415static bool zynqmp_disp_layer_is_video(const struct zynqmp_disp_layer *layer)416{417	return layer->id == ZYNQMP_DPSUB_LAYER_VID;418}419 420/**421 * zynqmp_disp_avbuf_set_format - Set the input format for a layer422 * @disp: Display controller423 * @layer: The layer424 * @fmt: The format information425 *426 * Set the video buffer manager format for @layer to @fmt.427 */428static void zynqmp_disp_avbuf_set_format(struct zynqmp_disp *disp,429					 struct zynqmp_disp_layer *layer,430					 const struct zynqmp_disp_format *fmt)431{432	unsigned int i;433	u32 val, reg;434 435	layer->disp_fmt = fmt;436	if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {437		reg = ZYNQMP_DISP_AV_BUF_FMT;438		val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_FMT);439		val &= zynqmp_disp_layer_is_video(layer)440		    ? ~ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK441		    : ~ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK;442		val |= fmt->buf_fmt;443		zynqmp_disp_avbuf_write(disp, reg, val);444	} else {445		reg = zynqmp_disp_layer_is_video(layer)446		    ? ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG447		    : ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG;448		val = fmt->buf_fmt;449		zynqmp_disp_avbuf_write(disp, reg, val);450	}451 452	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_SF; i++) {453		reg = zynqmp_disp_layer_is_video(layer)454		    ? ZYNQMP_DISP_AV_BUF_VID_COMP_SF(i)455		    : ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(i);456 457		zynqmp_disp_avbuf_write(disp, reg, fmt->sf[i]);458	}459}460 461/**462 * zynqmp_disp_avbuf_set_clocks_sources - Set the clocks sources463 * @disp: Display controller464 * @video_from_ps: True if the video clock originates from the PS465 * @audio_from_ps: True if the audio clock originates from the PS466 * @timings_internal: True if video timings are generated internally467 *468 * Set the source for the video and audio clocks, as well as for the video469 * timings. Clocks can originate from the PS or PL, and timings can be470 * generated internally or externally.471 */472static void473zynqmp_disp_avbuf_set_clocks_sources(struct zynqmp_disp *disp,474				     bool video_from_ps, bool audio_from_ps,475				     bool timings_internal)476{477	u32 val = 0;478 479	if (video_from_ps)480		val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_FROM_PS;481	if (audio_from_ps)482		val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_AUD_FROM_PS;483	if (timings_internal)484		val |= ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING;485 486	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CLK_SRC, val);487}488 489/**490 * zynqmp_disp_avbuf_enable_channels - Enable buffer channels491 * @disp: Display controller492 *493 * Enable all (video and audio) buffer channels.494 */495static void zynqmp_disp_avbuf_enable_channels(struct zynqmp_disp *disp)496{497	unsigned int i;498	u32 val;499 500	val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |501	      (ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_MAX <<502	       ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT);503 504	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_VID_GFX_BUFFERS; i++)505		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),506					val);507 508	val = ZYNQMP_DISP_AV_BUF_CHBUF_EN |509	      (ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_AUD_MAX <<510	       ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT);511 512	for (; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++)513		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),514					val);515}516 517/**518 * zynqmp_disp_avbuf_disable_channels - Disable buffer channels519 * @disp: Display controller520 *521 * Disable all (video and audio) buffer channels.522 */523static void zynqmp_disp_avbuf_disable_channels(struct zynqmp_disp *disp)524{525	unsigned int i;526 527	for (i = 0; i < ZYNQMP_DISP_AV_BUF_NUM_BUFFERS; i++)528		zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_CHBUF(i),529					ZYNQMP_DISP_AV_BUF_CHBUF_FLUSH);530}531 532/**533 * zynqmp_disp_avbuf_enable_audio - Enable audio534 * @disp: Display controller535 *536 * Enable all audio buffers with a non-live (memory) source.537 */538static void zynqmp_disp_avbuf_enable_audio(struct zynqmp_disp *disp)539{540	u32 val;541 542	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);543	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK;544	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MEM;545	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN;546	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);547}548 549/**550 * zynqmp_disp_avbuf_disable_audio - Disable audio551 * @disp: Display controller552 *553 * Disable all audio buffers.554 */555static void zynqmp_disp_avbuf_disable_audio(struct zynqmp_disp *disp)556{557	u32 val;558 559	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);560	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK;561	val |= ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_DISABLE;562	val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN;563	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);564}565 566/**567 * zynqmp_disp_avbuf_enable_video - Enable a video layer568 * @disp: Display controller569 * @layer: The layer570 *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{576	u32 val;577 578	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);579	if (zynqmp_disp_layer_is_video(layer)) {580		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;581		if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)582			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM;583		else584			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_LIVE;585	} else {586		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK;587		val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM;588		if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE)589			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM;590		else591			val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE;592	}593	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);594}595 596/**597 * zynqmp_disp_avbuf_disable_video - Disable a video layer598 * @disp: Display controller599 * @layer: The layer600 *601 * Disable the video/graphics buffer for @layer.602 */603static void zynqmp_disp_avbuf_disable_video(struct zynqmp_disp *disp,604					    struct zynqmp_disp_layer *layer)605{606	u32 val;607 608	val = zynqmp_disp_avbuf_read(disp, ZYNQMP_DISP_AV_BUF_OUTPUT);609	if (zynqmp_disp_layer_is_video(layer)) {610		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK;611		val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_NONE;612	} else {613		val &= ~ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK;614		val |= ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_DISABLE;615	}616	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_OUTPUT, val);617}618 619/**620 * zynqmp_disp_avbuf_enable - Enable the video pipe621 * @disp: Display controller622 *623 * De-assert the video pipe reset.624 */625static void zynqmp_disp_avbuf_enable(struct zynqmp_disp *disp)626{627	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG, 0);628}629 630/**631 * zynqmp_disp_avbuf_disable - Disable the video pipe632 * @disp: Display controller633 *634 * Assert the video pipe reset.635 */636static void zynqmp_disp_avbuf_disable(struct zynqmp_disp *disp)637{638	zynqmp_disp_avbuf_write(disp, ZYNQMP_DISP_AV_BUF_SRST_REG,639				ZYNQMP_DISP_AV_BUF_SRST_REG_VID_RST);640}641 642/* -----------------------------------------------------------------------------643 * Blender (Video Pipeline)644 */645 646static void zynqmp_disp_blend_write(struct zynqmp_disp *disp, int reg, u32 val)647{648	writel(val, disp->blend + reg);649}650 651/*652 * Colorspace conversion matrices.653 *654 * Hardcode RGB <-> YUV conversion to full-range SDTV for now.655 */656static const u16 csc_zero_matrix[] = {657	0x0,    0x0,    0x0,658	0x0,    0x0,    0x0,659	0x0,    0x0,    0x0660};661 662static const u16 csc_identity_matrix[] = {663	0x1000, 0x0,    0x0,664	0x0,    0x1000, 0x0,665	0x0,    0x0,    0x1000666};667 668static const u32 csc_zero_offsets[] = {669	0, 0, 0670};671 672static const u16 csc_rgb_to_sdtv_matrix[] = {673	0x4c9,  0x864,  0x1d3,674	0x7d4d, 0x7ab3, 0x800,675	0x800,  0x794d, 0x7eb3676};677 678static const u32 csc_rgb_to_sdtv_offsets[] = {679	0x0, 0x8000000, 0x8000000680};681 682static const u16 csc_sdtv_to_rgb_matrix[] = {683	0x1000, 0x166f, 0x0,684	0x1000, 0x7483, 0x7a7f,685	0x1000, 0x0,    0x1c5a686};687 688static const u32 csc_sdtv_to_rgb_offsets[] = {689	0x0, 0x1800, 0x1800690};691 692/**693 * zynqmp_disp_blend_set_output_format - Set the output format of the blender694 * @disp: Display controller695 * @format: Output format696 *697 * Set the output format of the blender to @format.698 */699static void zynqmp_disp_blend_set_output_format(struct zynqmp_disp *disp,700						enum zynqmp_dpsub_format format)701{702	static const unsigned int blend_output_fmts[] = {703		[ZYNQMP_DPSUB_FORMAT_RGB] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB,704		[ZYNQMP_DPSUB_FORMAT_YCRCB444] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR444,705		[ZYNQMP_DPSUB_FORMAT_YCRCB422] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR422706					       | ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_EN_DOWNSAMPLE,707		[ZYNQMP_DPSUB_FORMAT_YONLY] = ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YONLY,708	};709 710	u32 fmt = blend_output_fmts[format];711	const u16 *coeffs;712	const u32 *offsets;713	unsigned int i;714 715	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT, fmt);716	if (fmt == ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB) {717		coeffs = csc_identity_matrix;718		offsets = csc_zero_offsets;719	} else {720		coeffs = csc_rgb_to_sdtv_matrix;721		offsets = csc_rgb_to_sdtv_offsets;722	}723 724	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i++)725		zynqmp_disp_blend_write(disp,726					ZYNQMP_DISP_V_BLEND_RGB2YCBCR_COEFF(i),727					coeffs[i]);728 729	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++)730		zynqmp_disp_blend_write(disp,731					ZYNQMP_DISP_V_BLEND_OUTCSC_OFFSET(i),732					offsets[i]);733}734 735/**736 * zynqmp_disp_blend_set_bg_color - Set the background color737 * @disp: Display controller738 * @rcr: Red/Cr color component739 * @gy: Green/Y color component740 * @bcb: Blue/Cb color component741 *742 * Set the background color to (@rcr, @gy, @bcb), corresponding to the R, G and743 * B or Cr, Y and Cb components respectively depending on the selected output744 * format.745 */746static void zynqmp_disp_blend_set_bg_color(struct zynqmp_disp *disp,747					   u32 rcr, u32 gy, u32 bcb)748{749	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_0, rcr);750	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_1, gy);751	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_BG_CLR_2, bcb);752}753 754/**755 * zynqmp_disp_blend_set_global_alpha - Configure global alpha blending756 * @disp: Display controller757 * @enable: True to enable global alpha blending758 * @alpha: Global alpha value (ignored if @enabled is false)759 */760void zynqmp_disp_blend_set_global_alpha(struct zynqmp_disp *disp,761					bool enable, u32 alpha)762{763	zynqmp_disp_blend_write(disp, ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA,764				ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE(alpha) |765				(enable ? ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_EN : 0));766}767 768/**769 * zynqmp_disp_blend_layer_set_csc - Configure colorspace conversion for layer770 * @disp: Display controller771 * @layer: The layer772 * @coeffs: Colorspace conversion matrix773 * @offsets: Colorspace conversion offsets774 *775 * Configure the input colorspace conversion matrix and offsets for the @layer.776 * Columns of the matrix are automatically swapped based on the input format to777 * handle RGB and YCrCb components permutations.778 */779static void zynqmp_disp_blend_layer_set_csc(struct zynqmp_disp *disp,780					    struct zynqmp_disp_layer *layer,781					    const u16 *coeffs,782					    const u32 *offsets)783{784	unsigned int swap[3] = { 0, 1, 2 };785	unsigned int reg;786	unsigned int i;787 788	if (layer->disp_fmt->swap) {789		if (layer->drm_fmt->is_yuv) {790			/* Swap U and V. */791			swap[1] = 2;792			swap[2] = 1;793		} else {794			/* Swap R and B. */795			swap[0] = 2;796			swap[2] = 0;797		}798	}799 800	if (zynqmp_disp_layer_is_video(layer))801		reg = ZYNQMP_DISP_V_BLEND_IN1CSC_COEFF(0);802	else803		reg = ZYNQMP_DISP_V_BLEND_IN2CSC_COEFF(0);804 805	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_COEFF; i += 3, reg += 12) {806		zynqmp_disp_blend_write(disp, reg + 0, coeffs[i + swap[0]]);807		zynqmp_disp_blend_write(disp, reg + 4, coeffs[i + swap[1]]);808		zynqmp_disp_blend_write(disp, reg + 8, coeffs[i + swap[2]]);809	}810 811	if (zynqmp_disp_layer_is_video(layer))812		reg = ZYNQMP_DISP_V_BLEND_IN1CSC_OFFSET(0);813	else814		reg = ZYNQMP_DISP_V_BLEND_IN2CSC_OFFSET(0);815 816	for (i = 0; i < ZYNQMP_DISP_V_BLEND_NUM_OFFSET; i++)817		zynqmp_disp_blend_write(disp, reg + i * 4, offsets[i]);818}819 820/**821 * zynqmp_disp_blend_layer_enable - Enable a layer822 * @disp: Display controller823 * @layer: The layer824 */825static void zynqmp_disp_blend_layer_enable(struct zynqmp_disp *disp,826					   struct zynqmp_disp_layer *layer)827{828	const u16 *coeffs;829	const u32 *offsets;830	u32 val;831 832	val = (layer->drm_fmt->is_yuv ?833	       0 : ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_RGB) |834	      (layer->drm_fmt->hsub > 1 ?835	       ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_EN_US : 0);836 837	zynqmp_disp_blend_write(disp,838				ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),839				val);840 841	if (layer->drm_fmt->is_yuv) {842		coeffs = csc_sdtv_to_rgb_matrix;843		offsets = csc_sdtv_to_rgb_offsets;844	} else {845		coeffs = csc_identity_matrix;846		offsets = csc_zero_offsets;847	}848 849	zynqmp_disp_blend_layer_set_csc(disp, layer, coeffs, offsets);850}851 852/**853 * zynqmp_disp_blend_layer_disable - Disable a layer854 * @disp: Display controller855 * @layer: The layer856 */857static void zynqmp_disp_blend_layer_disable(struct zynqmp_disp *disp,858					    struct zynqmp_disp_layer *layer)859{860	zynqmp_disp_blend_write(disp,861				ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(layer->id),862				0);863 864	zynqmp_disp_blend_layer_set_csc(disp, layer, csc_zero_matrix,865					csc_zero_offsets);866}867 868/* -----------------------------------------------------------------------------869 * Audio Mixer870 */871 872static void zynqmp_disp_audio_write(struct zynqmp_disp *disp, int reg, u32 val)873{874	writel(val, disp->audio + reg);875}876 877/**878 * zynqmp_disp_audio_enable - Enable the audio mixer879 * @disp: Display controller880 *881 * Enable the audio mixer by de-asserting the soft reset. The audio state is set to882 * default values by the reset, set the default mixer volume explicitly.883 */884static void zynqmp_disp_audio_enable(struct zynqmp_disp *disp)885{886	/* Clear the audio soft reset register as it's an non-reset flop. */887	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET, 0);888	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_MIXER_VOLUME,889				ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE);890}891 892/**893 * zynqmp_disp_audio_disable - Disable the audio mixer894 * @disp: Display controller895 *896 * Disable the audio mixer by asserting its soft reset.897 */898static void zynqmp_disp_audio_disable(struct zynqmp_disp *disp)899{900	zynqmp_disp_audio_write(disp, ZYNQMP_DISP_AUD_SOFT_RESET,901				ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST);902}903 904/* -----------------------------------------------------------------------------905 * ZynqMP Display Layer & DRM Plane906 */907 908/**909 * zynqmp_disp_layer_find_format - Find format information for a DRM format910 * @layer: The layer911 * @drm_fmt: DRM format to search912 *913 * Search display subsystem format information corresponding to the given DRM914 * format @drm_fmt for the @layer, and return a pointer to the format915 * descriptor.916 *917 * Return: A pointer to the format descriptor if found, NULL otherwise918 */919static const struct zynqmp_disp_format *920zynqmp_disp_layer_find_format(struct zynqmp_disp_layer *layer,921			      u32 drm_fmt)922{923	unsigned int i;924 925	for (i = 0; i < layer->info->num_formats; i++) {926		if (layer->info->formats[i].drm_fmt == drm_fmt)927			return &layer->info->formats[i];928	}929 930	return NULL;931}932 933/**934 * zynqmp_disp_layer_find_live_format - Find format information for given935 * media bus format936 * @layer: The layer937 * @media_bus_format: Media bus format to search938 *939 * Search display subsystem format information corresponding to the given media940 * bus format @media_bus_format for the @layer, and return a pointer to the941 * format descriptor.942 *943 * Return: A pointer to the format descriptor if found, NULL otherwise944 */945static const struct zynqmp_disp_format *946zynqmp_disp_layer_find_live_format(struct zynqmp_disp_layer *layer,947				   u32 media_bus_format)948{949	unsigned int i;950 951	for (i = 0; i < layer->info->num_formats; i++)952		if (layer->info->formats[i].bus_fmt == media_bus_format)953			return &layer->info->formats[i];954 955	return NULL;956}957 958/**959 * zynqmp_disp_layer_drm_formats - Return the DRM formats supported by the layer960 * @layer: The layer961 * @num_formats: Pointer to the returned number of formats962 *963 * NOTE: This function doesn't make sense for live video layers and will964 * always return an empty list in such cases. zynqmp_disp_live_layer_formats()965 * should be used to query a list of media bus formats supported by the live966 * video input layer.967 *968 * Return: A newly allocated u32 array that stores all the DRM formats969 * supported by the layer. The number of formats in the array is returned970 * through the num_formats argument.971 */972u32 *zynqmp_disp_layer_drm_formats(struct zynqmp_disp_layer *layer,973				   unsigned int *num_formats)974{975	unsigned int i;976	u32 *formats;977 978	if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_NONLIVE)) {979		*num_formats = 0;980		return NULL;981	}982 983	formats = kcalloc(layer->info->num_formats, sizeof(*formats),984			  GFP_KERNEL);985	if (!formats) {986		*num_formats = 0;987		return NULL;988	}989 990	for (i = 0; i < layer->info->num_formats; ++i)991		formats[i] = layer->info->formats[i].drm_fmt;992 993	*num_formats = layer->info->num_formats;994	return formats;995}996 997/**998 * zynqmp_disp_live_layer_formats - Return the media bus formats supported by999 * the live video layer1000 * @layer: The layer1001 * @num_formats: Pointer to the returned number of formats1002 *1003 * NOTE: This function should be used only for live video input layers.1004 *1005 * Return: A newly allocated u32 array of media bus formats supported by the1006 * layer. The number of formats in the array is returned through the1007 * @num_formats argument.1008 */1009u32 *zynqmp_disp_live_layer_formats(struct zynqmp_disp_layer *layer,1010				    unsigned int *num_formats)1011{1012	unsigned int i;1013	u32 *formats;1014 1015	if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_LIVE)) {1016		*num_formats = 0;1017		return NULL;1018	}1019 1020	formats = kcalloc(layer->info->num_formats, sizeof(*formats),1021			  GFP_KERNEL);1022	if (!formats) {1023		*num_formats = 0;1024		return NULL;1025	}1026 1027	for (i = 0; i < layer->info->num_formats; ++i)1028		formats[i] = layer->info->formats[i].bus_fmt;1029 1030	*num_formats = layer->info->num_formats;1031	return formats;1032}1033 1034/**1035 * zynqmp_disp_layer_enable - Enable a layer1036 * @layer: The layer1037 *1038 * Enable the @layer in the audio/video buffer manager and the blender. DMA1039 * channels are started separately by zynqmp_disp_layer_update().1040 */1041void zynqmp_disp_layer_enable(struct zynqmp_disp_layer *layer)1042{1043	zynqmp_disp_avbuf_enable_video(layer->disp, layer);1044	zynqmp_disp_blend_layer_enable(layer->disp, layer);1045}1046 1047/**1048 * zynqmp_disp_layer_disable - Disable the layer1049 * @layer: The layer1050 *1051 * Disable the layer by stopping its DMA channels and disabling it in the1052 * audio/video buffer manager and the blender.1053 */1054void zynqmp_disp_layer_disable(struct zynqmp_disp_layer *layer)1055{1056	unsigned int i;1057 1058	if (layer->mode == ZYNQMP_DPSUB_LAYER_NONLIVE) {1059		for (i = 0; i < layer->drm_fmt->num_planes; i++)1060			dmaengine_terminate_sync(layer->dmas[i].chan);1061	}1062 1063	zynqmp_disp_avbuf_disable_video(layer->disp, layer);1064	zynqmp_disp_blend_layer_disable(layer->disp, layer);1065}1066 1067/**1068 * zynqmp_disp_layer_set_format - Set the layer format1069 * @layer: The layer1070 * @info: The format info1071 *1072 * NOTE: Use zynqmp_disp_layer_set_live_format() to set media bus format for1073 * live video layers.1074 *1075 * Set the format for @layer to @info. The layer must be disabled.1076 */1077void zynqmp_disp_layer_set_format(struct zynqmp_disp_layer *layer,1078				  const struct drm_format_info *info)1079{1080	unsigned int i;1081 1082	if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_NONLIVE))1083		return;1084 1085	layer->disp_fmt = zynqmp_disp_layer_find_format(layer, info->format);1086	if (WARN_ON(!layer->disp_fmt))1087		return;1088	layer->drm_fmt = info;1089 1090	zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);1091 1092	/*1093	 * Set pconfig for each DMA channel to indicate they're part of a1094	 * video group.1095	 */1096	for (i = 0; i < info->num_planes; i++) {1097		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1098		struct xilinx_dpdma_peripheral_config pconfig = {1099			.video_group = true,1100		};1101		struct dma_slave_config config = {1102			.direction = DMA_MEM_TO_DEV,1103			.peripheral_config = &pconfig,1104			.peripheral_size = sizeof(pconfig),1105		};1106 1107		dmaengine_slave_config(dma->chan, &config);1108	}1109}1110 1111/**1112 * zynqmp_disp_layer_set_live_format - Set the live video layer format1113 * @layer: The layer1114 * @media_bus_format: Media bus format to set1115 *1116 * NOTE: This function should not be used to set format for non-live video1117 * layer. Use zynqmp_disp_layer_set_format() instead.1118 *1119 * Set the display format for the live @layer. The layer must be disabled.1120 */1121void zynqmp_disp_layer_set_live_format(struct zynqmp_disp_layer *layer,1122				       u32 media_bus_format)1123{1124	if (WARN_ON(layer->mode != ZYNQMP_DPSUB_LAYER_LIVE))1125		return;1126 1127	layer->disp_fmt = zynqmp_disp_layer_find_live_format(layer,1128							     media_bus_format);1129	if (WARN_ON(!layer->disp_fmt))1130		return;1131 1132	zynqmp_disp_avbuf_set_format(layer->disp, layer, layer->disp_fmt);1133 1134	layer->drm_fmt = drm_format_info(layer->disp_fmt->drm_fmt);1135}1136 1137/**1138 * zynqmp_disp_layer_update - Update the layer framebuffer1139 * @layer: The layer1140 * @state: The plane state1141 *1142 * Update the framebuffer for the layer by issuing a new DMA engine transaction1143 * for the new framebuffer.1144 *1145 * Return: 0 on success, or the DMA descriptor failure error otherwise1146 */1147int zynqmp_disp_layer_update(struct zynqmp_disp_layer *layer,1148			     struct drm_plane_state *state)1149{1150	const struct drm_format_info *info = layer->drm_fmt;1151	unsigned int i;1152 1153	if (layer->mode == ZYNQMP_DPSUB_LAYER_LIVE)1154		return 0;1155 1156	for (i = 0; i < info->num_planes; i++) {1157		unsigned int width = state->crtc_w / (i ? info->hsub : 1);1158		unsigned int height = state->crtc_h / (i ? info->vsub : 1);1159		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1160		struct dma_async_tx_descriptor *desc;1161		dma_addr_t dma_addr;1162 1163		dma_addr = drm_fb_dma_get_gem_addr(state->fb, state, i);1164 1165		dma->xt.numf = height;1166		dma->sgl.size = width * info->cpp[i];1167		dma->sgl.icg = state->fb->pitches[i] - dma->sgl.size;1168		dma->xt.src_start = dma_addr;1169		dma->xt.frame_size = 1;1170		dma->xt.dir = DMA_MEM_TO_DEV;1171		dma->xt.src_sgl = true;1172		dma->xt.dst_sgl = false;1173 1174		desc = dmaengine_prep_interleaved_dma(dma->chan, &dma->xt,1175						      DMA_CTRL_ACK |1176						      DMA_PREP_REPEAT |1177						      DMA_PREP_LOAD_EOT);1178		if (!desc) {1179			dev_err(layer->disp->dev,1180				"failed to prepare DMA descriptor\n");1181			return -ENOMEM;1182		}1183 1184		dmaengine_submit(desc);1185		dma_async_issue_pending(dma->chan);1186	}1187 1188	return 0;1189}1190 1191/**1192 * zynqmp_disp_layer_release_dma - Release DMA channels for a layer1193 * @disp: Display controller1194 * @layer: The layer1195 *1196 * Release the DMA channels associated with @layer.1197 */1198static void zynqmp_disp_layer_release_dma(struct zynqmp_disp *disp,1199					  struct zynqmp_disp_layer *layer)1200{1201	unsigned int i;1202 1203	for (i = 0; i < layer->info->num_channels; i++) {1204		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1205 1206		if (!dma->chan)1207			continue;1208 1209		/* Make sure the channel is terminated before release. */1210		dmaengine_terminate_sync(dma->chan);1211		dma_release_channel(dma->chan);1212	}1213}1214 1215/**1216 * zynqmp_disp_destroy_layers - Destroy all layers1217 * @disp: Display controller1218 */1219static void zynqmp_disp_destroy_layers(struct zynqmp_disp *disp)1220{1221	unsigned int i;1222 1223	for (i = 0; i < ARRAY_SIZE(disp->layers); i++)1224		zynqmp_disp_layer_release_dma(disp, &disp->layers[i]);1225}1226 1227/**1228 * zynqmp_disp_layer_request_dma - Request DMA channels for a layer1229 * @disp: Display controller1230 * @layer: The layer1231 *1232 * Request all DMA engine channels needed by @layer.1233 *1234 * Return: 0 on success, or the DMA channel request error otherwise1235 */1236static int zynqmp_disp_layer_request_dma(struct zynqmp_disp *disp,1237					 struct zynqmp_disp_layer *layer)1238{1239	static const char * const dma_names[] = { "vid", "gfx" };1240	unsigned int i;1241	int ret;1242 1243	for (i = 0; i < layer->info->num_channels; i++) {1244		struct zynqmp_disp_layer_dma *dma = &layer->dmas[i];1245		char dma_channel_name[16];1246 1247		snprintf(dma_channel_name, sizeof(dma_channel_name),1248			 "%s%u", dma_names[layer->id], i);1249		dma->chan = dma_request_chan(disp->dev, dma_channel_name);1250		if (IS_ERR(dma->chan)) {1251			ret = dev_err_probe(disp->dev, PTR_ERR(dma->chan),1252					    "failed to request dma channel\n");1253			dma->chan = NULL;1254			return ret;1255		}1256	}1257 1258	return 0;1259}1260 1261/**1262 * zynqmp_disp_create_layers - Create and initialize all layers1263 * @disp: Display controller1264 *1265 * Return: 0 on success, or the DMA channel request error otherwise1266 */1267static int zynqmp_disp_create_layers(struct zynqmp_disp *disp)1268{1269	static const struct zynqmp_disp_layer_info layer_info[] = {1270		[ZYNQMP_DPSUB_LAYER_VID] = {1271			.formats = avbuf_vid_fmts,1272			.num_formats = ARRAY_SIZE(avbuf_vid_fmts),1273			.num_channels = 3,1274		},1275		[ZYNQMP_DPSUB_LAYER_GFX] = {1276			.formats = avbuf_gfx_fmts,1277			.num_formats = ARRAY_SIZE(avbuf_gfx_fmts),1278			.num_channels = 1,1279		},1280	};1281	static const struct zynqmp_disp_layer_info live_layer_info = {1282		.formats = avbuf_live_fmts,1283		.num_formats = ARRAY_SIZE(avbuf_live_fmts),1284		.num_channels = 0,1285	};1286 1287	unsigned int i;1288	int ret;1289 1290	for (i = 0; i < ARRAY_SIZE(disp->layers); i++) {1291		struct zynqmp_disp_layer *layer = &disp->layers[i];1292 1293		layer->id = i;1294		layer->disp = disp;1295		/*1296		 * For now assume dpsub works in either live or non-live mode for both layers.1297		 * Hybrid mode is not supported yet.1298		 */1299		if (disp->dpsub->dma_enabled) {1300			layer->mode = ZYNQMP_DPSUB_LAYER_NONLIVE;1301			layer->info = &layer_info[i];1302		} else {1303			layer->mode = ZYNQMP_DPSUB_LAYER_LIVE;1304			layer->info = &live_layer_info;1305		}1306 1307		ret = zynqmp_disp_layer_request_dma(disp, layer);1308		if (ret)1309			goto err;1310 1311		disp->dpsub->layers[i] = layer;1312	}1313 1314	return 0;1315 1316err:1317	zynqmp_disp_destroy_layers(disp);1318	return ret;1319}1320 1321/* -----------------------------------------------------------------------------1322 * ZynqMP Display1323 */1324 1325/**1326 * zynqmp_disp_enable - Enable the display controller1327 * @disp: Display controller1328 */1329void zynqmp_disp_enable(struct zynqmp_disp *disp)1330{1331	zynqmp_disp_blend_set_output_format(disp, ZYNQMP_DPSUB_FORMAT_RGB);1332	zynqmp_disp_blend_set_bg_color(disp, 0, 0, 0);1333 1334	zynqmp_disp_avbuf_enable(disp);1335	/* Choose clock source based on the DT clock handle. */1336	zynqmp_disp_avbuf_set_clocks_sources(disp, disp->dpsub->vid_clk_from_ps,1337					     disp->dpsub->aud_clk_from_ps,1338					     disp->dpsub->vid_clk_from_ps);1339	zynqmp_disp_avbuf_enable_channels(disp);1340	zynqmp_disp_avbuf_enable_audio(disp);1341 1342	zynqmp_disp_audio_enable(disp);1343}1344 1345/**1346 * zynqmp_disp_disable - Disable the display controller1347 * @disp: Display controller1348 */1349void zynqmp_disp_disable(struct zynqmp_disp *disp)1350{1351	zynqmp_disp_audio_disable(disp);1352 1353	zynqmp_disp_avbuf_disable_audio(disp);1354	zynqmp_disp_avbuf_disable_channels(disp);1355	zynqmp_disp_avbuf_disable(disp);1356}1357 1358/**1359 * zynqmp_disp_setup_clock - Configure the display controller pixel clock rate1360 * @disp: Display controller1361 * @mode_clock: The pixel clock rate, in Hz1362 *1363 * Return: 0 on success, or a negative error clock otherwise1364 */1365int zynqmp_disp_setup_clock(struct zynqmp_disp *disp,1366			    unsigned long mode_clock)1367{1368	unsigned long rate;1369	long diff;1370	int ret;1371 1372	ret = clk_set_rate(disp->dpsub->vid_clk, mode_clock);1373	if (ret) {1374		dev_err(disp->dev, "failed to set the video clock\n");1375		return ret;1376	}1377 1378	rate = clk_get_rate(disp->dpsub->vid_clk);1379	diff = rate - mode_clock;1380	if (abs(diff) > mode_clock / 20)1381		dev_info(disp->dev,1382			 "requested pixel rate: %lu actual rate: %lu\n",1383			 mode_clock, rate);1384	else1385		dev_dbg(disp->dev,1386			"requested pixel rate: %lu actual rate: %lu\n",1387			mode_clock, rate);1388 1389	return 0;1390}1391 1392/* -----------------------------------------------------------------------------1393 * Initialization & Cleanup1394 */1395 1396int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub)1397{1398	struct platform_device *pdev = to_platform_device(dpsub->dev);1399	struct zynqmp_disp *disp;1400	int ret;1401 1402	disp = kzalloc(sizeof(*disp), GFP_KERNEL);1403	if (!disp)1404		return -ENOMEM;1405 1406	disp->dev = &pdev->dev;1407	disp->dpsub = dpsub;1408 1409	disp->blend = devm_platform_ioremap_resource_byname(pdev, "blend");1410	if (IS_ERR(disp->blend)) {1411		ret = PTR_ERR(disp->blend);1412		goto error;1413	}1414 1415	disp->avbuf = devm_platform_ioremap_resource_byname(pdev, "av_buf");1416	if (IS_ERR(disp->avbuf)) {1417		ret = PTR_ERR(disp->avbuf);1418		goto error;1419	}1420 1421	disp->audio = devm_platform_ioremap_resource_byname(pdev, "aud");1422	if (IS_ERR(disp->audio)) {1423		ret = PTR_ERR(disp->audio);1424		goto error;1425	}1426 1427	ret = zynqmp_disp_create_layers(disp);1428	if (ret)1429		goto error;1430 1431	if (disp->dpsub->dma_enabled) {1432		struct zynqmp_disp_layer *layer;1433 1434		layer = &disp->layers[ZYNQMP_DPSUB_LAYER_VID];1435		dpsub->dma_align = 1 << layer->dmas[0].chan->device->copy_align;1436	}1437 1438	dpsub->disp = disp;1439 1440	return 0;1441 1442error:1443	kfree(disp);1444	return ret;1445}1446 1447void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub)1448{1449	struct zynqmp_disp *disp = dpsub->disp;1450 1451	zynqmp_disp_destroy_layers(disp);1452}1453