diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index bfaf69378ac208b33f8ec3e956be0d2136b802dc..2c3a9e178fb5e65a073dc777b1c7dd86c7a9f34f 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -8,4 +8,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
 obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
 obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
 obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
-obj-$(CONFIG_DRM_IMX_IPUV3)	+= ipuv3-crtc.o
+obj-$(CONFIG_DRM_IMX_IPUV3)	+= ipuv3-crtc.o ipuv3-plane.o
diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
index 9cfa2a7efdc06818a91fa81e11f8ee34530fcddf..6a9da94c957341a1a09312414bb687848cb688d2 100644
--- a/drivers/staging/imx-drm/TODO
+++ b/drivers/staging/imx-drm/TODO
@@ -9,7 +9,6 @@ TODO:
 
 Missing features (not necessarily for moving out of staging):
 
-- Add KMS plane support for CRTC driver
 - Add i.MX6 HDMI support
 - Add support for IC (Image converter)
 - Add support for CSI (CMOS Sensor interface)
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 3f683372c1174d33fad5298be0bc3b03f13b8aa1..d306f3a0173f41ea9380d07207c4adb323028a0d 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -68,6 +68,11 @@ struct imx_drm_connector {
 	struct module				*owner;
 };
 
+int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
+{
+	return crtc->pipe;
+}
+
 static void imx_drm_driver_lastclose(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index f2aac91ddf5d51e45f739c041e57b53c5eb868e5..ae90c9c15312c2ca57fb1884b622a8bf0469cf0e 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -14,6 +14,8 @@ struct drm_fbdev_cma;
 struct drm_framebuffer;
 struct platform_device;
 
+int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
+
 struct imx_drm_crtc_helper_funcs {
 	int (*enable_vblank)(struct drm_crtc *crtc);
 	void (*disable_vblank)(struct drm_crtc *crtc);
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 5ca42f0900888e967614fd73ad4a45a93824e3e5..a0e7fc2f40319fbb78a1cdd483f37ffcd122f2fd 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -981,7 +981,7 @@ static const struct ipu_platform_reg client_reg[] = {
 			.dc = 5,
 			.dp = IPU_DP_FLOW_SYNC_BG,
 			.dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
-			.dma[1] = -EINVAL,
+			.dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
 		},
 		.name = "imx-ipuv3-crtc",
 	}, {
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index ae50dd43fa151c0162613c64f145141d2f83858e..f1112dfa6bf6b4a861f7306b85d43ebd5b43baa6 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -25,11 +25,13 @@
 #include <drm/drm_crtc_helper.h>
 #include <linux/fb.h>
 #include <linux/clk.h>
+#include <linux/errno.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
 #include "ipu-v3/imx-ipu-v3.h"
 #include "imx-drm.h"
+#include "ipuv3-plane.h"
 
 #define DRIVER_DESC		"i.MX IPUv3 Graphics"
 
@@ -37,10 +39,11 @@ struct ipu_crtc {
 	struct device		*dev;
 	struct drm_crtc		base;
 	struct imx_drm_crtc	*imx_crtc;
-	struct ipuv3_channel	*ipu_ch;
+
+	/* plane[0] is the full plane, plane[1] is the partial plane */
+	struct ipu_plane	*plane[2];
+
 	struct ipu_dc		*dc;
-	struct ipu_dp		*dp;
-	struct dmfc_channel	*dmfc;
 	struct ipu_di		*di;
 	int			enabled;
 	struct drm_pending_vblank_event *page_flip_event;
@@ -54,35 +57,14 @@ struct ipu_crtc {
 
 #define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
 
-static int calc_vref(struct drm_display_mode *mode)
-{
-	unsigned long htotal, vtotal;
-
-	htotal = mode->htotal;
-	vtotal = mode->vtotal;
-
-	if (!htotal || !vtotal)
-		return 60;
-
-	return mode->clock * 1000 / vtotal / htotal;
-}
-
-static int calc_bandwidth(struct drm_display_mode *mode, unsigned int vref)
-{
-	return mode->hdisplay * mode->vdisplay * vref;
-}
-
 static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
 {
 	if (ipu_crtc->enabled)
 		return;
 
 	ipu_di_enable(ipu_crtc->di);
-	ipu_dmfc_enable_channel(ipu_crtc->dmfc);
-	ipu_idmac_enable_channel(ipu_crtc->ipu_ch);
 	ipu_dc_enable_channel(ipu_crtc->dc);
-	if (ipu_crtc->dp)
-		ipu_dp_enable_channel(ipu_crtc->dp);
+	ipu_plane_enable(ipu_crtc->plane[0]);
 
 	ipu_crtc->enabled = 1;
 }
@@ -92,12 +74,8 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
 	if (!ipu_crtc->enabled)
 		return;
 
-	if (ipu_crtc->dp)
-		ipu_dp_disable_channel(ipu_crtc->dp);
+	ipu_plane_disable(ipu_crtc->plane[0]);
 	ipu_dc_disable_channel(ipu_crtc->dc);
-	ipu_idmac_wait_busy(ipu_crtc->ipu_ch, 50);
-	ipu_idmac_disable_channel(ipu_crtc->ipu_ch);
-	ipu_dmfc_disable_channel(ipu_crtc->dmfc);
 	ipu_di_disable(ipu_crtc->di);
 
 	ipu_crtc->enabled = 0;
@@ -153,33 +131,6 @@ static const struct drm_crtc_funcs ipu_crtc_funcs = {
 	.page_flip = ipu_page_flip,
 };
 
-static int ipu_drm_set_base(struct drm_crtc *crtc, int x, int y)
-{
-	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-	struct drm_gem_cma_object *cma_obj;
-	struct drm_framebuffer *fb = crtc->fb;
-	unsigned long phys;
-
-	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
-	if (!cma_obj) {
-		DRM_LOG_KMS("entry is null.\n");
-		return -EFAULT;
-	}
-
-	phys = cma_obj->paddr;
-	phys += x * (fb->bits_per_pixel >> 3);
-	phys += y * fb->pitches[0];
-
-	dev_dbg(ipu_crtc->dev, "%s: phys: 0x%lx\n", __func__, phys);
-	dev_dbg(ipu_crtc->dev, "%s: xy: %dx%d\n", __func__, x, y);
-
-	ipu_cpmem_set_stride(ipu_get_cpmem(ipu_crtc->ipu_ch), fb->pitches[0]);
-	ipu_cpmem_set_buffer(ipu_get_cpmem(ipu_crtc->ipu_ch),
-			  0, phys);
-
-	return 0;
-}
-
 static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 			       struct drm_display_mode *orig_mode,
 			       struct drm_display_mode *mode,
@@ -187,45 +138,15 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 			       struct drm_framebuffer *old_fb)
 {
 	struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
-	struct drm_framebuffer *fb = ipu_crtc->base.fb;
 	int ret;
 	struct ipu_di_signal_cfg sig_cfg = {};
 	u32 out_pixel_fmt;
-	struct ipu_ch_param __iomem *cpmem = ipu_get_cpmem(ipu_crtc->ipu_ch);
-	int bpp;
-	u32 v4l2_fmt;
 
 	dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
 			mode->hdisplay);
 	dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
 			mode->vdisplay);
 
-	ipu_ch_param_zero(cpmem);
-
-	switch (fb->pixel_format) {
-	case DRM_FORMAT_XRGB8888:
-	case DRM_FORMAT_ARGB8888:
-		v4l2_fmt = V4L2_PIX_FMT_RGB32;
-		bpp = 32;
-		break;
-	case DRM_FORMAT_RGB565:
-		v4l2_fmt = V4L2_PIX_FMT_RGB565;
-		bpp = 16;
-		break;
-	case DRM_FORMAT_RGB888:
-		v4l2_fmt = V4L2_PIX_FMT_RGB24;
-		bpp = 24;
-		break;
-	case DRM_FORMAT_BGR888:
-		v4l2_fmt = V4L2_PIX_FMT_BGR24;
-		bpp = 24;
-		break;
-	default:
-		dev_err(ipu_crtc->dev, "unsupported pixel format 0x%08x\n",
-				fb->pixel_format);
-		return -EINVAL;
-	}
-
 	out_pixel_fmt = ipu_crtc->interface_pix_fmt;
 
 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
@@ -255,18 +176,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 	sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
 	sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
 
-	if (ipu_crtc->dp) {
-		ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB,
-				IPUV3_COLORSPACE_RGB);
-		if (ret) {
-			dev_err(ipu_crtc->dev,
-				"initializing display processor failed with %d\n",
-				ret);
-			return ret;
-		}
-		ipu_dp_set_global_alpha(ipu_crtc->dp, 1, 0, 1);
-	}
-
 	ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
 			out_pixel_fmt, mode->hdisplay);
 	if (ret) {
@@ -283,30 +192,9 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
 		return ret;
 	}
 
-	ipu_cpmem_set_resolution(cpmem, mode->hdisplay, mode->vdisplay);
-	ipu_cpmem_set_fmt(cpmem, v4l2_fmt);
-	ipu_cpmem_set_high_priority(ipu_crtc->ipu_ch);
-
-	ret = ipu_dmfc_init_channel(ipu_crtc->dmfc, mode->hdisplay);
-	if (ret) {
-		dev_err(ipu_crtc->dev,
-				"initializing dmfc channel failed with %d\n",
-				ret);
-		return ret;
-	}
-
-	ret = ipu_dmfc_alloc_bandwidth(ipu_crtc->dmfc,
-			calc_bandwidth(mode, calc_vref(mode)), 64);
-	if (ret) {
-		dev_err(ipu_crtc->dev,
-				"allocating dmfc bandwidth failed with %d\n",
-				ret);
-		return ret;
-	}
-
-	ipu_drm_set_base(crtc, x, y);
-
-	return 0;
+	return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb,
+				  0, 0, mode->hdisplay, mode->vdisplay,
+				  x, y, mode->hdisplay, mode->vdisplay);
 }
 
 static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
@@ -330,7 +218,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
 
 	if (ipu_crtc->newfb) {
 		ipu_crtc->newfb = NULL;
-		ipu_drm_set_base(&ipu_crtc->base, 0, 0);
+		ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb, 0, 0);
 		ipu_crtc_handle_pageflip(ipu_crtc);
 	}
 
@@ -413,12 +301,8 @@ static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
 
 static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
 {
-	if (!IS_ERR_OR_NULL(ipu_crtc->ipu_ch))
-		ipu_idmac_put(ipu_crtc->ipu_ch);
-	if (!IS_ERR_OR_NULL(ipu_crtc->dmfc))
-		ipu_dmfc_put(ipu_crtc->dmfc);
-	if (!IS_ERR_OR_NULL(ipu_crtc->dp))
-		ipu_dp_put(ipu_crtc->dp);
+	if (!IS_ERR_OR_NULL(ipu_crtc->dc))
+		ipu_dc_put(ipu_crtc->dc);
 	if (!IS_ERR_OR_NULL(ipu_crtc->di))
 		ipu_di_put(ipu_crtc->di);
 }
@@ -429,32 +313,12 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
 	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
 	int ret;
 
-	ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]);
-	if (IS_ERR(ipu_crtc->ipu_ch)) {
-		ret = PTR_ERR(ipu_crtc->ipu_ch);
-		goto err_out;
-	}
-
 	ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
 	if (IS_ERR(ipu_crtc->dc)) {
 		ret = PTR_ERR(ipu_crtc->dc);
 		goto err_out;
 	}
 
-	ipu_crtc->dmfc = ipu_dmfc_get(ipu, pdata->dma[0]);
-	if (IS_ERR(ipu_crtc->dmfc)) {
-		ret = PTR_ERR(ipu_crtc->dmfc);
-		goto err_out;
-	}
-
-	if (pdata->dp >= 0) {
-		ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp);
-		if (IS_ERR(ipu_crtc->dp)) {
-			ret = PTR_ERR(ipu_crtc->dp);
-			goto err_out;
-		}
-	}
-
 	ipu_crtc->di = ipu_di_get(ipu, pdata->di);
 	if (IS_ERR(ipu_crtc->di)) {
 		ret = PTR_ERR(ipu_crtc->di);
@@ -472,7 +336,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		struct ipu_client_platformdata *pdata)
 {
 	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
+	int dp = -EINVAL;
 	int ret;
+	int id;
 
 	ret = ipu_get_resources(ipu_crtc, pdata);
 	if (ret) {
@@ -490,17 +356,42 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		goto err_put_resources;
 	}
 
-	ipu_crtc->irq = ipu_idmac_channel_irq(ipu, ipu_crtc->ipu_ch,
-			IPU_IRQ_EOF);
+	if (pdata->dp >= 0)
+		dp = IPU_DP_FLOW_SYNC_BG;
+	id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
+	ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu,
+					    pdata->dma[0], dp, BIT(id), true);
+	ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
+	if (ret) {
+		dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
+			ret);
+		goto err_remove_crtc;
+	}
+
+	/* If this crtc is using the DP, add an overlay plane */
+	if (pdata->dp >= 0 && pdata->dma[1] > 0) {
+		ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu,
+						    pdata->dma[1],
+						    IPU_DP_FLOW_SYNC_FG,
+						    BIT(id), false);
+		if (IS_ERR(ipu_crtc->plane[1]))
+			ipu_crtc->plane[1] = NULL;
+	}
+
+	ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
 	ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
 			"imx_drm", ipu_crtc);
 	if (ret < 0) {
 		dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
-		goto err_put_resources;
+		goto err_put_plane_res;
 	}
 
 	return 0;
 
+err_put_plane_res:
+	ipu_plane_put_resources(ipu_crtc->plane[0]);
+err_remove_crtc:
+	imx_drm_remove_crtc(ipu_crtc->imx_crtc);
 err_put_resources:
 	ipu_put_resources(ipu_crtc);
 
@@ -539,6 +430,7 @@ static int ipu_drm_remove(struct platform_device *pdev)
 
 	imx_drm_remove_crtc(ipu_crtc->imx_crtc);
 
+	ipu_plane_put_resources(ipu_crtc->plane[0]);
 	ipu_put_resources(ipu_crtc);
 
 	return 0;
diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c
new file mode 100644
index 0000000000000000000000000000000000000000..d97454a0dffd947a5cf51d039f7c816ea2145748
--- /dev/null
+++ b/drivers/staging/imx-drm/ipuv3-plane.c
@@ -0,0 +1,375 @@
+/*
+ * i.MX IPUv3 DP Overlay Planes
+ *
+ * Copyright (C) 2013 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "ipu-v3/imx-ipu-v3.h"
+#include "ipuv3-plane.h"
+
+#define to_ipu_plane(x)	container_of(x, struct ipu_plane, base)
+
+static const uint32_t ipu_plane_formats[] = {
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_XBGR1555,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ABGR8888,
+	DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_YVYU,
+	DRM_FORMAT_YUV420,
+	DRM_FORMAT_YVU420,
+};
+
+int ipu_plane_irq(struct ipu_plane *ipu_plane)
+{
+	return ipu_idmac_channel_irq(ipu_plane->ipu, ipu_plane->ipu_ch,
+				     IPU_IRQ_EOF);
+}
+
+static int calc_vref(struct drm_display_mode *mode)
+{
+	unsigned long htotal, vtotal;
+
+	htotal = mode->htotal;
+	vtotal = mode->vtotal;
+
+	if (!htotal || !vtotal)
+		return 60;
+
+	return DIV_ROUND_UP(mode->clock * 1000, vtotal * htotal);
+}
+
+static inline int calc_bandwidth(int width, int height, unsigned int vref)
+{
+	return width * height * vref;
+}
+
+int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
+		       int x, int y)
+{
+	struct ipu_ch_param __iomem *cpmem;
+	struct drm_gem_cma_object *cma_obj;
+
+	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
+	if (!cma_obj) {
+		DRM_LOG_KMS("entry is null.\n");
+		return -EFAULT;
+	}
+
+	dev_dbg(ipu_plane->base.dev->dev, "phys = 0x%x, x = %d, y = %d",
+		cma_obj->paddr, x, y);
+
+	cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
+	ipu_cpmem_set_stride(cpmem, fb->pitches[0]);
+	ipu_cpmem_set_buffer(cpmem, 0, cma_obj->paddr + fb->offsets[0] +
+			     fb->pitches[0] * y + x);
+
+	return 0;
+}
+
+int ipu_plane_mode_set(struct ipu_plane *ipu_plane, struct drm_crtc *crtc,
+		       struct drm_display_mode *mode,
+		       struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+		       unsigned int crtc_w, unsigned int crtc_h,
+		       uint32_t src_x, uint32_t src_y,
+		       uint32_t src_w, uint32_t src_h)
+{
+	struct ipu_ch_param __iomem *cpmem;
+	struct device *dev = ipu_plane->base.dev->dev;
+	int ret;
+
+	/* no scaling */
+	if (src_w != crtc_w || src_h != crtc_h)
+		return -EINVAL;
+
+	/* clip to crtc bounds */
+	if (crtc_x < 0) {
+		if (-crtc_x > crtc_w)
+			return -EINVAL;
+		src_x += -crtc_x;
+		src_w -= -crtc_x;
+		crtc_w -= -crtc_x;
+		crtc_x = 0;
+	}
+	if (crtc_y < 0) {
+		if (-crtc_y > crtc_h)
+			return -EINVAL;
+		src_y += -crtc_y;
+		src_h -= -crtc_y;
+		crtc_h -= -crtc_y;
+		crtc_y = 0;
+	}
+	if (crtc_x + crtc_w > mode->hdisplay) {
+		if (crtc_x > mode->hdisplay)
+			return -EINVAL;
+		crtc_w = mode->hdisplay - crtc_x;
+		src_w = crtc_w;
+	}
+	if (crtc_y + crtc_h > mode->vdisplay) {
+		if (crtc_y > mode->vdisplay)
+			return -EINVAL;
+		crtc_h = mode->vdisplay - crtc_y;
+		src_h = crtc_h;
+	}
+	/* full plane minimum width is 13 pixels */
+	if (crtc_w < 13 && (ipu_plane->dp_flow != IPU_DP_FLOW_SYNC_FG))
+		return -EINVAL;
+	if (crtc_h < 2)
+		return -EINVAL;
+
+	switch (ipu_plane->dp_flow) {
+	case IPU_DP_FLOW_SYNC_BG:
+		ret = ipu_dp_setup_channel(ipu_plane->dp,
+				IPUV3_COLORSPACE_RGB,
+				IPUV3_COLORSPACE_RGB);
+		if (ret) {
+			dev_err(dev,
+				"initializing display processor failed with %d\n",
+				ret);
+			return ret;
+		}
+		ipu_dp_set_global_alpha(ipu_plane->dp, 1, 0, 1);
+		break;
+	case IPU_DP_FLOW_SYNC_FG:
+		ipu_dp_setup_channel(ipu_plane->dp,
+				ipu_drm_fourcc_to_colorspace(fb->pixel_format),
+				IPUV3_COLORSPACE_UNKNOWN);
+		ipu_dp_set_window_pos(ipu_plane->dp, crtc_x, crtc_y);
+		break;
+	}
+
+	ret = ipu_dmfc_init_channel(ipu_plane->dmfc, crtc_w);
+	if (ret) {
+		dev_err(dev, "initializing dmfc channel failed with %d\n", ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(ipu_plane->dmfc,
+			calc_bandwidth(crtc_w, crtc_h,
+				       calc_vref(mode)), 64);
+	if (ret) {
+		dev_err(dev, "allocating dmfc bandwidth failed with %d\n", ret);
+		return ret;
+	}
+
+	cpmem = ipu_get_cpmem(ipu_plane->ipu_ch);
+	ipu_ch_param_zero(cpmem);
+	ipu_cpmem_set_resolution(cpmem, src_w, src_h);
+	ret = ipu_cpmem_set_fmt(cpmem, fb->pixel_format);
+	if (ret < 0) {
+		dev_err(dev, "unsupported pixel format 0x%08x\n",
+			fb->pixel_format);
+		return ret;
+	}
+	ipu_cpmem_set_high_priority(ipu_plane->ipu_ch);
+
+	ret = ipu_plane_set_base(ipu_plane, fb, src_x, src_y);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+void ipu_plane_put_resources(struct ipu_plane *ipu_plane)
+{
+	if (!IS_ERR_OR_NULL(ipu_plane->dp))
+		ipu_dp_put(ipu_plane->dp);
+	if (!IS_ERR_OR_NULL(ipu_plane->dmfc))
+		ipu_dmfc_put(ipu_plane->dmfc);
+	if (!IS_ERR_OR_NULL(ipu_plane->ipu_ch))
+		ipu_idmac_put(ipu_plane->ipu_ch);
+}
+
+int ipu_plane_get_resources(struct ipu_plane *ipu_plane)
+{
+	int ret;
+
+	ipu_plane->ipu_ch = ipu_idmac_get(ipu_plane->ipu, ipu_plane->dma);
+	if (IS_ERR(ipu_plane->ipu_ch)) {
+		ret = PTR_ERR(ipu_plane->ipu_ch);
+		DRM_ERROR("failed to get idmac channel: %d\n", ret);
+		return ret;
+	}
+
+	ipu_plane->dmfc = ipu_dmfc_get(ipu_plane->ipu, ipu_plane->dma);
+	if (IS_ERR(ipu_plane->dmfc)) {
+		ret = PTR_ERR(ipu_plane->dmfc);
+		DRM_ERROR("failed to get dmfc: ret %d\n", ret);
+		goto err_out;
+	}
+
+	if (ipu_plane->dp_flow >= 0) {
+		ipu_plane->dp = ipu_dp_get(ipu_plane->ipu, ipu_plane->dp_flow);
+		if (IS_ERR(ipu_plane->dp)) {
+			ret = PTR_ERR(ipu_plane->dp);
+			DRM_ERROR("failed to get dp flow: %d\n", ret);
+			goto err_out;
+		}
+	}
+
+	return 0;
+err_out:
+	ipu_plane_put_resources(ipu_plane);
+
+	return ret;
+}
+
+void ipu_plane_enable(struct ipu_plane *ipu_plane)
+{
+	ipu_dmfc_enable_channel(ipu_plane->dmfc);
+	ipu_idmac_enable_channel(ipu_plane->ipu_ch);
+	if (ipu_plane->dp)
+		ipu_dp_enable_channel(ipu_plane->dp);
+
+	ipu_plane->enabled = true;
+}
+
+void ipu_plane_disable(struct ipu_plane *ipu_plane)
+{
+	ipu_plane->enabled = false;
+
+	ipu_idmac_wait_busy(ipu_plane->ipu_ch, 50);
+
+	if (ipu_plane->dp)
+		ipu_dp_disable_channel(ipu_plane->dp);
+	ipu_idmac_disable_channel(ipu_plane->ipu_ch);
+	ipu_dmfc_disable_channel(ipu_plane->dmfc);
+}
+
+static void ipu_plane_dpms(struct ipu_plane *ipu_plane, int mode)
+{
+	bool enable;
+
+	DRM_DEBUG_KMS("mode = %d", mode);
+
+	enable = (mode == DRM_MODE_DPMS_ON);
+
+	if (enable == ipu_plane->enabled)
+		return;
+
+	if (enable) {
+		ipu_plane_enable(ipu_plane);
+	} else {
+		ipu_plane_disable(ipu_plane);
+
+		ipu_idmac_put(ipu_plane->ipu_ch);
+		ipu_dmfc_put(ipu_plane->dmfc);
+		ipu_dp_put(ipu_plane->dp);
+	}
+}
+
+/*
+ * drm_plane API
+ */
+
+static int ipu_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+			    struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+			    unsigned int crtc_w, unsigned int crtc_h,
+			    uint32_t src_x, uint32_t src_y,
+			    uint32_t src_w, uint32_t src_h)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+	int ret = 0;
+
+	DRM_DEBUG_KMS("plane - %p\n", plane);
+
+	if (!ipu_plane->enabled)
+		ret = ipu_plane_get_resources(ipu_plane);
+	if (ret < 0)
+		return ret;
+
+	ret = ipu_plane_mode_set(ipu_plane, crtc, &crtc->hwmode, fb,
+			crtc_x, crtc_y, crtc_w, crtc_h,
+			src_x >> 16, src_y >> 16, src_w >> 16, src_h >> 16);
+	if (ret < 0) {
+		ipu_plane_put_resources(ipu_plane);
+		return ret;
+	}
+
+	if (crtc != plane->crtc)
+		dev_info(plane->dev->dev, "crtc change: %p -> %p\n",
+				plane->crtc, crtc);
+	plane->crtc = crtc;
+
+	ipu_plane_dpms(ipu_plane, DRM_MODE_DPMS_ON);
+
+	return 0;
+}
+
+static int ipu_disable_plane(struct drm_plane *plane)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	ipu_plane_dpms(ipu_plane, DRM_MODE_DPMS_OFF);
+
+	ipu_plane_put_resources(ipu_plane);
+
+	return 0;
+}
+
+static void ipu_plane_destroy(struct drm_plane *plane)
+{
+	struct ipu_plane *ipu_plane = to_ipu_plane(plane);
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	ipu_disable_plane(plane);
+	drm_plane_cleanup(plane);
+	kfree(ipu_plane);
+}
+
+static struct drm_plane_funcs ipu_plane_funcs = {
+	.update_plane	= ipu_update_plane,
+	.disable_plane	= ipu_disable_plane,
+	.destroy	= ipu_plane_destroy,
+};
+
+struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
+				 int dma, int dp, unsigned int possible_crtcs,
+				 bool priv)
+{
+	struct ipu_plane *ipu_plane;
+	int ret;
+
+	DRM_DEBUG_KMS("channel %d, dp flow %d, possible_crtcs=0x%x\n",
+		      dma, dp, possible_crtcs);
+
+	ipu_plane = kzalloc(sizeof(*ipu_plane), GFP_KERNEL);
+	if (!ipu_plane) {
+		DRM_ERROR("failed to allocate plane\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	ipu_plane->ipu = ipu;
+	ipu_plane->dma = dma;
+	ipu_plane->dp_flow = dp;
+
+	ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
+			     &ipu_plane_funcs, ipu_plane_formats,
+			     ARRAY_SIZE(ipu_plane_formats),
+			     priv);
+	if (ret) {
+		DRM_ERROR("failed to initialize plane\n");
+		kfree(ipu_plane);
+		return ERR_PTR(ret);
+	}
+
+	return ipu_plane;
+}
diff --git a/drivers/staging/imx-drm/ipuv3-plane.h b/drivers/staging/imx-drm/ipuv3-plane.h
new file mode 100644
index 0000000000000000000000000000000000000000..c0aae5bcb5d457e3e7f07cf5bca3de79878d719a
--- /dev/null
+++ b/drivers/staging/imx-drm/ipuv3-plane.h
@@ -0,0 +1,55 @@
+#ifndef __IPUV3_PLANE_H__
+#define __IPUV3_PLANE_H__
+
+#include <drm/drm_crtc.h> /* drm_plane */
+
+struct drm_plane;
+struct drm_device;
+struct ipu_soc;
+struct drm_crtc;
+struct drm_framebuffer;
+
+struct ipuv3_channel;
+struct dmfc_channel;
+struct ipu_dp;
+
+struct ipu_plane {
+	struct drm_plane	base;
+
+	struct ipu_soc		*ipu;
+	struct ipuv3_channel	*ipu_ch;
+	struct dmfc_channel	*dmfc;
+	struct ipu_dp		*dp;
+
+	int			dma;
+	int			dp_flow;
+
+	int			x;
+	int			y;
+
+	bool			enabled;
+};
+
+struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
+				 int dma, int dp, unsigned int possible_crtcs,
+				 bool priv);
+
+/* Init IDMAC, DMFC, DP */
+int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
+		       struct drm_display_mode *mode,
+		       struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+		       unsigned int crtc_w, unsigned int crtc_h,
+		       uint32_t src_x, uint32_t src_y, uint32_t src_w,
+		       uint32_t src_h);
+
+void ipu_plane_enable(struct ipu_plane *plane);
+void ipu_plane_disable(struct ipu_plane *plane);
+int ipu_plane_set_base(struct ipu_plane *plane, struct drm_framebuffer *fb,
+		       int x, int y);
+
+int ipu_plane_get_resources(struct ipu_plane *plane);
+void ipu_plane_put_resources(struct ipu_plane *plane);
+
+int ipu_plane_irq(struct ipu_plane *plane);
+
+#endif