mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	drm: xlnx: DRM/KMS driver for Xilinx ZynqMP DisplayPort Subsystem
The Xilinx ZynqMP SoC has a hardened display pipeline named DisplayPort Subsystem. It includes a buffer manager, a video pipeline renderer (blender), an audio mixer and a DisplayPort source controller (transmitter). The DMA engine the provide data to the buffer manager, as well as the DisplayPort PHYs that drive the lanes, are external to the subsystem and interfaced using the DMA engine and PHY APIs respectively. This driver supports the DisplayPort Subsystem and implements - Two planes, for graphics and video - One CRTC that supports alpha blending - One encoder for the DisplayPort transmitter - One connector for an external monitor It currently doesn't support - Color keying - Test pattern generation - Audio - Live input from the Programmable Logic (FPGA) - Output to the Programmable Logic (FPGA) Signed-off-by: Hyun Kwon <hyun.kwon@xilinx.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
		
							parent
							
								
									e7c7970a67
								
							
						
					
					
						commit
						d76271d226
					
				
					 12 changed files with 4104 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -5843,6 +5843,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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								drivers/gpu/drm/xlnx/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								drivers/gpu/drm/xlnx/Kconfig
									
									
									
									
									
										Normal 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.
 | 
			
		||||
							
								
								
									
										2
									
								
								drivers/gpu/drm/xlnx/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								drivers/gpu/drm/xlnx/Makefile
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										1697
									
								
								drivers/gpu/drm/xlnx/zynqmp_disp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1697
									
								
								drivers/gpu/drm/xlnx/zynqmp_disp.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										42
									
								
								drivers/gpu/drm/xlnx/zynqmp_disp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								drivers/gpu/drm/xlnx/zynqmp_disp.h
									
									
									
									
									
										Normal 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_ */
 | 
			
		||||
							
								
								
									
										201
									
								
								drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								drivers/gpu/drm/xlnx/zynqmp_disp_regs.h
									
									
									
									
									
										Normal 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_ */
 | 
			
		||||
							
								
								
									
										1734
									
								
								drivers/gpu/drm/xlnx/zynqmp_dp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1734
									
								
								drivers/gpu/drm/xlnx/zynqmp_dp.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										27
									
								
								drivers/gpu/drm/xlnx/zynqmp_dp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								drivers/gpu/drm/xlnx/zynqmp_dp.h
									
									
									
									
									
										Normal 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_ */
 | 
			
		||||
							
								
								
									
										322
									
								
								drivers/gpu/drm/xlnx/zynqmp_dpsub.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								drivers/gpu/drm/xlnx/zynqmp_dpsub.c
									
									
									
									
									
										Normal 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");
 | 
			
		||||
							
								
								
									
										54
									
								
								drivers/gpu/drm/xlnx/zynqmp_dpsub.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								drivers/gpu/drm/xlnx/zynqmp_dpsub.h
									
									
									
									
									
										Normal 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_ */
 | 
			
		||||
		Loading…
	
		Reference in a new issue