Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux

Pull Exynos DRM changes from Dave Airlie:
 "So I totally missed Inki's pull request for -next, its fully exynos
  self contained."

(I took just the actual commits, not Dave's two extraneous merges)

* 'drm-next' of git://people.freedesktop.org/~airlied/linux: (30 commits)
  drm/exynos: fixed exception to page allocation failure
  drm/exynos: use __free_page() to deallocate memory
  drm/exynos: fixed a comment to gem size.
  drm/exynos: removed unnecessary variable
  drm/exynos: do not release memory region from exporter.
  drm/exynos: set buffer type from exporter.
  drm/exynos: use alloc_page() to allocate pages.
  drm/exynos: fixed build warning.
  drm/exynos: fixed edid data setting at vidi connection request
  drm/exynos: check if raw edid data is fake or not for test
  drm/exynos: set edid fake data only for test.
  drm/exynos: removed unnecessary declaration.
  drm/exynos: fix buffer pitch calculation
  drm/exynos: check for null in return value of dma_buf_map_attachment()
  drm/exynos: return NULL if exynos_pages_to_sg fails
  drm/exynos: Use devm_* functions in exynos_mixer.c
  drm/exynos: Use devm_* functions in exynos_hdmi.c
  drm/exynos: Use devm_* functions in exynos_drm_fimd.c
  drm/exynos: Add missing static storage class specifier
  drm/exynos: add property for crtc mode
  ...
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index bf791fa..d956819 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -196,7 +196,8 @@
 	return ret;
 }
 
-struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *exynos_drm_best_encoder(
+						struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
 	struct exynos_drm_connector *exynos_connector =
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index eaf630d..84dd099 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -33,7 +33,6 @@
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
-static struct drm_device *drm_dev;
 
 static int exynos_drm_subdrv_probe(struct drm_device *dev,
 					struct exynos_drm_subdrv *subdrv)
@@ -120,8 +119,6 @@
 	if (!dev)
 		return -EINVAL;
 
-	drm_dev = dev;
-
 	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
 		subdrv->drm_dev = dev;
 		err = exynos_drm_subdrv_probe(dev, subdrv);
@@ -149,8 +146,6 @@
 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
 		exynos_drm_subdrv_remove(dev, subdrv);
 
-	drm_dev = NULL;
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 32a34c8..abb1e2f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -29,21 +29,23 @@
 #include "drmP.h"
 #include "drm_crtc_helper.h"
 
-#include "exynos_drm_crtc.h"
 #include "exynos_drm_drv.h"
-#include "exynos_drm_fb.h"
 #include "exynos_drm_encoder.h"
-#include "exynos_drm_gem.h"
+#include "exynos_drm_plane.h"
 
 #define to_exynos_crtc(x)	container_of(x, struct exynos_drm_crtc,\
 				drm_crtc)
 
+enum exynos_crtc_mode {
+	CRTC_MODE_NORMAL,	/* normal mode */
+	CRTC_MODE_BLANK,	/* The private plane of crtc is blank */
+};
+
 /*
  * Exynos specific crtc structure.
  *
  * @drm_crtc: crtc object.
- * @overlay: contain information common to display controller and hdmi and
- *	contents of this overlay object would be copied to sub driver size.
+ * @drm_plane: pointer of private plane object for this crtc
  * @pipe: a crtc index created at load() with a new crtc object creation
  *	and the crtc object would be set to private->crtc array
  *	to get a crtc object corresponding to this pipe from private->crtc
@@ -52,115 +54,16 @@
  *	we can refer to the crtc to current hardware interrupt occured through
  *	this pipe value.
  * @dpms: store the crtc dpms value
+ * @mode: store the crtc mode value
  */
 struct exynos_drm_crtc {
 	struct drm_crtc			drm_crtc;
-	struct exynos_drm_overlay	overlay;
+	struct drm_plane		*plane;
 	unsigned int			pipe;
 	unsigned int			dpms;
+	enum exynos_crtc_mode		mode;
 };
 
-static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
-{
-	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-	struct exynos_drm_overlay *overlay = &exynos_crtc->overlay;
-
-	exynos_drm_fn_encoder(crtc, overlay,
-			exynos_drm_encoder_crtc_mode_set);
-	exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
-			exynos_drm_encoder_crtc_commit);
-}
-
-int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
-			      struct drm_framebuffer *fb,
-			      struct drm_display_mode *mode,
-			      struct exynos_drm_crtc_pos *pos)
-{
-	struct exynos_drm_gem_buf *buffer;
-	unsigned int actual_w;
-	unsigned int actual_h;
-	int nr = exynos_drm_format_num_buffers(fb->pixel_format);
-	int i;
-
-	for (i = 0; i < nr; i++) {
-		buffer = exynos_drm_fb_buffer(fb, i);
-		if (!buffer) {
-			DRM_LOG_KMS("buffer is null\n");
-			return -EFAULT;
-		}
-
-		overlay->dma_addr[i] = buffer->dma_addr;
-		overlay->vaddr[i] = buffer->kvaddr;
-
-		DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
-				i, (unsigned long)overlay->vaddr[i],
-				(unsigned long)overlay->dma_addr[i]);
-	}
-
-	actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
-	actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
-
-	/* set drm framebuffer data. */
-	overlay->fb_x = pos->fb_x;
-	overlay->fb_y = pos->fb_y;
-	overlay->fb_width = fb->width;
-	overlay->fb_height = fb->height;
-	overlay->src_width = pos->src_w;
-	overlay->src_height = pos->src_h;
-	overlay->bpp = fb->bits_per_pixel;
-	overlay->pitch = fb->pitches[0];
-	overlay->pixel_format = fb->pixel_format;
-
-	/* set overlay range to be displayed. */
-	overlay->crtc_x = pos->crtc_x;
-	overlay->crtc_y = pos->crtc_y;
-	overlay->crtc_width = actual_w;
-	overlay->crtc_height = actual_h;
-
-	/* set drm mode data. */
-	overlay->mode_width = mode->hdisplay;
-	overlay->mode_height = mode->vdisplay;
-	overlay->refresh = mode->vrefresh;
-	overlay->scan_flag = mode->flags;
-
-	DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
-			overlay->crtc_x, overlay->crtc_y,
-			overlay->crtc_width, overlay->crtc_height);
-
-	return 0;
-}
-
-static int exynos_drm_crtc_update(struct drm_crtc *crtc)
-{
-	struct exynos_drm_crtc *exynos_crtc;
-	struct exynos_drm_overlay *overlay;
-	struct exynos_drm_crtc_pos pos;
-	struct drm_display_mode *mode = &crtc->mode;
-	struct drm_framebuffer *fb = crtc->fb;
-
-	if (!mode || !fb)
-		return -EINVAL;
-
-	exynos_crtc = to_exynos_crtc(crtc);
-	overlay = &exynos_crtc->overlay;
-
-	memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
-
-	/* it means the offset of framebuffer to be displayed. */
-	pos.fb_x = crtc->x;
-	pos.fb_y = crtc->y;
-
-	/* OSD position to be displayed. */
-	pos.crtc_x = 0;
-	pos.crtc_y = 0;
-	pos.crtc_w = fb->width - crtc->x;
-	pos.crtc_h = fb->height - crtc->y;
-	pos.src_w = pos.crtc_w;
-	pos.src_h = pos.crtc_h;
-
-	return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
-}
-
 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
 	struct drm_device *dev = crtc->dev;
@@ -175,23 +78,8 @@
 
 	mutex_lock(&dev->struct_mutex);
 
-	switch (mode) {
-	case DRM_MODE_DPMS_ON:
-		exynos_drm_fn_encoder(crtc, &mode,
-				exynos_drm_encoder_crtc_dpms);
-		exynos_crtc->dpms = mode;
-		break;
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
-	case DRM_MODE_DPMS_OFF:
-		exynos_drm_fn_encoder(crtc, &mode,
-				exynos_drm_encoder_crtc_dpms);
-		exynos_crtc->dpms = mode;
-		break;
-	default:
-		DRM_ERROR("unspecified mode %d\n", mode);
-		break;
-	}
+	exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms);
+	exynos_crtc->dpms = mode;
 
 	mutex_unlock(&dev->struct_mutex);
 }
@@ -209,30 +97,8 @@
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	/*
-	 * when set_crtc is requested from user or at booting time,
-	 * crtc->commit would be called without dpms call so if dpms is
-	 * no power on then crtc->dpms should be called
-	 * with DRM_MODE_DPMS_ON for the hardware power to be on.
-	 */
-	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
-		int mode = DRM_MODE_DPMS_ON;
-
-		/*
-		 * enable hardware(power on) to all encoders hdmi connected
-		 * to current crtc.
-		 */
-		exynos_drm_crtc_dpms(crtc, mode);
-		/*
-		 * enable dma to all encoders connected to current crtc and
-		 * lcd panel.
-		 */
-		exynos_drm_fn_encoder(crtc, &mode,
-					exynos_drm_encoder_dpms_from_crtc);
-	}
-
-	exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
-			exynos_drm_encoder_crtc_commit);
+	exynos_plane_commit(exynos_crtc->plane);
+	exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
 }
 
 static bool
@@ -251,31 +117,61 @@
 			  struct drm_display_mode *adjusted_mode, int x, int y,
 			  struct drm_framebuffer *old_fb)
 {
+	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct drm_plane *plane = exynos_crtc->plane;
+	unsigned int crtc_w;
+	unsigned int crtc_h;
+	int pipe = exynos_crtc->pipe;
+	int ret;
+
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
+	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
 	/*
 	 * copy the mode data adjusted by mode_fixup() into crtc->mode
 	 * so that hardware can be seet to proper mode.
 	 */
 	memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
 
-	return exynos_drm_crtc_update(crtc);
+	crtc_w = crtc->fb->width - x;
+	crtc_h = crtc->fb->height - y;
+
+	ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+				    x, y, crtc_w, crtc_h);
+	if (ret)
+		return ret;
+
+	plane->crtc = crtc;
+	plane->fb = crtc->fb;
+
+	exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
+
+	return 0;
 }
 
 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 					  struct drm_framebuffer *old_fb)
 {
+	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct drm_plane *plane = exynos_crtc->plane;
+	unsigned int crtc_w;
+	unsigned int crtc_h;
 	int ret;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	ret = exynos_drm_crtc_update(crtc);
+	crtc_w = crtc->fb->width - x;
+	crtc_h = crtc->fb->height - y;
+
+	ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+				    x, y, crtc_w, crtc_h);
 	if (ret)
 		return ret;
 
-	exynos_drm_crtc_apply(crtc);
+	exynos_drm_crtc_commit(crtc);
 
-	return ret;
+	return 0;
 }
 
 static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
@@ -284,6 +180,16 @@
 	/* drm framework doesn't check NULL */
 }
 
+static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
+{
+	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF);
+	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
 	.dpms		= exynos_drm_crtc_dpms,
 	.prepare	= exynos_drm_crtc_prepare,
@@ -292,6 +198,7 @@
 	.mode_set	= exynos_drm_crtc_mode_set,
 	.mode_set_base	= exynos_drm_crtc_mode_set_base,
 	.load_lut	= exynos_drm_crtc_load_lut,
+	.disable	= exynos_drm_crtc_disable,
 };
 
 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
@@ -327,7 +234,8 @@
 				&dev_priv->pageflip_event_list);
 
 		crtc->fb = fb;
-		ret = exynos_drm_crtc_update(crtc);
+		ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y,
+						    NULL);
 		if (ret) {
 			crtc->fb = old_fb;
 			drm_vblank_put(dev, exynos_crtc->pipe);
@@ -335,14 +243,6 @@
 
 			goto out;
 		}
-
-		/*
-		 * the values related to a buffer of the drm framebuffer
-		 * to be applied should be set at here. because these values
-		 * first, are set to shadow registers and then to
-		 * real registers at vsync front porch period.
-		 */
-		exynos_drm_crtc_apply(crtc);
 	}
 out:
 	mutex_unlock(&dev->struct_mutex);
@@ -362,18 +262,73 @@
 	kfree(exynos_crtc);
 }
 
+static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
+					struct drm_property *property,
+					uint64_t val)
+{
+	struct drm_device *dev = crtc->dev;
+	struct exynos_drm_private *dev_priv = dev->dev_private;
+	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+
+	DRM_DEBUG_KMS("%s\n", __func__);
+
+	if (property == dev_priv->crtc_mode_property) {
+		enum exynos_crtc_mode mode = val;
+
+		if (mode == exynos_crtc->mode)
+			return 0;
+
+		exynos_crtc->mode = mode;
+
+		switch (mode) {
+		case CRTC_MODE_NORMAL:
+			exynos_drm_crtc_commit(crtc);
+			break;
+		case CRTC_MODE_BLANK:
+			exynos_plane_dpms(exynos_crtc->plane,
+					  DRM_MODE_DPMS_OFF);
+			break;
+		default:
+			break;
+		}
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static struct drm_crtc_funcs exynos_crtc_funcs = {
 	.set_config	= drm_crtc_helper_set_config,
 	.page_flip	= exynos_drm_crtc_page_flip,
 	.destroy	= exynos_drm_crtc_destroy,
+	.set_property	= exynos_drm_crtc_set_property,
 };
 
-struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
-		struct drm_crtc *crtc)
-{
-	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+static const struct drm_prop_enum_list mode_names[] = {
+	{ CRTC_MODE_NORMAL, "normal" },
+	{ CRTC_MODE_BLANK, "blank" },
+};
 
-	return &exynos_crtc->overlay;
+static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct exynos_drm_private *dev_priv = dev->dev_private;
+	struct drm_property *prop;
+
+	DRM_DEBUG_KMS("%s\n", __func__);
+
+	prop = dev_priv->crtc_mode_property;
+	if (!prop) {
+		prop = drm_property_create_enum(dev, 0, "mode", mode_names,
+						ARRAY_SIZE(mode_names));
+		if (!prop)
+			return;
+
+		dev_priv->crtc_mode_property = prop;
+	}
+
+	drm_object_attach_property(&crtc->base, prop, 0);
 }
 
 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
@@ -392,7 +347,12 @@
 
 	exynos_crtc->pipe = nr;
 	exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
-	exynos_crtc->overlay.zpos = DEFAULT_ZPOS;
+	exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
+	if (!exynos_crtc->plane) {
+		kfree(exynos_crtc);
+		return -ENOMEM;
+	}
+
 	crtc = &exynos_crtc->drm_crtc;
 
 	private->crtc[nr] = crtc;
@@ -400,6 +360,8 @@
 	drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
 	drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
+	exynos_drm_crtc_attach_mode_property(crtc);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index 16b8e21..6bae8d8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -29,39 +29,8 @@
 #ifndef _EXYNOS_DRM_CRTC_H_
 #define _EXYNOS_DRM_CRTC_H_
 
-struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
-		struct drm_crtc *crtc);
 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
 
-/*
- * Exynos specific crtc postion structure.
- *
- * @fb_x: offset x on a framebuffer to be displyed
- *	- the unit is screen coordinates.
- * @fb_y: offset y on a framebuffer to be displayed
- *	- the unit is screen coordinates.
- * @src_w: width of source area to be displayed from a framebuffer.
- * @src_h: height of source area to be displayed from a framebuffer.
- * @crtc_x: offset x on hardware screen.
- * @crtc_y: offset y on hardware screen.
- * @crtc_w: width of hardware screen.
- * @crtc_h: height of hardware screen.
- */
-struct exynos_drm_crtc_pos {
-	unsigned int fb_x;
-	unsigned int fb_y;
-	unsigned int src_w;
-	unsigned int src_h;
-	unsigned int crtc_x;
-	unsigned int crtc_y;
-	unsigned int crtc_w;
-	unsigned int crtc_h;
-};
-
-int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
-			      struct drm_framebuffer *fb,
-			      struct drm_display_mode *mode,
-			      struct exynos_drm_crtc_pos *pos);
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index 2749092..613bf8a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -25,6 +25,7 @@
 
 #include "drmP.h"
 #include "drm.h"
+#include "exynos_drm.h"
 #include "exynos_drm_drv.h"
 #include "exynos_drm_gem.h"
 
@@ -86,6 +87,10 @@
 	npages = buf->size / buf->page_size;
 
 	sgt = exynos_pages_to_sg(buf->pages, npages, buf->page_size);
+	if (!sgt) {
+		DRM_DEBUG_PRIME("exynos_pages_to_sg returned NULL!\n");
+		goto err_unlock;
+	}
 	nents = dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
 
 	DRM_DEBUG_PRIME("npages = %d buffer size = 0x%lx page_size = 0x%lx\n",
@@ -186,7 +191,7 @@
 	struct exynos_drm_gem_obj *exynos_gem_obj;
 	struct exynos_drm_gem_buf *buffer;
 	struct page *page;
-	int ret, i = 0;
+	int ret;
 
 	DRM_DEBUG_PRIME("%s\n", __FILE__);
 
@@ -210,7 +215,7 @@
 
 
 	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
-	if (IS_ERR(sgt)) {
+	if (IS_ERR_OR_NULL(sgt)) {
 		ret = PTR_ERR(sgt);
 		goto err_buf_detach;
 	}
@@ -236,13 +241,25 @@
 	}
 
 	sgl = sgt->sgl;
-	buffer->dma_addr = sg_dma_address(sgl);
 
-	while (i < sgt->nents) {
-		buffer->pages[i] = sg_page(sgl);
-		buffer->size += sg_dma_len(sgl);
-		sgl = sg_next(sgl);
-		i++;
+	if (sgt->nents == 1) {
+		buffer->dma_addr = sg_dma_address(sgt->sgl);
+		buffer->size = sg_dma_len(sgt->sgl);
+
+		/* always physically continuous memory if sgt->nents is 1. */
+		exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
+	} else {
+		unsigned int i = 0;
+
+		buffer->dma_addr = sg_dma_address(sgl);
+		while (i < sgt->nents) {
+			buffer->pages[i] = sg_page(sgl);
+			buffer->size += sg_dma_len(sgl);
+			sgl = sg_next(sgl);
+			i++;
+		}
+
+		exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
 	}
 
 	exynos_gem_obj->buffer = buffer;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index d6de2e07f..ebacec6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -85,8 +85,11 @@
 	}
 
 	for (nr = 0; nr < MAX_PLANE; nr++) {
-		ret = exynos_plane_init(dev, nr);
-		if (ret)
+		struct drm_plane *plane;
+		unsigned int possible_crtcs = (1 << MAX_CRTC) - 1;
+
+		plane = exynos_plane_init(dev, possible_crtcs, false);
+		if (!plane)
 			goto err_crtc;
 	}
 
@@ -221,8 +224,6 @@
 			exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
 			exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
-	DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
-			DRM_UNLOCKED | DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
 			vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
 	DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 277653d..e22704b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -59,12 +59,14 @@
  *
  * @mode_set: copy drm overlay info to hw specific overlay info.
  * @commit: apply hardware specific overlay data to registers.
+ * @enable: enable hardware specific overlay.
  * @disable: disable hardware specific overlay.
  */
 struct exynos_drm_overlay_ops {
 	void (*mode_set)(struct device *subdrv_dev,
 			 struct exynos_drm_overlay *overlay);
 	void (*commit)(struct device *subdrv_dev, int zpos);
+	void (*enable)(struct device *subdrv_dev, int zpos);
 	void (*disable)(struct device *subdrv_dev, int zpos);
 };
 
@@ -235,6 +237,8 @@
 	 * this array is used to be aware of which crtc did it request vblank.
 	 */
 	struct drm_crtc *crtc[MAX_CRTC];
+	struct drm_property *plane_zpos_property;
+	struct drm_property *crtc_mode_property;
 };
 
 /*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 4a13a74..2c037cd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -30,7 +30,6 @@
 #include "drm_crtc_helper.h"
 
 #include "exynos_drm_drv.h"
-#include "exynos_drm_crtc.h"
 #include "exynos_drm_encoder.h"
 
 #define to_exynos_encoder(x)	container_of(x, struct exynos_drm_encoder,\
@@ -136,21 +135,16 @@
 	struct drm_connector *connector;
 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-	struct exynos_drm_overlay *overlay = get_exynos_drm_overlay(dev,
-						encoder->crtc);
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
+	exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
+		if (connector->encoder == encoder)
 			if (manager_ops && manager_ops->mode_set)
 				manager_ops->mode_set(manager->dev,
 							adjusted_mode);
-
-			if (overlay_ops && overlay_ops->mode_set)
-				overlay_ops->mode_set(manager->dev, overlay);
-		}
 	}
 }
 
@@ -310,8 +304,8 @@
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	int crtc = *(int *)data;
 
-	if (manager->pipe == -1)
-		manager->pipe = crtc;
+	if (manager->pipe != crtc)
+		return;
 
 	if (manager_ops->enable_vblank)
 		manager_ops->enable_vblank(manager->dev);
@@ -324,65 +318,18 @@
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	int crtc = *(int *)data;
 
-	if (manager->pipe == -1)
-		manager->pipe = crtc;
+	if (manager->pipe != crtc)
+		return;
 
 	if (manager_ops->disable_vblank)
 		manager_ops->disable_vblank(manager->dev);
 }
 
-void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
-					  void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-	int zpos = DEFAULT_ZPOS;
-
-	if (data)
-		zpos = *(int *)data;
-
-	if (overlay_ops && overlay_ops->commit)
-		overlay_ops->commit(manager->dev, zpos);
-}
-
-void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	int crtc = *(int *)data;
-	int zpos = DEFAULT_ZPOS;
-
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	/*
-	 * when crtc is detached from encoder, this pipe is used
-	 * to select manager operation
-	 */
-	manager->pipe = crtc;
-
-	exynos_drm_encoder_crtc_plane_commit(encoder, &zpos);
-}
-
-void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-	int mode = *(int *)data;
-
-	DRM_DEBUG_KMS("%s\n", __FILE__);
-
-	exynos_drm_encoder_dpms(encoder, mode);
-
-	exynos_encoder->dpms = mode;
-}
-
 void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
 {
-	struct drm_device *dev = encoder->dev;
 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 	struct exynos_drm_manager *manager = exynos_encoder->manager;
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	struct drm_connector *connector;
 	int mode = *(int *)data;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -391,15 +338,6 @@
 		manager_ops->dpms(manager->dev, mode);
 
 	/*
-	 * set current dpms mode to the connector connected to
-	 * current encoder. connector->dpms would be checked
-	 * at drm_helper_connector_dpms()
-	 */
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-		if (connector->encoder == encoder)
-			connector->dpms = mode;
-
-	/*
 	 * if this condition is ok then it means that the crtc is already
 	 * detached from encoder and last function for detaching is properly
 	 * done, so clear pipe from manager to prevent repeated call.
@@ -410,25 +348,74 @@
 	}
 }
 
-void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data)
+void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
+{
+	struct exynos_drm_manager *manager =
+		to_exynos_encoder(encoder)->manager;
+	int pipe = *(int *)data;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	/*
+	 * when crtc is detached from encoder, this pipe is used
+	 * to select manager operation
+	 */
+	manager->pipe = pipe;
+}
+
+void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
 {
 	struct exynos_drm_manager *manager =
 		to_exynos_encoder(encoder)->manager;
 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
 	struct exynos_drm_overlay *overlay = data;
 
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
 	if (overlay_ops && overlay_ops->mode_set)
 		overlay_ops->mode_set(manager->dev, overlay);
 }
 
-void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data)
+void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
 {
 	struct exynos_drm_manager *manager =
 		to_exynos_encoder(encoder)->manager;
 	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
 	int zpos = DEFAULT_ZPOS;
 
-	DRM_DEBUG_KMS("\n");
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (data)
+		zpos = *(int *)data;
+
+	if (overlay_ops && overlay_ops->commit)
+		overlay_ops->commit(manager->dev, zpos);
+}
+
+void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
+{
+	struct exynos_drm_manager *manager =
+		to_exynos_encoder(encoder)->manager;
+	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+	int zpos = DEFAULT_ZPOS;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (data)
+		zpos = *(int *)data;
+
+	if (overlay_ops && overlay_ops->enable)
+		overlay_ops->enable(manager->dev, zpos);
+}
+
+void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
+{
+	struct exynos_drm_manager *manager =
+		to_exynos_encoder(encoder)->manager;
+	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+	int zpos = DEFAULT_ZPOS;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
 
 	if (data)
 		zpos = *(int *)data;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
index eb7d231..6470d9d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
@@ -40,13 +40,11 @@
 			    void (*fn)(struct drm_encoder *, void *));
 void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
 void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_plane_commit(struct drm_encoder *encoder,
-					  void *data);
-void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_dpms_from_crtc(struct drm_encoder *encoder,
-					void *data);
 void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
+void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
 
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 29fdbfe..a68d2b3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -78,7 +78,6 @@
 	struct drm_crtc			*crtc;
 	struct clk			*bus_clk;
 	struct clk			*lcd_clk;
-	struct resource			*regs_res;
 	void __iomem			*regs;
 	struct fimd_win_data		win_data[WINDOWS_NR];
 	unsigned int			clkdiv;
@@ -813,7 +812,7 @@
 		return -EINVAL;
 	}
 
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
@@ -838,33 +837,26 @@
 		goto err_clk;
 	}
 
-	ctx->regs_res = request_mem_region(res->start, resource_size(res),
-					   dev_name(dev));
-	if (!ctx->regs_res) {
-		dev_err(dev, "failed to claim register region\n");
-		ret = -ENOENT;
-		goto err_clk;
-	}
-
-	ctx->regs = ioremap(res->start, resource_size(res));
+	ctx->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!ctx->regs) {
 		dev_err(dev, "failed to map registers\n");
 		ret = -ENXIO;
-		goto err_req_region_io;
+		goto err_clk;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 		dev_err(dev, "irq request failed.\n");
-		goto err_req_region_irq;
+		goto err_clk;
 	}
 
 	ctx->irq = res->start;
 
-	ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx);
-	if (ret < 0) {
+	ret = devm_request_irq(&pdev->dev, ctx->irq, fimd_irq_handler,
+							0, "drm_fimd", ctx);
+	if (ret) {
 		dev_err(dev, "irq request failed.\n");
-		goto err_req_irq;
+		goto err_clk;
 	}
 
 	ctx->vidcon0 = pdata->vidcon0;
@@ -899,14 +891,6 @@
 
 	return 0;
 
-err_req_irq:
-err_req_region_irq:
-	iounmap(ctx->regs);
-
-err_req_region_io:
-	release_resource(ctx->regs_res);
-	kfree(ctx->regs_res);
-
 err_clk:
 	clk_disable(ctx->lcd_clk);
 	clk_put(ctx->lcd_clk);
@@ -916,7 +900,6 @@
 	clk_put(ctx->bus_clk);
 
 err_clk_get:
-	kfree(ctx);
 	return ret;
 }
 
@@ -944,13 +927,6 @@
 	clk_put(ctx->lcd_clk);
 	clk_put(ctx->bus_clk);
 
-	iounmap(ctx->regs);
-	release_resource(ctx->regs_res);
-	kfree(ctx->regs_res);
-	free_irq(ctx->irq, ctx);
-
-	kfree(ctx);
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 5c8b683..f9efde4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -99,25 +99,17 @@
 struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
 						gfp_t gfpmask)
 {
-	struct inode *inode;
-	struct address_space *mapping;
 	struct page *p, **pages;
 	int i, npages;
 
-	/* This is the shared memory object that backs the GEM resource */
-	inode = obj->filp->f_path.dentry->d_inode;
-	mapping = inode->i_mapping;
-
 	npages = obj->size >> PAGE_SHIFT;
 
 	pages = drm_malloc_ab(npages, sizeof(struct page *));
 	if (pages == NULL)
 		return ERR_PTR(-ENOMEM);
 
-	gfpmask |= mapping_gfp_mask(mapping);
-
 	for (i = 0; i < npages; i++) {
-		p = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
+		p = alloc_page(gfpmask);
 		if (IS_ERR(p))
 			goto fail;
 		pages[i] = p;
@@ -126,31 +118,22 @@
 	return pages;
 
 fail:
-	while (i--)
-		page_cache_release(pages[i]);
+	while (--i)
+		__free_page(pages[i]);
 
 	drm_free_large(pages);
 	return ERR_PTR(PTR_ERR(p));
 }
 
 static void exynos_gem_put_pages(struct drm_gem_object *obj,
-					struct page **pages,
-					bool dirty, bool accessed)
+					struct page **pages)
 {
-	int i, npages;
+	int npages;
 
 	npages = obj->size >> PAGE_SHIFT;
 
-	for (i = 0; i < npages; i++) {
-		if (dirty)
-			set_page_dirty(pages[i]);
-
-		if (accessed)
-			mark_page_accessed(pages[i]);
-
-		/* Undo the reference we took when populating the table */
-		page_cache_release(pages[i]);
-	}
+	while (--npages >= 0)
+		__free_page(pages[npages]);
 
 	drm_free_large(pages);
 }
@@ -189,7 +172,7 @@
 		return -EINVAL;
 	}
 
-	pages = exynos_gem_get_pages(obj, GFP_KERNEL);
+	pages = exynos_gem_get_pages(obj, GFP_HIGHUSER_MOVABLE);
 	if (IS_ERR(pages)) {
 		DRM_ERROR("failed to get pages.\n");
 		return PTR_ERR(pages);
@@ -230,7 +213,7 @@
 	kfree(buf->sgt);
 	buf->sgt = NULL;
 err:
-	exynos_gem_put_pages(obj, pages, true, false);
+	exynos_gem_put_pages(obj, pages);
 	return ret;
 
 }
@@ -248,7 +231,7 @@
 	kfree(buf->sgt);
 	buf->sgt = NULL;
 
-	exynos_gem_put_pages(obj, buf->pages, true, false);
+	exynos_gem_put_pages(obj, buf->pages);
 	buf->pages = NULL;
 
 	/* add some codes for UNCACHED type here. TODO */
@@ -291,11 +274,21 @@
 	if (!buf->pages)
 		return;
 
+	/*
+	 * do not release memory region from exporter.
+	 *
+	 * the region will be released by exporter
+	 * once dmabuf's refcount becomes 0.
+	 */
+	if (obj->import_attach)
+		goto out;
+
 	if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG)
 		exynos_drm_gem_put_pages(obj);
 	else
 		exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf);
 
+out:
 	exynos_drm_fini_buf(obj->dev, buf);
 	exynos_gem_obj->buffer = NULL;
 
@@ -668,7 +661,7 @@
 	 *	with DRM_IOCTL_MODE_CREATE_DUMB command.
 	 */
 
-	args->pitch = args->width * args->bpp >> 3;
+	args->pitch = args->width * ((args->bpp + 7) / 8);
 	args->size = PAGE_ALIGN(args->pitch * args->height);
 
 	exynos_gem_obj = exynos_drm_gem_create(dev, args->flags, args->size);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 14d038b..085b2a5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -63,7 +63,8 @@
  *	by user request or at framebuffer creation.
  *	continuous memory region allocated by user request
  *	or at framebuffer creation.
- * @size: total memory size to physically non-continuous memory region.
+ * @size: size requested from user, in bytes and this size is aligned
+ *	in page unit.
  * @flags: indicate memory type to allocated buffer and cache attruibute.
  *
  * P.S. this object would be transfered to user as kms_bo.handle so
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index c4c6525..b89829e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -12,9 +12,12 @@
 #include "drmP.h"
 
 #include "exynos_drm.h"
-#include "exynos_drm_crtc.h"
 #include "exynos_drm_drv.h"
 #include "exynos_drm_encoder.h"
+#include "exynos_drm_fb.h"
+#include "exynos_drm_gem.h"
+
+#define to_exynos_plane(x)	container_of(x, struct exynos_plane, base)
 
 struct exynos_plane {
 	struct drm_plane		base;
@@ -30,6 +33,108 @@
 	DRM_FORMAT_NV12MT,
 };
 
+int exynos_plane_mode_set(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 exynos_plane *exynos_plane = to_exynos_plane(plane);
+	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
+	unsigned int actual_w;
+	unsigned int actual_h;
+	int nr;
+	int i;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	nr = exynos_drm_format_num_buffers(fb->pixel_format);
+	for (i = 0; i < nr; i++) {
+		struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);
+
+		if (!buffer) {
+			DRM_LOG_KMS("buffer is null\n");
+			return -EFAULT;
+		}
+
+		overlay->dma_addr[i] = buffer->dma_addr;
+		overlay->vaddr[i] = buffer->kvaddr;
+
+		DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n",
+				i, (unsigned long)overlay->vaddr[i],
+				(unsigned long)overlay->dma_addr[i]);
+	}
+
+	actual_w = min((unsigned)(crtc->mode.hdisplay - crtc_x), crtc_w);
+	actual_h = min((unsigned)(crtc->mode.vdisplay - crtc_y), crtc_h);
+
+	/* set drm framebuffer data. */
+	overlay->fb_x = src_x;
+	overlay->fb_y = src_y;
+	overlay->fb_width = fb->width;
+	overlay->fb_height = fb->height;
+	overlay->src_width = src_w;
+	overlay->src_height = src_h;
+	overlay->bpp = fb->bits_per_pixel;
+	overlay->pitch = fb->pitches[0];
+	overlay->pixel_format = fb->pixel_format;
+
+	/* set overlay range to be displayed. */
+	overlay->crtc_x = crtc_x;
+	overlay->crtc_y = crtc_y;
+	overlay->crtc_width = actual_w;
+	overlay->crtc_height = actual_h;
+
+	/* set drm mode data. */
+	overlay->mode_width = crtc->mode.hdisplay;
+	overlay->mode_height = crtc->mode.vdisplay;
+	overlay->refresh = crtc->mode.vrefresh;
+	overlay->scan_flag = crtc->mode.flags;
+
+	DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
+			overlay->crtc_x, overlay->crtc_y,
+			overlay->crtc_width, overlay->crtc_height);
+
+	exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
+
+	return 0;
+}
+
+void exynos_plane_commit(struct drm_plane *plane)
+{
+	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
+
+	exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+			exynos_drm_encoder_plane_commit);
+}
+
+void exynos_plane_dpms(struct drm_plane *plane, int mode)
+{
+	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	if (mode == DRM_MODE_DPMS_ON) {
+		if (exynos_plane->enabled)
+			return;
+
+		exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+				exynos_drm_encoder_plane_enable);
+
+		exynos_plane->enabled = true;
+	} else {
+		if (!exynos_plane->enabled)
+			return;
+
+		exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
+				exynos_drm_encoder_plane_disable);
+
+		exynos_plane->enabled = false;
+	}
+}
+
 static int
 exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
 		     struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -37,64 +142,37 @@
 		     uint32_t src_x, uint32_t src_y,
 		     uint32_t src_w, uint32_t src_h)
 {
-	struct exynos_plane *exynos_plane =
-		container_of(plane, struct exynos_plane, base);
-	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-	struct exynos_drm_crtc_pos pos;
 	int ret;
 
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-	memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
-	pos.crtc_x = crtc_x;
-	pos.crtc_y = crtc_y;
-	pos.crtc_w = crtc_w;
-	pos.crtc_h = crtc_h;
-
-	/* considering 16.16 fixed point of source values */
-	pos.fb_x = src_x >> 16;
-	pos.fb_y = src_y >> 16;
-	pos.src_w = src_w >> 16;
-	pos.src_h = src_h >> 16;
-
-	ret = exynos_drm_overlay_update(overlay, fb, &crtc->mode, &pos);
+	ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
+			crtc_w, crtc_h, src_x >> 16, src_y >> 16,
+			src_w >> 16, src_h >> 16);
 	if (ret < 0)
 		return ret;
 
-	exynos_drm_fn_encoder(crtc, overlay,
-			exynos_drm_encoder_crtc_mode_set);
-	exynos_drm_fn_encoder(crtc, &overlay->zpos,
-			exynos_drm_encoder_crtc_plane_commit);
+	plane->crtc = crtc;
+	plane->fb = crtc->fb;
 
-	exynos_plane->enabled = true;
+	exynos_plane_commit(plane);
+	exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
 
 	return 0;
 }
 
 static int exynos_disable_plane(struct drm_plane *plane)
 {
-	struct exynos_plane *exynos_plane =
-		container_of(plane, struct exynos_plane, base);
-	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-	if (!exynos_plane->enabled)
-		return 0;
-
-	exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-			exynos_drm_encoder_crtc_disable);
-
-	exynos_plane->enabled = false;
-	exynos_plane->overlay.zpos = DEFAULT_ZPOS;
+	exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
 
 	return 0;
 }
 
 static void exynos_plane_destroy(struct drm_plane *plane)
 {
-	struct exynos_plane *exynos_plane =
-		container_of(plane, struct exynos_plane, base);
+	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
@@ -103,69 +181,79 @@
 	kfree(exynos_plane);
 }
 
+static int exynos_plane_set_property(struct drm_plane *plane,
+				     struct drm_property *property,
+				     uint64_t val)
+{
+	struct drm_device *dev = plane->dev;
+	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+	struct exynos_drm_private *dev_priv = dev->dev_private;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	if (property == dev_priv->plane_zpos_property) {
+		exynos_plane->overlay.zpos = val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static struct drm_plane_funcs exynos_plane_funcs = {
 	.update_plane	= exynos_update_plane,
 	.disable_plane	= exynos_disable_plane,
 	.destroy	= exynos_plane_destroy,
+	.set_property	= exynos_plane_set_property,
 };
 
-int exynos_plane_init(struct drm_device *dev, unsigned int nr)
+static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
 {
-	struct exynos_plane *exynos_plane;
-	uint32_t possible_crtcs;
-
-	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
-	if (!exynos_plane)
-		return -ENOMEM;
-
-	/* all CRTCs are available */
-	possible_crtcs = (1 << MAX_CRTC) - 1;
-
-	exynos_plane->overlay.zpos = DEFAULT_ZPOS;
-
-	return drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
-			      &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
-			      false);
-}
-
-int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
-				struct drm_file *file_priv)
-{
-	struct drm_exynos_plane_set_zpos *zpos_req = data;
-	struct drm_mode_object *obj;
-	struct drm_plane *plane;
-	struct exynos_plane *exynos_plane;
-	int ret = 0;
+	struct drm_device *dev = plane->dev;
+	struct exynos_drm_private *dev_priv = dev->dev_private;
+	struct drm_property *prop;
 
 	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 
-	if (!drm_core_check_feature(dev, DRIVER_MODESET))
-		return -EINVAL;
+	prop = dev_priv->plane_zpos_property;
+	if (!prop) {
+		prop = drm_property_create_range(dev, 0, "zpos", 0,
+						 MAX_PLANE - 1);
+		if (!prop)
+			return;
 
-	if (zpos_req->zpos < 0 || zpos_req->zpos >= MAX_PLANE) {
-		if (zpos_req->zpos != DEFAULT_ZPOS) {
-			DRM_ERROR("zpos not within limits\n");
-			return -EINVAL;
-		}
+		dev_priv->plane_zpos_property = prop;
 	}
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_object_attach_property(&plane->base, prop, 0);
+}
 
-	obj = drm_mode_object_find(dev, zpos_req->plane_id,
-			DRM_MODE_OBJECT_PLANE);
-	if (!obj) {
-		DRM_DEBUG_KMS("Unknown plane ID %d\n",
-			      zpos_req->plane_id);
-		ret = -EINVAL;
-		goto out;
+struct drm_plane *exynos_plane_init(struct drm_device *dev,
+				    unsigned int possible_crtcs, bool priv)
+{
+	struct exynos_plane *exynos_plane;
+	int err;
+
+	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+	exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
+	if (!exynos_plane) {
+		DRM_ERROR("failed to allocate plane\n");
+		return NULL;
 	}
 
-	plane = obj_to_plane(obj);
-	exynos_plane = container_of(plane, struct exynos_plane, base);
+	err = drm_plane_init(dev, &exynos_plane->base, possible_crtcs,
+			      &exynos_plane_funcs, formats, ARRAY_SIZE(formats),
+			      priv);
+	if (err) {
+		DRM_ERROR("failed to initialize plane\n");
+		kfree(exynos_plane);
+		return NULL;
+	}
 
-	exynos_plane->overlay.zpos = zpos_req->zpos;
+	if (priv)
+		exynos_plane->overlay.zpos = DEFAULT_ZPOS;
+	else
+		exynos_plane_attach_zpos_property(&exynos_plane->base);
 
-out:
-	mutex_unlock(&dev->mode_config.mutex);
-	return ret;
+	return &exynos_plane->base;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h
index 16b71f8..8831245 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h
@@ -9,6 +9,12 @@
  *
  */
 
-int exynos_plane_init(struct drm_device *dev, unsigned int nr);
-int exynos_plane_set_zpos_ioctl(struct drm_device *dev, void *data,
-				struct drm_file *file_priv);
+int exynos_plane_mode_set(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);
+void exynos_plane_commit(struct drm_plane *plane);
+void exynos_plane_dpms(struct drm_plane *plane, int mode);
+struct drm_plane *exynos_plane_init(struct drm_device *dev,
+				    unsigned int possible_crtcs, bool priv);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 7b9c153..bb1550c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -85,8 +85,6 @@
 	0x00, 0x00, 0x00, 0x06
 };
 
-static void vidi_fake_vblank_handler(struct work_struct *work);
-
 static bool vidi_display_is_connected(struct device *dev)
 {
 	struct vidi_context *ctx = get_vidi_context(dev);
@@ -531,6 +529,16 @@
 	if (ctx->connected > 1)
 		return -EINVAL;
 
+	/* use fake edid data for test. */
+	if (!ctx->raw_edid)
+		ctx->raw_edid = (struct edid *)fake_edid_info;
+
+	/* if raw_edid isn't same as fake data then it can't be tested. */
+	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
+		DRM_DEBUG_KMS("edid data is not fake data.\n");
+		return -EINVAL;
+	}
+
 	DRM_DEBUG_KMS("requested connection.\n");
 
 	drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
@@ -549,6 +557,8 @@
 	struct exynos_drm_manager *manager;
 	struct exynos_drm_display_ops *display_ops;
 	struct drm_exynos_vidi_connection *vidi = data;
+	struct edid *raw_edid;
+	int edid_len;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -557,11 +567,6 @@
 		return -EINVAL;
 	}
 
-	if (!vidi->edid) {
-		DRM_DEBUG_KMS("edid data is null.\n");
-		return -EINVAL;
-	}
-
 	if (vidi->connection > 1) {
 		DRM_DEBUG_KMS("connection should be 0 or 1.\n");
 		return -EINVAL;
@@ -588,8 +593,30 @@
 		return -EINVAL;
 	}
 
-	if (vidi->connection)
-		ctx->raw_edid = (struct edid *)vidi->edid;
+	if (vidi->connection) {
+		if (!vidi->edid) {
+			DRM_DEBUG_KMS("edid data is null.\n");
+			return -EINVAL;
+		}
+		raw_edid = (struct edid *)(uint32_t)vidi->edid;
+		edid_len = (1 + raw_edid->extensions) * EDID_LENGTH;
+		ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL);
+		if (!ctx->raw_edid) {
+			DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
+			return -ENOMEM;
+		}
+		memcpy(ctx->raw_edid, raw_edid, edid_len);
+	} else {
+		/*
+		 * with connection = 0, free raw_edid
+		 * only if raw edid data isn't same as fake data.
+		 */
+		if (ctx->raw_edid && ctx->raw_edid !=
+				(struct edid *)fake_edid_info) {
+			kfree(ctx->raw_edid);
+			ctx->raw_edid = NULL;
+		}
+	}
 
 	ctx->connected = vidi->connection;
 	drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
@@ -614,9 +641,6 @@
 
 	INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
 
-	/* for test */
-	ctx->raw_edid = (struct edid *)fake_edid_info;
-
 	subdrv = &ctx->subdrv;
 	subdrv->dev = dev;
 	subdrv->manager = &vidi_manager;
@@ -644,6 +668,11 @@
 
 	exynos_drm_subdrv_unregister(&ctx->subdrv);
 
+	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
+		kfree(ctx->raw_edid);
+		ctx->raw_edid = NULL;
+	}
+
 	kfree(ctx);
 
 	return 0;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 066bde3..409e2ec 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -63,7 +63,6 @@
 	bool				dvi_mode;
 	struct mutex			hdmi_mutex;
 
-	struct resource			*regs_res;
 	void __iomem			*regs;
 	unsigned int			external_irq;
 	unsigned int			internal_irq;
@@ -2280,16 +2279,17 @@
 		return -EINVAL;
 	}
 
-	drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
+	drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
+								GFP_KERNEL);
 	if (!drm_hdmi_ctx) {
 		DRM_ERROR("failed to allocate common hdmi context.\n");
 		return -ENOMEM;
 	}
 
-	hdata = kzalloc(sizeof(struct hdmi_context), GFP_KERNEL);
+	hdata = devm_kzalloc(&pdev->dev, sizeof(struct hdmi_context),
+								GFP_KERNEL);
 	if (!hdata) {
 		DRM_ERROR("out of memory\n");
-		kfree(drm_hdmi_ctx);
 		return -ENOMEM;
 	}
 
@@ -2318,26 +2318,18 @@
 		goto err_resource;
 	}
 
-	hdata->regs_res = request_mem_region(res->start, resource_size(res),
-					   dev_name(dev));
-	if (!hdata->regs_res) {
-		DRM_ERROR("failed to claim register region\n");
-		ret = -ENOENT;
-		goto err_resource;
-	}
-
-	hdata->regs = ioremap(res->start, resource_size(res));
+	hdata->regs = devm_request_and_ioremap(&pdev->dev, res);
 	if (!hdata->regs) {
 		DRM_ERROR("failed to map registers\n");
 		ret = -ENXIO;
-		goto err_req_region;
+		goto err_resource;
 	}
 
 	/* DDC i2c driver */
 	if (i2c_add_driver(&ddc_driver)) {
 		DRM_ERROR("failed to register ddc i2c driver\n");
 		ret = -ENOENT;
-		goto err_iomap;
+		goto err_resource;
 	}
 
 	hdata->ddc_port = hdmi_ddc;
@@ -2398,16 +2390,9 @@
 	i2c_del_driver(&hdmiphy_driver);
 err_ddc:
 	i2c_del_driver(&ddc_driver);
-err_iomap:
-	iounmap(hdata->regs);
-err_req_region:
-	release_mem_region(hdata->regs_res->start,
-			resource_size(hdata->regs_res));
 err_resource:
 	hdmi_resources_cleanup(hdata);
 err_data:
-	kfree(hdata);
-	kfree(drm_hdmi_ctx);
 	return ret;
 }
 
@@ -2425,18 +2410,11 @@
 
 	hdmi_resources_cleanup(hdata);
 
-	iounmap(hdata->regs);
-
-	release_mem_region(hdata->regs_res->start,
-			resource_size(hdata->regs_res));
-
 	/* hdmiphy i2c driver */
 	i2c_del_driver(&hdmiphy_driver);
 	/* DDC i2c driver */
 	i2c_del_driver(&ddc_driver);
 
-	kfree(hdata);
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index e2147a2..30fcc12 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -956,7 +956,8 @@
 
 	clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
 
-	mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
+	mixer_res->mixer_regs = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
 	if (mixer_res->mixer_regs == NULL) {
 		dev_err(dev, "register mapping failed.\n");
 		ret = -ENXIO;
@@ -967,38 +968,34 @@
 	if (res == NULL) {
 		dev_err(dev, "get memory resource failed.\n");
 		ret = -ENXIO;
-		goto fail_mixer_regs;
+		goto fail;
 	}
 
-	mixer_res->vp_regs = ioremap(res->start, resource_size(res));
+	mixer_res->vp_regs = devm_ioremap(&pdev->dev, res->start,
+							resource_size(res));
 	if (mixer_res->vp_regs == NULL) {
 		dev_err(dev, "register mapping failed.\n");
 		ret = -ENXIO;
-		goto fail_mixer_regs;
+		goto fail;
 	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
 	if (res == NULL) {
 		dev_err(dev, "get interrupt resource failed.\n");
 		ret = -ENXIO;
-		goto fail_vp_regs;
+		goto fail;
 	}
 
-	ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
+	ret = devm_request_irq(&pdev->dev, res->start, mixer_irq_handler,
+							0, "drm_mixer", ctx);
 	if (ret) {
 		dev_err(dev, "request interrupt failed.\n");
-		goto fail_vp_regs;
+		goto fail;
 	}
 	mixer_res->irq = res->start;
 
 	return 0;
 
-fail_vp_regs:
-	iounmap(mixer_res->vp_regs);
-
-fail_mixer_regs:
-	iounmap(mixer_res->mixer_regs);
-
 fail:
 	if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
 		clk_put(mixer_res->sclk_dac);
@@ -1013,16 +1010,6 @@
 	return ret;
 }
 
-static void mixer_resources_cleanup(struct mixer_context *ctx)
-{
-	struct mixer_resources *res = &ctx->mixer_res;
-
-	free_irq(res->irq, ctx);
-
-	iounmap(res->vp_regs);
-	iounmap(res->mixer_regs);
-}
-
 static int __devinit mixer_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1032,16 +1019,16 @@
 
 	dev_info(dev, "probe start\n");
 
-	drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
+	drm_hdmi_ctx = devm_kzalloc(&pdev->dev, sizeof(*drm_hdmi_ctx),
+								GFP_KERNEL);
 	if (!drm_hdmi_ctx) {
 		DRM_ERROR("failed to allocate common hdmi context.\n");
 		return -ENOMEM;
 	}
 
-	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx) {
 		DRM_ERROR("failed to alloc mixer context.\n");
-		kfree(drm_hdmi_ctx);
 		return -ENOMEM;
 	}
 
@@ -1072,17 +1059,10 @@
 
 static int mixer_remove(struct platform_device *pdev)
 {
-	struct device *dev = &pdev->dev;
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx =
-					platform_get_drvdata(pdev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
-
-	dev_info(dev, "remove successful\n");
+	dev_info(&pdev->dev, "remove successful\n");
 
 	pm_runtime_disable(&pdev->dev);
 
-	mixer_resources_cleanup(ctx);
-
 	return 0;
 }
 
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 6873358..c20b001 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -107,11 +107,6 @@
 	uint64_t edid;
 };
 
-struct drm_exynos_plane_set_zpos {
-	__u32 plane_id;
-	__s32 zpos;
-};
-
 /* memory type definitions. */
 enum e_drm_exynos_gem_mem_type {
 	/* Physically Continuous memory and used as default. */
@@ -164,7 +159,6 @@
 #define DRM_EXYNOS_GEM_MMAP		0x02
 /* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
 #define DRM_EXYNOS_GEM_GET		0x04
-#define DRM_EXYNOS_PLANE_SET_ZPOS	0x06
 #define DRM_EXYNOS_VIDI_CONNECTION	0x07
 
 /* G2D */
@@ -184,9 +178,6 @@
 #define DRM_IOCTL_EXYNOS_GEM_GET	DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_GEM_GET,	struct drm_exynos_gem_info)
 
-#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS	DRM_IOWR(DRM_COMMAND_BASE + \
-		DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
-
 #define DRM_IOCTL_EXYNOS_VIDI_CONNECTION	DRM_IOWR(DRM_COMMAND_BASE + \
 		DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)