Xilinx ZynqMP DisplayPort Subsystem driver

-----BEGIN PGP SIGNATURE-----
 
 iQJWBAABCgBAFiEEvZRkio5H7O2/GZsYYiVdKZ4oCyQFAl8SPokiHGxhdXJlbnQu
 cGluY2hhcnRAaWRlYXNvbmJvYXJkLmNvbQAKCRBiJV0pnigLJEfMEACTOIz88BhU
 UHi/ZiLGrziEgQ/tr+TnGE98Usclm2C1PLOHR+vHQKvm4fhppqvDaAFdXCuDg1Qd
 korMYFMSBC3iD8TMHrU7CPX5H3tDixpnwE6DreifHnTXWvLSJA9bgYrqLuOD5fv9
 dTyhfzQQhfLjNmqwTJDQAmZqW9lBsYwBXxvCwgACjnSZo3CMzNbUEADv7ZdptuzN
 k+CbR4mgn+plQljaOp1iRvQz30BdNxQMPyIqsFU/oDxjznls/RQ2YFtU40k72mso
 dUrpP/VdBTkYXAu7nsfGTlATgPoj8z7ZVSAGNGvltmasQw/t2Na62kmmC+AAGNmw
 KHPP2HUMqTnC1SjlHOZIMncSRr/64fdY8Gr26Z3Qtb/odNlJ2k6pWM4O7/7DBPlJ
 QBfOWWVBfhezj525KJkLU8MkBa0ztuENFqmDHe3d5SkBtCfIkw0LC6Orjn2HROqd
 rhsUw8DUKrWxVe8lar+twCueoK21GqvyIc9rAJxvR/Uph7dJUYCzAHeCNysMOjlf
 hpfCJ4pwksXzUjVSqEUazh3TWqkVwDQSEmg5KO4OM/Tpg3oHFKDE0O4VMsz2CZ4W
 1tLlnNwHwXmPX3AS34Qe2LTnXqueIqEj6uqNsNfZNLhYKirDWNKnroigRdfoXvXI
 I6Eeo5caMBMmdjZwgt+US2y9lhX2YpxQyA==
 =eq5n
 -----END PGP SIGNATURE-----

Merge tag 'drm-xilinx-dpsub-20200718' of git://linuxtv.org/pinchartl/media into drm-next

Xilinx ZynqMP DisplayPort Subsystem driver

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200718001755.GA5962@pendragon.ideasonboard.com
This commit is contained in:
Dave Airlie 2020-07-23 15:31:29 +10:00
commit 959ed53808
21 changed files with 5984 additions and 1 deletions

View file

@ -0,0 +1,174 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/display/xlnx/xlnx,zynqmp-dpsub.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Xilinx ZynqMP DisplayPort Subsystem
description: |
The DisplayPort subsystem of Xilinx ZynqMP (Zynq UltraScale+ MPSoC)
implements the display and audio pipelines based on the DisplayPort v1.2
standard. The subsystem includes multiple functional blocks as below:
+------------------------------------------------------------+
+--------+ | +----------------+ +-----------+ |
| DPDMA | --->| | --> | Video | Video +-------------+ |
| 4x vid | | | | | Rendering | -+--> | | | +------+
| 2x aud | | | Audio/Video | --> | Pipeline | | | DisplayPort |---> | PHY0 |
+--------+ | | Buffer Manager | +-----------+ | | Source | | +------+
| | and STC | +-----------+ | | Controller | | +------+
Live Video --->| | --> | Audio | Audio | |---> | PHY1 |
| | | | Mixer | --+-> | | | +------+
Live Audio --->| | --> | | || +-------------+ |
| +----------------+ +-----------+ || |
+---------------------------------------||-------------------+
vv
Blended Video and
Mixed Audio to PL
The Buffer Manager interacts with external interface such as DMA engines or
live audio/video streams from the programmable logic. The Video Rendering
Pipeline blends the video and graphics layers and performs colorspace
conversion. The Audio Mixer mixes the incoming audio streams. The DisplayPort
Source Controller handles the DisplayPort protocol and connects to external
PHYs.
The subsystem supports 2 video and 2 audio streams, and various pixel formats
and depths up to 4K@30 resolution.
Please refer to "Zynq UltraScale+ Device Technical Reference Manual"
(https://www.xilinx.com/support/documentation/user_guides/ug1085-zynq-ultrascale-trm.pdf)
for more details.
maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
properties:
compatible:
const: xlnx,zynqmp-dpsub-1.7
reg:
maxItems: 4
reg-names:
items:
- const: dp
- const: blend
- const: av_buf
- const: aud
interrupts:
maxItems: 1
clocks:
description:
The APB clock and at least one video clock are mandatory, the audio clock
is optional.
minItems: 2
maxItems: 4
items:
- description: dp_apb_clk is the APB clock
- description: dp_aud_clk is the Audio clock
- description:
dp_vtc_pixel_clk_in is the non-live video clock (from Processing
System)
- description:
dp_live_video_in_clk is the live video clock (from Programmable
Logic)
clock-names:
oneOf:
- minItems: 2
maxItems: 3
items:
- const: dp_apb_clk
- enum: [ dp_vtc_pixel_clk_in, dp_live_video_in_clk ]
- enum: [ dp_vtc_pixel_clk_in, dp_live_video_in_clk ]
- minItems: 3
maxItems: 4
items:
- const: dp_apb_clk
- const: dp_aud_clk
- enum: [ dp_vtc_pixel_clk_in, dp_live_video_in_clk ]
- enum: [ dp_vtc_pixel_clk_in, dp_live_video_in_clk ]
power-domains:
maxItems: 1
resets:
maxItems: 1
dmas:
maxItems: 4
items:
- description: Video layer, plane 0 (RGB or luma)
- description: Video layer, plane 1 (U/V or U)
- description: Video layer, plane 2 (V)
- description: Graphics layer
dma-names:
items:
- const: vid0
- const: vid1
- const: vid2
- const: gfx0
phys:
description: PHYs for the DP data lanes
minItems: 1
maxItems: 2
phy-names:
minItems: 1
maxItems: 2
items:
- const: dp-phy0
- const: dp-phy1
required:
- compatible
- reg
- reg-names
- interrupts
- clocks
- clock-names
- power-domains
- resets
- dmas
- dma-names
- phys
- phy-names
additionalProperties: false
examples:
- |
#include <dt-bindings/phy/phy.h>
#include <dt-bindings/reset/xlnx-zynqmp-resets.h>
display@fd4a0000 {
compatible = "xlnx,zynqmp-dpsub-1.7";
reg = <0x0 0xfd4a0000 0x0 0x1000>,
<0x0 0xfd4aa000 0x0 0x1000>,
<0x0 0xfd4ab000 0x0 0x1000>,
<0x0 0xfd4ac000 0x0 0x1000>;
reg-names = "dp", "blend", "av_buf", "aud";
interrupts = <0 119 4>;
interrupt-parent = <&gic>;
clock-names = "dp_apb_clk", "dp_aud_clk", "dp_live_video_in_clk";
clocks = <&dp_aclk>, <&clkc 17>, <&si570_1>;
power-domains = <&pd_dp>;
resets = <&reset ZYNQMP_RESET_DP>;
dma-names = "vid0", "vid1", "vid2", "gfx0";
dmas = <&xlnx_dpdma 0>,
<&xlnx_dpdma 1>,
<&xlnx_dpdma 2>,
<&xlnx_dpdma 3>;
phys = <&psgtr 1 PHY_TYPE_DP 0 3 27000000>,
<&psgtr 0 PHY_TYPE_DP 1 3 27000000>;
phy-names = "dp-phy0", "dp-phy1";
};
...

View file

@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/dma/xilinx/xlnx,zynqmp-dpdma.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Xilinx ZynqMP DisplayPort DMA Controller Device Tree Bindings
description: |
These bindings describe the DMA engine included in the Xilinx ZynqMP
DisplayPort Subsystem. The DMA engine supports up to 6 DMA channels (3
channels for a video stream, 1 channel for a graphics stream, and 2 channels
for an audio stream).
maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
allOf:
- $ref: "../dma-controller.yaml#"
properties:
"#dma-cells":
const: 1
description: |
The cell is the DMA channel ID (see dt-bindings/dma/xlnx-zynqmp-dpdma.h
for a list of channel IDs).
compatible:
const: xlnx,zynqmp-dpdma
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
description: The AXI clock
maxItems: 1
clock-names:
const: axi_clk
required:
- "#dma-cells"
- compatible
- reg
- interrupts
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
dma: dma-controller@fd4c0000 {
compatible = "xlnx,zynqmp-dpdma";
reg = <0x0 0xfd4c0000 0x0 0x1000>;
interrupts = <GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
clocks = <&dpdma_clk>;
clock-names = "axi_clk";
#dma-cells = <1>;
};
...

View file

@ -86,7 +86,9 @@ The details of these operations are:
- interleaved_dma: This is common to Slave as well as M2M clients. For slave
address of devices' fifo could be already known to the driver.
Various types of operations could be expressed by setting
appropriate values to the 'dma_interleaved_template' members.
appropriate values to the 'dma_interleaved_template' members. Cyclic
interleaved DMA transfers are also possible if supported by the channel by
setting the DMA_PREP_REPEAT transfer flag.
A non-NULL return of this transfer API represents a "descriptor" for
the given transaction.

View file

@ -239,6 +239,27 @@ Currently, the types available are:
want to transfer a portion of uncompressed data directly to the
display to print it
- DMA_REPEAT
- The device supports repeated transfers. A repeated transfer, indicated by
the DMA_PREP_REPEAT transfer flag, is similar to a cyclic transfer in that
it gets automatically repeated when it ends, but can additionally be
replaced by the client.
- This feature is limited to interleaved transfers, this flag should thus not
be set if the DMA_INTERLEAVE flag isn't set. This limitation is based on
the current needs of DMA clients, support for additional transfer types
should be added in the future if and when the need arises.
- DMA_LOAD_EOT
- The device supports replacing repeated transfers at end of transfer (EOT)
by queuing a new transfer with the DMA_PREP_LOAD_EOT flag set.
- Support for replacing a currently running transfer at another point (such
as end of burst instead of end of transfer) will be added in the future
based on DMA clients needs, if and when the need arises.
These various types will also affect how the source and destination
addresses change over time.
@ -531,6 +552,34 @@ DMA_CTRL_REUSE
writes for which the descriptor should be in different format from
normal data descriptors.
- DMA_PREP_REPEAT
- If set, the transfer will be automatically repeated when it ends until a
new transfer is queued on the same channel with the DMA_PREP_LOAD_EOT flag.
If the next transfer to be queued on the channel does not have the
DMA_PREP_LOAD_EOT flag set, the current transfer will be repeated until the
client terminates all transfers.
- This flag is only supported if the channel reports the DMA_REPEAT
capability.
- DMA_PREP_LOAD_EOT
- If set, the transfer will replace the transfer currently being executed at
the end of the transfer.
- This is the default behaviour for non-repeated transfers, specifying
DMA_PREP_LOAD_EOT for non-repeated transfers will thus make no difference.
- When using repeated transfers, DMA clients will usually need to set the
DMA_PREP_LOAD_EOT flag on all transfers, otherwise the channel will keep
repeating the last repeated transfer and ignore the new transfers being
queued. Failure to set DMA_PREP_LOAD_EOT will appear as if the channel was
stuck on the previous transfer.
- This flag is only supported if the channel reports the DMA_LOAD_EOT
capability.
General Design Notes
====================

View file

@ -5839,6 +5839,15 @@ T: git git://anongit.freedesktop.org/drm/drm-misc
F: Documentation/gpu/xen-front.rst
F: drivers/gpu/drm/xen/
DRM DRIVERS FOR XILINX
M: Hyun Kwon <hyun.kwon@xilinx.com>
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git git://anongit.freedesktop.org/drm/drm-misc
F: Documentation/devicetree/bindings/display/xlnx/
F: drivers/gpu/drm/xlnx/
DRM DRIVERS FOR ZTE ZX
M: Shawn Guo <shawnguo@kernel.org>
L: dri-devel@lists.freedesktop.org
@ -18853,6 +18862,15 @@ F: Documentation/devicetree/bindings/media/xilinx/
F: drivers/media/platform/xilinx/
F: include/uapi/linux/xilinx-v4l2-controls.h
XILINX ZYNQMP DPDMA DRIVER
M: Hyun Kwon <hyun.kwon@xilinx.com>
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: dmaengine@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/dma/xilinx/xlnx,zynqmp-dpdma.yaml
F: drivers/dma/xilinx/xilinx_dpdma.c
F: include/dt-bindings/dma/xlnx-zynqmp-dpdma.h
XILLYBUS DRIVER
M: Eli Billauer <eli.billauer@gmail.com>
L: linux-kernel@vger.kernel.org

View file

@ -707,6 +707,16 @@ config XILINX_ZYNQMP_DMA
help
Enable support for Xilinx ZynqMP DMA controller.
config XILINX_ZYNQMP_DPDMA
tristate "Xilinx DPDMA Engine"
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
Enable support for Xilinx ZynqMP DisplayPort DMA. Choose this option
if you have a Xilinx ZynqMP SoC with a DisplayPort subsystem. The
driver provides the dmaengine required by the DisplayPort subsystem
display driver.
config ZX_DMA
tristate "ZTE ZX DMA support"
depends on ARCH_ZX || COMPILE_TEST

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_XILINX_DMA) += xilinx_dma.o
obj-$(CONFIG_XILINX_ZYNQMP_DMA) += zynqmp_dma.o
obj-$(CONFIG_XILINX_ZYNQMP_DPDMA) += xilinx_dpdma.o

File diff suppressed because it is too large Load diff

View file

@ -386,6 +386,8 @@ source "drivers/gpu/drm/mcde/Kconfig"
source "drivers/gpu/drm/tidss/Kconfig"
source "drivers/gpu/drm/xlnx/Kconfig"
# Keep legacy drivers last
menuconfig DRM_LEGACY

View file

@ -123,3 +123,4 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/
obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
obj-$(CONFIG_DRM_MCDE) += mcde/
obj-$(CONFIG_DRM_TIDSS) += tidss/
obj-y += xlnx/

View file

@ -0,0 +1,13 @@
config DRM_ZYNQMP_DPSUB
tristate "ZynqMP DisplayPort Controller Driver"
depends on ARCH_ZYNQMP || COMPILE_TEST
depends on COMMON_CLK && DRM && OF
select DMA_ENGINE
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
select DRM_KMS_HELPER
select GENERIC_PHY
help
This is a DRM/KMS driver for ZynqMP DisplayPort controller. Choose
this option if you have a Xilinx ZynqMP SoC with DisplayPort
subsystem.

View file

@ -0,0 +1,2 @@
zynqmp-dpsub-y := zynqmp_disp.o zynqmp_dpsub.o zynqmp_dp.o
obj-$(CONFIG_DRM_ZYNQMP_DPSUB) += zynqmp-dpsub.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ZynqMP Display Driver
*
* Copyright (C) 2017 - 2020 Xilinx, Inc.
*
* Authors:
* - Hyun Woo Kwon <hyun.kwon@xilinx.com>
* - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#ifndef _ZYNQMP_DISP_H_
#define _ZYNQMP_DISP_H_
#include <linux/types.h>
/*
* 3840x2160 is advertised as the maximum resolution, but almost any
* resolutions under a 300Mhz pixel rate would work. Pick 4096x4096.
*/
#define ZYNQMP_DISP_MAX_WIDTH 4096
#define ZYNQMP_DISP_MAX_HEIGHT 4096
/* The DPDMA is limited to 44 bit addressing. */
#define ZYNQMP_DISP_MAX_DMA_BIT 44
struct device;
struct drm_device;
struct platform_device;
struct zynqmp_disp;
struct zynqmp_dpsub;
void zynqmp_disp_handle_vblank(struct zynqmp_disp *disp);
bool zynqmp_disp_audio_enabled(struct zynqmp_disp *disp);
unsigned int zynqmp_disp_get_audio_clk_rate(struct zynqmp_disp *disp);
uint32_t zynqmp_disp_get_crtc_mask(struct zynqmp_disp *disp);
int zynqmp_disp_drm_init(struct zynqmp_dpsub *dpsub);
int zynqmp_disp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm);
void zynqmp_disp_remove(struct zynqmp_dpsub *dpsub);
#endif /* _ZYNQMP_DISP_H_ */

View file

@ -0,0 +1,201 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ZynqMP Display Controller Driver - Register Definitions
*
* Copyright (C) 2017 - 2020 Xilinx, Inc.
*
* Authors:
* - Hyun Woo Kwon <hyun.kwon@xilinx.com>
* - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#ifndef _ZYNQMP_DISP_REGS_H_
#define _ZYNQMP_DISP_REGS_H_
#include <linux/bits.h>
/* Blender registers */
#define ZYNQMP_DISP_V_BLEND_BG_CLR_0 0x0
#define ZYNQMP_DISP_V_BLEND_BG_CLR_1 0x4
#define ZYNQMP_DISP_V_BLEND_BG_CLR_2 0x8
#define ZYNQMP_DISP_V_BLEND_BG_MAX 0xfff
#define ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA 0xc
#define ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_VALUE(n) ((n) << 1)
#define ZYNQMP_DISP_V_BLEND_SET_GLOBAL_ALPHA_EN BIT(0)
#define ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT 0x14
#define ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_RGB 0x0
#define ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR444 0x1
#define ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YCBCR422 0x2
#define ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_YONLY 0x3
#define ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_XVYCC 0x4
#define ZYNQMP_DISP_V_BLEND_OUTPUT_VID_FMT_EN_DOWNSAMPLE BIT(4)
#define ZYNQMP_DISP_V_BLEND_LAYER_CONTROL(n) (0x18 + ((n) * 4))
#define ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_EN_US BIT(0)
#define ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_RGB BIT(1)
#define ZYNQMP_DISP_V_BLEND_LAYER_CONTROL_BYPASS BIT(8)
#define ZYNQMP_DISP_V_BLEND_NUM_COEFF 9
#define ZYNQMP_DISP_V_BLEND_NUM_OFFSET 3
#define ZYNQMP_DISP_V_BLEND_RGB2YCBCR_COEFF(n) (0x20 + ((n) * 4))
#define ZYNQMP_DISP_V_BLEND_IN1CSC_COEFF(n) (0x44 + ((n) * 4))
#define ZYNQMP_DISP_V_BLEND_IN1CSC_OFFSET(n) (0x68 + ((n) * 4))
#define ZYNQMP_DISP_V_BLEND_OUTCSC_OFFSET(n) (0x74 + ((n) * 4))
#define ZYNQMP_DISP_V_BLEND_IN2CSC_COEFF(n) (0x80 + ((n) * 4))
#define ZYNQMP_DISP_V_BLEND_IN2CSC_OFFSET(n) (0xa4 + ((n) * 4))
#define ZYNQMP_DISP_V_BLEND_CHROMA_KEY_ENABLE 0x1d0
#define ZYNQMP_DISP_V_BLEND_CHROMA_KEY_COMP1 0x1d4
#define ZYNQMP_DISP_V_BLEND_CHROMA_KEY_COMP2 0x1d8
#define ZYNQMP_DISP_V_BLEND_CHROMA_KEY_COMP3 0x1dc
/* AV buffer manager registers */
#define ZYNQMP_DISP_AV_BUF_FMT 0x0
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_SHIFT 0
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MASK (0x1f << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_UYVY (0 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_VYUY (1 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YVYU (2 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUYV (3 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16 (4 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24 (5 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI (6 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_MONO (7 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI2 (8 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUV444 (9 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888 (10 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGBA8880 (11 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_RGB888_10 (12 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YUV444_10 (13 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI2_10 (14 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_10 (15 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_10 (16 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV24_10 (17 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YONLY_10 (18 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420 (19 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420 (20 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI2_420 (21 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16_420_10 (22 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI_420_10 (23 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_VID_YV16CI2_420_10 (24 << 0)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_SHIFT 8
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_MASK (0xf << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA8888 (0 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_ABGR8888 (1 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB888 (2 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_BGR888 (3 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA5551 (4 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGBA4444 (5 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_RGB565 (6 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_8BPP (7 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_4BPP (8 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_2BPP (9 << 8)
#define ZYNQMP_DISP_AV_BUF_FMT_NL_GFX_1BPP (10 << 8)
#define ZYNQMP_DISP_AV_BUF_NON_LIVE_LATENCY 0x8
#define ZYNQMP_DISP_AV_BUF_CHBUF(n) (0x10 + ((n) * 4))
#define ZYNQMP_DISP_AV_BUF_CHBUF_EN BIT(0)
#define ZYNQMP_DISP_AV_BUF_CHBUF_FLUSH BIT(1)
#define ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_SHIFT 2
#define ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_MASK (0xf << 2)
#define ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_MAX 0xf
#define ZYNQMP_DISP_AV_BUF_CHBUF_BURST_LEN_AUD_MAX 0x3
#define ZYNQMP_DISP_AV_BUF_STATUS 0x28
#define ZYNQMP_DISP_AV_BUF_STC_CTRL 0x2c
#define ZYNQMP_DISP_AV_BUF_STC_CTRL_EN BIT(0)
#define ZYNQMP_DISP_AV_BUF_STC_CTRL_EVENT_SHIFT 1
#define ZYNQMP_DISP_AV_BUF_STC_CTRL_EVENT_EX_VSYNC 0
#define ZYNQMP_DISP_AV_BUF_STC_CTRL_EVENT_EX_VID 1
#define ZYNQMP_DISP_AV_BUF_STC_CTRL_EVENT_EX_AUD 2
#define ZYNQMP_DISP_AV_BUF_STC_CTRL_EVENT_INT_VSYNC 3
#define ZYNQMP_DISP_AV_BUF_STC_INIT_VALUE0 0x30
#define ZYNQMP_DISP_AV_BUF_STC_INIT_VALUE1 0x34
#define ZYNQMP_DISP_AV_BUF_STC_ADJ 0x38
#define ZYNQMP_DISP_AV_BUF_STC_VID_VSYNC_TS0 0x3c
#define ZYNQMP_DISP_AV_BUF_STC_VID_VSYNC_TS1 0x40
#define ZYNQMP_DISP_AV_BUF_STC_EXT_VSYNC_TS0 0x44
#define ZYNQMP_DISP_AV_BUF_STC_EXT_VSYNC_TS1 0x48
#define ZYNQMP_DISP_AV_BUF_STC_CUSTOM_EVENT_TS0 0x4c
#define ZYNQMP_DISP_AV_BUF_STC_CUSTOM_EVENT_TS1 0x50
#define ZYNQMP_DISP_AV_BUF_STC_CUSTOM_EVENT2_TS0 0x54
#define ZYNQMP_DISP_AV_BUF_STC_CUSTOM_EVENT2_TS1 0x58
#define ZYNQMP_DISP_AV_BUF_STC_SNAPSHOT0 0x60
#define ZYNQMP_DISP_AV_BUF_STC_SNAPSHOT1 0x64
#define ZYNQMP_DISP_AV_BUF_OUTPUT 0x70
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_SHIFT 0
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MASK (0x3 << 0)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_LIVE (0 << 0)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_MEM (1 << 0)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_PATTERN (2 << 0)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID1_NONE (3 << 0)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_SHIFT 2
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MASK (0x3 << 2)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_DISABLE (0 << 2)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_MEM (1 << 2)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_LIVE (2 << 2)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_VID2_NONE (3 << 2)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_SHIFT 4
#define ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MASK (0x3 << 4)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_PL (0 << 4)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_MEM (1 << 4)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_PATTERN (2 << 4)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_AUD1_DISABLE (3 << 4)
#define ZYNQMP_DISP_AV_BUF_OUTPUT_AUD2_EN BIT(6)
#define ZYNQMP_DISP_AV_BUF_HCOUNT_VCOUNT_INT0 0x74
#define ZYNQMP_DISP_AV_BUF_HCOUNT_VCOUNT_INT1 0x78
#define ZYNQMP_DISP_AV_BUF_PATTERN_GEN_SELECT 0x100
#define ZYNQMP_DISP_AV_BUF_CLK_SRC 0x120
#define ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_FROM_PS BIT(0)
#define ZYNQMP_DISP_AV_BUF_CLK_SRC_AUD_FROM_PS BIT(1)
#define ZYNQMP_DISP_AV_BUF_CLK_SRC_VID_INTERNAL_TIMING BIT(2)
#define ZYNQMP_DISP_AV_BUF_SRST_REG 0x124
#define ZYNQMP_DISP_AV_BUF_SRST_REG_VID_RST BIT(1)
#define ZYNQMP_DISP_AV_BUF_AUDIO_CH_CONFIG 0x12c
#define ZYNQMP_DISP_AV_BUF_GFX_COMP_SF(n) (0x200 + ((n) * 4))
#define ZYNQMP_DISP_AV_BUF_VID_COMP_SF(n) (0x20c + ((n) * 4))
#define ZYNQMP_DISP_AV_BUF_LIVD_VID_COMP_SF(n) (0x218 + ((n) * 4))
#define ZYNQMP_DISP_AV_BUF_LIVE_VID_CONFIG 0x224
#define ZYNQMP_DISP_AV_BUF_LIVD_GFX_COMP_SF(n) (0x228 + ((n) * 4))
#define ZYNQMP_DISP_AV_BUF_LIVE_GFX_CONFIG 0x234
#define ZYNQMP_DISP_AV_BUF_4BIT_SF 0x11111
#define ZYNQMP_DISP_AV_BUF_5BIT_SF 0x10842
#define ZYNQMP_DISP_AV_BUF_6BIT_SF 0x10410
#define ZYNQMP_DISP_AV_BUF_8BIT_SF 0x10101
#define ZYNQMP_DISP_AV_BUF_10BIT_SF 0x10040
#define ZYNQMP_DISP_AV_BUF_NULL_SF 0
#define ZYNQMP_DISP_AV_BUF_NUM_SF 3
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_6 0x0
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_8 0x1
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_10 0x2
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_12 0x3
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_BPC_MASK GENMASK(2, 0)
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_RGB 0x0
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV444 0x1
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YUV422 0x2
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_YONLY 0x3
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_FMT_MASK GENMASK(5, 4)
#define ZYNQMP_DISP_AV_BUF_LIVE_CONFIG_CB_FIRST BIT(8)
#define ZYNQMP_DISP_AV_BUF_PALETTE_MEMORY 0x400
/* Audio registers */
#define ZYNQMP_DISP_AUD_MIXER_VOLUME 0x0
#define ZYNQMP_DISP_AUD_MIXER_VOLUME_NO_SCALE 0x20002000
#define ZYNQMP_DISP_AUD_MIXER_META_DATA 0x4
#define ZYNQMP_DISP_AUD_CH_STATUS0 0x8
#define ZYNQMP_DISP_AUD_CH_STATUS1 0xc
#define ZYNQMP_DISP_AUD_CH_STATUS2 0x10
#define ZYNQMP_DISP_AUD_CH_STATUS3 0x14
#define ZYNQMP_DISP_AUD_CH_STATUS4 0x18
#define ZYNQMP_DISP_AUD_CH_STATUS5 0x1c
#define ZYNQMP_DISP_AUD_CH_A_DATA0 0x20
#define ZYNQMP_DISP_AUD_CH_A_DATA1 0x24
#define ZYNQMP_DISP_AUD_CH_A_DATA2 0x28
#define ZYNQMP_DISP_AUD_CH_A_DATA3 0x2c
#define ZYNQMP_DISP_AUD_CH_A_DATA4 0x30
#define ZYNQMP_DISP_AUD_CH_A_DATA5 0x34
#define ZYNQMP_DISP_AUD_CH_B_DATA0 0x38
#define ZYNQMP_DISP_AUD_CH_B_DATA1 0x3c
#define ZYNQMP_DISP_AUD_CH_B_DATA2 0x40
#define ZYNQMP_DISP_AUD_CH_B_DATA3 0x44
#define ZYNQMP_DISP_AUD_CH_B_DATA4 0x48
#define ZYNQMP_DISP_AUD_CH_B_DATA5 0x4c
#define ZYNQMP_DISP_AUD_SOFT_RESET 0xc00
#define ZYNQMP_DISP_AUD_SOFT_RESET_AUD_SRST BIT(0)
#endif /* _ZYNQMP_DISP_REGS_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ZynqMP DisplayPort Driver
*
* Copyright (C) 2017 - 2020 Xilinx, Inc.
*
* Authors:
* - Hyun Woo Kwon <hyun.kwon@xilinx.com>
* - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#ifndef _ZYNQMP_DP_H_
#define _ZYNQMP_DP_H_
struct drm_device;
struct platform_device;
struct zynqmp_dp;
struct zynqmp_dpsub;
void zynqmp_dp_enable_vblank(struct zynqmp_dp *dp);
void zynqmp_dp_disable_vblank(struct zynqmp_dp *dp);
int zynqmp_dp_drm_init(struct zynqmp_dpsub *dpsub);
int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub, struct drm_device *drm);
void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub);
#endif /* _ZYNQMP_DP_H_ */

View file

@ -0,0 +1,322 @@
// SPDX-License-Identifier: GPL-2.0
/*
* ZynqMP DisplayPort Subsystem Driver
*
* Copyright (C) 2017 - 2020 Xilinx, Inc.
*
* Authors:
* - Hyun Woo Kwon <hyun.kwon@xilinx.com>
* - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_gem_framebuffer_helper.h>
#include <drm/drm_managed.h>
#include <drm/drm_mode_config.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "zynqmp_disp.h"
#include "zynqmp_dp.h"
#include "zynqmp_dpsub.h"
/* -----------------------------------------------------------------------------
* Dumb Buffer & Framebuffer Allocation
*/
static int zynqmp_dpsub_dumb_create(struct drm_file *file_priv,
struct drm_device *drm,
struct drm_mode_create_dumb *args)
{
struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
unsigned int pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
/* Enforce the alignment constraints of the DMA engine. */
args->pitch = ALIGN(pitch, dpsub->dma_align);
return drm_gem_cma_dumb_create_internal(file_priv, drm, args);
}
static struct drm_framebuffer *
zynqmp_dpsub_fb_create(struct drm_device *drm, struct drm_file *file_priv,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct zynqmp_dpsub *dpsub = to_zynqmp_dpsub(drm);
struct drm_mode_fb_cmd2 cmd = *mode_cmd;
unsigned int i;
/* Enforce the alignment constraints of the DMA engine. */
for (i = 0; i < ARRAY_SIZE(cmd.pitches); ++i)
cmd.pitches[i] = ALIGN(cmd.pitches[i], dpsub->dma_align);
return drm_gem_fb_create(drm, file_priv, &cmd);
}
static const struct drm_mode_config_funcs zynqmp_dpsub_mode_config_funcs = {
.fb_create = zynqmp_dpsub_fb_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
};
/* -----------------------------------------------------------------------------
* DRM/KMS Driver
*/
DEFINE_DRM_GEM_CMA_FOPS(zynqmp_dpsub_drm_fops);
static struct drm_driver zynqmp_dpsub_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM |
DRIVER_ATOMIC,
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
.gem_prime_export = drm_gem_prime_export,
.gem_prime_import = drm_gem_prime_import,
.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
.gem_prime_vmap = drm_gem_cma_prime_vmap,
.gem_prime_vunmap = drm_gem_cma_prime_vunmap,
.gem_prime_mmap = drm_gem_cma_prime_mmap,
.gem_free_object_unlocked = drm_gem_cma_free_object,
.gem_vm_ops = &drm_gem_cma_vm_ops,
.dumb_create = zynqmp_dpsub_dumb_create,
.dumb_destroy = drm_gem_dumb_destroy,
.fops = &zynqmp_dpsub_drm_fops,
.name = "zynqmp-dpsub",
.desc = "Xilinx DisplayPort Subsystem Driver",
.date = "20130509",
.major = 1,
.minor = 0,
};
static int zynqmp_dpsub_drm_init(struct zynqmp_dpsub *dpsub)
{
struct drm_device *drm = &dpsub->drm;
int ret;
/* Initialize mode config, vblank and the KMS poll helper. */
ret = drmm_mode_config_init(drm);
if (ret < 0)
goto err_dev_put;
drm->mode_config.funcs = &zynqmp_dpsub_mode_config_funcs;
drm->mode_config.min_width = 0;
drm->mode_config.min_height = 0;
drm->mode_config.max_width = ZYNQMP_DISP_MAX_WIDTH;
drm->mode_config.max_height = ZYNQMP_DISP_MAX_HEIGHT;
ret = drm_vblank_init(drm, 1);
if (ret)
goto err_dev_put;
drm->irq_enabled = 1;
drm_kms_helper_poll_init(drm);
/*
* Initialize the DISP and DP components. This will creates planes,
* CRTC, encoder and connector. The DISP should be initialized first as
* the DP encoder needs the CRTC.
*/
ret = zynqmp_disp_drm_init(dpsub);
if (ret)
goto err_poll_fini;
ret = zynqmp_dp_drm_init(dpsub);
if (ret)
goto err_poll_fini;
/* Reset all components and register the DRM device. */
drm_mode_config_reset(drm);
ret = drm_dev_register(drm, 0);
if (ret < 0)
goto err_poll_fini;
/* Initialize fbdev generic emulation. */
drm_fbdev_generic_setup(drm, 24);
return 0;
err_poll_fini:
drm_kms_helper_poll_fini(drm);
err_dev_put:
drm_dev_put(drm);
return ret;
}
/* -----------------------------------------------------------------------------
* Power Management
*/
static int __maybe_unused zynqmp_dpsub_suspend(struct device *dev)
{
struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev);
return drm_mode_config_helper_suspend(&dpsub->drm);
}
static int __maybe_unused zynqmp_dpsub_resume(struct device *dev)
{
struct zynqmp_dpsub *dpsub = dev_get_drvdata(dev);
return drm_mode_config_helper_resume(&dpsub->drm);
}
static const struct dev_pm_ops zynqmp_dpsub_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(zynqmp_dpsub_suspend, zynqmp_dpsub_resume)
};
/* -----------------------------------------------------------------------------
* Probe & Remove
*/
static int zynqmp_dpsub_init_clocks(struct zynqmp_dpsub *dpsub)
{
int ret;
dpsub->apb_clk = devm_clk_get(dpsub->dev, "dp_apb_clk");
if (IS_ERR(dpsub->apb_clk))
return PTR_ERR(dpsub->apb_clk);
ret = clk_prepare_enable(dpsub->apb_clk);
if (ret) {
dev_err(dpsub->dev, "failed to enable the APB clock\n");
return ret;
}
return 0;
}
static int zynqmp_dpsub_probe(struct platform_device *pdev)
{
struct zynqmp_dpsub *dpsub;
int ret;
/* Allocate private data. */
dpsub = kzalloc(sizeof(*dpsub), GFP_KERNEL);
if (!dpsub)
return -ENOMEM;
dpsub->dev = &pdev->dev;
platform_set_drvdata(pdev, dpsub);
dma_set_mask(dpsub->dev, DMA_BIT_MASK(ZYNQMP_DISP_MAX_DMA_BIT));
/*
* Initialize the DRM device early, as the DRM core mandates usage of
* the managed memory helpers tied to the DRM device.
*/
ret = drm_dev_init(&dpsub->drm, &zynqmp_dpsub_drm_driver, &pdev->dev);
if (ret < 0) {
kfree(dpsub);
return ret;
}
drmm_add_final_kfree(&dpsub->drm, dpsub);
/* Try the reserved memory. Proceed if there's none. */
of_reserved_mem_device_init(&pdev->dev);
ret = zynqmp_dpsub_init_clocks(dpsub);
if (ret < 0)
goto err_mem;
pm_runtime_enable(&pdev->dev);
/*
* DP should be probed first so that the zynqmp_disp can set the output
* format accordingly.
*/
ret = zynqmp_dp_probe(dpsub, &dpsub->drm);
if (ret)
goto err_pm;
ret = zynqmp_disp_probe(dpsub, &dpsub->drm);
if (ret)
goto err_dp;
ret = zynqmp_dpsub_drm_init(dpsub);
if (ret)
goto err_disp;
dev_info(&pdev->dev, "ZynqMP DisplayPort Subsystem driver probed");
return 0;
err_disp:
zynqmp_disp_remove(dpsub);
err_dp:
zynqmp_dp_remove(dpsub);
err_pm:
pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(dpsub->apb_clk);
err_mem:
of_reserved_mem_device_release(&pdev->dev);
return ret;
}
static int zynqmp_dpsub_remove(struct platform_device *pdev)
{
struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev);
struct drm_device *drm = &dpsub->drm;
drm_dev_unregister(drm);
drm_atomic_helper_shutdown(drm);
drm_kms_helper_poll_fini(drm);
zynqmp_disp_remove(dpsub);
zynqmp_dp_remove(dpsub);
pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(dpsub->apb_clk);
of_reserved_mem_device_release(&pdev->dev);
drm_dev_put(drm);
return 0;
}
static void zynqmp_dpsub_shutdown(struct platform_device *pdev)
{
struct zynqmp_dpsub *dpsub = platform_get_drvdata(pdev);
drm_atomic_helper_shutdown(&dpsub->drm);
}
static const struct of_device_id zynqmp_dpsub_of_match[] = {
{ .compatible = "xlnx,zynqmp-dpsub-1.7", },
{ /* end of table */ },
};
MODULE_DEVICE_TABLE(of, zynqmp_dpsub_of_match);
static struct platform_driver zynqmp_dpsub_driver = {
.probe = zynqmp_dpsub_probe,
.remove = zynqmp_dpsub_remove,
.shutdown = zynqmp_dpsub_shutdown,
.driver = {
.name = "zynqmp-dpsub",
.pm = &zynqmp_dpsub_pm_ops,
.of_match_table = zynqmp_dpsub_of_match,
},
};
module_platform_driver(zynqmp_dpsub_driver);
MODULE_AUTHOR("Xilinx, Inc.");
MODULE_DESCRIPTION("ZynqMP DP Subsystem Driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ZynqMP DPSUB Subsystem Driver
*
* Copyright (C) 2017 - 2020 Xilinx, Inc.
*
* Authors:
* - Hyun Woo Kwon <hyun.kwon@xilinx.com>
* - Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#ifndef _ZYNQMP_DPSUB_H_
#define _ZYNQMP_DPSUB_H_
struct clk;
struct device;
struct drm_device;
struct zynqmp_disp;
struct zynqmp_dp;
enum zynqmp_dpsub_format {
ZYNQMP_DPSUB_FORMAT_RGB,
ZYNQMP_DPSUB_FORMAT_YCRCB444,
ZYNQMP_DPSUB_FORMAT_YCRCB422,
ZYNQMP_DPSUB_FORMAT_YONLY,
};
/**
* struct zynqmp_dpsub - ZynqMP DisplayPort Subsystem
* @drm: The DRM/KMS device
* @dev: The physical device
* @apb_clk: The APB clock
* @disp: The display controller
* @dp: The DisplayPort controller
* @dma_align: DMA alignment constraint (must be a power of 2)
*/
struct zynqmp_dpsub {
struct drm_device drm;
struct device *dev;
struct clk *apb_clk;
struct zynqmp_disp *disp;
struct zynqmp_dp *dp;
unsigned int dma_align;
};
static inline struct zynqmp_dpsub *to_zynqmp_dpsub(struct drm_device *drm)
{
return container_of(drm, struct zynqmp_dpsub, drm);
}
#endif /* _ZYNQMP_DPSUB_H_ */

View file

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*/
#ifndef __DT_BINDINGS_DMA_XLNX_ZYNQMP_DPDMA_H__
#define __DT_BINDINGS_DMA_XLNX_ZYNQMP_DPDMA_H__
#define ZYNQMP_DPDMA_VIDEO0 0
#define ZYNQMP_DPDMA_VIDEO1 1
#define ZYNQMP_DPDMA_VIDEO2 2
#define ZYNQMP_DPDMA_GRAPHICS 3
#define ZYNQMP_DPDMA_AUDIO0 4
#define ZYNQMP_DPDMA_AUDIO1 5
#endif /* __DT_BINDINGS_DMA_XLNX_ZYNQMP_DPDMA_H__ */

View file

@ -61,6 +61,8 @@ enum dma_transaction_type {
DMA_SLAVE,
DMA_CYCLIC,
DMA_INTERLEAVE,
DMA_REPEAT,
DMA_LOAD_EOT,
/* last transaction type for creation of the capabilities mask */
DMA_TX_TYPE_END,
};
@ -176,6 +178,16 @@ struct dma_interleaved_template {
* @DMA_PREP_CMD: tell the driver that the data passed to DMA API is command
* data and the descriptor should be in different format from normal
* data descriptors.
* @DMA_PREP_REPEAT: tell the driver that the transaction shall be automatically
* repeated when it ends until a transaction is issued on the same channel
* with the DMA_PREP_LOAD_EOT flag set. This flag is only applicable to
* interleaved transactions and is ignored for all other transaction types.
* @DMA_PREP_LOAD_EOT: tell the driver that the transaction shall replace any
* active repeated (as indicated by DMA_PREP_REPEAT) transaction when the
* repeated transaction ends. Not setting this flag when the previously queued
* transaction is marked with DMA_PREP_REPEAT will cause the new transaction
* to never be processed and stay in the issued queue forever. The flag is
* ignored if the previous transaction is not a repeated transaction.
*/
enum dma_ctrl_flags {
DMA_PREP_INTERRUPT = (1 << 0),
@ -186,6 +198,8 @@ enum dma_ctrl_flags {
DMA_PREP_FENCE = (1 << 5),
DMA_CTRL_REUSE = (1 << 6),
DMA_PREP_CMD = (1 << 7),
DMA_PREP_REPEAT = (1 << 8),
DMA_PREP_LOAD_EOT = (1 << 9),
};
/**
@ -980,6 +994,9 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma(
{
if (!chan || !chan->device || !chan->device->device_prep_interleaved_dma)
return NULL;
if (flags & DMA_PREP_REPEAT &&
!test_bit(DMA_REPEAT, chan->device->cap_mask.bits))
return NULL;
return chan->device->device_prep_interleaved_dma(chan, xt, flags);
}