All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andreas Kemnade <andreas@kemnade.info>
To: p.zabel@pengutronix.de, airlied@linux.ie, daniel@ffwll.ch,
	robh+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com, linux-imx@nxp.com,
	maarten.lankhorst@linux.intel.com, mripard@kernel.org,
	tzimmermann@suse.de, andreas@kemnade.info,
	dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, alistair@alistair23.me,
	samuel@sholland.org, josua.mayer@jm0.eu,
	letux-kernel@openphoenux.org
Subject: [RFC PATCH 2/6] drm: Add skeleton for EPDC driver
Date: Sun,  6 Feb 2022 09:00:12 +0100	[thread overview]
Message-ID: <20220206080016.796556-3-andreas@kemnade.info> (raw)
In-Reply-To: <20220206080016.796556-1-andreas@kemnade.info>

This driver is for the EPD controller in the i.MX SoCs. Add a skeleton
and basic things for the driver

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
---
 drivers/gpu/drm/Kconfig                 |   2 +
 drivers/gpu/drm/Makefile                |   1 +
 drivers/gpu/drm/mxc-epdc/Kconfig        |  15 +
 drivers/gpu/drm/mxc-epdc/Makefile       |   5 +
 drivers/gpu/drm/mxc-epdc/epdc_regs.h    | 442 ++++++++++++++++++++++++
 drivers/gpu/drm/mxc-epdc/mxc_epdc.h     |  20 ++
 drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c | 248 +++++++++++++
 7 files changed, 733 insertions(+)
 create mode 100644 drivers/gpu/drm/mxc-epdc/Kconfig
 create mode 100644 drivers/gpu/drm/mxc-epdc/Makefile
 create mode 100644 drivers/gpu/drm/mxc-epdc/epdc_regs.h
 create mode 100644 drivers/gpu/drm/mxc-epdc/mxc_epdc.h
 create mode 100644 drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b1f22e457fd0..6b6b44ff7556 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -390,6 +390,8 @@ source "drivers/gpu/drm/gud/Kconfig"
 
 source "drivers/gpu/drm/sprd/Kconfig"
 
+source "drivers/gpu/drm/mxc-epdc/Kconfig"
+
 config DRM_HYPERV
 	tristate "DRM Support for Hyper-V synthetic video device"
 	depends on DRM && PCI && MMU && HYPERV
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 301a44dc18e3..e5eb9815cf9a 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -131,6 +131,7 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/
 obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
 obj-$(CONFIG_DRM_MCDE) += mcde/
 obj-$(CONFIG_DRM_TIDSS) += tidss/
+obj-$(CONFIG_DRM_MXC_EPDC) += mxc-epdc/
 obj-y			+= xlnx/
 obj-y			+= gud/
 obj-$(CONFIG_DRM_HYPERV) += hyperv/
diff --git a/drivers/gpu/drm/mxc-epdc/Kconfig b/drivers/gpu/drm/mxc-epdc/Kconfig
new file mode 100644
index 000000000000..3f5744161cff
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+config DRM_MXC_EPDC
+	tristate "i.MX EPD Controller"
+	depends on DRM && OF
+	depends on (COMPILE_TEST || ARCH_MXC)
+	select DRM_KMS_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DMA_CMA if HAVE_DMA_CONTIGUOUS
+	select CMA if HAVE_DMA_CONTIGUOUS
+	help
+	  Choose this option if you have an i.MX system with an EPDC.
+	  It enables the usage of E-paper displays. A waveform is expected
+	  to be present in /lib/firmware/imx/epdc/epdc.fw
+
+	  If M is selected this module will be called mxc_epdc_drm.
diff --git a/drivers/gpu/drm/mxc-epdc/Makefile b/drivers/gpu/drm/mxc-epdc/Makefile
new file mode 100644
index 000000000000..a47ced72b7f6
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+mxc_epdc_drm-y := mxc_epdc_drv.o
+
+obj-$(CONFIG_DRM_MXC_EPDC) += mxc_epdc_drm.o
+
diff --git a/drivers/gpu/drm/mxc-epdc/epdc_regs.h b/drivers/gpu/drm/mxc-epdc/epdc_regs.h
new file mode 100644
index 000000000000..83445c56d911
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/epdc_regs.h
@@ -0,0 +1,442 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2010-2013 Freescale Semiconductor, Inc. */
+
+#ifndef __EPDC_REGS_INCLUDED__
+#define __EPDC_REGS_INCLUDED__
+
+/*************************************
+ * Register addresses
+ **************************************/
+
+#define EPDC_CTRL			0x000
+#define EPDC_CTRL_SET			0x004
+#define EPDC_CTRL_CLEAR			0x008
+#define EPDC_CTRL_TOGGLE		0x00C
+#define EPDC_WB_ADDR_TCE_V3		0x010
+#define EPDC_WVADDR			0x020
+#define EPDC_WB_ADDR			0x030
+#define EPDC_RES			0x040
+#define EPDC_FORMAT			0x050
+#define EPDC_FORMAT_SET			0x054
+#define EPDC_FORMAT_CLEAR		0x058
+#define EPDC_FORMAT_TOGGLE		0x05C
+#define EPDC_WB_FIELD0			0x060
+#define EPDC_WB_FIELD0_SET		0x064
+#define EPDC_WB_FIELD0_CLEAR		0x068
+#define EPDC_WB_FIELD0_TOGGLE		0x06C
+#define EPDC_WB_FIELD1			0x070
+#define EPDC_WB_FIELD1_SET		0x074
+#define EPDC_WB_FIELD1_CLEAR		0x078
+#define EPDC_WB_FIELD1_TOGGLE		0x07C
+#define EPDC_WB_FIELD2			0x080
+#define EPDC_WB_FIELD2_SET		0x084
+#define EPDC_WB_FIELD2_CLEAR		0x088
+#define EPDC_WB_FIELD2_TOGGLE		0x08C
+#define EPDC_WB_FIELD3			0x090
+#define EPDC_WB_FIELD3_SET		0x094
+#define EPDC_WB_FIELD3_CLEAR		0x098
+#define EPDC_WB_FIELD3_TOGGLE		0x09C
+#define EPDC_FIFOCTRL			0x0A0
+#define EPDC_FIFOCTRL_SET		0x0A4
+#define EPDC_FIFOCTRL_CLEAR		0x0A8
+#define EPDC_FIFOCTRL_TOGGLE		0x0AC
+#define EPDC_UPD_ADDR			0x100
+#define EPDC_UPD_STRIDE			0x110
+#define EPDC_UPD_CORD			0x120
+#define EPDC_UPD_SIZE			0x140
+#define EPDC_UPD_CTRL			0x160
+#define EPDC_UPD_FIXED			0x180
+#define EPDC_TEMP			0x1A0
+#define EPDC_AUTOWV_LUT			0x1C0
+#define EPDC_TCE_CTRL			0x200
+#define EPDC_TCE_SDCFG			0x220
+#define EPDC_TCE_GDCFG			0x240
+#define EPDC_TCE_HSCAN1			0x260
+#define EPDC_TCE_HSCAN2			0x280
+#define EPDC_TCE_VSCAN			0x2A0
+#define EPDC_TCE_OE			0x2C0
+#define EPDC_TCE_POLARITY		0x2E0
+#define EPDC_TCE_TIMING1		0x300
+#define EPDC_TCE_TIMING2		0x310
+#define EPDC_TCE_TIMING3		0x320
+#define EPDC_PIGEON_CTRL0		0x380
+#define EPDC_PIGEON_CTRL1		0x390
+#define EPDC_IRQ_MASK1			0x3C0
+#define EPDC_IRQ_MASK1_SET		0x3C4
+#define EPDC_IRQ_MASK1_CLEAR		0x3C8
+#define EPDC_IRQ_MASK1_TOGGLE		0x3CC
+#define EPDC_IRQ_MASK2			0x3D0
+#define EPDC_IRQ_MASK2_SET		0x3D4
+#define EPDC_IRQ_MASK2_CLEAR		0x3D8
+#define EPDC_IRQ_MASK2_TOGGLE		0x3DC
+#define EPDC_IRQ1			0x3E0
+#define EPDC_IRQ1_SET			0x3E4
+#define EPDC_IRQ1_CLEAR			0x3E8
+#define EPDC_IRQ1_TOGGLE		0x3EC
+#define EPDC_IRQ2			0x3F0
+#define EPDC_IRQ2_SET			0x3F4
+#define EPDC_IRQ2_CLEAR			0x3F8
+#define EPDC_IRQ2_TOGGLE		0x3FC
+#define EPDC_IRQ_MASK			0x400
+#define EPDC_IRQ_MASK_SET		0x404
+#define EPDC_IRQ_MASK_CLEAR		0x408
+#define EPDC_IRQ_MASK_TOGGLE		0x40C
+#define EPDC_IRQ			0x420
+#define EPDC_IRQ_SET			0x424
+#define EPDC_IRQ_CLEAR			0x428
+#define EPDC_IRQ_TOGGLE			0x42C
+#define EPDC_STATUS_LUTS		0x440
+#define EPDC_STATUS_LUTS_SET		0x444
+#define EPDC_STATUS_LUTS_CLEAR		0x448
+#define EPDC_STATUS_LUTS_TOGGLE		0x44C
+#define EPDC_STATUS_LUTS2		0x450
+#define EPDC_STATUS_LUTS2_SET		0x454
+#define EPDC_STATUS_LUTS2_CLEAR		0x458
+#define EPDC_STATUS_LUTS2_TOGGLE	0x45C
+#define EPDC_STATUS_NEXTLUT		0x460
+#define EPDC_STATUS_COL			0x480
+#define EPDC_STATUS_COL2		0x490
+#define EPDC_STATUS			0x4A0
+#define EPDC_STATUS_SET			0x4A4
+#define EPDC_STATUS_CLEAR		0x4A8
+#define EPDC_STATUS_TOGGLE		0x4AC
+#define EPDC_UPD_COL_CORD		0x4C0
+#define EPDC_UPD_COL_SIZE		0x4E0
+#define EPDC_DEBUG			0x500
+#define EPDC_DEBUG_LUT			0x530
+#define EPDC_HIST1_PARAM		0x600
+#define EPDC_HIST2_PARAM		0x610
+#define EPDC_HIST4_PARAM		0x620
+#define EPDC_HIST8_PARAM0		0x630
+#define EPDC_HIST8_PARAM1		0x640
+#define EPDC_HIST16_PARAM0		0x650
+#define EPDC_HIST16_PARAM1		0x660
+#define EPDC_HIST16_PARAM2		0x670
+#define EPDC_HIST16_PARAM3		0x680
+#define EPDC_GPIO			0x700
+#define EPDC_VERSION			0x7F0
+#define EPDC_PIGEON_0_0			0x800
+#define EPDC_PIGEON_0_1			0x810
+#define EPDC_PIGEON_0_2			0x820
+#define EPDC_PIGEON_1_0			0x840
+#define EPDC_PIGEON_1_1			0x850
+#define EPDC_PIGEON_1_2			0x860
+#define EPDC_PIGEON_2_0			0x880
+#define EPDC_PIGEON_2_1			0x890
+#define EPDC_PIGEON_2_2			0x8A0
+#define EPDC_PIGEON_3_0			0x8C0
+#define EPDC_PIGEON_3_1			0x8D0
+#define EPDC_PIGEON_3_2			0x8E0
+#define EPDC_PIGEON_4_0			0x900
+#define EPDC_PIGEON_4_1			0x910
+#define EPDC_PIGEON_4_2			0x920
+#define EPDC_PIGEON_5_0			0x940
+#define EPDC_PIGEON_5_1			0x950
+#define EPDC_PIGEON_5_2			0x960
+#define EPDC_PIGEON_6_0			0x980
+#define EPDC_PIGEON_6_1			0x990
+#define EPDC_PIGEON_6_2			0x9A0
+#define EPDC_PIGEON_7_0			0x9C0
+#define EPDC_PIGEON_7_1			0x9D0
+#define EPDC_PIGEON_7_2			0x9E0
+#define EPDC_PIGEON_8_0			0xA00
+#define EPDC_PIGEON_8_1			0xA10
+#define EPDC_PIGEON_8_2			0xA20
+#define EPDC_PIGEON_9_0			0xA40
+#define EPDC_PIGEON_9_1			0xA50
+#define EPDC_PIGEON_9_2			0xA60
+#define EPDC_PIGEON_10_0		0xA80
+#define EPDC_PIGEON_10_1		0xA90
+#define EPDC_PIGEON_10_2		0xAA0
+#define EPDC_PIGEON_11_0		0xAC0
+#define EPDC_PIGEON_11_1		0xAD0
+#define EPDC_PIGEON_11_2		0xAE0
+#define EPDC_PIGEON_12_0		0xB00
+#define EPDC_PIGEON_12_1		0xB10
+#define EPDC_PIGEON_12_2		0xB20
+#define EPDC_PIGEON_13_0		0xB40
+#define EPDC_PIGEON_13_1		0xB50
+#define EPDC_PIGEON_13_2		0xB60
+#define EPDC_PIGEON_14_0		0xB80
+#define EPDC_PIGEON_14_1		0xB90
+#define EPDC_PIGEON_14_2		0xBA0
+#define EPDC_PIGEON_15_0		0xBC0
+#define EPDC_PIGEON_15_1		0xBD0
+#define EPDC_PIGEON_15_2		0xBE0
+#define EPDC_WB_ADDR_TCE		0xC10
+
+/*
+ * Register field definitions
+ */
+
+enum {
+/* EPDC_CTRL field values */
+	EPDC_CTRL_SFTRST = 0x80000000,
+	EPDC_CTRL_CLKGATE = 0x40000000,
+	EPDC_CTRL_SRAM_POWERDOWN = 0x100,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_MASK = 0xC0,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_NO_SWAP = 0,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_ALL_BYTES_SWAP = 0x40,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_HWD_SWAP = 0x80,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_HWD_BYTE_SWAP = 0xC0,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_MASK = 0x30,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_NO_SWAP = 0,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_ALL_BYTES_SWAP = 0x10,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_HWD_SWAP = 0x20,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_HWD_BYTE_SWAP = 0x30,
+	EPDC_CTRL_BURST_LEN_8_8 = 0x1,
+	EPDC_CTRL_BURST_LEN_8_16 = 0,
+
+/* EPDC_RES field values */
+	EPDC_RES_VERTICAL_MASK = 0x1FFF0000,
+	EPDC_RES_VERTICAL_OFFSET = 16,
+	EPDC_RES_HORIZONTAL_MASK = 0x1FFF,
+	EPDC_RES_HORIZONTAL_OFFSET = 0,
+
+/* EPDC_FORMAT field values */
+	EPDC_FORMAT_BUF_PIXEL_SCALE_ROUND = 0x1000000,
+	EPDC_FORMAT_DEFAULT_TFT_PIXEL_MASK = 0xFF0000,
+	EPDC_FORMAT_DEFAULT_TFT_PIXEL_OFFSET = 16,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_MASK = 0x700,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_P2N = 0x200,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_P3N = 0x300,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N = 0x400,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N = 0x500,
+	EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT = 0x0,
+	EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT_VCOM = 0x1,
+	EPDC_FORMAT_TFT_PIXEL_FORMAT_4BIT = 0x2,
+	EPDC_FORMAT_TFT_PIXEL_FORMAT_4BIT_VCOM = 0x3,
+
+/* EPDC_FIFOCTRL field values */
+	EPDC_FIFOCTRL_ENABLE_PRIORITY = 0x80000000,
+	EPDC_FIFOCTRL_FIFO_INIT_LEVEL_MASK = 0xFF0000,
+	EPDC_FIFOCTRL_FIFO_INIT_LEVEL_OFFSET = 16,
+	EPDC_FIFOCTRL_FIFO_H_LEVEL_MASK = 0xFF00,
+	EPDC_FIFOCTRL_FIFO_H_LEVEL_OFFSET = 8,
+	EPDC_FIFOCTRL_FIFO_L_LEVEL_MASK = 0xFF,
+	EPDC_FIFOCTRL_FIFO_L_LEVEL_OFFSET = 0,
+
+/* EPDC_UPD_CORD field values */
+	EPDC_UPD_CORD_YCORD_MASK = 0x1FFF0000,
+	EPDC_UPD_CORD_YCORD_OFFSET = 16,
+	EPDC_UPD_CORD_XCORD_MASK = 0x1FFF,
+	EPDC_UPD_CORD_XCORD_OFFSET = 0,
+
+/* EPDC_UPD_SIZE field values */
+	EPDC_UPD_SIZE_HEIGHT_MASK = 0x1FFF0000,
+	EPDC_UPD_SIZE_HEIGHT_OFFSET = 16,
+	EPDC_UPD_SIZE_WIDTH_MASK = 0x1FFF,
+	EPDC_UPD_SIZE_WIDTH_OFFSET = 0,
+
+/* EPDC_UPD_CTRL field values */
+	EPDC_UPD_CTRL_USE_FIXED = 0x80000000,
+	EPDC_UPD_CTRL_LUT_SEL_MASK = 0x3F0000,
+	EPDC_UPD_CTRL_LUT_SEL_OFFSET = 16,
+	EPDC_UPD_CTRL_WAVEFORM_MODE_MASK = 0xFF00,
+	EPDC_UPD_CTRL_WAVEFORM_MODE_OFFSET = 8,
+	EPDC_UPD_CTRL_AUTOWV_PAUSE = 0x8,
+	EPDC_UPD_CTRL_AUTOWV = 0x4,
+	EPDC_UPD_CTRL_DRY_RUN = 0x2,
+	EPDC_UPD_CTRL_UPDATE_MODE_FULL = 0x1,
+
+/* EPDC_UPD_FIXED field values */
+	EPDC_UPD_FIXED_FIXNP_EN = 0x80000000,
+	EPDC_UPD_FIXED_FIXCP_EN = 0x40000000,
+	EPDC_UPD_FIXED_FIXNP_MASK = 0xFF00,
+	EPDC_UPD_FIXED_FIXNP_OFFSET = 8,
+	EPDC_UPD_FIXED_FIXCP_MASK = 0xFF,
+	EPDC_UPD_FIXED_FIXCP_OFFSET = 0,
+
+/* EPDC_AUTOWV_LUT field values */
+	EPDC_AUTOWV_LUT_DATA_MASK = 0xFF0000,
+	EPDC_AUTOWV_LUT_DATA_OFFSET = 16,
+	EPDC_AUTOWV_LUT_ADDR_MASK = 0xFF,
+	EPDC_AUTOWV_LUT_ADDR_OFFSET = 0,
+
+/* EPDC_TCE_CTRL field values */
+	EPDC_TCE_CTRL_VSCAN_HOLDOFF_MASK = 0x1FF0000,
+	EPDC_TCE_CTRL_VSCAN_HOLDOFF_OFFSET = 16,
+	EPDC_TCE_CTRL_VCOM_VAL_MASK = 0xC00,
+	EPDC_TCE_CTRL_VCOM_VAL_OFFSET = 10,
+	EPDC_TCE_CTRL_VCOM_MODE_AUTO = 0x200,
+	EPDC_TCE_CTRL_VCOM_MODE_MANUAL = 0x000,
+	EPDC_TCE_CTRL_DDR_MODE_ENABLE = 0x100,
+	EPDC_TCE_CTRL_LVDS_MODE_CE_ENABLE = 0x80,
+	EPDC_TCE_CTRL_LVDS_MODE_ENABLE = 0x40,
+	EPDC_TCE_CTRL_SCAN_DIR_1_UP = 0x20,
+	EPDC_TCE_CTRL_SCAN_DIR_0_UP = 0x10,
+	EPDC_TCE_CTRL_DUAL_SCAN_ENABLE = 0x8,
+	EPDC_TCE_CTRL_SDDO_WIDTH_16BIT = 0x4,
+	EPDC_TCE_CTRL_PIXELS_PER_SDCLK_2 = 1,
+	EPDC_TCE_CTRL_PIXELS_PER_SDCLK_4 = 2,
+	EPDC_TCE_CTRL_PIXELS_PER_SDCLK_8 = 3,
+
+/* EPDC_TCE_SDCFG field values */
+	EPDC_TCE_SDCFG_SDCLK_HOLD = 0x200000,
+	EPDC_TCE_SDCFG_SDSHR = 0x100000,
+	EPDC_TCE_SDCFG_NUM_CE_MASK = 0xF0000,
+	EPDC_TCE_SDCFG_NUM_CE_OFFSET = 16,
+	EPDC_TCE_SDCFG_SDDO_REFORMAT_STANDARD = 0,
+	EPDC_TCE_SDCFG_SDDO_REFORMAT_FLIP_PIXELS = 0x4000,
+	EPDC_TCE_SDCFG_SDDO_INVERT_ENABLE = 0x2000,
+	EPDC_TCE_SDCFG_PIXELS_PER_CE_MASK = 0x1FFF,
+	EPDC_TCE_SDCFG_PIXELS_PER_CE_OFFSET = 0,
+
+/* EPDC_TCE_GDCFG field values */
+	EPDC_TCE_SDCFG_GDRL = 0x10,
+	EPDC_TCE_SDCFG_GDOE_MODE_DELAYED_GDCLK = 0x2,
+	EPDC_TCE_SDCFG_GDSP_MODE_FRAME_SYNC = 0x1,
+	EPDC_TCE_SDCFG_GDSP_MODE_ONE_LINE = 0x0,
+
+/* EPDC_TCE_HSCAN1 field values */
+	EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_MASK = 0xFFF0000,
+	EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_OFFSET = 16,
+	EPDC_TCE_HSCAN1_LINE_SYNC_MASK = 0xFFF,
+	EPDC_TCE_HSCAN1_LINE_SYNC_OFFSET = 0,
+
+/* EPDC_TCE_HSCAN2 field values */
+	EPDC_TCE_HSCAN2_LINE_END_MASK = 0xFFF0000,
+	EPDC_TCE_HSCAN2_LINE_END_OFFSET = 16,
+	EPDC_TCE_HSCAN2_LINE_BEGIN_MASK = 0xFFF,
+	EPDC_TCE_HSCAN2_LINE_BEGIN_OFFSET = 0,
+
+/* EPDC_TCE_VSCAN field values */
+	EPDC_TCE_VSCAN_FRAME_END_MASK = 0xFF0000,
+	EPDC_TCE_VSCAN_FRAME_END_OFFSET = 16,
+	EPDC_TCE_VSCAN_FRAME_BEGIN_MASK = 0xFF00,
+	EPDC_TCE_VSCAN_FRAME_BEGIN_OFFSET = 8,
+	EPDC_TCE_VSCAN_FRAME_SYNC_MASK = 0xFF,
+	EPDC_TCE_VSCAN_FRAME_SYNC_OFFSET = 0,
+
+/* EPDC_TCE_OE field values */
+	EPDC_TCE_OE_SDOED_WIDTH_MASK = 0xFF000000,
+	EPDC_TCE_OE_SDOED_WIDTH_OFFSET = 24,
+	EPDC_TCE_OE_SDOED_DLY_MASK = 0xFF0000,
+	EPDC_TCE_OE_SDOED_DLY_OFFSET = 16,
+	EPDC_TCE_OE_SDOEZ_WIDTH_MASK = 0xFF00,
+	EPDC_TCE_OE_SDOEZ_WIDTH_OFFSET = 8,
+	EPDC_TCE_OE_SDOEZ_DLY_MASK = 0xFF,
+	EPDC_TCE_OE_SDOEZ_DLY_OFFSET = 0,
+
+/* EPDC_TCE_POLARITY field values */
+	EPDC_TCE_POLARITY_GDSP_POL_ACTIVE_HIGH = 0x10,
+	EPDC_TCE_POLARITY_GDOE_POL_ACTIVE_HIGH = 0x8,
+	EPDC_TCE_POLARITY_SDOE_POL_ACTIVE_HIGH = 0x4,
+	EPDC_TCE_POLARITY_SDLE_POL_ACTIVE_HIGH = 0x2,
+	EPDC_TCE_POLARITY_SDCE_POL_ACTIVE_HIGH = 0x1,
+
+/* EPDC_TCE_TIMING1 field values */
+	EPDC_TCE_TIMING1_SDLE_SHIFT_NONE = 0x00,
+	EPDC_TCE_TIMING1_SDLE_SHIFT_1 = 0x10,
+	EPDC_TCE_TIMING1_SDLE_SHIFT_2 = 0x20,
+	EPDC_TCE_TIMING1_SDLE_SHIFT_3 = 0x30,
+	EPDC_TCE_TIMING1_SDCLK_INVERT = 0x8,
+	EPDC_TCE_TIMING1_SDCLK_SHIFT_NONE = 0,
+	EPDC_TCE_TIMING1_SDCLK_SHIFT_1CYCLE = 1,
+	EPDC_TCE_TIMING1_SDCLK_SHIFT_2CYCLES = 2,
+	EPDC_TCE_TIMING1_SDCLK_SHIFT_3CYCLES = 3,
+
+/* EPDC_TCE_TIMING2 field values */
+	EPDC_TCE_TIMING2_GDCLK_HP_MASK = 0xFFFF0000,
+	EPDC_TCE_TIMING2_GDCLK_HP_OFFSET = 16,
+	EPDC_TCE_TIMING2_GDSP_OFFSET_MASK = 0xFFFF,
+	EPDC_TCE_TIMING2_GDSP_OFFSET_OFFSET = 0,
+
+/* EPDC_TCE_TIMING3 field values */
+	EPDC_TCE_TIMING3_GDOE_OFFSET_MASK = 0xFFFF0000,
+	EPDC_TCE_TIMING3_GDOE_OFFSET_OFFSET = 16,
+	EPDC_TCE_TIMING3_GDCLK_OFFSET_MASK = 0xFFFF,
+	EPDC_TCE_TIMING3_GDCLK_OFFSET_OFFSET = 0,
+
+/* EPDC_IRQ_MASK/EPDC_IRQ field values */
+	EPDC_IRQ_WB_CMPLT_IRQ = 0x10000,
+	EPDC_IRQ_LUT_COL_IRQ = 0x20000,
+	EPDC_IRQ_TCE_UNDERRUN_IRQ = 0x40000,
+	EPDC_IRQ_FRAME_END_IRQ = 0x80000,
+	EPDC_IRQ_BUS_ERROR_IRQ = 0x100000,
+	EPDC_IRQ_TCE_IDLE_IRQ = 0x200000,
+	EPDC_IRQ_UPD_DONE_IRQ = 0x400000,
+	EPDC_IRQ_PWR_IRQ = 0x800000,
+
+/* EPDC_STATUS_NEXTLUT field values */
+	EPDC_STATUS_NEXTLUT_NEXT_LUT_VALID = 0x100,
+	EPDC_STATUS_NEXTLUT_NEXT_LUT_MASK = 0x3F,
+	EPDC_STATUS_NEXTLUT_NEXT_LUT_OFFSET = 0,
+
+/* EPDC_STATUS field values */
+	EPDC_STATUS_HISTOGRAM_CP_MASK = 0x1F0000,
+	EPDC_STATUS_HISTOGRAM_CP_OFFSET = 16,
+	EPDC_STATUS_HISTOGRAM_NP_MASK = 0x1F00,
+	EPDC_STATUS_HISTOGRAM_NP_OFFSET = 8,
+	EPDC_STATUS_UPD_VOID = 0x8,
+	EPDC_STATUS_LUTS_UNDERRUN = 0x4,
+	EPDC_STATUS_LUTS_BUSY = 0x2,
+	EPDC_STATUS_WB_BUSY = 0x1,
+
+/* EPDC_UPD_COL_CORD field values */
+	EPDC_UPD_COL_CORD_YCORD_MASK = 0x1FFF0000,
+	EPDC_UPD_COL_CORD_YCORD_OFFSET = 16,
+	EPDC_UPD_COL_CORD_XCORD_MASK = 0x1FFF,
+	EPDC_UPD_COL_CORD_XCORD_OFFSET = 0,
+
+/* EPDC_UPD_COL_SIZE field values */
+	EPDC_UPD_COL_SIZE_HEIGHT_MASK = 0x1FFF0000,
+	EPDC_UPD_COL_SIZE_HEIGHT_OFFSET = 16,
+	EPDC_UPD_COL_SIZE_WIDTH_MASK = 0x1FFF,
+	EPDC_UPD_COL_SIZE_WIDTH_OFFSET = 0,
+
+/* EPDC_DEBUG field values */
+	EPDC_DEBUG_UNDERRUN_RECOVER = 0x2,
+	EPDC_DEBUG_COLLISION_OFF = 0x1,
+
+/* EPDC_HISTx_PARAM field values */
+	EPDC_HIST_PARAM_VALUE0_MASK = 0x1F,
+	EPDC_HIST_PARAM_VALUE0_OFFSET = 0,
+	EPDC_HIST_PARAM_VALUE1_MASK = 0x1F00,
+	EPDC_HIST_PARAM_VALUE1_OFFSET = 8,
+	EPDC_HIST_PARAM_VALUE2_MASK = 0x1F0000,
+	EPDC_HIST_PARAM_VALUE2_OFFSET = 16,
+	EPDC_HIST_PARAM_VALUE3_MASK = 0x1F000000,
+	EPDC_HIST_PARAM_VALUE3_OFFSET = 24,
+	EPDC_HIST_PARAM_VALUE4_MASK = 0x1F,
+	EPDC_HIST_PARAM_VALUE4_OFFSET = 0,
+	EPDC_HIST_PARAM_VALUE5_MASK = 0x1F00,
+	EPDC_HIST_PARAM_VALUE5_OFFSET = 8,
+	EPDC_HIST_PARAM_VALUE6_MASK = 0x1F0000,
+	EPDC_HIST_PARAM_VALUE6_OFFSET = 16,
+	EPDC_HIST_PARAM_VALUE7_MASK = 0x1F000000,
+	EPDC_HIST_PARAM_VALUE7_OFFSET = 24,
+	EPDC_HIST_PARAM_VALUE8_MASK = 0x1F,
+	EPDC_HIST_PARAM_VALUE8_OFFSET = 0,
+	EPDC_HIST_PARAM_VALUE9_MASK = 0x1F00,
+	EPDC_HIST_PARAM_VALUE9_OFFSET = 8,
+	EPDC_HIST_PARAM_VALUE10_MASK = 0x1F0000,
+	EPDC_HIST_PARAM_VALUE10_OFFSET = 16,
+	EPDC_HIST_PARAM_VALUE11_MASK = 0x1F000000,
+	EPDC_HIST_PARAM_VALUE11_OFFSET = 24,
+	EPDC_HIST_PARAM_VALUE12_MASK = 0x1F,
+	EPDC_HIST_PARAM_VALUE12_OFFSET = 0,
+	EPDC_HIST_PARAM_VALUE13_MASK = 0x1F00,
+	EPDC_HIST_PARAM_VALUE13_OFFSET = 8,
+	EPDC_HIST_PARAM_VALUE14_MASK = 0x1F0000,
+	EPDC_HIST_PARAM_VALUE14_OFFSET = 16,
+	EPDC_HIST_PARAM_VALUE15_MASK = 0x1F000000,
+	EPDC_HIST_PARAM_VALUE15_OFFSET = 24,
+
+/* EPDC_GPIO field values */
+	EPDC_GPIO_PWRCOM = 0x40,
+	EPDC_GPIO_PWRCTRL_MASK = 0x3C,
+	EPDC_GPIO_PWRCTRL_OFFSET = 2,
+	EPDC_GPIO_BDR_MASK = 0x3,
+	EPDC_GPIO_BDR_OFFSET = 0,
+
+/* EPDC_VERSION field values */
+	EPDC_VERSION_MAJOR_MASK = 0xFF000000,
+	EPDC_VERSION_MAJOR_OFFSET = 24,
+	EPDC_VERSION_MINOR_MASK = 0xFF0000,
+	EPDC_VERSION_MINOR_OFFSET = 16,
+	EPDC_VERSION_STEP_MASK = 0xFFFF,
+	EPDC_VERSION_STEP_OFFSET = 0,
+};
+
+#endif	/* __EPDC_REGS_INCLUDED__ */
diff --git a/drivers/gpu/drm/mxc-epdc/mxc_epdc.h b/drivers/gpu/drm/mxc-epdc/mxc_epdc.h
new file mode 100644
index 000000000000..c5f5280b574f
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/mxc_epdc.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2022 Andreas Kemnade */
+
+#include <video/display_timing.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_simple_kms_helper.h>
+
+struct clk;
+struct regulator;
+struct mxc_epdc {
+	struct drm_device drm;
+	struct drm_simple_display_pipe pipe;
+	struct drm_connector connector;
+	struct display_timing timing;
+};
+
diff --git a/drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c b/drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c
new file mode 100644
index 000000000000..c0b0a3bcdb57
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) 2022 Andreas Kemnade
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_file.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_prime.h>
+#include <drm/drm_probe_helper.h>
+#include "mxc_epdc.h"
+
+#define DRIVER_NAME "mxc_epdc"
+#define DRIVER_DESC "IMX EPDC"
+#define DRIVER_DATE "20220202"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#define to_mxc_epdc(x) container_of(x, struct mxc_epdc, drm)
+
+static const struct drm_mode_config_funcs mxc_epdc_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.atomic_check	   = drm_atomic_helper_check,
+	.atomic_commit	  = drm_atomic_helper_commit,
+};
+
+static struct mxc_epdc *
+drm_pipe_to_mxc_epdc(struct drm_simple_display_pipe *pipe)
+{
+	return container_of(pipe, struct mxc_epdc, pipe);
+}
+
+static struct mxc_epdc *
+drm_connector_to_mxc_epdc(struct drm_connector *connector)
+{
+	return container_of(connector, struct mxc_epdc, connector);
+}
+
+static void mxc_epdc_setup_mode_config(struct drm_device *drm)
+{
+	drm_mode_config_init(drm);
+
+	drm->mode_config.min_width = 0;
+	drm->mode_config.min_height = 0;
+	/*
+	 * Maximum update buffer image width due to v2.0 and v2.1 errata
+	 * ERR005313.
+	 */
+	drm->mode_config.max_width = 2047;
+	drm->mode_config.max_height = 2048;
+	drm->mode_config.funcs = &mxc_epdc_mode_config_funcs;
+}
+
+
+DEFINE_DRM_GEM_CMA_FOPS(fops);
+
+static int mxc_epdc_get_modes(struct drm_connector *connector)
+{
+	struct mxc_epdc *priv = drm_connector_to_mxc_epdc(connector);
+	struct drm_display_mode *mode;
+	struct videomode vm;
+
+	videomode_from_timing(&priv->timing, &vm);
+	mode = drm_mode_create(connector->dev);
+	if (!mode) {
+		dev_err(priv->drm.dev, "failed to add mode\n");
+		return 0;
+	}
+
+	drm_display_mode_from_videomode(&vm, mode);
+	mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+	drm_mode_probed_add(connector, mode);
+
+	connector->display_info.width_mm = mode->width_mm;
+	connector->display_info.height_mm = mode->height_mm;
+
+	return 1;
+}
+
+static const struct
+drm_connector_helper_funcs mxc_epdc_connector_helper_funcs = {
+	.get_modes = mxc_epdc_get_modes,
+};
+
+static const struct drm_connector_funcs mxc_epdc_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy  = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+int mxc_epdc_output(struct drm_device *drm)
+{
+	struct mxc_epdc *priv = to_mxc_epdc(drm);
+	int ret;
+
+	priv->connector.dpms = DRM_MODE_DPMS_OFF;
+	priv->connector.polled = 0;
+	drm_connector_helper_add(&priv->connector,
+				 &mxc_epdc_connector_helper_funcs);
+	ret = drm_connector_init(drm, &priv->connector,
+				 &mxc_epdc_connector_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (ret)
+		return ret;
+	ret = of_get_display_timing(drm->dev->of_node, "timing", &priv->timing);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void mxc_epdc_pipe_enable(struct drm_simple_display_pipe *pipe,
+				   struct drm_crtc_state *crtc_state,
+				   struct drm_plane_state *plane_state)
+{
+	struct mxc_epdc *priv = drm_pipe_to_mxc_epdc(pipe);
+	struct drm_display_mode *m = &pipe->crtc.state->adjusted_mode;
+
+	dev_info(priv->drm.dev, "Mode: %d x %d\n", m->hdisplay, m->vdisplay);
+}
+
+static void mxc_epdc_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+	struct mxc_epdc *priv = drm_pipe_to_mxc_epdc(pipe);
+
+	dev_dbg(priv->drm.dev, "pipe disable\n");
+}
+
+static void mxc_epdc_pipe_update(struct drm_simple_display_pipe *pipe,
+				   struct drm_plane_state *plane_state)
+{
+	struct mxc_epdc *priv = drm_pipe_to_mxc_epdc(pipe);
+
+	dev_dbg(priv->drm.dev, "pipe update\n");
+}
+
+static const struct drm_simple_display_pipe_funcs mxc_epdc_funcs = {
+	.enable	 = mxc_epdc_pipe_enable,
+	.disable = mxc_epdc_pipe_disable,
+	.update	= mxc_epdc_pipe_update,
+	.prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
+};
+
+
+static const uint32_t mxc_epdc_formats[] = {
+	DRM_FORMAT_XRGB8888,
+};
+
+static struct drm_driver mxc_epdc_driver = {
+	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+	.fops = &fops,
+	.dumb_create	    = drm_gem_cma_dumb_create,
+	.prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_mmap	 = drm_gem_prime_mmap,
+
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESC,
+	.date = DRIVER_DATE,
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+};
+
+
+static int mxc_epdc_probe(struct platform_device *pdev)
+{
+	struct mxc_epdc *priv;
+	int ret;
+
+	priv = devm_drm_dev_alloc(&pdev->dev, &mxc_epdc_driver, struct mxc_epdc, drm);
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
+
+	platform_set_drvdata(pdev, priv);
+
+	mxc_epdc_setup_mode_config(&priv->drm);
+
+	ret = mxc_epdc_output(&priv->drm);
+	if (ret)
+		return ret;
+
+	drm_simple_display_pipe_init(&priv->drm, &priv->pipe, &mxc_epdc_funcs,
+				     mxc_epdc_formats,
+				     ARRAY_SIZE(mxc_epdc_formats),
+				     NULL,
+				     &priv->connector);
+	drm_plane_enable_fb_damage_clips(&priv->pipe.plane);
+
+	drm_mode_config_reset(&priv->drm);
+
+	ret = drm_dev_register(&priv->drm, 0);
+
+	drm_fbdev_generic_setup(&priv->drm, 32);
+	return 0;
+}
+
+static int mxc_epdc_remove(struct platform_device *pdev)
+{
+	struct mxc_epdc *priv = platform_get_drvdata(pdev);
+
+	drm_dev_unregister(&priv->drm);
+	drm_kms_helper_poll_fini(&priv->drm);
+	drm_mode_config_cleanup(&priv->drm);
+	return 0;
+}
+
+static const struct of_device_id imx_epdc_dt_ids[] = {
+	{ .compatible = "fsl,imx6sl-epdc", },
+	{ .compatible = "fsl,imx6sll-epdc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_epdc_dt_ids);
+
+static struct platform_driver pdev = {
+	.driver = {
+		.name   = "mxc_epdc",
+		.of_match_table = of_match_ptr(imx_epdc_dt_ids),
+	},
+	.probe  = mxc_epdc_probe,
+	.remove = mxc_epdc_remove,
+};
+
+module_platform_driver(pdev);
+MODULE_DESCRIPTION("IMX EPDC driver");
+MODULE_LICENSE("GPL");
+
-- 
2.30.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: Andreas Kemnade <andreas@kemnade.info>
To: p.zabel@pengutronix.de, airlied@linux.ie, daniel@ffwll.ch,
	robh+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de,
	kernel@pengutronix.de, festevam@gmail.com, linux-imx@nxp.com,
	maarten.lankhorst@linux.intel.com, mripard@kernel.org,
	tzimmermann@suse.de, andreas@kemnade.info,
	dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, alistair@alistair23.me,
	samuel@sholland.org, josua.mayer@jm0.eu,
	letux-kernel@openphoenux.org
Subject: [RFC PATCH 2/6] drm: Add skeleton for EPDC driver
Date: Sun,  6 Feb 2022 09:00:12 +0100	[thread overview]
Message-ID: <20220206080016.796556-3-andreas@kemnade.info> (raw)
In-Reply-To: <20220206080016.796556-1-andreas@kemnade.info>

This driver is for the EPD controller in the i.MX SoCs. Add a skeleton
and basic things for the driver

Signed-off-by: Andreas Kemnade <andreas@kemnade.info>
---
 drivers/gpu/drm/Kconfig                 |   2 +
 drivers/gpu/drm/Makefile                |   1 +
 drivers/gpu/drm/mxc-epdc/Kconfig        |  15 +
 drivers/gpu/drm/mxc-epdc/Makefile       |   5 +
 drivers/gpu/drm/mxc-epdc/epdc_regs.h    | 442 ++++++++++++++++++++++++
 drivers/gpu/drm/mxc-epdc/mxc_epdc.h     |  20 ++
 drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c | 248 +++++++++++++
 7 files changed, 733 insertions(+)
 create mode 100644 drivers/gpu/drm/mxc-epdc/Kconfig
 create mode 100644 drivers/gpu/drm/mxc-epdc/Makefile
 create mode 100644 drivers/gpu/drm/mxc-epdc/epdc_regs.h
 create mode 100644 drivers/gpu/drm/mxc-epdc/mxc_epdc.h
 create mode 100644 drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b1f22e457fd0..6b6b44ff7556 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -390,6 +390,8 @@ source "drivers/gpu/drm/gud/Kconfig"
 
 source "drivers/gpu/drm/sprd/Kconfig"
 
+source "drivers/gpu/drm/mxc-epdc/Kconfig"
+
 config DRM_HYPERV
 	tristate "DRM Support for Hyper-V synthetic video device"
 	depends on DRM && PCI && MMU && HYPERV
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 301a44dc18e3..e5eb9815cf9a 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -131,6 +131,7 @@ obj-$(CONFIG_DRM_PANFROST) += panfrost/
 obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
 obj-$(CONFIG_DRM_MCDE) += mcde/
 obj-$(CONFIG_DRM_TIDSS) += tidss/
+obj-$(CONFIG_DRM_MXC_EPDC) += mxc-epdc/
 obj-y			+= xlnx/
 obj-y			+= gud/
 obj-$(CONFIG_DRM_HYPERV) += hyperv/
diff --git a/drivers/gpu/drm/mxc-epdc/Kconfig b/drivers/gpu/drm/mxc-epdc/Kconfig
new file mode 100644
index 000000000000..3f5744161cff
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0
+config DRM_MXC_EPDC
+	tristate "i.MX EPD Controller"
+	depends on DRM && OF
+	depends on (COMPILE_TEST || ARCH_MXC)
+	select DRM_KMS_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DMA_CMA if HAVE_DMA_CONTIGUOUS
+	select CMA if HAVE_DMA_CONTIGUOUS
+	help
+	  Choose this option if you have an i.MX system with an EPDC.
+	  It enables the usage of E-paper displays. A waveform is expected
+	  to be present in /lib/firmware/imx/epdc/epdc.fw
+
+	  If M is selected this module will be called mxc_epdc_drm.
diff --git a/drivers/gpu/drm/mxc-epdc/Makefile b/drivers/gpu/drm/mxc-epdc/Makefile
new file mode 100644
index 000000000000..a47ced72b7f6
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+mxc_epdc_drm-y := mxc_epdc_drv.o
+
+obj-$(CONFIG_DRM_MXC_EPDC) += mxc_epdc_drm.o
+
diff --git a/drivers/gpu/drm/mxc-epdc/epdc_regs.h b/drivers/gpu/drm/mxc-epdc/epdc_regs.h
new file mode 100644
index 000000000000..83445c56d911
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/epdc_regs.h
@@ -0,0 +1,442 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2010-2013 Freescale Semiconductor, Inc. */
+
+#ifndef __EPDC_REGS_INCLUDED__
+#define __EPDC_REGS_INCLUDED__
+
+/*************************************
+ * Register addresses
+ **************************************/
+
+#define EPDC_CTRL			0x000
+#define EPDC_CTRL_SET			0x004
+#define EPDC_CTRL_CLEAR			0x008
+#define EPDC_CTRL_TOGGLE		0x00C
+#define EPDC_WB_ADDR_TCE_V3		0x010
+#define EPDC_WVADDR			0x020
+#define EPDC_WB_ADDR			0x030
+#define EPDC_RES			0x040
+#define EPDC_FORMAT			0x050
+#define EPDC_FORMAT_SET			0x054
+#define EPDC_FORMAT_CLEAR		0x058
+#define EPDC_FORMAT_TOGGLE		0x05C
+#define EPDC_WB_FIELD0			0x060
+#define EPDC_WB_FIELD0_SET		0x064
+#define EPDC_WB_FIELD0_CLEAR		0x068
+#define EPDC_WB_FIELD0_TOGGLE		0x06C
+#define EPDC_WB_FIELD1			0x070
+#define EPDC_WB_FIELD1_SET		0x074
+#define EPDC_WB_FIELD1_CLEAR		0x078
+#define EPDC_WB_FIELD1_TOGGLE		0x07C
+#define EPDC_WB_FIELD2			0x080
+#define EPDC_WB_FIELD2_SET		0x084
+#define EPDC_WB_FIELD2_CLEAR		0x088
+#define EPDC_WB_FIELD2_TOGGLE		0x08C
+#define EPDC_WB_FIELD3			0x090
+#define EPDC_WB_FIELD3_SET		0x094
+#define EPDC_WB_FIELD3_CLEAR		0x098
+#define EPDC_WB_FIELD3_TOGGLE		0x09C
+#define EPDC_FIFOCTRL			0x0A0
+#define EPDC_FIFOCTRL_SET		0x0A4
+#define EPDC_FIFOCTRL_CLEAR		0x0A8
+#define EPDC_FIFOCTRL_TOGGLE		0x0AC
+#define EPDC_UPD_ADDR			0x100
+#define EPDC_UPD_STRIDE			0x110
+#define EPDC_UPD_CORD			0x120
+#define EPDC_UPD_SIZE			0x140
+#define EPDC_UPD_CTRL			0x160
+#define EPDC_UPD_FIXED			0x180
+#define EPDC_TEMP			0x1A0
+#define EPDC_AUTOWV_LUT			0x1C0
+#define EPDC_TCE_CTRL			0x200
+#define EPDC_TCE_SDCFG			0x220
+#define EPDC_TCE_GDCFG			0x240
+#define EPDC_TCE_HSCAN1			0x260
+#define EPDC_TCE_HSCAN2			0x280
+#define EPDC_TCE_VSCAN			0x2A0
+#define EPDC_TCE_OE			0x2C0
+#define EPDC_TCE_POLARITY		0x2E0
+#define EPDC_TCE_TIMING1		0x300
+#define EPDC_TCE_TIMING2		0x310
+#define EPDC_TCE_TIMING3		0x320
+#define EPDC_PIGEON_CTRL0		0x380
+#define EPDC_PIGEON_CTRL1		0x390
+#define EPDC_IRQ_MASK1			0x3C0
+#define EPDC_IRQ_MASK1_SET		0x3C4
+#define EPDC_IRQ_MASK1_CLEAR		0x3C8
+#define EPDC_IRQ_MASK1_TOGGLE		0x3CC
+#define EPDC_IRQ_MASK2			0x3D0
+#define EPDC_IRQ_MASK2_SET		0x3D4
+#define EPDC_IRQ_MASK2_CLEAR		0x3D8
+#define EPDC_IRQ_MASK2_TOGGLE		0x3DC
+#define EPDC_IRQ1			0x3E0
+#define EPDC_IRQ1_SET			0x3E4
+#define EPDC_IRQ1_CLEAR			0x3E8
+#define EPDC_IRQ1_TOGGLE		0x3EC
+#define EPDC_IRQ2			0x3F0
+#define EPDC_IRQ2_SET			0x3F4
+#define EPDC_IRQ2_CLEAR			0x3F8
+#define EPDC_IRQ2_TOGGLE		0x3FC
+#define EPDC_IRQ_MASK			0x400
+#define EPDC_IRQ_MASK_SET		0x404
+#define EPDC_IRQ_MASK_CLEAR		0x408
+#define EPDC_IRQ_MASK_TOGGLE		0x40C
+#define EPDC_IRQ			0x420
+#define EPDC_IRQ_SET			0x424
+#define EPDC_IRQ_CLEAR			0x428
+#define EPDC_IRQ_TOGGLE			0x42C
+#define EPDC_STATUS_LUTS		0x440
+#define EPDC_STATUS_LUTS_SET		0x444
+#define EPDC_STATUS_LUTS_CLEAR		0x448
+#define EPDC_STATUS_LUTS_TOGGLE		0x44C
+#define EPDC_STATUS_LUTS2		0x450
+#define EPDC_STATUS_LUTS2_SET		0x454
+#define EPDC_STATUS_LUTS2_CLEAR		0x458
+#define EPDC_STATUS_LUTS2_TOGGLE	0x45C
+#define EPDC_STATUS_NEXTLUT		0x460
+#define EPDC_STATUS_COL			0x480
+#define EPDC_STATUS_COL2		0x490
+#define EPDC_STATUS			0x4A0
+#define EPDC_STATUS_SET			0x4A4
+#define EPDC_STATUS_CLEAR		0x4A8
+#define EPDC_STATUS_TOGGLE		0x4AC
+#define EPDC_UPD_COL_CORD		0x4C0
+#define EPDC_UPD_COL_SIZE		0x4E0
+#define EPDC_DEBUG			0x500
+#define EPDC_DEBUG_LUT			0x530
+#define EPDC_HIST1_PARAM		0x600
+#define EPDC_HIST2_PARAM		0x610
+#define EPDC_HIST4_PARAM		0x620
+#define EPDC_HIST8_PARAM0		0x630
+#define EPDC_HIST8_PARAM1		0x640
+#define EPDC_HIST16_PARAM0		0x650
+#define EPDC_HIST16_PARAM1		0x660
+#define EPDC_HIST16_PARAM2		0x670
+#define EPDC_HIST16_PARAM3		0x680
+#define EPDC_GPIO			0x700
+#define EPDC_VERSION			0x7F0
+#define EPDC_PIGEON_0_0			0x800
+#define EPDC_PIGEON_0_1			0x810
+#define EPDC_PIGEON_0_2			0x820
+#define EPDC_PIGEON_1_0			0x840
+#define EPDC_PIGEON_1_1			0x850
+#define EPDC_PIGEON_1_2			0x860
+#define EPDC_PIGEON_2_0			0x880
+#define EPDC_PIGEON_2_1			0x890
+#define EPDC_PIGEON_2_2			0x8A0
+#define EPDC_PIGEON_3_0			0x8C0
+#define EPDC_PIGEON_3_1			0x8D0
+#define EPDC_PIGEON_3_2			0x8E0
+#define EPDC_PIGEON_4_0			0x900
+#define EPDC_PIGEON_4_1			0x910
+#define EPDC_PIGEON_4_2			0x920
+#define EPDC_PIGEON_5_0			0x940
+#define EPDC_PIGEON_5_1			0x950
+#define EPDC_PIGEON_5_2			0x960
+#define EPDC_PIGEON_6_0			0x980
+#define EPDC_PIGEON_6_1			0x990
+#define EPDC_PIGEON_6_2			0x9A0
+#define EPDC_PIGEON_7_0			0x9C0
+#define EPDC_PIGEON_7_1			0x9D0
+#define EPDC_PIGEON_7_2			0x9E0
+#define EPDC_PIGEON_8_0			0xA00
+#define EPDC_PIGEON_8_1			0xA10
+#define EPDC_PIGEON_8_2			0xA20
+#define EPDC_PIGEON_9_0			0xA40
+#define EPDC_PIGEON_9_1			0xA50
+#define EPDC_PIGEON_9_2			0xA60
+#define EPDC_PIGEON_10_0		0xA80
+#define EPDC_PIGEON_10_1		0xA90
+#define EPDC_PIGEON_10_2		0xAA0
+#define EPDC_PIGEON_11_0		0xAC0
+#define EPDC_PIGEON_11_1		0xAD0
+#define EPDC_PIGEON_11_2		0xAE0
+#define EPDC_PIGEON_12_0		0xB00
+#define EPDC_PIGEON_12_1		0xB10
+#define EPDC_PIGEON_12_2		0xB20
+#define EPDC_PIGEON_13_0		0xB40
+#define EPDC_PIGEON_13_1		0xB50
+#define EPDC_PIGEON_13_2		0xB60
+#define EPDC_PIGEON_14_0		0xB80
+#define EPDC_PIGEON_14_1		0xB90
+#define EPDC_PIGEON_14_2		0xBA0
+#define EPDC_PIGEON_15_0		0xBC0
+#define EPDC_PIGEON_15_1		0xBD0
+#define EPDC_PIGEON_15_2		0xBE0
+#define EPDC_WB_ADDR_TCE		0xC10
+
+/*
+ * Register field definitions
+ */
+
+enum {
+/* EPDC_CTRL field values */
+	EPDC_CTRL_SFTRST = 0x80000000,
+	EPDC_CTRL_CLKGATE = 0x40000000,
+	EPDC_CTRL_SRAM_POWERDOWN = 0x100,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_MASK = 0xC0,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_NO_SWAP = 0,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_ALL_BYTES_SWAP = 0x40,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_HWD_SWAP = 0x80,
+	EPDC_CTRL_UPD_DATA_SWIZZLE_HWD_BYTE_SWAP = 0xC0,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_MASK = 0x30,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_NO_SWAP = 0,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_ALL_BYTES_SWAP = 0x10,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_HWD_SWAP = 0x20,
+	EPDC_CTRL_LUT_DATA_SWIZZLE_HWD_BYTE_SWAP = 0x30,
+	EPDC_CTRL_BURST_LEN_8_8 = 0x1,
+	EPDC_CTRL_BURST_LEN_8_16 = 0,
+
+/* EPDC_RES field values */
+	EPDC_RES_VERTICAL_MASK = 0x1FFF0000,
+	EPDC_RES_VERTICAL_OFFSET = 16,
+	EPDC_RES_HORIZONTAL_MASK = 0x1FFF,
+	EPDC_RES_HORIZONTAL_OFFSET = 0,
+
+/* EPDC_FORMAT field values */
+	EPDC_FORMAT_BUF_PIXEL_SCALE_ROUND = 0x1000000,
+	EPDC_FORMAT_DEFAULT_TFT_PIXEL_MASK = 0xFF0000,
+	EPDC_FORMAT_DEFAULT_TFT_PIXEL_OFFSET = 16,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_MASK = 0x700,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_P2N = 0x200,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_P3N = 0x300,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_P4N = 0x400,
+	EPDC_FORMAT_BUF_PIXEL_FORMAT_P5N = 0x500,
+	EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT = 0x0,
+	EPDC_FORMAT_TFT_PIXEL_FORMAT_2BIT_VCOM = 0x1,
+	EPDC_FORMAT_TFT_PIXEL_FORMAT_4BIT = 0x2,
+	EPDC_FORMAT_TFT_PIXEL_FORMAT_4BIT_VCOM = 0x3,
+
+/* EPDC_FIFOCTRL field values */
+	EPDC_FIFOCTRL_ENABLE_PRIORITY = 0x80000000,
+	EPDC_FIFOCTRL_FIFO_INIT_LEVEL_MASK = 0xFF0000,
+	EPDC_FIFOCTRL_FIFO_INIT_LEVEL_OFFSET = 16,
+	EPDC_FIFOCTRL_FIFO_H_LEVEL_MASK = 0xFF00,
+	EPDC_FIFOCTRL_FIFO_H_LEVEL_OFFSET = 8,
+	EPDC_FIFOCTRL_FIFO_L_LEVEL_MASK = 0xFF,
+	EPDC_FIFOCTRL_FIFO_L_LEVEL_OFFSET = 0,
+
+/* EPDC_UPD_CORD field values */
+	EPDC_UPD_CORD_YCORD_MASK = 0x1FFF0000,
+	EPDC_UPD_CORD_YCORD_OFFSET = 16,
+	EPDC_UPD_CORD_XCORD_MASK = 0x1FFF,
+	EPDC_UPD_CORD_XCORD_OFFSET = 0,
+
+/* EPDC_UPD_SIZE field values */
+	EPDC_UPD_SIZE_HEIGHT_MASK = 0x1FFF0000,
+	EPDC_UPD_SIZE_HEIGHT_OFFSET = 16,
+	EPDC_UPD_SIZE_WIDTH_MASK = 0x1FFF,
+	EPDC_UPD_SIZE_WIDTH_OFFSET = 0,
+
+/* EPDC_UPD_CTRL field values */
+	EPDC_UPD_CTRL_USE_FIXED = 0x80000000,
+	EPDC_UPD_CTRL_LUT_SEL_MASK = 0x3F0000,
+	EPDC_UPD_CTRL_LUT_SEL_OFFSET = 16,
+	EPDC_UPD_CTRL_WAVEFORM_MODE_MASK = 0xFF00,
+	EPDC_UPD_CTRL_WAVEFORM_MODE_OFFSET = 8,
+	EPDC_UPD_CTRL_AUTOWV_PAUSE = 0x8,
+	EPDC_UPD_CTRL_AUTOWV = 0x4,
+	EPDC_UPD_CTRL_DRY_RUN = 0x2,
+	EPDC_UPD_CTRL_UPDATE_MODE_FULL = 0x1,
+
+/* EPDC_UPD_FIXED field values */
+	EPDC_UPD_FIXED_FIXNP_EN = 0x80000000,
+	EPDC_UPD_FIXED_FIXCP_EN = 0x40000000,
+	EPDC_UPD_FIXED_FIXNP_MASK = 0xFF00,
+	EPDC_UPD_FIXED_FIXNP_OFFSET = 8,
+	EPDC_UPD_FIXED_FIXCP_MASK = 0xFF,
+	EPDC_UPD_FIXED_FIXCP_OFFSET = 0,
+
+/* EPDC_AUTOWV_LUT field values */
+	EPDC_AUTOWV_LUT_DATA_MASK = 0xFF0000,
+	EPDC_AUTOWV_LUT_DATA_OFFSET = 16,
+	EPDC_AUTOWV_LUT_ADDR_MASK = 0xFF,
+	EPDC_AUTOWV_LUT_ADDR_OFFSET = 0,
+
+/* EPDC_TCE_CTRL field values */
+	EPDC_TCE_CTRL_VSCAN_HOLDOFF_MASK = 0x1FF0000,
+	EPDC_TCE_CTRL_VSCAN_HOLDOFF_OFFSET = 16,
+	EPDC_TCE_CTRL_VCOM_VAL_MASK = 0xC00,
+	EPDC_TCE_CTRL_VCOM_VAL_OFFSET = 10,
+	EPDC_TCE_CTRL_VCOM_MODE_AUTO = 0x200,
+	EPDC_TCE_CTRL_VCOM_MODE_MANUAL = 0x000,
+	EPDC_TCE_CTRL_DDR_MODE_ENABLE = 0x100,
+	EPDC_TCE_CTRL_LVDS_MODE_CE_ENABLE = 0x80,
+	EPDC_TCE_CTRL_LVDS_MODE_ENABLE = 0x40,
+	EPDC_TCE_CTRL_SCAN_DIR_1_UP = 0x20,
+	EPDC_TCE_CTRL_SCAN_DIR_0_UP = 0x10,
+	EPDC_TCE_CTRL_DUAL_SCAN_ENABLE = 0x8,
+	EPDC_TCE_CTRL_SDDO_WIDTH_16BIT = 0x4,
+	EPDC_TCE_CTRL_PIXELS_PER_SDCLK_2 = 1,
+	EPDC_TCE_CTRL_PIXELS_PER_SDCLK_4 = 2,
+	EPDC_TCE_CTRL_PIXELS_PER_SDCLK_8 = 3,
+
+/* EPDC_TCE_SDCFG field values */
+	EPDC_TCE_SDCFG_SDCLK_HOLD = 0x200000,
+	EPDC_TCE_SDCFG_SDSHR = 0x100000,
+	EPDC_TCE_SDCFG_NUM_CE_MASK = 0xF0000,
+	EPDC_TCE_SDCFG_NUM_CE_OFFSET = 16,
+	EPDC_TCE_SDCFG_SDDO_REFORMAT_STANDARD = 0,
+	EPDC_TCE_SDCFG_SDDO_REFORMAT_FLIP_PIXELS = 0x4000,
+	EPDC_TCE_SDCFG_SDDO_INVERT_ENABLE = 0x2000,
+	EPDC_TCE_SDCFG_PIXELS_PER_CE_MASK = 0x1FFF,
+	EPDC_TCE_SDCFG_PIXELS_PER_CE_OFFSET = 0,
+
+/* EPDC_TCE_GDCFG field values */
+	EPDC_TCE_SDCFG_GDRL = 0x10,
+	EPDC_TCE_SDCFG_GDOE_MODE_DELAYED_GDCLK = 0x2,
+	EPDC_TCE_SDCFG_GDSP_MODE_FRAME_SYNC = 0x1,
+	EPDC_TCE_SDCFG_GDSP_MODE_ONE_LINE = 0x0,
+
+/* EPDC_TCE_HSCAN1 field values */
+	EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_MASK = 0xFFF0000,
+	EPDC_TCE_HSCAN1_LINE_SYNC_WIDTH_OFFSET = 16,
+	EPDC_TCE_HSCAN1_LINE_SYNC_MASK = 0xFFF,
+	EPDC_TCE_HSCAN1_LINE_SYNC_OFFSET = 0,
+
+/* EPDC_TCE_HSCAN2 field values */
+	EPDC_TCE_HSCAN2_LINE_END_MASK = 0xFFF0000,
+	EPDC_TCE_HSCAN2_LINE_END_OFFSET = 16,
+	EPDC_TCE_HSCAN2_LINE_BEGIN_MASK = 0xFFF,
+	EPDC_TCE_HSCAN2_LINE_BEGIN_OFFSET = 0,
+
+/* EPDC_TCE_VSCAN field values */
+	EPDC_TCE_VSCAN_FRAME_END_MASK = 0xFF0000,
+	EPDC_TCE_VSCAN_FRAME_END_OFFSET = 16,
+	EPDC_TCE_VSCAN_FRAME_BEGIN_MASK = 0xFF00,
+	EPDC_TCE_VSCAN_FRAME_BEGIN_OFFSET = 8,
+	EPDC_TCE_VSCAN_FRAME_SYNC_MASK = 0xFF,
+	EPDC_TCE_VSCAN_FRAME_SYNC_OFFSET = 0,
+
+/* EPDC_TCE_OE field values */
+	EPDC_TCE_OE_SDOED_WIDTH_MASK = 0xFF000000,
+	EPDC_TCE_OE_SDOED_WIDTH_OFFSET = 24,
+	EPDC_TCE_OE_SDOED_DLY_MASK = 0xFF0000,
+	EPDC_TCE_OE_SDOED_DLY_OFFSET = 16,
+	EPDC_TCE_OE_SDOEZ_WIDTH_MASK = 0xFF00,
+	EPDC_TCE_OE_SDOEZ_WIDTH_OFFSET = 8,
+	EPDC_TCE_OE_SDOEZ_DLY_MASK = 0xFF,
+	EPDC_TCE_OE_SDOEZ_DLY_OFFSET = 0,
+
+/* EPDC_TCE_POLARITY field values */
+	EPDC_TCE_POLARITY_GDSP_POL_ACTIVE_HIGH = 0x10,
+	EPDC_TCE_POLARITY_GDOE_POL_ACTIVE_HIGH = 0x8,
+	EPDC_TCE_POLARITY_SDOE_POL_ACTIVE_HIGH = 0x4,
+	EPDC_TCE_POLARITY_SDLE_POL_ACTIVE_HIGH = 0x2,
+	EPDC_TCE_POLARITY_SDCE_POL_ACTIVE_HIGH = 0x1,
+
+/* EPDC_TCE_TIMING1 field values */
+	EPDC_TCE_TIMING1_SDLE_SHIFT_NONE = 0x00,
+	EPDC_TCE_TIMING1_SDLE_SHIFT_1 = 0x10,
+	EPDC_TCE_TIMING1_SDLE_SHIFT_2 = 0x20,
+	EPDC_TCE_TIMING1_SDLE_SHIFT_3 = 0x30,
+	EPDC_TCE_TIMING1_SDCLK_INVERT = 0x8,
+	EPDC_TCE_TIMING1_SDCLK_SHIFT_NONE = 0,
+	EPDC_TCE_TIMING1_SDCLK_SHIFT_1CYCLE = 1,
+	EPDC_TCE_TIMING1_SDCLK_SHIFT_2CYCLES = 2,
+	EPDC_TCE_TIMING1_SDCLK_SHIFT_3CYCLES = 3,
+
+/* EPDC_TCE_TIMING2 field values */
+	EPDC_TCE_TIMING2_GDCLK_HP_MASK = 0xFFFF0000,
+	EPDC_TCE_TIMING2_GDCLK_HP_OFFSET = 16,
+	EPDC_TCE_TIMING2_GDSP_OFFSET_MASK = 0xFFFF,
+	EPDC_TCE_TIMING2_GDSP_OFFSET_OFFSET = 0,
+
+/* EPDC_TCE_TIMING3 field values */
+	EPDC_TCE_TIMING3_GDOE_OFFSET_MASK = 0xFFFF0000,
+	EPDC_TCE_TIMING3_GDOE_OFFSET_OFFSET = 16,
+	EPDC_TCE_TIMING3_GDCLK_OFFSET_MASK = 0xFFFF,
+	EPDC_TCE_TIMING3_GDCLK_OFFSET_OFFSET = 0,
+
+/* EPDC_IRQ_MASK/EPDC_IRQ field values */
+	EPDC_IRQ_WB_CMPLT_IRQ = 0x10000,
+	EPDC_IRQ_LUT_COL_IRQ = 0x20000,
+	EPDC_IRQ_TCE_UNDERRUN_IRQ = 0x40000,
+	EPDC_IRQ_FRAME_END_IRQ = 0x80000,
+	EPDC_IRQ_BUS_ERROR_IRQ = 0x100000,
+	EPDC_IRQ_TCE_IDLE_IRQ = 0x200000,
+	EPDC_IRQ_UPD_DONE_IRQ = 0x400000,
+	EPDC_IRQ_PWR_IRQ = 0x800000,
+
+/* EPDC_STATUS_NEXTLUT field values */
+	EPDC_STATUS_NEXTLUT_NEXT_LUT_VALID = 0x100,
+	EPDC_STATUS_NEXTLUT_NEXT_LUT_MASK = 0x3F,
+	EPDC_STATUS_NEXTLUT_NEXT_LUT_OFFSET = 0,
+
+/* EPDC_STATUS field values */
+	EPDC_STATUS_HISTOGRAM_CP_MASK = 0x1F0000,
+	EPDC_STATUS_HISTOGRAM_CP_OFFSET = 16,
+	EPDC_STATUS_HISTOGRAM_NP_MASK = 0x1F00,
+	EPDC_STATUS_HISTOGRAM_NP_OFFSET = 8,
+	EPDC_STATUS_UPD_VOID = 0x8,
+	EPDC_STATUS_LUTS_UNDERRUN = 0x4,
+	EPDC_STATUS_LUTS_BUSY = 0x2,
+	EPDC_STATUS_WB_BUSY = 0x1,
+
+/* EPDC_UPD_COL_CORD field values */
+	EPDC_UPD_COL_CORD_YCORD_MASK = 0x1FFF0000,
+	EPDC_UPD_COL_CORD_YCORD_OFFSET = 16,
+	EPDC_UPD_COL_CORD_XCORD_MASK = 0x1FFF,
+	EPDC_UPD_COL_CORD_XCORD_OFFSET = 0,
+
+/* EPDC_UPD_COL_SIZE field values */
+	EPDC_UPD_COL_SIZE_HEIGHT_MASK = 0x1FFF0000,
+	EPDC_UPD_COL_SIZE_HEIGHT_OFFSET = 16,
+	EPDC_UPD_COL_SIZE_WIDTH_MASK = 0x1FFF,
+	EPDC_UPD_COL_SIZE_WIDTH_OFFSET = 0,
+
+/* EPDC_DEBUG field values */
+	EPDC_DEBUG_UNDERRUN_RECOVER = 0x2,
+	EPDC_DEBUG_COLLISION_OFF = 0x1,
+
+/* EPDC_HISTx_PARAM field values */
+	EPDC_HIST_PARAM_VALUE0_MASK = 0x1F,
+	EPDC_HIST_PARAM_VALUE0_OFFSET = 0,
+	EPDC_HIST_PARAM_VALUE1_MASK = 0x1F00,
+	EPDC_HIST_PARAM_VALUE1_OFFSET = 8,
+	EPDC_HIST_PARAM_VALUE2_MASK = 0x1F0000,
+	EPDC_HIST_PARAM_VALUE2_OFFSET = 16,
+	EPDC_HIST_PARAM_VALUE3_MASK = 0x1F000000,
+	EPDC_HIST_PARAM_VALUE3_OFFSET = 24,
+	EPDC_HIST_PARAM_VALUE4_MASK = 0x1F,
+	EPDC_HIST_PARAM_VALUE4_OFFSET = 0,
+	EPDC_HIST_PARAM_VALUE5_MASK = 0x1F00,
+	EPDC_HIST_PARAM_VALUE5_OFFSET = 8,
+	EPDC_HIST_PARAM_VALUE6_MASK = 0x1F0000,
+	EPDC_HIST_PARAM_VALUE6_OFFSET = 16,
+	EPDC_HIST_PARAM_VALUE7_MASK = 0x1F000000,
+	EPDC_HIST_PARAM_VALUE7_OFFSET = 24,
+	EPDC_HIST_PARAM_VALUE8_MASK = 0x1F,
+	EPDC_HIST_PARAM_VALUE8_OFFSET = 0,
+	EPDC_HIST_PARAM_VALUE9_MASK = 0x1F00,
+	EPDC_HIST_PARAM_VALUE9_OFFSET = 8,
+	EPDC_HIST_PARAM_VALUE10_MASK = 0x1F0000,
+	EPDC_HIST_PARAM_VALUE10_OFFSET = 16,
+	EPDC_HIST_PARAM_VALUE11_MASK = 0x1F000000,
+	EPDC_HIST_PARAM_VALUE11_OFFSET = 24,
+	EPDC_HIST_PARAM_VALUE12_MASK = 0x1F,
+	EPDC_HIST_PARAM_VALUE12_OFFSET = 0,
+	EPDC_HIST_PARAM_VALUE13_MASK = 0x1F00,
+	EPDC_HIST_PARAM_VALUE13_OFFSET = 8,
+	EPDC_HIST_PARAM_VALUE14_MASK = 0x1F0000,
+	EPDC_HIST_PARAM_VALUE14_OFFSET = 16,
+	EPDC_HIST_PARAM_VALUE15_MASK = 0x1F000000,
+	EPDC_HIST_PARAM_VALUE15_OFFSET = 24,
+
+/* EPDC_GPIO field values */
+	EPDC_GPIO_PWRCOM = 0x40,
+	EPDC_GPIO_PWRCTRL_MASK = 0x3C,
+	EPDC_GPIO_PWRCTRL_OFFSET = 2,
+	EPDC_GPIO_BDR_MASK = 0x3,
+	EPDC_GPIO_BDR_OFFSET = 0,
+
+/* EPDC_VERSION field values */
+	EPDC_VERSION_MAJOR_MASK = 0xFF000000,
+	EPDC_VERSION_MAJOR_OFFSET = 24,
+	EPDC_VERSION_MINOR_MASK = 0xFF0000,
+	EPDC_VERSION_MINOR_OFFSET = 16,
+	EPDC_VERSION_STEP_MASK = 0xFFFF,
+	EPDC_VERSION_STEP_OFFSET = 0,
+};
+
+#endif	/* __EPDC_REGS_INCLUDED__ */
diff --git a/drivers/gpu/drm/mxc-epdc/mxc_epdc.h b/drivers/gpu/drm/mxc-epdc/mxc_epdc.h
new file mode 100644
index 000000000000..c5f5280b574f
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/mxc_epdc.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2022 Andreas Kemnade */
+
+#include <video/display_timing.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+
+#include <drm/drm_drv.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_simple_kms_helper.h>
+
+struct clk;
+struct regulator;
+struct mxc_epdc {
+	struct drm_device drm;
+	struct drm_simple_display_pipe pipe;
+	struct drm_connector connector;
+	struct display_timing timing;
+};
+
diff --git a/drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c b/drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c
new file mode 100644
index 000000000000..c0b0a3bcdb57
--- /dev/null
+++ b/drivers/gpu/drm/mxc-epdc/mxc_epdc_drv.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (C) 2022 Andreas Kemnade
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/fs.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_file.h>
+#include <drm/drm_format_helper.h>
+#include <drm/drm_gem_atomic_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_prime.h>
+#include <drm/drm_probe_helper.h>
+#include "mxc_epdc.h"
+
+#define DRIVER_NAME "mxc_epdc"
+#define DRIVER_DESC "IMX EPDC"
+#define DRIVER_DATE "20220202"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#define to_mxc_epdc(x) container_of(x, struct mxc_epdc, drm)
+
+static const struct drm_mode_config_funcs mxc_epdc_mode_config_funcs = {
+	.fb_create = drm_gem_fb_create_with_dirty,
+	.atomic_check	   = drm_atomic_helper_check,
+	.atomic_commit	  = drm_atomic_helper_commit,
+};
+
+static struct mxc_epdc *
+drm_pipe_to_mxc_epdc(struct drm_simple_display_pipe *pipe)
+{
+	return container_of(pipe, struct mxc_epdc, pipe);
+}
+
+static struct mxc_epdc *
+drm_connector_to_mxc_epdc(struct drm_connector *connector)
+{
+	return container_of(connector, struct mxc_epdc, connector);
+}
+
+static void mxc_epdc_setup_mode_config(struct drm_device *drm)
+{
+	drm_mode_config_init(drm);
+
+	drm->mode_config.min_width = 0;
+	drm->mode_config.min_height = 0;
+	/*
+	 * Maximum update buffer image width due to v2.0 and v2.1 errata
+	 * ERR005313.
+	 */
+	drm->mode_config.max_width = 2047;
+	drm->mode_config.max_height = 2048;
+	drm->mode_config.funcs = &mxc_epdc_mode_config_funcs;
+}
+
+
+DEFINE_DRM_GEM_CMA_FOPS(fops);
+
+static int mxc_epdc_get_modes(struct drm_connector *connector)
+{
+	struct mxc_epdc *priv = drm_connector_to_mxc_epdc(connector);
+	struct drm_display_mode *mode;
+	struct videomode vm;
+
+	videomode_from_timing(&priv->timing, &vm);
+	mode = drm_mode_create(connector->dev);
+	if (!mode) {
+		dev_err(priv->drm.dev, "failed to add mode\n");
+		return 0;
+	}
+
+	drm_display_mode_from_videomode(&vm, mode);
+	mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+
+	drm_mode_probed_add(connector, mode);
+
+	connector->display_info.width_mm = mode->width_mm;
+	connector->display_info.height_mm = mode->height_mm;
+
+	return 1;
+}
+
+static const struct
+drm_connector_helper_funcs mxc_epdc_connector_helper_funcs = {
+	.get_modes = mxc_epdc_get_modes,
+};
+
+static const struct drm_connector_funcs mxc_epdc_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.destroy  = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+int mxc_epdc_output(struct drm_device *drm)
+{
+	struct mxc_epdc *priv = to_mxc_epdc(drm);
+	int ret;
+
+	priv->connector.dpms = DRM_MODE_DPMS_OFF;
+	priv->connector.polled = 0;
+	drm_connector_helper_add(&priv->connector,
+				 &mxc_epdc_connector_helper_funcs);
+	ret = drm_connector_init(drm, &priv->connector,
+				 &mxc_epdc_connector_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (ret)
+		return ret;
+	ret = of_get_display_timing(drm->dev->of_node, "timing", &priv->timing);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void mxc_epdc_pipe_enable(struct drm_simple_display_pipe *pipe,
+				   struct drm_crtc_state *crtc_state,
+				   struct drm_plane_state *plane_state)
+{
+	struct mxc_epdc *priv = drm_pipe_to_mxc_epdc(pipe);
+	struct drm_display_mode *m = &pipe->crtc.state->adjusted_mode;
+
+	dev_info(priv->drm.dev, "Mode: %d x %d\n", m->hdisplay, m->vdisplay);
+}
+
+static void mxc_epdc_pipe_disable(struct drm_simple_display_pipe *pipe)
+{
+	struct mxc_epdc *priv = drm_pipe_to_mxc_epdc(pipe);
+
+	dev_dbg(priv->drm.dev, "pipe disable\n");
+}
+
+static void mxc_epdc_pipe_update(struct drm_simple_display_pipe *pipe,
+				   struct drm_plane_state *plane_state)
+{
+	struct mxc_epdc *priv = drm_pipe_to_mxc_epdc(pipe);
+
+	dev_dbg(priv->drm.dev, "pipe update\n");
+}
+
+static const struct drm_simple_display_pipe_funcs mxc_epdc_funcs = {
+	.enable	 = mxc_epdc_pipe_enable,
+	.disable = mxc_epdc_pipe_disable,
+	.update	= mxc_epdc_pipe_update,
+	.prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
+};
+
+
+static const uint32_t mxc_epdc_formats[] = {
+	DRM_FORMAT_XRGB8888,
+};
+
+static struct drm_driver mxc_epdc_driver = {
+	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
+	.fops = &fops,
+	.dumb_create	    = drm_gem_cma_dumb_create,
+	.prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_mmap	 = drm_gem_prime_mmap,
+
+	.name = DRIVER_NAME,
+	.desc = DRIVER_DESC,
+	.date = DRIVER_DATE,
+	.major = DRIVER_MAJOR,
+	.minor = DRIVER_MINOR,
+	.patchlevel = DRIVER_PATCHLEVEL,
+};
+
+
+static int mxc_epdc_probe(struct platform_device *pdev)
+{
+	struct mxc_epdc *priv;
+	int ret;
+
+	priv = devm_drm_dev_alloc(&pdev->dev, &mxc_epdc_driver, struct mxc_epdc, drm);
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
+
+	platform_set_drvdata(pdev, priv);
+
+	mxc_epdc_setup_mode_config(&priv->drm);
+
+	ret = mxc_epdc_output(&priv->drm);
+	if (ret)
+		return ret;
+
+	drm_simple_display_pipe_init(&priv->drm, &priv->pipe, &mxc_epdc_funcs,
+				     mxc_epdc_formats,
+				     ARRAY_SIZE(mxc_epdc_formats),
+				     NULL,
+				     &priv->connector);
+	drm_plane_enable_fb_damage_clips(&priv->pipe.plane);
+
+	drm_mode_config_reset(&priv->drm);
+
+	ret = drm_dev_register(&priv->drm, 0);
+
+	drm_fbdev_generic_setup(&priv->drm, 32);
+	return 0;
+}
+
+static int mxc_epdc_remove(struct platform_device *pdev)
+{
+	struct mxc_epdc *priv = platform_get_drvdata(pdev);
+
+	drm_dev_unregister(&priv->drm);
+	drm_kms_helper_poll_fini(&priv->drm);
+	drm_mode_config_cleanup(&priv->drm);
+	return 0;
+}
+
+static const struct of_device_id imx_epdc_dt_ids[] = {
+	{ .compatible = "fsl,imx6sl-epdc", },
+	{ .compatible = "fsl,imx6sll-epdc", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_epdc_dt_ids);
+
+static struct platform_driver pdev = {
+	.driver = {
+		.name   = "mxc_epdc",
+		.of_match_table = of_match_ptr(imx_epdc_dt_ids),
+	},
+	.probe  = mxc_epdc_probe,
+	.remove = mxc_epdc_remove,
+};
+
+module_platform_driver(pdev);
+MODULE_DESCRIPTION("IMX EPDC driver");
+MODULE_LICENSE("GPL");
+
-- 
2.30.2


  parent reply	other threads:[~2022-02-06  8:03 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-06  8:00 [RFC PATCH 0/6] drm: EPDC driver for i.MX6 Andreas Kemnade
2022-02-06  8:00 ` Andreas Kemnade
2022-02-06  8:00 ` [RFC PATCH 1/6] dt-bindings: display: imx: Add EPDC Andreas Kemnade
2022-02-06  8:00   ` Andreas Kemnade
2022-02-11 15:46   ` Rob Herring
2022-02-11 15:46     ` Rob Herring
2022-02-11 15:46     ` Rob Herring
2022-02-14 22:45     ` Andreas Kemnade
2022-02-14 22:45       ` Andreas Kemnade
2022-02-14 22:45       ` Andreas Kemnade
2022-02-16 23:52       ` Rob Herring
2022-02-16 23:52         ` Rob Herring
2022-02-16 23:52         ` Rob Herring
2022-02-17  9:21   ` Krzysztof Kozlowski
2022-02-17  9:21     ` Krzysztof Kozlowski
2022-02-17 11:31     ` Andreas Kemnade
2022-02-17 11:31       ` Andreas Kemnade
2022-02-17 11:31       ` Andreas Kemnade
2022-02-17 11:43       ` Krzysztof Kozlowski
2022-02-17 11:43         ` Krzysztof Kozlowski
2022-02-17 11:43         ` Krzysztof Kozlowski
2022-03-12 19:23   ` Jonathan Neuschäfer
2022-03-12 19:23     ` Jonathan Neuschäfer
2022-03-12 19:23     ` Jonathan Neuschäfer
2022-03-14 22:04     ` Andreas Kemnade
2022-03-14 22:04       ` Andreas Kemnade
2022-03-14 22:04       ` Andreas Kemnade
2022-02-06  8:00 ` Andreas Kemnade [this message]
2022-02-06  8:00   ` [RFC PATCH 2/6] drm: Add skeleton for EPDC driver Andreas Kemnade
2022-02-06 10:08   ` kernel test robot
2022-03-12 19:41   ` Jonathan Neuschäfer
2022-03-12 19:41     ` Jonathan Neuschäfer
2022-03-12 19:41     ` Jonathan Neuschäfer
2022-02-06  8:00 ` [RFC PATCH 3/6] drm: mxc-epdc: Add display and waveform initialisation Andreas Kemnade
2022-02-06  8:00   ` Andreas Kemnade
2022-02-06 10:08   ` kernel test robot
2022-02-06 10:18   ` kernel test robot
2022-03-12 20:12   ` Jonathan Neuschäfer
2022-03-12 20:12     ` Jonathan Neuschäfer
2022-03-12 20:12     ` Jonathan Neuschäfer
2022-02-06  8:00 ` [RFC PATCH 4/6] drm: mxc-epdc: Add update management Andreas Kemnade
2022-02-06  8:00   ` Andreas Kemnade
2022-02-06 11:09   ` kernel test robot
2022-03-12 20:21   ` Jonathan Neuschäfer
2022-03-12 20:21     ` Jonathan Neuschäfer
2022-03-12 20:21     ` Jonathan Neuschäfer
2022-02-06  8:00 ` [RFC PATCH 5/6] ARM: dts: imx6sll: add EPDC Andreas Kemnade
2022-02-06  8:00   ` Andreas Kemnade
2022-02-06  8:00 ` [RFC PATCH 6/6] arm: dts: imx6sl: Add EPDC Andreas Kemnade
2022-02-06  8:00   ` Andreas Kemnade

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220206080016.796556-3-andreas@kemnade.info \
    --to=andreas@kemnade.info \
    --cc=airlied@linux.ie \
    --cc=alistair@alistair23.me \
    --cc=daniel@ffwll.ch \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=festevam@gmail.com \
    --cc=josua.mayer@jm0.eu \
    --cc=kernel@pengutronix.de \
    --cc=letux-kernel@openphoenux.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-imx@nxp.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mripard@kernel.org \
    --cc=p.zabel@pengutronix.de \
    --cc=robh+dt@kernel.org \
    --cc=s.hauer@pengutronix.de \
    --cc=samuel@sholland.org \
    --cc=shawnguo@kernel.org \
    --cc=tzimmermann@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.