[PATCH] drm: Add Drm driver for Rockchip Socs

mark yao mark.yao at rock-chips.com
Thu Jul 3 04:08:13 PDT 2014


From: mark <mark.yao at rock-chips.com>

This patch is a DRM Driver for Rockchip Socs and now only add the
framework of Rockchips Socs, but we will add Rockchips Socs soon.

Signed-off-by: mark <mark.yao at rock-chips.com>
---
 drivers/gpu/drm/Kconfig                           |    2 +
 drivers/gpu/drm/Makefile                          |    1 +
 drivers/gpu/drm/rockchip/Kconfig                  |   35 +
 drivers/gpu/drm/rockchip/Makefile                 |   14 +
 drivers/gpu/drm/rockchip/rockchip_drm_buf.c       |  191 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_buf.h       |   39 ++
 drivers/gpu/drm/rockchip/rockchip_drm_connector.c |  261 ++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_connector.h |   24 +
 drivers/gpu/drm/rockchip/rockchip_drm_core.c      |  163 +++++
 drivers/gpu/drm/rockchip/rockchip_drm_crtc.c      |  515 ++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_crtc.h      |   42 ++
 drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c    |  290 ++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h    |   32 +
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c       |  618 +++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h       |  319 +++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_encoder.c   |  206 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_encoder.h   |   30 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c        |  333 ++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_fb.h        |   39 ++
 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c     |  380 +++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h     |   26 +
 drivers/gpu/drm/rockchip/rockchip_drm_gem.c       |  738 +++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_gem.h       |  198 ++++++
 drivers/gpu/drm/rockchip/rockchip_drm_iommu.c     |  149 +++++
 drivers/gpu/drm/rockchip/rockchip_drm_iommu.h     |   76 +++
 drivers/gpu/drm/rockchip/rockchip_drm_plane.c     |  290 ++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_plane.h     |   30 +
 include/uapi/drm/rockchip_drm.h                   |  155 +++++
 28 files changed, 5196 insertions(+)
 create mode 100644 drivers/gpu/drm/rockchip/Kconfig
 create mode 100644 drivers/gpu/drm/rockchip/Makefile
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_buf.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_buf.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_connector.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_connector.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_core.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_crtc.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_crtc.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_drv.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_drv.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_encoder.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_encoder.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_fb.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_fb.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_gem.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_gem.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_iommu.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_iommu.h
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_plane.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_plane.h
 create mode 100644 include/uapi/drm/rockchip_drm.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index f512004..5951c2c 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -170,6 +170,8 @@ config DRM_SAVAGE
 
 source "drivers/gpu/drm/exynos/Kconfig"
 
+source "drivers/gpu/drm/rockchip/Kconfig"
+
 source "drivers/gpu/drm/vmwgfx/Kconfig"
 
 source "drivers/gpu/drm/gma500/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index dd2ba42..40babd2 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
 obj-$(CONFIG_DRM_VIA)	+=via/
 obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
+obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/
 obj-$(CONFIG_DRM_GMA500) += gma500/
 obj-$(CONFIG_DRM_UDL) += udl/
 obj-$(CONFIG_DRM_AST) += ast/
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
new file mode 100644
index 0000000..9350316
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -0,0 +1,35 @@
+config DRM_ROCKCHIP
+	tristate "DRM Support for Rockchip "
+	depends on DRM
+	select DRM_KMS_HELPER
+	select DRM_KMS_FB_HELPER
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
+	select VIDEOMODE_HELPERS
+	select OF
+	help
+	  Choose this option if you have a  ROCKCHIP soc chipset.
+	  support will be included for lcd controller and display interface.
+	  use dma buffer and iommu to get continus Continuous memory.
+	  If M is selected the module will be called rockchipdrm.
+
+config DRM_ROCKCHIP_IOMMU
+	bool "ROCKCHIP DRM IOMMU Support"
+	depends on DRM_ROCKCHIP && ARM_DMA_USE_IOMMU
+	help
+	  Choose this option if you want to use IOMMU feature for DRM.
+	  support will be included for rk3288 lcd controller.
+	  the IOMMU takes care of mapping device-visible virtual addresses
+	  to physical addresses.
+
+
+config DRM_ROCKCHIP_DMABUF
+	bool "ROCKCHIP DRM DMABUF"
+	depends on DRM_ROCKCHIP
+	help
+	  Choose this option if you want to use DMABUF feature for DRM.
+	  device drivers need dma buffers, we should use dma mapping APIs,
+	  if DRM_ROCKCHIP_IOMMU is not support, CMA should work behind
+	  kernel DMA mapping.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
new file mode 100644
index 0000000..6768319
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/rockchip
+rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_encoder.o \
+		rockchip_drm_crtc.o rockchip_drm_fbdev.o rockchip_drm_fb.o \
+		rockchip_drm_buf.o rockchip_drm_gem.o rockchip_drm_core.o \
+		rockchip_drm_plane.o
+
+rockchipdrm-$(CONFIG_DRM_ROCKCHIP_IOMMU) += rockchip_drm_iommu.o
+rockchipdrm-$(CONFIG_DRM_ROCKCHIP_DMABUF) += rockchip_drm_dmabuf.o
+
+obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_buf.c b/drivers/gpu/drm/rockchip/rockchip_drm_buf.c
new file mode 100644
index 0000000..513d7c1
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_buf.c
@@ -0,0 +1,191 @@
+/* rockchip_drm_buf.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_buf.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_buf.h"
+#include "rockchip_drm_iommu.h"
+
+static int lowlevel_buffer_allocate(struct drm_device *dev,
+		unsigned int flags, struct rockchip_drm_gem_buf *buf)
+{
+	int ret = 0;
+	enum dma_attr attr;
+	unsigned int nr_pages;
+
+	if (buf->dma_addr) {
+		DRM_DEBUG_KMS("already allocated.\n");
+		return 0;
+	}
+
+	init_dma_attrs(&buf->dma_attrs);
+
+	/*
+	 * if ROCKCHIP_BO_CONTIG, fully physically contiguous memory
+	 * region will be allocated else physically contiguous
+	 * as possible.
+	 */
+	if (!(flags & ROCKCHIP_BO_NONCONTIG))
+		dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);
+
+	/*
+	 * if ROCKCHIP_BO_WC or ROCKCHIP_BO_NONCACHABLE, writecombine mapping
+	 * else cachable mapping.
+	 */
+	if (flags & ROCKCHIP_BO_WC || !(flags & ROCKCHIP_BO_CACHABLE))
+		attr = DMA_ATTR_WRITE_COMBINE;
+	else
+		attr = DMA_ATTR_NON_CONSISTENT;
+
+	dma_set_attr(attr, &buf->dma_attrs);
+	dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);
+
+	nr_pages = buf->size >> PAGE_SHIFT;
+
+	if (!is_drm_iommu_supported(dev)) {
+		dma_addr_t start_addr;
+		unsigned int i = 0;
+
+		buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
+		if (!buf->pages) {
+			DRM_ERROR("failed to allocate pages.\n");
+			return -ENOMEM;
+		}
+
+		buf->kvaddr = (void __iomem *)dma_alloc_attrs(dev->dev,
+					buf->size,
+					&buf->dma_addr, GFP_KERNEL,
+					&buf->dma_attrs);
+		if (!buf->kvaddr) {
+			DRM_ERROR("failed to allocate buffer.\n");
+			ret = -ENOMEM;
+			goto err_free;
+		}
+
+		start_addr = buf->dma_addr;
+		while (i < nr_pages) {
+			buf->pages[i] = phys_to_page(start_addr);
+			start_addr += PAGE_SIZE;
+			i++;
+		}
+	} else {
+
+		buf->pages = dma_alloc_attrs(dev->dev, buf->size,
+					&buf->dma_addr, GFP_KERNEL,
+					&buf->dma_attrs);
+		if (!buf->pages) {
+			DRM_ERROR("failed to allocate buffer.\n");
+			return -ENOMEM;
+		}
+	}
+
+	buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
+	if (IS_ERR(buf->sgt)) {
+		DRM_ERROR("failed to get sg table.\n");
+		ret = PTR_ERR(buf->sgt);
+		goto err_free_attrs;
+	}
+
+	DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
+			(unsigned long)buf->dma_addr,
+			buf->size);
+
+	return ret;
+
+err_free_attrs:
+	dma_free_attrs(dev->dev, buf->size, buf->pages,
+			(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
+	buf->dma_addr = (dma_addr_t)NULL;
+err_free:
+	if (!is_drm_iommu_supported(dev))
+		drm_free_large(buf->pages);
+
+	return ret;
+}
+
+static void lowlevel_buffer_deallocate(struct drm_device *dev,
+		unsigned int flags, struct rockchip_drm_gem_buf *buf)
+{
+	if (!buf->dma_addr) {
+		DRM_DEBUG_KMS("dma_addr is invalid.\n");
+		return;
+	}
+
+	DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
+			(unsigned long)buf->dma_addr,
+			buf->size);
+
+	sg_free_table(buf->sgt);
+
+	kfree(buf->sgt);
+	buf->sgt = NULL;
+
+	if (!is_drm_iommu_supported(dev)) {
+		dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
+				(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
+		drm_free_large(buf->pages);
+	} else
+		dma_free_attrs(dev->dev, buf->size, buf->pages,
+				(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
+
+	buf->dma_addr = (dma_addr_t)NULL;
+}
+
+struct rockchip_drm_gem_buf *rockchip_drm_init_buf(struct drm_device *dev,
+						unsigned int size)
+{
+	struct rockchip_drm_gem_buf *buffer;
+
+	DRM_DEBUG_KMS("desired size = 0x%x\n", size);
+
+	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+	if (!buffer)
+		return NULL;
+
+	buffer->size = size;
+
+	return buffer;
+}
+
+void rockchip_drm_fini_buf(struct drm_device *dev,
+				struct rockchip_drm_gem_buf *buffer)
+{
+	kfree(buffer);
+	buffer = NULL;
+}
+
+int rockchip_drm_alloc_buf(struct drm_device *dev,
+		struct rockchip_drm_gem_buf *buf, unsigned int flags)
+{
+	/*
+	 * allocate memory region and set the memory information
+	 * to vaddr and dma_addr of a buffer object.
+	 */
+	if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void rockchip_drm_free_buf(struct drm_device *dev,
+		unsigned int flags, struct rockchip_drm_gem_buf *buffer)
+{
+	lowlevel_buffer_deallocate(dev, flags, buffer);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_buf.h b/drivers/gpu/drm/rockchip/rockchip_drm_buf.h
new file mode 100644
index 0000000..a4e5d00
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_buf.h
@@ -0,0 +1,39 @@
+/* rockchip_drm_buf.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_buf.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_BUF_H_
+#define _ROCKCHIP_DRM_BUF_H_
+
+/* create and initialize buffer object. */
+struct rockchip_drm_gem_buf *rockchip_drm_init_buf(struct drm_device *dev,
+						unsigned int size);
+
+/* destroy buffer object. */
+void rockchip_drm_fini_buf(struct drm_device *dev,
+				struct rockchip_drm_gem_buf *buffer);
+
+/* allocate physical memory region and setup sgt. */
+int rockchip_drm_alloc_buf(struct drm_device *dev,
+				struct rockchip_drm_gem_buf *buf,
+				unsigned int flags);
+
+/* release physical memory region, and sgt. */
+void rockchip_drm_free_buf(struct drm_device *dev,
+				unsigned int flags,
+				struct rockchip_drm_gem_buf *buffer);
+
+#endif /* _ROCKCHIP_DRM_BUF_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_connector.c b/drivers/gpu/drm/rockchip/rockchip_drm_connector.c
new file mode 100644
index 0000000..3005788
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_connector.c
@@ -0,0 +1,261 @@
+/* rockchip_drm_connector.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_connector.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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_crtc_helper.h>
+
+#include <drm/rockchip_drm.h>
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_connector.h"
+
+#define to_rockchip_connector(x) \
+		container_of(x, struct rockchip_drm_connector, drm_connector)
+
+struct rockchip_drm_connector {
+	struct drm_connector drm_connector;
+	struct rockchip_drm_display *display;
+	uint32_t encoder_id;
+};
+
+static int rockchip_drm_connector_get_modes(struct drm_connector *connector)
+{
+	struct rockchip_drm_connector *rockchip_connector =
+					to_rockchip_connector(connector);
+	struct rockchip_drm_display *display = rockchip_connector->display;
+	struct edid *edid = NULL;
+	unsigned int count = 0;
+	int ret;
+
+	/*
+	 * if get_edid() exists then get_edid() callback of hdmi side
+	 * is called to get edid data through i2c interface else
+	 * get timing from the FIMD driver(display controller).
+	 *
+	 * P.S. in case of lcd panel, count is always 1 if success
+	 * because lcd panel has only one mode.
+	 */
+	if (display->ops->get_edid) {
+		edid = display->ops->get_edid(display, connector);
+		if (IS_ERR_OR_NULL(edid)) {
+			ret = PTR_ERR(edid);
+			edid = NULL;
+			DRM_ERROR("Panel operation get_edid failed %d\n", ret);
+			goto out;
+		}
+
+		count = drm_add_edid_modes(connector, edid);
+		if (!count) {
+			DRM_ERROR("Add edid modes failed %d\n", count);
+			goto out;
+		}
+
+		drm_mode_connector_update_edid_property(connector, edid);
+	} else {
+		struct rockchip_drm_panel_info *panel;
+		struct drm_display_mode *mode =
+					drm_mode_create(connector->dev);
+		if (!mode) {
+			DRM_ERROR("failed to create a new display mode.\n");
+			return 0;
+		}
+
+		if (display->ops->get_panel)
+			panel = display->ops->get_panel(display);
+		else {
+			drm_mode_destroy(connector->dev, mode);
+			return 0;
+		}
+
+		drm_display_mode_from_videomode(&panel->vm, mode);
+		mode->width_mm = panel->width_mm;
+		mode->height_mm = panel->height_mm;
+		connector->display_info.width_mm = mode->width_mm;
+		connector->display_info.height_mm = mode->height_mm;
+
+		mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+		drm_mode_set_name(mode);
+		drm_mode_probed_add(connector, mode);
+
+		count = 1;
+	}
+
+out:
+	kfree(edid);
+	return count;
+}
+
+static int rockchip_drm_connector_mode_valid(struct drm_connector *connector,
+					    struct drm_display_mode *mode)
+{
+	struct rockchip_drm_connector *rockchip_connector =
+					to_rockchip_connector(connector);
+	struct rockchip_drm_display *display = rockchip_connector->display;
+	int ret = MODE_BAD;
+
+	if (display->ops->check_mode)
+		if (!display->ops->check_mode(display, mode))
+			ret = MODE_OK;
+
+	return ret;
+}
+
+static struct drm_encoder *rockchip_drm_best_encoder(
+		struct drm_connector *connector)
+{
+	struct drm_device *dev = connector->dev;
+	struct rockchip_drm_connector *rockchip_connector =
+					to_rockchip_connector(connector);
+	struct drm_mode_object *obj;
+	struct drm_encoder *encoder;
+
+	obj = drm_mode_object_find(dev, rockchip_connector->encoder_id,
+				   DRM_MODE_OBJECT_ENCODER);
+	if (!obj) {
+		DRM_DEBUG_KMS("Unknown ENCODER ID %d\n",
+				rockchip_connector->encoder_id);
+		return NULL;
+	}
+
+	encoder = obj_to_encoder(obj);
+
+	return encoder;
+}
+
+static struct drm_connector_helper_funcs rockchip_connector_helper_funcs = {
+	.get_modes = rockchip_drm_connector_get_modes,
+	.mode_valid = rockchip_drm_connector_mode_valid,
+	.best_encoder = rockchip_drm_best_encoder,
+};
+
+static int rockchip_drm_connector_fill_modes(struct drm_connector *connector,
+			unsigned int max_width, unsigned int max_height)
+{
+	struct rockchip_drm_connector *rockchip_connector =
+					to_rockchip_connector(connector);
+	struct rockchip_drm_display *display = rockchip_connector->display;
+	unsigned int width, height;
+
+	width = max_width;
+	height = max_height;
+
+	/*
+	 * if specific driver want to find desired_mode using maxmum
+	 * resolution then get max width and height from that driver.
+	 */
+	if (display->ops->get_max_resol)
+		display->ops->get_max_resol(display, &width, &height);
+
+	return drm_helper_probe_single_connector_modes(connector, width,
+							height);
+}
+
+/* get detection status of display device. */
+static enum drm_connector_status
+rockchip_drm_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct rockchip_drm_connector *rockchip_connector =
+					to_rockchip_connector(connector);
+	struct rockchip_drm_display *display = rockchip_connector->display;
+	enum drm_connector_status status = connector_status_disconnected;
+
+	if (display->ops->is_connected) {
+		if (display->ops->is_connected(display))
+			status = connector_status_connected;
+		else
+			status = connector_status_disconnected;
+	}
+
+	return status;
+}
+
+static void rockchip_drm_connector_destroy(struct drm_connector *connector)
+{
+	struct rockchip_drm_connector *rockchip_connector =
+		to_rockchip_connector(connector);
+
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+	kfree(rockchip_connector);
+}
+
+static struct drm_connector_funcs rockchip_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = rockchip_drm_connector_fill_modes,
+	.detect = rockchip_drm_connector_detect,
+	.destroy = rockchip_drm_connector_destroy,
+};
+
+struct drm_connector *rockchip_drm_connector_create(struct drm_device *dev,
+						   struct drm_encoder *encoder)
+{
+	struct rockchip_drm_connector *rockchip_connector;
+	struct rockchip_drm_display *display =
+				rockchip_drm_get_display(encoder);
+	struct drm_connector *connector;
+	int type;
+	int err;
+
+	rockchip_connector = kzalloc(sizeof(*rockchip_connector), GFP_KERNEL);
+	if (!rockchip_connector)
+		return NULL;
+
+	connector = &rockchip_connector->drm_connector;
+
+	switch (display->type) {
+	case ROCKCHIP_DISPLAY_TYPE_HDMI:
+		type = DRM_MODE_CONNECTOR_HDMIA;
+		connector->interlace_allowed = true;
+		connector->polled = DRM_CONNECTOR_POLL_HPD;
+		break;
+	case ROCKCHIP_DISPLAY_TYPE_LCD:
+		type = DRM_MODE_CONNECTOR_LVDS;
+		break;
+	default:
+		type = DRM_MODE_CONNECTOR_Unknown;
+		break;
+	}
+
+	drm_connector_init(dev, connector, &rockchip_connector_funcs, type);
+	drm_connector_helper_add(connector, &rockchip_connector_helper_funcs);
+
+	err = drm_sysfs_connector_add(connector);
+	if (err)
+		goto err_connector;
+
+	rockchip_connector->encoder_id = encoder->base.id;
+	rockchip_connector->display = display;
+	connector->dpms = DRM_MODE_DPMS_OFF;
+	connector->encoder = encoder;
+
+	err = drm_mode_connector_attach_encoder(connector, encoder);
+	if (err) {
+		DRM_ERROR("failed to attach a connector to a encoder\n");
+		goto err_sysfs;
+	}
+
+	DRM_DEBUG_KMS("connector has been created\n");
+
+	return connector;
+
+err_sysfs:
+	drm_sysfs_connector_remove(connector);
+err_connector:
+	drm_connector_cleanup(connector);
+	kfree(rockchip_connector);
+	return NULL;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_connector.h b/drivers/gpu/drm/rockchip/rockchip_drm_connector.h
new file mode 100644
index 0000000..6235aba
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_connector.h
@@ -0,0 +1,24 @@
+/* rockchip_drm_connector.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_connector.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_CONNECTOR_H_
+#define _ROCKCHIP_DRM_CONNECTOR_H_
+
+struct drm_connector *rockchip_drm_connector_create(struct drm_device *dev,
+						struct drm_encoder *encoder);
+
+#endif /* _ROCKCHIP_DRM_CONNECTOR_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_core.c b/drivers/gpu/drm/rockchip/rockchip_drm_core.c
new file mode 100644
index 0000000..ebdd3d0
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_core.c
@@ -0,0 +1,163 @@
+/* rockchip_drm_core.c
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_core.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 "rockchip_drm_drv.h"
+#include "rockchip_drm_crtc.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_fbdev.h"
+
+static LIST_HEAD(rockchip_drm_subdrv_list);
+
+int rockchip_drm_create_enc_conn(struct drm_device *dev,
+					struct rockchip_drm_display *display)
+{
+	struct drm_encoder *encoder;
+	int ret;
+	unsigned long possible_crtcs = 0;
+
+	ret = rockchip_drm_crtc_get_pipe_from_type(dev, display->type);
+	if (ret < 0)
+		return ret;
+
+	possible_crtcs |= 1 << ret;
+
+	/* create and initialize a encoder for this sub driver. */
+	encoder = rockchip_drm_encoder_create(dev, display, possible_crtcs);
+	if (!encoder) {
+		DRM_ERROR("failed to create encoder\n");
+		return -EFAULT;
+	}
+
+	display->encoder = encoder;
+
+	ret = display->ops->create_connector(display, encoder);
+	if (ret) {
+		DRM_ERROR("failed to create connector ret = %d\n", ret);
+		goto err_destroy_encoder;
+	}
+
+	return 0;
+
+err_destroy_encoder:
+	encoder->funcs->destroy(encoder);
+	return ret;
+}
+
+int rockchip_drm_subdrv_register(struct rockchip_drm_subdrv *subdrv)
+{
+	if (!subdrv)
+		return -EINVAL;
+
+	list_add_tail(&subdrv->list, &rockchip_drm_subdrv_list);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_register);
+
+int rockchip_drm_subdrv_unregister(struct rockchip_drm_subdrv *subdrv)
+{
+	if (!subdrv)
+		return -EINVAL;
+
+	list_del(&subdrv->list);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_unregister);
+
+int rockchip_drm_device_subdrv_probe(struct drm_device *dev)
+{
+	struct rockchip_drm_subdrv *subdrv, *n;
+	int err;
+
+	if (!dev)
+		return -EINVAL;
+
+	list_for_each_entry_safe(subdrv, n, &rockchip_drm_subdrv_list, list) {
+		if (subdrv->probe) {
+			subdrv->drm_dev = dev;
+
+			/*
+			 * this probe callback would be called by sub driver
+			 * after setting of all resources to this sub driver,
+			 * such as clock, irq and register map are done.
+			 */
+			err = subdrv->probe(dev, subdrv->dev);
+			if (err) {
+				DRM_DEBUG("rockchip drm subdrv probe fail.\n");
+				list_del(&subdrv->list);
+				continue;
+			}
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_device_subdrv_probe);
+
+int rockchip_drm_device_subdrv_remove(struct drm_device *dev)
+{
+	struct rockchip_drm_subdrv *subdrv;
+
+	if (!dev) {
+		WARN(1, "Unexpected drm device unregister!\n");
+		return -EINVAL;
+	}
+
+	list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) {
+		if (subdrv->remove)
+			subdrv->remove(dev, subdrv->dev);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_device_subdrv_remove);
+
+int rockchip_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
+{
+	struct rockchip_drm_subdrv *subdrv;
+	int ret;
+
+	list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) {
+		if (subdrv->open) {
+			ret = subdrv->open(dev, subdrv->dev, file);
+			if (ret)
+				goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	list_for_each_entry_reverse(subdrv, &subdrv->list, list) {
+		if (subdrv->close)
+			subdrv->close(dev, subdrv->dev, file);
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_open);
+
+void rockchip_drm_subdrv_close(struct drm_device *dev, struct drm_file *file)
+{
+	struct rockchip_drm_subdrv *subdrv;
+
+	list_for_each_entry(subdrv, &rockchip_drm_subdrv_list, list) {
+		if (subdrv->close)
+			subdrv->close(dev, subdrv->dev, file);
+	}
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_subdrv_close);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_crtc.c b/drivers/gpu/drm/rockchip/rockchip_drm_crtc.c
new file mode 100644
index 0000000..2400940
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_crtc.c
@@ -0,0 +1,515 @@
+/* rockchip_drm_crtc.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_crtc.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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_crtc_helper.h>
+
+#include "rockchip_drm_crtc.h"
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_plane.h"
+
+#define to_rockchip_crtc(x)	container_of(x, struct rockchip_drm_crtc,\
+				drm_crtc)
+
+enum rockchip_crtc_mode {
+	/* normal mode */
+	CRTC_MODE_NORMAL,
+	/* The private plane of crtc is blank */
+	CRTC_MODE_BLANK,
+};
+
+/*
+ * Rockchip specific crtc structure.
+ *
+ * @drm_crtc: crtc object.
+ * @drm_plane: pointer of private plane object for this crtc
+ * @manager: the manager associated with 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
+ *      array when irq interrupt occurred. the reason of using this pipe is that
+ *      drm framework doesn't support multiple irq yet.
+ *      we can refer to the crtc to current hardware interrupt occurred through
+ *      this pipe value.
+ * @dpms: store the crtc dpms value
+ * @mode: store the crtc mode value
+ */
+struct rockchip_drm_crtc {
+	struct drm_crtc drm_crtc;
+	struct drm_plane *plane;
+	struct rockchip_drm_manager *manager;
+	wait_queue_head_t pending_flip_queue;
+	enum rockchip_crtc_mode mode;
+	atomic_t pending_flip;
+	unsigned int pipe;
+	unsigned int dpms;
+};
+
+static void rockchip_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+	struct rockchip_drm_manager *manager = rockchip_crtc->manager;
+
+	DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
+
+	if (rockchip_crtc->dpms == mode) {
+		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
+		return;
+	}
+
+	if (mode > DRM_MODE_DPMS_ON) {
+		/* wait for the completion of page flip. */
+		wait_event(rockchip_crtc->pending_flip_queue,
+			atomic_read(&rockchip_crtc->pending_flip) == 0);
+		drm_vblank_off(crtc->dev, rockchip_crtc->pipe);
+	}
+
+	if (manager->ops->dpms)
+		manager->ops->dpms(manager, mode);
+
+	rockchip_crtc->dpms = mode;
+}
+
+static void rockchip_drm_crtc_prepare(struct drm_crtc *crtc)
+{
+	/* drm framework doesn't check NULL. */
+}
+
+static void rockchip_drm_crtc_commit(struct drm_crtc *crtc)
+{
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+	struct rockchip_drm_manager *manager = rockchip_crtc->manager;
+
+	rockchip_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
+	rockchip_plane_commit(rockchip_crtc->plane);
+
+	if (manager->ops->commit)
+		manager->ops->commit(manager);
+
+	rockchip_plane_dpms(rockchip_crtc->plane, DRM_MODE_DPMS_ON);
+}
+
+static bool rockchip_drm_crtc_mode_fixup(struct drm_crtc *crtc,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+	struct rockchip_drm_manager *manager = rockchip_crtc->manager;
+
+	if (manager->ops->mode_fixup)
+		return manager->ops->mode_fixup(manager, mode, adjusted_mode);
+
+	return true;
+}
+
+static int rockchip_drm_crtc_mode_set(struct drm_crtc *crtc,
+			struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode, int x, int y,
+			struct drm_framebuffer *old_fb)
+{
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+	struct rockchip_drm_manager *manager = rockchip_crtc->manager;
+	struct drm_plane *plane = rockchip_crtc->plane;
+	unsigned int crtc_w;
+	unsigned int crtc_h;
+	int ret;
+
+	/*
+	 * 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));
+
+	crtc_w = crtc->primary->fb->width - x;
+	crtc_h = crtc->primary->fb->height - y;
+
+	if (manager->ops->mode_set)
+		manager->ops->mode_set(manager, &crtc->mode);
+
+	ret = rockchip_plane_mode_set(plane, crtc, crtc->primary->fb,
+					0, 0, crtc_w, crtc_h,
+					x, y, crtc_w, crtc_h);
+	if (ret)
+		return ret;
+
+	plane->crtc = crtc;
+	plane->fb = crtc->primary->fb;
+	drm_framebuffer_reference(plane->fb);
+
+	return 0;
+}
+
+static int rockchip_drm_crtc_mode_set_commit(struct drm_crtc *crtc,
+				int x, int y, struct drm_framebuffer *old_fb)
+{
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+	struct drm_plane *plane = rockchip_crtc->plane;
+	unsigned int crtc_w;
+	unsigned int crtc_h;
+	int ret;
+
+	/* when framebuffer changing is requested, crtc's dpms should be on */
+	if (rockchip_crtc->dpms > DRM_MODE_DPMS_ON) {
+		DRM_ERROR("failed framebuffer changing request.\n");
+		return -EPERM;
+	}
+
+	crtc_w = crtc->primary->fb->width - x;
+	crtc_h = crtc->primary->fb->height - y;
+
+	ret = rockchip_plane_mode_set(plane, crtc, crtc->primary->fb,
+				0, 0, crtc_w, crtc_h, x, y, crtc_w, crtc_h);
+	if (ret)
+		return ret;
+
+	rockchip_drm_crtc_commit(crtc);
+
+	return 0;
+}
+
+static int rockchip_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+					  struct drm_framebuffer *old_fb)
+{
+	return rockchip_drm_crtc_mode_set_commit(crtc, x, y, old_fb);
+}
+
+static void rockchip_drm_crtc_disable(struct drm_crtc *crtc)
+{
+	struct drm_plane *plane;
+	int ret;
+
+	rockchip_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+	drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
+		if (plane->crtc != crtc)
+			continue;
+
+		ret = plane->funcs->disable_plane(plane);
+		if (ret)
+			DRM_ERROR("Failed to disable plane %d\n", ret);
+	}
+}
+
+static struct drm_crtc_helper_funcs rockchip_crtc_helper_funcs = {
+	.dpms = rockchip_drm_crtc_dpms,
+	.prepare = rockchip_drm_crtc_prepare,
+	.commit = rockchip_drm_crtc_commit,
+	.mode_fixup = rockchip_drm_crtc_mode_fixup,
+	.mode_set = rockchip_drm_crtc_mode_set,
+	.mode_set_base = rockchip_drm_crtc_mode_set_base,
+	.disable = rockchip_drm_crtc_disable,
+};
+
+static int rockchip_drm_crtc_page_flip(struct drm_crtc *crtc,
+				     struct drm_framebuffer *fb,
+				     struct drm_pending_vblank_event *event,
+				     uint32_t page_flip_flags)
+{
+	struct drm_device *dev = crtc->dev;
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+	struct drm_framebuffer *old_fb = crtc->primary->fb;
+	int ret = -EINVAL;
+
+	/* when the page flip is requested, crtc's dpms should be on */
+	if (rockchip_crtc->dpms > DRM_MODE_DPMS_ON) {
+		DRM_ERROR("failed page flip request.\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&dev->struct_mutex);
+
+	if (event) {
+		/*
+		 * the pipe from user always is 0 so we can set pipe number
+		 * of current owner to event.
+		 */
+		event->pipe = rockchip_crtc->pipe;
+
+		ret = drm_vblank_get(dev, rockchip_crtc->pipe);
+		if (ret) {
+			DRM_DEBUG("failed to acquire vblank counter\n");
+
+			goto out;
+		}
+
+		spin_lock_irq(&dev->event_lock);
+		list_add_tail(&event->base.link,
+				&dev_priv->pageflip_event_list);
+		atomic_set(&rockchip_crtc->pending_flip, 1);
+		spin_unlock_irq(&dev->event_lock);
+
+		crtc->primary->fb = fb;
+		ret = rockchip_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
+						    NULL);
+		if (ret) {
+			crtc->primary->fb = old_fb;
+
+			spin_lock_irq(&dev->event_lock);
+			drm_vblank_put(dev, rockchip_crtc->pipe);
+			list_del(&event->base.link);
+			spin_unlock_irq(&dev->event_lock);
+
+			goto out;
+		}
+	}
+out:
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
+
+static void rockchip_drm_crtc_destroy(struct drm_crtc *crtc)
+{
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+	struct rockchip_drm_private *private = crtc->dev->dev_private;
+
+	private->crtc[rockchip_crtc->pipe] = NULL;
+
+	drm_crtc_cleanup(crtc);
+	kfree(rockchip_crtc);
+}
+
+static int rockchip_drm_crtc_set_property(struct drm_crtc *crtc,
+					struct drm_property *property,
+					uint64_t val)
+{
+	struct drm_device *dev = crtc->dev;
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(crtc);
+
+	if (property == dev_priv->crtc_mode_property) {
+		enum rockchip_crtc_mode mode = val;
+
+		if (mode == rockchip_crtc->mode)
+			return 0;
+
+		rockchip_crtc->mode = mode;
+
+		switch (mode) {
+		case CRTC_MODE_NORMAL:
+			rockchip_drm_crtc_commit(crtc);
+			break;
+		case CRTC_MODE_BLANK:
+			rockchip_plane_dpms(rockchip_crtc->plane,
+					  DRM_MODE_DPMS_OFF);
+			break;
+		default:
+			break;
+		}
+
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static struct drm_crtc_funcs rockchip_crtc_funcs = {
+	.set_config = drm_crtc_helper_set_config,
+	.page_flip = rockchip_drm_crtc_page_flip,
+	.destroy = rockchip_drm_crtc_destroy,
+	.set_property = rockchip_drm_crtc_set_property,
+};
+
+static const struct drm_prop_enum_list mode_names[] = {
+	{ CRTC_MODE_NORMAL, "normal" },
+	{ CRTC_MODE_BLANK, "blank" },
+};
+
+static void rockchip_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+	struct drm_property *prop;
+
+	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 rockchip_drm_crtc_create(struct rockchip_drm_manager *manager)
+{
+	struct rockchip_drm_crtc *rockchip_crtc;
+	struct rockchip_drm_private *private = manager->drm_dev->dev_private;
+	struct drm_crtc *crtc;
+
+	rockchip_crtc = kzalloc(sizeof(*rockchip_crtc), GFP_KERNEL);
+	if (!rockchip_crtc)
+		return -ENOMEM;
+
+	init_waitqueue_head(&rockchip_crtc->pending_flip_queue);
+	atomic_set(&rockchip_crtc->pending_flip, 0);
+
+	rockchip_crtc->dpms = DRM_MODE_DPMS_OFF;
+	rockchip_crtc->manager = manager;
+	rockchip_crtc->pipe = manager->pipe;
+	rockchip_crtc->plane = rockchip_plane_init(manager->drm_dev,
+				1 << manager->pipe, true);
+	if (!rockchip_crtc->plane) {
+		kfree(rockchip_crtc);
+		return -ENOMEM;
+	}
+
+	manager->crtc = &rockchip_crtc->drm_crtc;
+	crtc = &rockchip_crtc->drm_crtc;
+
+	private->crtc[manager->pipe] = crtc;
+
+	drm_crtc_init(manager->drm_dev, crtc, &rockchip_crtc_funcs);
+	drm_crtc_helper_add(crtc, &rockchip_crtc_helper_funcs);
+
+	rockchip_drm_crtc_attach_mode_property(crtc);
+
+	return 0;
+}
+
+int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct rockchip_drm_crtc *rockchip_crtc =
+		to_rockchip_crtc(private->crtc[pipe]);
+	struct rockchip_drm_manager *manager = rockchip_crtc->manager;
+
+	if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
+		return -EPERM;
+
+	if (manager->ops->enable_vblank)
+		manager->ops->enable_vblank(manager);
+
+	return 0;
+}
+
+void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct rockchip_drm_crtc *rockchip_crtc =
+		to_rockchip_crtc(private->crtc[pipe]);
+	struct rockchip_drm_manager *manager = rockchip_crtc->manager;
+
+	if (rockchip_crtc->dpms != DRM_MODE_DPMS_ON)
+		return;
+
+	if (manager->ops->disable_vblank)
+		manager->ops->disable_vblank(manager);
+}
+
+void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
+{
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+	struct drm_pending_vblank_event *e, *t;
+	struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
+	struct rockchip_drm_crtc *rockchip_crtc = to_rockchip_crtc(drm_crtc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+
+	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
+			base.link) {
+		/* if event's pipe isn't same as crtc then ignore it. */
+		if (pipe != e->pipe)
+			continue;
+
+		list_del(&e->base.link);
+		drm_send_vblank_event(dev, -1, e);
+		drm_vblank_put(dev, pipe);
+		atomic_set(&rockchip_crtc->pending_flip, 0);
+		wake_up(&rockchip_crtc->pending_flip_queue);
+	}
+
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+void rockchip_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+			struct rockchip_drm_overlay *overlay)
+{
+	struct rockchip_drm_manager *manager = to_rockchip_crtc(crtc)->manager;
+
+	if (manager->ops->win_mode_set)
+		manager->ops->win_mode_set(manager, overlay);
+}
+
+void rockchip_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos)
+{
+	struct rockchip_drm_manager *manager = to_rockchip_crtc(crtc)->manager;
+
+	if (manager->ops->win_commit)
+		manager->ops->win_commit(manager, zpos);
+}
+
+void rockchip_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos)
+{
+	struct rockchip_drm_manager *manager = to_rockchip_crtc(crtc)->manager;
+
+	if (manager->ops->win_enable)
+		manager->ops->win_enable(manager, zpos);
+}
+
+void rockchip_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos)
+{
+	struct rockchip_drm_manager *manager = to_rockchip_crtc(crtc)->manager;
+
+	if (manager->ops->win_disable)
+		manager->ops->win_disable(manager, zpos);
+}
+
+void rockchip_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
+{
+	struct rockchip_drm_manager *manager;
+	struct drm_device *dev = fb->dev;
+	struct drm_crtc *crtc;
+
+	/*
+	 * make sure that overlay data are updated to real hardware
+	 * for all encoders.
+	 */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		manager = to_rockchip_crtc(crtc)->manager;
+
+		/*
+		 * wait for vblank interrupt
+		 * - this makes sure that overlay data are updated to
+		 *     real hardware.
+		 */
+		if (manager->ops->wait_for_vblank)
+			manager->ops->wait_for_vblank(manager);
+	}
+}
+
+int rockchip_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
+					unsigned int out_type)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
+		struct rockchip_drm_crtc *rockchip_crtc;
+
+		rockchip_crtc = to_rockchip_crtc(crtc);
+		if (rockchip_crtc->manager->type == out_type)
+			return rockchip_crtc->manager->pipe;
+	}
+
+	return -EPERM;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_crtc.h b/drivers/gpu/drm/rockchip/rockchip_drm_crtc.h
new file mode 100644
index 0000000..bbf7214
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_crtc.h
@@ -0,0 +1,42 @@
+/* rockchip_drm_crtc.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_crtc.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_CRTC_H_
+#define _ROCKCHIP_DRM_CRTC_H_
+
+struct drm_device;
+struct drm_crtc;
+struct rockchip_drm_manager;
+struct rockchip_drm_overlay;
+
+int rockchip_drm_crtc_create(struct rockchip_drm_manager *manager);
+int rockchip_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
+void rockchip_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
+void rockchip_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
+void rockchip_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
+
+void rockchip_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+			struct rockchip_drm_overlay *overlay);
+void rockchip_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
+void rockchip_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
+void rockchip_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
+
+/* This function gets pipe value to crtc device matched with out_type. */
+int rockchip_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
+					unsigned int out_type);
+
+#endif /* _ROCKCHIP_DRM_CRTC_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c b/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c
new file mode 100644
index 0000000..d3e237d
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.c
@@ -0,0 +1,290 @@
+/* rockchip_drm_dmabuf.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_dmabuf.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/dma-buf.h>
+#include <drm/drmP.h>
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_dmabuf.h"
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+
+
+struct rockchip_drm_dmabuf_attachment {
+	struct sg_table sgt;
+	enum dma_data_direction dir;
+	bool is_mapped;
+};
+
+static struct rockchip_drm_gem_obj *dma_buf_to_obj(struct dma_buf *buf)
+{
+	return to_rockchip_gem_obj(buf->priv);
+}
+
+static int rockchip_gem_attach_dma_buf(struct dma_buf *dmabuf,
+					struct device *dev,
+					struct dma_buf_attachment *attach)
+{
+	struct rockchip_drm_dmabuf_attachment *rockchip_attach;
+
+	rockchip_attach = kzalloc(sizeof(*rockchip_attach), GFP_KERNEL);
+	if (!rockchip_attach)
+		return -ENOMEM;
+
+	rockchip_attach->dir = DMA_NONE;
+	attach->priv = rockchip_attach;
+
+	return 0;
+}
+
+static void rockchip_gem_detach_dma_buf(struct dma_buf *dmabuf,
+					struct dma_buf_attachment *attach)
+{
+	struct rockchip_drm_dmabuf_attachment *rockchip_attach = attach->priv;
+	struct sg_table *sgt;
+
+	if (!rockchip_attach)
+		return;
+
+	sgt = &rockchip_attach->sgt;
+
+	if (rockchip_attach->dir != DMA_NONE)
+		dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,
+				rockchip_attach->dir);
+
+	sg_free_table(sgt);
+	kfree(rockchip_attach);
+	attach->priv = NULL;
+}
+
+static struct sg_table *
+		rockchip_gem_map_dma_buf(struct dma_buf_attachment *attach,
+					enum dma_data_direction dir)
+{
+	struct rockchip_drm_dmabuf_attachment *rockchip_attach = attach->priv;
+	struct rockchip_drm_gem_obj *gem_obj = dma_buf_to_obj(attach->dmabuf);
+	struct drm_device *dev = gem_obj->base.dev;
+	struct rockchip_drm_gem_buf *buf;
+	struct scatterlist *rd, *wr;
+	struct sg_table *sgt = NULL;
+	unsigned int i;
+	int nents, ret;
+
+	/* just return current sgt if already requested. */
+	if (rockchip_attach->dir == dir && rockchip_attach->is_mapped)
+		return &rockchip_attach->sgt;
+
+	buf = gem_obj->buffer;
+	if (!buf) {
+		DRM_ERROR("buffer is null.\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sgt = &rockchip_attach->sgt;
+
+	ret = sg_alloc_table(sgt, buf->sgt->orig_nents, GFP_KERNEL);
+	if (ret) {
+		DRM_ERROR("failed to alloc sgt.\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	mutex_lock(&dev->struct_mutex);
+
+	rd = buf->sgt->sgl;
+	wr = sgt->sgl;
+	for (i = 0; i < sgt->orig_nents; ++i) {
+		sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
+		rd = sg_next(rd);
+		wr = sg_next(wr);
+	}
+
+	if (dir != DMA_NONE) {
+		nents = dma_map_sg(attach->dev, sgt->sgl,
+					sgt->orig_nents, dir);
+		if (!nents) {
+			DRM_ERROR("failed to map sgl with iommu.\n");
+			sg_free_table(sgt);
+			sgt = ERR_PTR(-EIO);
+			goto err_unlock;
+		}
+	}
+
+	rockchip_attach->is_mapped = true;
+	rockchip_attach->dir = dir;
+	attach->priv = rockchip_attach;
+
+	DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size);
+
+err_unlock:
+	mutex_unlock(&dev->struct_mutex);
+	return sgt;
+}
+
+static void rockchip_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
+						struct sg_table *sgt,
+						enum dma_data_direction dir)
+{
+	/* Nothing to do. */
+}
+
+static void *rockchip_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
+						unsigned long page_num)
+{
+	/* TODO */
+
+	return NULL;
+}
+
+static void rockchip_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
+						unsigned long page_num,
+						void *addr)
+{
+	/* TODO */
+}
+
+static void *rockchip_gem_dmabuf_kmap(struct dma_buf *dma_buf,
+					unsigned long page_num)
+{
+	/* TODO */
+
+	return NULL;
+}
+
+static void rockchip_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
+					unsigned long page_num, void *addr)
+{
+	/* TODO */
+}
+
+static int rockchip_gem_dmabuf_mmap(struct dma_buf *dma_buf,
+	struct vm_area_struct *vma)
+{
+	return -ENOTTY;
+}
+
+static struct dma_buf_ops rockchip_dmabuf_ops = {
+	.attach = rockchip_gem_attach_dma_buf,
+	.detach = rockchip_gem_detach_dma_buf,
+	.map_dma_buf = rockchip_gem_map_dma_buf,
+	.unmap_dma_buf = rockchip_gem_unmap_dma_buf,
+	.kmap = rockchip_gem_dmabuf_kmap,
+	.kmap_atomic = rockchip_gem_dmabuf_kmap_atomic,
+	.kunmap = rockchip_gem_dmabuf_kunmap,
+	.kunmap_atomic = rockchip_gem_dmabuf_kunmap_atomic,
+	.mmap = rockchip_gem_dmabuf_mmap,
+	.release = drm_gem_dmabuf_release,
+};
+
+struct dma_buf *rockchip_dmabuf_prime_export(struct drm_device *drm_dev,
+				struct drm_gem_object *obj, int flags)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj =
+						to_rockchip_gem_obj(obj);
+
+	return dma_buf_export(obj, &rockchip_dmabuf_ops,
+				rockchip_gem_obj->base.size, flags);
+}
+
+struct drm_gem_object *rockchip_dmabuf_prime_import(struct drm_device *drm_dev,
+				struct dma_buf *dma_buf)
+{
+	struct dma_buf_attachment *attach;
+	struct sg_table *sgt;
+	struct scatterlist *sgl;
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct rockchip_drm_gem_buf *buffer;
+	int ret;
+
+	/* is this one of own objects? */
+	if (dma_buf->ops == &rockchip_dmabuf_ops) {
+		struct drm_gem_object *obj;
+
+		obj = dma_buf->priv;
+
+		/* is it from our device? */
+		if (obj->dev == drm_dev) {
+			/*
+			 * Importing dmabuf exported from out own gem increases
+			 * refcount on gem itself instead of f_count of dmabuf.
+			 */
+			drm_gem_object_reference(obj);
+			return obj;
+		}
+	}
+
+	attach = dma_buf_attach(dma_buf, drm_dev->dev);
+	if (IS_ERR(attach))
+		return ERR_PTR(-EINVAL);
+
+	get_dma_buf(dma_buf);
+
+	sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+	if (IS_ERR(sgt)) {
+		ret = PTR_ERR(sgt);
+		goto err_buf_detach;
+	}
+
+	buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto err_unmap_attach;
+	}
+
+	rockchip_gem_obj = rockchip_drm_gem_init(drm_dev, dma_buf->size);
+	if (!rockchip_gem_obj) {
+		ret = -ENOMEM;
+		goto err_free_buffer;
+	}
+
+	sgl = sgt->sgl;
+
+	buffer->size = dma_buf->size;
+	buffer->dma_addr = sg_dma_address(sgl);
+
+	if (sgt->nents == 1) {
+		/* always physically continuous memory if sgt->nents is 1. */
+		rockchip_gem_obj->flags |= ROCKCHIP_BO_CONTIG;
+	} else {
+		/*
+		 * this case could be CONTIG or NONCONTIG type but for now
+		 * sets NONCONTIG.
+		 * TODO. we have to find a way that exporter can notify
+		 * the type of its own buffer to importer.
+		 */
+		rockchip_gem_obj->flags |= ROCKCHIP_BO_NONCONTIG;
+	}
+
+	rockchip_gem_obj->buffer = buffer;
+	buffer->sgt = sgt;
+	rockchip_gem_obj->base.import_attach = attach;
+
+	DRM_DEBUG_PRIME("dma_addr = %pad, size = 0x%lx\n", &buffer->dma_addr,
+								buffer->size);
+
+	return &rockchip_gem_obj->base;
+
+err_free_buffer:
+	kfree(buffer);
+	buffer = NULL;
+err_unmap_attach:
+	dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+err_buf_detach:
+	dma_buf_detach(dma_buf, attach);
+	dma_buf_put(dma_buf);
+
+	return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h b/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h
new file mode 100644
index 0000000..93c1c77
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_dmabuf.h
@@ -0,0 +1,32 @@
+/* rockchip_drm_dmabuf.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_dmabuf.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_DMABUF_H_
+#define _ROCKCHIP_DRM_DMABUF_H_
+
+#ifdef CONFIG_DRM_ROCKCHIP_DMABUF
+struct dma_buf *rockchip_dmabuf_prime_export(struct drm_device *drm_dev,
+				struct drm_gem_object *obj, int flags);
+
+struct drm_gem_object *rockchip_dmabuf_prime_import(struct drm_device *drm_dev,
+						struct dma_buf *dma_buf);
+#else
+#define rockchip_dmabuf_prime_export		NULL
+#define rockchip_dmabuf_prime_import		NULL
+#endif
+
+#endif /* _ROCKCHIP_DRM_DMABUF_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
new file mode 100644
index 0000000..33136ba
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -0,0 +1,618 @@
+/* rockchip_drm_drv.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_drv.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <linux/pm_runtime.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include <linux/anon_inodes.h>
+#include <linux/component.h>
+
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_crtc.h"
+#include "rockchip_drm_encoder.h"
+#include "rockchip_drm_fbdev.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_plane.h"
+#include "rockchip_drm_dmabuf.h"
+#include "rockchip_drm_iommu.h"
+
+#define DRIVER_NAME	"rockchip"
+#define DRIVER_DESC	"rockchip Soc DRM"
+#define DRIVER_DATE	"20140623"
+#define DRIVER_MAJOR	1
+#define DRIVER_MINOR	0
+
+#define VBLANK_OFF_DELAY	50000
+
+static struct platform_device *rockchip_drm_pdev;
+
+static DEFINE_MUTEX(drm_component_lock);
+static LIST_HEAD(drm_component_list);
+
+struct component_dev {
+	struct list_head list;
+	struct device *crtc_dev;
+	struct device *conn_dev;
+	enum rockchip_drm_output_type out_type;
+	unsigned int dev_type_flag;
+};
+
+static int rockchip_drm_load(struct drm_device *dev, unsigned long flags)
+{
+	struct rockchip_drm_private *private;
+	int ret;
+	int nr;
+
+	private = kzalloc(sizeof(struct rockchip_drm_private), GFP_KERNEL);
+	if (!private)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&private->pageflip_event_list);
+	dev_set_drvdata(dev->dev, dev);
+	dev->dev_private = (void *)private;
+
+	/*
+	 * create mapping to manage iommu table and set a pointer to iommu
+	 * mapping structure to iommu_mapping of private data.
+	 * also this iommu_mapping can be used to check if iommu is supported
+	 * or not.
+	 */
+	ret = drm_create_iommu_mapping(dev);
+	if (ret < 0) {
+		DRM_ERROR("failed to create iommu mapping.\n");
+		goto err_free_private;
+	}
+
+	drm_mode_config_init(dev);
+
+	rockchip_drm_mode_config_init(dev);
+
+	for (nr = 0; nr < MAX_PLANE; nr++) {
+		struct drm_plane *plane;
+		unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
+
+		plane = rockchip_plane_init(dev, possible_crtcs, false);
+		if (!plane)
+			goto err_mode_config_cleanup;
+	}
+
+	/* init kms poll for handling hpd */
+	drm_kms_helper_poll_init(dev);
+
+	ret = drm_vblank_init(dev, MAX_CRTC);
+	if (ret)
+		goto err_mode_config_cleanup;
+
+	/* setup possible_clones. */
+	rockchip_drm_encoder_setup(dev);
+
+	drm_vblank_offdelay = VBLANK_OFF_DELAY;
+
+	platform_set_drvdata(dev->platformdev, dev);
+
+	/* Try to bind all sub drivers. */
+	ret = component_bind_all(dev->dev, dev);
+	if (ret)
+		goto err_cleanup_vblank;
+
+	/* Probe non kms sub drivers and virtual display driver. */
+	ret = rockchip_drm_device_subdrv_probe(dev);
+	if (ret)
+		goto err_unbind_all;
+
+	/* force connectors detection */
+	drm_helper_hpd_irq_event(dev);
+
+	return 0;
+
+err_unbind_all:
+	component_unbind_all(dev->dev, dev);
+err_cleanup_vblank:
+	drm_vblank_cleanup(dev);
+err_mode_config_cleanup:
+	drm_mode_config_cleanup(dev);
+	drm_release_iommu_mapping(dev);
+err_free_private:
+	kfree(private);
+
+	return ret;
+}
+
+static int rockchip_drm_unload(struct drm_device *dev)
+{
+	rockchip_drm_device_subdrv_remove(dev);
+
+	rockchip_drm_fbdev_fini(dev);
+	drm_vblank_cleanup(dev);
+	drm_kms_helper_poll_fini(dev);
+	drm_mode_config_cleanup(dev);
+
+	drm_release_iommu_mapping(dev);
+	kfree(dev->dev_private);
+
+	component_unbind_all(dev->dev, dev);
+	dev->dev_private = NULL;
+
+	return 0;
+}
+
+static const struct file_operations rockchip_drm_gem_fops = {
+	.mmap = rockchip_drm_gem_mmap_buffer,
+};
+
+static int rockchip_drm_suspend(struct drm_device *dev, pm_message_t state)
+{
+	struct drm_connector *connector;
+
+	drm_modeset_lock_all(dev);
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		int old_dpms = connector->dpms;
+
+		if (connector->funcs->dpms)
+			connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+
+		/* Set the old mode back to the connector for resume */
+		connector->dpms = old_dpms;
+	}
+	drm_modeset_unlock_all(dev);
+
+	return 0;
+}
+
+static int rockchip_drm_resume(struct drm_device *dev)
+{
+	struct drm_connector *connector;
+
+	drm_modeset_lock_all(dev);
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->funcs->dpms)
+			connector->funcs->dpms(connector, connector->dpms);
+	}
+	drm_modeset_unlock_all(dev);
+
+	drm_helper_resume_force_mode(dev);
+
+	return 0;
+}
+
+static int rockchip_drm_open(struct drm_device *dev, struct drm_file *file)
+{
+	struct drm_rockchip_file_private *file_priv;
+	struct file *anon_filp;
+	int ret;
+
+	file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
+	if (!file_priv)
+		return -ENOMEM;
+
+	file->driver_priv = file_priv;
+
+	ret = rockchip_drm_subdrv_open(dev, file);
+	if (ret)
+		goto err_file_priv_free;
+
+	anon_filp = anon_inode_getfile("rockchip_gem", &rockchip_drm_gem_fops,
+					NULL, 0);
+	if (IS_ERR(anon_filp)) {
+		ret = PTR_ERR(anon_filp);
+		goto err_subdrv_close;
+	}
+
+	anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
+	file_priv->anon_filp = anon_filp;
+
+	return ret;
+
+err_subdrv_close:
+	rockchip_drm_subdrv_close(dev, file);
+
+err_file_priv_free:
+	kfree(file_priv);
+	file->driver_priv = NULL;
+	return ret;
+}
+
+static void rockchip_drm_preclose(struct drm_device *dev,
+					struct drm_file *file)
+{
+	rockchip_drm_subdrv_close(dev, file);
+}
+
+static void rockchip_drm_postclose(struct drm_device *dev,
+					struct drm_file *file)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct drm_rockchip_file_private *file_priv;
+	struct drm_pending_vblank_event *v, *vt;
+	struct drm_pending_event *e, *et;
+	unsigned long flags;
+
+	if (!file->driver_priv)
+		return;
+
+	/* Release all events not unhandled by page flip handler. */
+	spin_lock_irqsave(&dev->event_lock, flags);
+	list_for_each_entry_safe(v, vt, &private->pageflip_event_list,
+			base.link) {
+		if (v->base.file_priv == file) {
+			list_del(&v->base.link);
+			drm_vblank_put(dev, v->pipe);
+			v->base.destroy(&v->base);
+		}
+	}
+
+	/* Release all events handled by page flip handler but not freed. */
+	list_for_each_entry_safe(e, et, &file->event_list, link) {
+		list_del(&e->link);
+		e->destroy(e);
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+
+	file_priv = file->driver_priv;
+	if (file_priv->anon_filp)
+		fput(file_priv->anon_filp);
+
+	kfree(file->driver_priv);
+	file->driver_priv = NULL;
+}
+
+static void rockchip_drm_lastclose(struct drm_device *dev)
+{
+	rockchip_drm_fbdev_restore_mode(dev);
+}
+
+static const struct vm_operations_struct rockchip_drm_gem_vm_ops = {
+	.fault = rockchip_drm_gem_fault,
+	.open = drm_gem_vm_open,
+	.close = drm_gem_vm_close,
+};
+
+static const struct drm_ioctl_desc rockchip_ioctls[] = {
+	DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_CREATE, rockchip_drm_gem_create_ioctl,
+			DRM_UNLOCKED | DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_MAP_OFFSET,
+			rockchip_drm_gem_map_offset_ioctl, DRM_UNLOCKED |
+			DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_MMAP,
+			rockchip_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
+	DRM_IOCTL_DEF_DRV(ROCKCHIP_GEM_GET,
+			rockchip_drm_gem_get_ioctl, DRM_UNLOCKED),
+};
+
+static const struct file_operations rockchip_drm_driver_fops = {
+	.owner = THIS_MODULE,
+	.open = drm_open,
+	.mmap = rockchip_drm_gem_mmap,
+	.poll = drm_poll,
+	.read = drm_read,
+	.unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = drm_compat_ioctl,
+#endif
+	.release = drm_release,
+};
+
+static struct drm_driver rockchip_drm_driver = {
+	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
+	.load			= rockchip_drm_load,
+	.unload			= rockchip_drm_unload,
+	.suspend		= rockchip_drm_suspend,
+	.resume			= rockchip_drm_resume,
+	.open			= rockchip_drm_open,
+	.preclose		= rockchip_drm_preclose,
+	.lastclose		= rockchip_drm_lastclose,
+	.postclose		= rockchip_drm_postclose,
+	.get_vblank_counter	= drm_vblank_count,
+	.enable_vblank		= rockchip_drm_crtc_enable_vblank,
+	.disable_vblank		= rockchip_drm_crtc_disable_vblank,
+	.gem_free_object	= rockchip_drm_gem_free_object,
+	.gem_vm_ops		= &rockchip_drm_gem_vm_ops,
+	.dumb_create		= rockchip_drm_gem_dumb_create,
+	.dumb_map_offset	= rockchip_drm_gem_dumb_map_offset,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_export	= rockchip_dmabuf_prime_export,
+	.gem_prime_import	= rockchip_dmabuf_prime_import,
+	.ioctls			= rockchip_ioctls,
+	.num_ioctls		= ARRAY_SIZE(rockchip_ioctls),
+	.fops			= &rockchip_drm_driver_fops,
+	.name	= DRIVER_NAME,
+	.desc	= DRIVER_DESC,
+	.date	= DRIVER_DATE,
+	.major	= DRIVER_MAJOR,
+	.minor	= DRIVER_MINOR,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int rockchip_drm_sys_suspend(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+	pm_message_t message;
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	message.event = PM_EVENT_SUSPEND;
+
+	return rockchip_drm_suspend(drm_dev, message);
+}
+
+static int rockchip_drm_sys_resume(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return rockchip_drm_resume(drm_dev);
+}
+#endif
+
+static const struct dev_pm_ops rockchip_drm_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(rockchip_drm_sys_suspend,
+					rockchip_drm_sys_resume)
+};
+
+int rockchip_drm_component_add(struct device *dev,
+				enum rockchip_drm_device_type dev_type,
+				enum rockchip_drm_output_type out_type)
+{
+	struct component_dev *cdev;
+
+	if (dev_type != ROCKCHIP_DEVICE_TYPE_CRTC &&
+			dev_type != ROCKCHIP_DEVICE_TYPE_CONNECTOR) {
+		DRM_ERROR("invalid device type.\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&drm_component_lock);
+
+	/*
+	 * Make sure to check if there is a component which has two device
+	 * objects, for connector and for encoder/connector.
+	 * It should make sure that crtc and encoder/connector drivers are
+	 * ready before rockchip drm core binds them.
+	 */
+	list_for_each_entry(cdev, &drm_component_list, list) {
+		if (cdev->out_type == out_type) {
+			/*
+			 * If crtc and encoder/connector device objects are
+			 * added already just return.
+			 */
+			if (cdev->dev_type_flag == (ROCKCHIP_DEVICE_TYPE_CRTC |
+					ROCKCHIP_DEVICE_TYPE_CONNECTOR)) {
+				mutex_unlock(&drm_component_lock);
+				return 0;
+			}
+
+			if (dev_type == ROCKCHIP_DEVICE_TYPE_CRTC) {
+				cdev->crtc_dev = dev;
+				cdev->dev_type_flag |= dev_type;
+			}
+
+			if (dev_type == ROCKCHIP_DEVICE_TYPE_CONNECTOR) {
+				cdev->conn_dev = dev;
+				cdev->dev_type_flag |= dev_type;
+			}
+
+			mutex_unlock(&drm_component_lock);
+			return 0;
+		}
+	}
+
+	mutex_unlock(&drm_component_lock);
+
+	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+	if (!cdev)
+		return -ENOMEM;
+
+	if (dev_type == ROCKCHIP_DEVICE_TYPE_CRTC)
+		cdev->crtc_dev = dev;
+	if (dev_type == ROCKCHIP_DEVICE_TYPE_CONNECTOR)
+		cdev->conn_dev = dev;
+
+	cdev->out_type = out_type;
+	cdev->dev_type_flag = dev_type;
+
+	mutex_lock(&drm_component_lock);
+	list_add_tail(&cdev->list, &drm_component_list);
+	mutex_unlock(&drm_component_lock);
+
+	return 0;
+}
+
+void rockchip_drm_component_del(struct device *dev,
+				enum rockchip_drm_device_type dev_type)
+{
+	struct component_dev *cdev, *next;
+
+	mutex_lock(&drm_component_lock);
+
+	list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
+		if (dev_type == ROCKCHIP_DEVICE_TYPE_CRTC) {
+			if (cdev->crtc_dev == dev) {
+				cdev->crtc_dev = NULL;
+				cdev->dev_type_flag &= ~dev_type;
+			}
+		}
+
+		if (dev_type == ROCKCHIP_DEVICE_TYPE_CONNECTOR) {
+			if (cdev->conn_dev == dev) {
+				cdev->conn_dev = NULL;
+				cdev->dev_type_flag &= ~dev_type;
+			}
+		}
+
+		/*
+		 * Release cdev object only in case that both of crtc and
+		 * encoder/connector device objects are NULL.
+		 */
+		if (!cdev->crtc_dev && !cdev->conn_dev) {
+			list_del(&cdev->list);
+			kfree(cdev);
+		}
+
+		break;
+	}
+
+	mutex_unlock(&drm_component_lock);
+}
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev == (struct device *)data;
+}
+
+static int rockchip_drm_add_components(struct device *dev, struct master *m)
+{
+	struct component_dev *cdev;
+	unsigned int attach_cnt = 0;
+
+	mutex_lock(&drm_component_lock);
+
+	list_for_each_entry(cdev, &drm_component_list, list) {
+		int ret;
+
+		/*
+		 * Add components to master only in case that crtc and
+		 * encoder/connector device objects exist.
+		 */
+		if (!cdev->crtc_dev || !cdev->conn_dev)
+			continue;
+
+		attach_cnt++;
+
+		mutex_unlock(&drm_component_lock);
+
+		/*
+		 * lcdc and dp modules have same device object so add
+		 * only crtc device object in this case.
+		 *
+		 * TODO. if dp module follows driver-model driver then
+		 * below codes can be removed.
+		 */
+		if (cdev->crtc_dev == cdev->conn_dev) {
+			ret = component_master_add_child(m, compare_of,
+					cdev->crtc_dev);
+			if (ret < 0)
+				return ret;
+
+			goto out_lock;
+		}
+
+		/*
+		 * Do not chage below call order.
+		 * crtc device first should be added to master because
+		 * connector/encoder need pipe number of crtc when they
+		 * are created.
+		 */
+		ret = component_master_add_child(m, compare_of, cdev->crtc_dev);
+		ret |= component_master_add_child(m, compare_of,
+							cdev->conn_dev);
+		if (ret < 0)
+			return ret;
+
+out_lock:
+		mutex_lock(&drm_component_lock);
+	}
+
+	mutex_unlock(&drm_component_lock);
+
+	return attach_cnt ? 0 : -ENODEV;
+}
+
+static int rockchip_drm_bind(struct device *dev)
+{
+	return drm_platform_init(&rockchip_drm_driver, to_platform_device(dev));
+}
+
+static void rockchip_drm_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops rockchip_drm_ops = {
+	.add_components = rockchip_drm_add_components,
+	.bind = rockchip_drm_bind,
+	.unbind = rockchip_drm_unbind,
+};
+
+static int rockchip_drm_platform_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	rockchip_drm_driver.num_ioctls = ARRAY_SIZE(rockchip_ioctls);
+
+	ret = component_master_add(&pdev->dev, &rockchip_drm_ops);
+	if (ret < 0)
+		DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
+
+	return 0;
+}
+
+static int rockchip_drm_platform_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &rockchip_drm_ops);
+
+	return 0;
+}
+
+static struct platform_driver rockchip_drm_platform_driver = {
+	.probe = rockchip_drm_platform_probe,
+	.remove = rockchip_drm_platform_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "rockchip-drm",
+		.pm = &rockchip_drm_pm_ops,
+	},
+};
+
+static int rockchip_drm_init(void)
+{
+	int ret;
+
+	rockchip_drm_pdev = platform_device_register_simple("rockchip-drm", -1,
+								NULL, 0);
+	if (IS_ERR(rockchip_drm_pdev))
+		return PTR_ERR(rockchip_drm_pdev);
+
+	ret = platform_driver_register(&rockchip_drm_platform_driver);
+	if (ret)
+		goto err_unregister_pd;
+
+	return 0;
+
+err_unregister_pd:
+	platform_device_unregister(rockchip_drm_pdev);
+
+	return ret;
+}
+
+static void rockchip_drm_exit(void)
+{
+	platform_device_unregister(rockchip_drm_pdev);
+	platform_driver_unregister(&rockchip_drm_platform_driver);
+}
+
+module_init(rockchip_drm_init);
+module_exit(rockchip_drm_exit);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
new file mode 100644
index 0000000..6340452
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -0,0 +1,319 @@
+/* rockchip_drm_drv.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_drv.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_DRV_H_
+#define _ROCKCHIP_DRM_DRV_H_
+
+#include <linux/module.h>
+
+#define MAX_CRTC	3
+#define MAX_PLANE	5
+#define MAX_FB_BUFFER	4
+#define DEFAULT_ZPOS	-1
+
+#define _wait_for(COND, MS) ({ \
+	unsigned long timeout__ = jiffies + msecs_to_jiffies(MS);	\
+	int ret__ = 0;							\
+	while (!(COND)) {						\
+		if (time_after(jiffies, timeout__)) {			\
+			ret__ = -ETIMEDOUT;				\
+			break;						\
+		}							\
+	}								\
+	ret__;								\
+})
+
+#define wait_for(COND, MS) _wait_for(COND, MS)
+
+struct drm_device;
+struct drm_connector;
+struct rockchip_drm_overlay;
+struct rockchip_drm_manager;
+
+extern unsigned int drm_vblank_offdelay;
+
+/* This enumerates device type. */
+enum rockchip_drm_device_type {
+	ROCKCHIP_DEVICE_TYPE_NONE,
+	ROCKCHIP_DEVICE_TYPE_CRTC,
+	ROCKCHIP_DEVICE_TYPE_CONNECTOR,
+};
+
+/* this enumerates display type. */
+enum rockchip_drm_output_type {
+	ROCKCHIP_DISPLAY_TYPE_NONE,
+	/* RGB or CPU Interface. */
+	ROCKCHIP_DISPLAY_TYPE_LCD,
+	/* HDMI Interface. */
+	ROCKCHIP_DISPLAY_TYPE_HDMI,
+	/* Virtual Display Interface. */
+	ROCKCHIP_DISPLAY_TYPE_VIDI,
+};
+
+/*
+ * Rockchip drm common overlay structure.
+ *
+ * @fb_x: offset x on a framebuffer to be displayed.
+ *      - the unit is screen coordinates.
+ * @fb_y: offset y on a framebuffer to be displayed.
+ *      - the unit is screen coordinates.
+ * @fb_width: width of a framebuffer.
+ * @fb_height: height of a framebuffer.
+ * @src_width: width of a partial image to be displayed from framebuffer.
+ * @src_height: height of a partial image to be displayed from framebuffer.
+ * @crtc_x: offset x on hardware screen.
+ * @crtc_y: offset y on hardware screen.
+ * @crtc_width: window width to be displayed (hardware screen).
+ * @crtc_height: window height to be displayed (hardware screen).
+ * @mode_width: width of screen mode.
+ * @mode_height: height of screen mode.
+ * @refresh: refresh rate.
+ * @scan_flag: interlace or progressive way.
+ *      (it could be DRM_MODE_FLAG_*)
+ * @bpp: pixel size.(in bit)
+ * @pixel_format: fourcc pixel format of this overlay
+ * @dma_addr: array of bus(accessed by dma) address to the memory region
+ *          allocated for a overlay.
+ * @zpos: order of overlay layer(z position).
+ * @default_win: a window to be enabled.
+ * @color_key: color key on or off.
+ * @index_color: if using color key feature then this value would be used
+ *             as index color.
+ * @local_path: in case of lcd type, local path mode on or off.
+ * @transparency: transparency on or off.
+ * @activated: activated or not.
+ *
+ * this structure is common to rockchip SoC and its contents would be copied
+ * to hardware specific overlay info.
+ */
+struct rockchip_drm_overlay {
+	unsigned int fb_x;
+	unsigned int fb_y;
+	unsigned int fb_width;
+	unsigned int fb_height;
+	unsigned int src_width;
+	unsigned int src_height;
+	unsigned int crtc_x;
+	unsigned int crtc_y;
+	unsigned int crtc_width;
+	unsigned int crtc_height;
+	unsigned int mode_width;
+	unsigned int mode_height;
+	unsigned int refresh;
+	unsigned int scan_flag;
+	unsigned int bpp;
+	unsigned int pitch;
+	uint32_t pixel_format;
+	dma_addr_t dma_addr[MAX_FB_BUFFER];
+	int zpos;
+
+	bool default_win;
+	bool color_key;
+	unsigned int index_color;
+	bool local_path;
+	bool transparency;
+	bool activated;
+};
+
+/*
+ * Rockchip DRM Display Structure.
+ *     - this structure is common to analog tv, digital tv and lcd panel.
+ *
+ * @remove: cleans up the display for removal
+ * @mode_fixup: fix mode data comparing to hw specific display mode.
+ * @mode_set: convert drm_display_mode to hw specific display mode and
+ *            would be called by encoder->mode_set().
+ * @check_mode: check if mode is valid or not.
+ * @dpms: display device on or off.
+ * @commit: apply changes to hw
+ */
+struct rockchip_drm_display;
+struct rockchip_drm_display_ops {
+	int (*create_connector)(struct rockchip_drm_display *display,
+				struct drm_encoder *encoder);
+	void (*remove)(struct rockchip_drm_display *display);
+	void (*mode_fixup)(struct rockchip_drm_display *display,
+				struct drm_connector *connector,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
+	void (*mode_set)(struct rockchip_drm_display *display,
+				struct drm_display_mode *mode);
+	int (*check_mode)(struct rockchip_drm_display *display,
+				struct drm_display_mode *mode);
+	void (*dpms)(struct rockchip_drm_display *display, int mode);
+	void (*commit)(struct rockchip_drm_display *display);
+};
+
+/*
+ * Rockchip drm display structure, maps 1:1 with an encoder/connector
+ *
+ * @list: the list entry for this manager
+ * @type: one of ROCKCHIP_DISPLAY_TYPE_LCD and HDMI.
+ * @encoder: encoder object this display maps to
+ * @connector: connector object this display maps to
+ * @ops: pointer to callbacks for rockchip drm specific functionality
+ * @ctx: A pointer to the display's implementation specific context
+ */
+struct rockchip_drm_display {
+	struct list_head list;
+	enum rockchip_drm_output_type type;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct rockchip_drm_display_ops *ops;
+	void *ctx;
+};
+
+/*
+ * Rockchip drm manager ops
+ *
+ * @dpms: control device power.
+ * @mode_fixup: fix mode data before applying it
+ * @mode_set: set the given mode to the manager
+ * @commit: set current hw specific display mode to hw.
+ * @enable_vblank: specific driver callback for enabling vblank interrupt.
+ * @disable_vblank: specific driver callback for disabling vblank interrupt.
+ * @wait_for_vblank: wait for vblank interrupt to make sure that
+ *      hardware overlay is updated.
+ * @win_mode_set: copy drm overlay info to hw specific overlay info.
+ * @win_commit: apply hardware specific overlay data to registers.
+ * @win_enable: enable hardware specific overlay.
+ * @win_disable: disable hardware specific overlay.
+ */
+struct rockchip_drm_manager_ops {
+	void (*dpms)(struct rockchip_drm_manager *mgr, int mode);
+	bool (*mode_fixup)(struct rockchip_drm_manager *mgr,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
+	void (*mode_set)(struct rockchip_drm_manager *mgr,
+				const struct drm_display_mode *mode);
+	void (*commit)(struct rockchip_drm_manager *mgr);
+	int (*enable_vblank)(struct rockchip_drm_manager *mgr);
+	void (*disable_vblank)(struct rockchip_drm_manager *mgr);
+	void (*wait_for_vblank)(struct rockchip_drm_manager *mgr);
+	void (*win_mode_set)(struct rockchip_drm_manager *mgr,
+				struct rockchip_drm_overlay *overlay);
+	void (*win_commit)(struct rockchip_drm_manager *mgr, int zpos);
+	void (*win_enable)(struct rockchip_drm_manager *mgr, int zpos);
+	void (*win_disable)(struct rockchip_drm_manager *mgr, int zpos);
+};
+
+/*
+ * Rockchip drm common manager structure, maps 1:1 with a crtc
+ *
+ * @list: the list entry for this manager
+ * @type: one of ROCKCHIP_DISPLAY_TYPE_LCD and HDMI.
+ * @drm_dev: pointer to the drm device
+ * @crtc: crtc object.
+ * @pipe: the pipe number for this crtc/manager
+ * @ops: pointer to callbacks for rockchip drm specific functionality
+ * @ctx: A pointer to the manager's implementation specific context
+ */
+struct rockchip_drm_manager {
+	struct list_head list;
+	enum rockchip_drm_output_type type;
+	struct drm_device *drm_dev;
+	struct drm_crtc *crtc;
+	int pipe;
+	struct rockchip_drm_manager_ops *ops;
+	void *ctx;
+};
+
+struct drm_rockchip_file_private {
+	struct file *anon_filp;
+};
+
+/*
+ * Rockchip drm private structure.
+ *
+ * @da_start: start address to device address space.
+ *      with iommu, device address space starts from this address
+ *      otherwise default one.
+ * @da_space_size: size of device address space.
+ *      if 0 then default value is used for it.
+ * @pipe: the pipe number for this crtc/manager.
+ */
+struct rockchip_drm_private {
+	struct drm_fb_helper *fb_helper;
+
+	/* list head for new event to be added. */
+	struct list_head pageflip_event_list;
+
+	/*
+	 * created crtc object would be contained at this array and
+	 * 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;
+
+	unsigned long da_start;
+	unsigned long da_space_size;
+
+	unsigned int pipe;
+};
+
+/*
+ * Rockchip drm sub driver structure.
+ *
+ * @list: sub driver has its own list object to register to rockchip drm driver.
+ * @dev: pointer to device object for subdrv device driver.
+ * @drm_dev: pointer to drm_device and this pointer would be set
+ *      when sub driver calls rockchip_drm_subdrv_register().
+ * @manager: subdrv has its own manager to control a hardware appropriately
+ *     and we can access a hardware drawing on this manager.
+ * @probe: this callback would be called by rockchip drm driver after
+ *     subdrv is registered to it.
+ * @remove: this callback is used to release resources created
+ *     by probe callback.
+ * @open: this would be called with drm device file open.
+ * @close: this would be called with drm device file close.
+ */
+struct rockchip_drm_subdrv {
+	struct list_head list;
+	struct device *dev;
+	struct drm_device *drm_dev;
+
+	int (*probe)(struct drm_device *drm_dev, struct device *dev);
+	void (*remove)(struct drm_device *drm_dev, struct device *dev);
+	int (*open)(struct drm_device *drm_dev, struct device *dev,
+			struct drm_file *file);
+	void (*close)(struct drm_device *drm_dev, struct device *dev,
+			struct drm_file *file);
+};
+
+ /* This function would be called by non kms drivers. */
+int rockchip_drm_subdrv_register(struct rockchip_drm_subdrv *drm_subdrv);
+
+/* this function removes subdrv list from rockchip drm driver */
+int rockchip_drm_subdrv_unregister(struct rockchip_drm_subdrv *drm_subdrv);
+
+int rockchip_drm_device_subdrv_probe(struct drm_device *dev);
+int rockchip_drm_device_subdrv_remove(struct drm_device *dev);
+int rockchip_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
+void rockchip_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
+
+/* This function creates a encoder and a connector, and initializes them. */
+int rockchip_drm_create_enc_conn(struct drm_device *dev,
+				struct rockchip_drm_display *display);
+
+int rockchip_drm_component_add(struct device *dev,
+				enum rockchip_drm_device_type dev_type,
+				enum rockchip_drm_output_type out_type);
+
+void rockchip_drm_component_del(struct device *dev,
+				enum rockchip_drm_device_type dev_type);
+#endif /* _ROCKCHIP_DRM_DRV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_encoder.c b/drivers/gpu/drm/rockchip/rockchip_drm_encoder.c
new file mode 100644
index 0000000..adc82ed
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_encoder.c
@@ -0,0 +1,206 @@
+/* rockchip_drm_encoder.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_encoder.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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_crtc_helper.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_encoder.h"
+
+#define to_rockchip_encoder(x)	container_of(x, struct rockchip_drm_encoder,\
+				drm_encoder)
+
+/*
+ * rockchip specific encoder structure.
+ *
+ * @drm_encoder: encoder object.
+ * @display: the display structure that maps to this encoder
+ */
+struct rockchip_drm_encoder {
+	struct drm_encoder drm_encoder;
+	struct rockchip_drm_display *display;
+};
+
+static void rockchip_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct rockchip_drm_encoder *rockchip_encoder =
+						to_rockchip_encoder(encoder);
+	struct rockchip_drm_display *display = rockchip_encoder->display;
+
+	DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
+
+	if (display->ops->dpms)
+		display->ops->dpms(display, mode);
+}
+
+static bool
+rockchip_drm_encoder_mode_fixup(struct drm_encoder *encoder,
+			       const struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode)
+{
+	struct drm_device *dev = encoder->dev;
+	struct rockchip_drm_encoder *rockchip_encoder =
+						to_rockchip_encoder(encoder);
+	struct rockchip_drm_display *display = rockchip_encoder->display;
+	struct drm_connector *connector;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->encoder != encoder)
+			continue;
+
+		if (display->ops->mode_fixup)
+			display->ops->mode_fixup(display, connector, mode,
+					adjusted_mode);
+	}
+
+	return true;
+}
+
+static void rockchip_drm_encoder_mode_set(struct drm_encoder *encoder,
+					struct drm_display_mode *mode,
+					struct drm_display_mode *adjusted_mode)
+{
+	struct rockchip_drm_encoder *rockchip_encoder =
+						to_rockchip_encoder(encoder);
+	struct rockchip_drm_display *display = rockchip_encoder->display;
+
+	if (display->ops->mode_set)
+		display->ops->mode_set(display, adjusted_mode);
+}
+
+static void rockchip_drm_encoder_prepare(struct drm_encoder *encoder)
+{
+	/* drm framework doesn't check NULL. */
+}
+
+static void rockchip_drm_encoder_commit(struct drm_encoder *encoder)
+{
+	struct rockchip_drm_encoder *rockchip_encoder =
+						to_rockchip_encoder(encoder);
+	struct rockchip_drm_display *display = rockchip_encoder->display;
+
+	if (display->ops->dpms)
+		display->ops->dpms(display, DRM_MODE_DPMS_ON);
+
+	if (display->ops->commit)
+		display->ops->commit(display);
+}
+
+static void rockchip_drm_encoder_disable(struct drm_encoder *encoder)
+{
+	struct drm_plane *plane;
+	struct drm_device *dev = encoder->dev;
+
+	rockchip_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+
+	/* all planes connected to this encoder should be also disabled. */
+	drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
+		if (plane->crtc == encoder->crtc)
+			plane->funcs->disable_plane(plane);
+	}
+}
+
+static struct drm_encoder_helper_funcs rockchip_encoder_helper_funcs = {
+	.dpms = rockchip_drm_encoder_dpms,
+	.mode_fixup = rockchip_drm_encoder_mode_fixup,
+	.mode_set = rockchip_drm_encoder_mode_set,
+	.prepare = rockchip_drm_encoder_prepare,
+	.commit = rockchip_drm_encoder_commit,
+	.disable = rockchip_drm_encoder_disable,
+};
+
+static void rockchip_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+	struct rockchip_drm_encoder *rockchip_encoder =
+						to_rockchip_encoder(encoder);
+
+	drm_encoder_cleanup(encoder);
+	kfree(rockchip_encoder);
+}
+
+static struct drm_encoder_funcs rockchip_encoder_funcs = {
+	.destroy = rockchip_drm_encoder_destroy,
+};
+
+static unsigned int rockchip_drm_encoder_clones(struct drm_encoder *encoder)
+{
+	struct drm_encoder *clone;
+	struct drm_device *dev = encoder->dev;
+	struct rockchip_drm_encoder *rockchip_encoder =
+						to_rockchip_encoder(encoder);
+	struct rockchip_drm_display *display = rockchip_encoder->display;
+	unsigned int clone_mask = 0;
+	int cnt = 0;
+
+	list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
+		switch (display->type) {
+		case ROCKCHIP_DISPLAY_TYPE_LCD:
+		case ROCKCHIP_DISPLAY_TYPE_HDMI:
+			clone_mask |= (1 << (cnt++));
+			break;
+		default:
+			continue;
+		}
+	}
+
+	return clone_mask;
+}
+
+void rockchip_drm_encoder_setup(struct drm_device *dev)
+{
+	struct drm_encoder *encoder;
+
+	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+		encoder->possible_clones =
+				rockchip_drm_encoder_clones(encoder);
+}
+
+struct drm_encoder *rockchip_drm_encoder_create(struct drm_device *dev,
+					struct rockchip_drm_display *display,
+					unsigned long possible_crtcs)
+{
+	struct drm_encoder *encoder;
+	struct rockchip_drm_encoder *rockchip_encoder;
+
+	if (!possible_crtcs)
+		return NULL;
+
+	rockchip_encoder = kzalloc(sizeof(*rockchip_encoder), GFP_KERNEL);
+	if (!rockchip_encoder)
+		return NULL;
+
+	rockchip_encoder->display = display;
+	encoder = &rockchip_encoder->drm_encoder;
+	encoder->possible_crtcs = possible_crtcs;
+
+	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+	drm_encoder_init(dev, encoder, &rockchip_encoder_funcs,
+			DRM_MODE_ENCODER_TMDS);
+
+	drm_encoder_helper_add(encoder, &rockchip_encoder_helper_funcs);
+
+	DRM_DEBUG_KMS("encoder has been created\n");
+
+	return encoder;
+}
+
+struct rockchip_drm_display *
+		rockchip_drm_get_display(struct drm_encoder *encoder)
+{
+	return to_rockchip_encoder(encoder)->display;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_encoder.h b/drivers/gpu/drm/rockchip/rockchip_drm_encoder.h
new file mode 100644
index 0000000..38b7dc0
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_encoder.h
@@ -0,0 +1,30 @@
+/* rockchip_drm_encoder.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_encoder.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_ENCODER_H_
+#define _ROCKCHIP_DRM_ENCODER_H_
+
+struct rockchip_drm_manager;
+
+void rockchip_drm_encoder_setup(struct drm_device *dev);
+struct drm_encoder *rockchip_drm_encoder_create(struct drm_device *dev,
+			struct rockchip_drm_display *mgr,
+			unsigned long possible_crtcs);
+struct rockchip_drm_display *
+		rockchip_drm_get_display(struct drm_encoder *encoder);
+
+#endif /* _ROCKCHIP_DRM_ENCODER_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
new file mode 100644
index 0000000..ca27d74
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -0,0 +1,333 @@
+/* rockchip_drm_fb.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_fb.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <uapi/drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_fbdev.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_iommu.h"
+#include "rockchip_drm_crtc.h"
+
+#define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
+
+/*
+ * rockchip specific framebuffer structure.
+ *
+ * @fb: drm framebuffer obejct.
+ * @buf_cnt: a buffer count to drm framebuffer.
+ * @rockchip_gem_obj: array of rockchip specific
+ *                    gem object containing a gem object.
+ */
+struct rockchip_drm_fb {
+	struct drm_framebuffer fb;
+	unsigned int buf_cnt;
+	struct rockchip_drm_gem_obj *rockchip_gem_obj[MAX_FB_BUFFER];
+};
+
+static int check_fb_gem_memory_type(struct drm_device *drm_dev,
+				struct rockchip_drm_gem_obj *rockchip_gem_obj)
+{
+	unsigned int flags;
+
+	/*
+	 * if rockchip drm driver supports iommu then framebuffer can use
+	 * all the buffer types.
+	 */
+	if (is_drm_iommu_supported(drm_dev))
+		return 0;
+
+	flags = rockchip_gem_obj->flags;
+
+	/*
+	 * without iommu support, not support physically non-continuous memory
+	 * for framebuffer.
+	 */
+	if (IS_NONCONTIG_BUFFER(flags)) {
+		DRM_ERROR("cannot use this gem memory type for fb.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void rockchip_drm_fb_destroy(struct drm_framebuffer *fb)
+{
+	struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
+	unsigned int i;
+
+	/* make sure that overlay data are updated before relesing fb. */
+	rockchip_drm_crtc_complete_scanout(fb);
+
+	drm_framebuffer_cleanup(fb);
+
+	for (i = 0; i < ARRAY_SIZE(rockchip_fb->rockchip_gem_obj); i++) {
+		struct drm_gem_object *obj;
+
+		if (rockchip_fb->rockchip_gem_obj[i] == NULL)
+			continue;
+
+		obj = &rockchip_fb->rockchip_gem_obj[i]->base;
+		drm_gem_object_unreference_unlocked(obj);
+	}
+
+	kfree(rockchip_fb);
+	rockchip_fb = NULL;
+}
+
+static int rockchip_drm_fb_create_handle(struct drm_framebuffer *fb,
+					struct drm_file *file_priv,
+					unsigned int *handle)
+{
+	struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
+
+	/* This fb should have only one gem object. */
+	if (WARN_ON(rockchip_fb->buf_cnt != 1))
+		return -EINVAL;
+
+	return drm_gem_handle_create(file_priv,
+			&rockchip_fb->rockchip_gem_obj[0]->base, handle);
+}
+
+static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
+				struct drm_file *file_priv, unsigned flags,
+				unsigned color, struct drm_clip_rect *clips,
+				unsigned num_clips)
+{
+	/* TODO */
+
+	return 0;
+}
+
+static struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
+	.destroy = rockchip_drm_fb_destroy,
+	.create_handle = rockchip_drm_fb_create_handle,
+	.dirty = rockchip_drm_fb_dirty,
+};
+
+void rockchip_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
+						unsigned int cnt)
+{
+	struct rockchip_drm_fb *rockchip_fb;
+
+	rockchip_fb = to_rockchip_fb(fb);
+
+	rockchip_fb->buf_cnt = cnt;
+}
+
+unsigned int rockchip_drm_fb_get_buf_cnt(struct drm_framebuffer *fb)
+{
+	struct rockchip_drm_fb *rockchip_fb;
+
+	rockchip_fb = to_rockchip_fb(fb);
+
+	return rockchip_fb->buf_cnt;
+}
+
+struct drm_framebuffer *
+rockchip_drm_framebuffer_init(struct drm_device *dev,
+			    struct drm_mode_fb_cmd2 *mode_cmd,
+			    struct drm_gem_object *obj)
+{
+	struct rockchip_drm_fb *rockchip_fb;
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	int ret;
+
+	rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+	ret = check_fb_gem_memory_type(dev, rockchip_gem_obj);
+	if (ret < 0) {
+		DRM_ERROR("cannot use this gem memory type for fb.\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
+	if (!rockchip_fb)
+		return ERR_PTR(-ENOMEM);
+
+	drm_helper_mode_fill_fb_struct(&rockchip_fb->fb, mode_cmd);
+	rockchip_fb->rockchip_gem_obj[0] = rockchip_gem_obj;
+
+	ret = drm_framebuffer_init(dev, &rockchip_fb->fb,
+					&rockchip_drm_fb_funcs);
+	if (ret) {
+		DRM_ERROR("failed to initialize framebuffer\n");
+		return ERR_PTR(ret);
+	}
+
+	return &rockchip_fb->fb;
+}
+
+static u32 rockchip_drm_format_num_buffers(struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	unsigned int cnt = 0;
+
+	if (mode_cmd->pixel_format != DRM_FORMAT_NV12)
+		return drm_format_num_planes(mode_cmd->pixel_format);
+
+	while (cnt != MAX_FB_BUFFER) {
+		if (!mode_cmd->handles[cnt])
+			break;
+		cnt++;
+	}
+
+	/*
+	 * check if NV12 or NV12M.
+	 *
+	 * NV12
+	 * handles[0] = base1, offsets[0] = 0
+	 * handles[1] = base1, offsets[1] = Y_size
+	 *
+	 * NV12M
+	 * handles[0] = base1, offsets[0] = 0
+	 * handles[1] = base2, offsets[1] = 0
+	 */
+	if (cnt == 2) {
+		/*
+		 * in case of NV12 format, offsets[1] is not 0 and
+		 * handles[0] is same as handles[1].
+		 */
+		if (mode_cmd->offsets[1] &&
+			mode_cmd->handles[0] == mode_cmd->handles[1])
+			cnt = 1;
+	}
+
+	return cnt;
+}
+
+static struct drm_framebuffer *
+rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
+		      struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct drm_gem_object *obj;
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct rockchip_drm_fb *rockchip_fb;
+	int i, ret;
+
+	rockchip_fb = kzalloc(sizeof(*rockchip_fb), GFP_KERNEL);
+	if (!rockchip_fb)
+		return ERR_PTR(-ENOMEM);
+
+	obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object\n");
+		ret = -ENOENT;
+		goto err_free;
+	}
+
+	drm_helper_mode_fill_fb_struct(&rockchip_fb->fb, mode_cmd);
+	rockchip_fb->rockchip_gem_obj[0] = to_rockchip_gem_obj(obj);
+	rockchip_fb->buf_cnt = rockchip_drm_format_num_buffers(mode_cmd);
+
+	DRM_DEBUG_KMS("buf_cnt = %d\n", rockchip_fb->buf_cnt);
+
+	for (i = 1; i < rockchip_fb->buf_cnt; i++) {
+		obj = drm_gem_object_lookup(dev, file_priv,
+				mode_cmd->handles[i]);
+		if (!obj) {
+			DRM_ERROR("failed to lookup gem object\n");
+			ret = -ENOENT;
+			rockchip_fb->buf_cnt = i;
+			goto err_unreference;
+		}
+
+		rockchip_gem_obj = to_rockchip_gem_obj(obj);
+		rockchip_fb->rockchip_gem_obj[i] = rockchip_gem_obj;
+
+		ret = check_fb_gem_memory_type(dev, rockchip_gem_obj);
+		if (ret < 0) {
+			DRM_ERROR("cannot use this gem memory type for fb.\n");
+			goto err_unreference;
+		}
+	}
+
+	ret = drm_framebuffer_init(dev, &rockchip_fb->fb,
+					&rockchip_drm_fb_funcs);
+	if (ret) {
+		DRM_ERROR("failed to init framebuffer.\n");
+		goto err_unreference;
+	}
+
+	return &rockchip_fb->fb;
+
+err_unreference:
+	for (i = 0; i < rockchip_fb->buf_cnt; i++) {
+		struct drm_gem_object *obj;
+
+		obj = &rockchip_fb->rockchip_gem_obj[i]->base;
+		if (obj)
+			drm_gem_object_unreference_unlocked(obj);
+	}
+err_free:
+	kfree(rockchip_fb);
+	return ERR_PTR(ret);
+}
+
+struct rockchip_drm_gem_buf *rockchip_drm_fb_buffer(struct drm_framebuffer *fb,
+						int index)
+{
+	struct rockchip_drm_fb *rockchip_fb = to_rockchip_fb(fb);
+	struct rockchip_drm_gem_buf *buffer;
+
+	if (index >= MAX_FB_BUFFER)
+		return NULL;
+
+	buffer = rockchip_fb->rockchip_gem_obj[index]->buffer;
+	if (!buffer)
+		return NULL;
+
+	DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr);
+
+	return buffer;
+}
+
+static void rockchip_drm_output_poll_changed(struct drm_device *dev)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct drm_fb_helper *fb_helper = private->fb_helper;
+
+	if (fb_helper)
+		drm_fb_helper_hotplug_event(fb_helper);
+	else
+		rockchip_drm_fbdev_init(dev);
+}
+
+static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
+	.fb_create = rockchip_user_fb_create,
+	.output_poll_changed = rockchip_drm_output_poll_changed,
+};
+
+void rockchip_drm_mode_config_init(struct drm_device *dev)
+{
+	dev->mode_config.min_width = 0;
+	dev->mode_config.min_height = 0;
+
+	/*
+	 * set max width and height as default value(4096x4096).
+	 * this value would be used to check framebuffer size limitation
+	 * at drm_mode_addfb().
+	 */
+	dev->mode_config.max_width = 4096;
+	dev->mode_config.max_height = 4096;
+
+	dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
new file mode 100644
index 0000000..1639ab20
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h
@@ -0,0 +1,39 @@
+/* rockchip_drm_fb.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_fb.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_FB_H_
+#define _ROCKCHIP_DRM_FB_H_
+
+struct drm_framebuffer *
+rockchip_drm_framebuffer_init(struct drm_device *dev,
+			    struct drm_mode_fb_cmd2 *mode_cmd,
+			    struct drm_gem_object *obj);
+
+/* get memory information of a drm framebuffer */
+struct rockchip_drm_gem_buf *rockchip_drm_fb_buffer(struct drm_framebuffer *fb,
+						 int index);
+
+void rockchip_drm_mode_config_init(struct drm_device *dev);
+
+/* set a buffer count to drm framebuffer. */
+void rockchip_drm_fb_set_buf_cnt(struct drm_framebuffer *fb,
+						unsigned int cnt);
+
+/* get a buffer count to drm framebuffer. */
+unsigned int rockchip_drm_fb_get_buf_cnt(struct drm_framebuffer *fb);
+
+#endif /* _ROCKCHIP_DRM_FB_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
new file mode 100644
index 0000000..49f41a9
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
@@ -0,0 +1,380 @@
+/* rockchip_drm_fbdev.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_fbdev.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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_crtc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_fbdev.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_iommu.h"
+
+#define MAX_CONNECTOR		4
+#define PREFERRED_BPP		32
+
+#define to_rockchip_fbdev(x)	container_of(x, struct rockchip_drm_fbdev,\
+				drm_fb_helper)
+
+struct rockchip_drm_fbdev {
+	struct drm_fb_helper drm_fb_helper;
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+};
+
+static int rockchip_drm_fb_mmap(struct fb_info *info,
+			struct vm_area_struct *vma)
+{
+	struct drm_fb_helper *helper = info->par;
+	struct rockchip_drm_fbdev *rockchip_fbd = to_rockchip_fbdev(helper);
+	struct rockchip_drm_gem_obj *rockchip_gem_obj =
+					rockchip_fbd->rockchip_gem_obj;
+	struct rockchip_drm_gem_buf *buffer = rockchip_gem_obj->buffer;
+	unsigned long vm_size;
+	int ret;
+
+	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+
+	vm_size = vma->vm_end - vma->vm_start;
+
+	if (vm_size > buffer->size)
+		return -EINVAL;
+
+	ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages,
+		buffer->dma_addr, buffer->size, &buffer->dma_attrs);
+	if (ret < 0) {
+		DRM_ERROR("failed to mmap.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct fb_ops rockchip_drm_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_mmap = rockchip_drm_fb_mmap,
+	.fb_fillrect = cfb_fillrect,
+	.fb_copyarea = cfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+	.fb_check_var = drm_fb_helper_check_var,
+	.fb_set_par = drm_fb_helper_set_par,
+	.fb_blank = drm_fb_helper_blank,
+	.fb_pan_display = drm_fb_helper_pan_display,
+	.fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static int rockchip_drm_fbdev_update(struct drm_fb_helper *helper,
+				     struct drm_framebuffer *fb)
+{
+	struct fb_info *fbi = helper->fbdev;
+	struct drm_device *dev = helper->dev;
+	struct rockchip_drm_gem_buf *buffer;
+	unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
+	unsigned long offset;
+
+	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
+	drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height);
+
+	/* RGB formats use only one buffer */
+	buffer = rockchip_drm_fb_buffer(fb, 0);
+	if (!buffer) {
+		DRM_DEBUG_KMS("buffer is null.\n");
+		return -EFAULT;
+	}
+
+	/* map pages with kernel virtual space. */
+	if (!buffer->kvaddr) {
+		if (is_drm_iommu_supported(dev)) {
+			unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
+
+			buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
+					nr_pages, VM_MAP,
+					pgprot_writecombine(PAGE_KERNEL));
+		} else {
+			phys_addr_t dma_addr = buffer->dma_addr;
+
+			if (dma_addr)
+				buffer->kvaddr =
+					(void __iomem *)phys_to_virt(dma_addr);
+			else
+				buffer->kvaddr = (void __iomem *)NULL;
+		}
+		if (!buffer->kvaddr) {
+			DRM_ERROR("failed to map pages to kernel space.\n");
+			return -EIO;
+		}
+	}
+
+	/* buffer count to framebuffer always is 1 at booting time. */
+	rockchip_drm_fb_set_buf_cnt(fb, 1);
+
+	offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3);
+	offset += fbi->var.yoffset * fb->pitches[0];
+
+	fbi->screen_base = buffer->kvaddr + offset;
+	fbi->screen_size = size;
+	fbi->fix.smem_len = size;
+
+	return 0;
+}
+
+static int rockchip_drm_fbdev_create(struct drm_fb_helper *helper,
+				    struct drm_fb_helper_surface_size *sizes)
+{
+	struct rockchip_drm_fbdev *rockchip_fbdev = to_rockchip_fbdev(helper);
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct drm_device *dev = helper->dev;
+	struct fb_info *fbi;
+	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+	struct platform_device *pdev = dev->platformdev;
+	unsigned long size;
+	int ret;
+
+	DRM_DEBUG_KMS("surface width(%d), height(%d) and bpp(%d\n",
+			sizes->surface_width, sizes->surface_height,
+			sizes->surface_bpp);
+
+	mode_cmd.width = sizes->surface_width;
+	mode_cmd.height = sizes->surface_height;
+	mode_cmd.pitches[0] = sizes->surface_width * (sizes->surface_bpp >> 3);
+	mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+							  sizes->surface_depth);
+
+	mutex_lock(&dev->struct_mutex);
+
+	fbi = framebuffer_alloc(0, &pdev->dev);
+	if (!fbi) {
+		DRM_ERROR("failed to allocate fb info.\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	size = mode_cmd.pitches[0] * mode_cmd.height;
+
+	rockchip_gem_obj = rockchip_drm_gem_create(dev,
+						ROCKCHIP_BO_CONTIG, size);
+	/*
+	 * If physically contiguous memory allocation fails and if IOMMU is
+	 * supported then try to get buffer from non physically contiguous
+	 * memory area.
+	 */
+	if (IS_ERR(rockchip_gem_obj) && is_drm_iommu_supported(dev)) {
+		dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n");
+		rockchip_gem_obj = rockchip_drm_gem_create(dev,
+					ROCKCHIP_BO_NONCONTIG, size);
+	}
+
+	if (IS_ERR(rockchip_gem_obj)) {
+		ret = PTR_ERR(rockchip_gem_obj);
+		goto err_release_framebuffer;
+	}
+
+	rockchip_fbdev->rockchip_gem_obj = rockchip_gem_obj;
+
+	helper->fb = rockchip_drm_framebuffer_init(dev, &mode_cmd,
+			&rockchip_gem_obj->base);
+	if (IS_ERR(helper->fb)) {
+		DRM_ERROR("failed to create drm framebuffer.\n");
+		ret = PTR_ERR(helper->fb);
+		goto err_destroy_gem;
+	}
+
+	helper->fbdev = fbi;
+
+	fbi->par = helper;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->fbops = &rockchip_drm_fb_ops;
+
+	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+	if (ret) {
+		DRM_ERROR("failed to allocate cmap.\n");
+		goto err_destroy_framebuffer;
+	}
+
+	ret = rockchip_drm_fbdev_update(helper, helper->fb);
+	if (ret < 0)
+		goto err_dealloc_cmap;
+
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+
+err_dealloc_cmap:
+	fb_dealloc_cmap(&fbi->cmap);
+err_destroy_framebuffer:
+	drm_framebuffer_cleanup(helper->fb);
+err_destroy_gem:
+	rockchip_drm_gem_destroy(rockchip_gem_obj);
+err_release_framebuffer:
+	framebuffer_release(fbi);
+
+/*
+ * if failed, all resources allocated above would be released by
+ * drm_mode_config_cleanup() when drm_load() had been called prior
+ * to any specific driver such as lcdc or hdmi driver.
+ */
+out:
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
+
+static struct drm_fb_helper_funcs rockchip_drm_fb_helper_funcs = {
+	.fb_probe = rockchip_drm_fbdev_create,
+};
+
+static bool rockchip_drm_fbdev_is_anything_connected(struct drm_device *dev)
+{
+	struct drm_connector *connector;
+	bool ret = false;
+
+	mutex_lock(&dev->mode_config.mutex);
+	list_for_each_entry(connector,
+			&dev->mode_config.connector_list, head) {
+		if (connector->status != connector_status_connected)
+			continue;
+
+		ret = true;
+		break;
+	}
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
+}
+
+int rockchip_drm_fbdev_init(struct drm_device *dev)
+{
+	struct rockchip_drm_fbdev *fbdev;
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct drm_fb_helper *helper;
+	unsigned int num_crtc;
+	int ret;
+
+	if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
+		return 0;
+
+	if (!rockchip_drm_fbdev_is_anything_connected(dev))
+		return 0;
+
+	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
+	if (!fbdev)
+		return -ENOMEM;
+
+	private->fb_helper = helper = &fbdev->drm_fb_helper;
+	helper->funcs = &rockchip_drm_fb_helper_funcs;
+
+	num_crtc = dev->mode_config.num_crtc;
+
+	ret = drm_fb_helper_init(dev, helper, num_crtc, MAX_CONNECTOR);
+	if (ret < 0) {
+		DRM_ERROR("failed to initialize drm fb helper.\n");
+		goto err_init;
+	}
+
+	ret = drm_fb_helper_single_add_all_connectors(helper);
+	if (ret < 0) {
+		DRM_ERROR("failed to register drm_fb_helper_connector.\n");
+		goto err_setup;
+	}
+
+	/* disable all the possible outputs/crtcs before entering KMS mode */
+	drm_helper_disable_unused_functions(dev);
+
+	ret = drm_fb_helper_initial_config(helper, PREFERRED_BPP);
+	if (ret < 0) {
+		DRM_ERROR("failed to set up hw configuration.\n");
+		goto err_setup;
+	}
+
+	return 0;
+
+err_setup:
+	drm_fb_helper_fini(helper);
+
+err_init:
+	private->fb_helper = NULL;
+	kfree(fbdev);
+
+	return ret;
+}
+
+static void rockchip_drm_fbdev_destroy(struct drm_device *dev,
+				      struct drm_fb_helper *fb_helper)
+{
+	struct rockchip_drm_fbdev *rockchip_fbd = to_rockchip_fbdev(fb_helper);
+	struct rockchip_drm_gem_obj *rockchip_gem_obj =
+						rockchip_fbd->rockchip_gem_obj;
+	struct drm_framebuffer *fb;
+
+	if (is_drm_iommu_supported(dev) && rockchip_gem_obj->buffer->kvaddr)
+		vunmap(rockchip_gem_obj->buffer->kvaddr);
+
+	/* release drm framebuffer and real buffer */
+	if (fb_helper->fb && fb_helper->fb->funcs) {
+		fb = fb_helper->fb;
+		if (fb) {
+			drm_framebuffer_unregister_private(fb);
+			drm_framebuffer_remove(fb);
+		}
+	}
+
+	/* release linux framebuffer */
+	if (fb_helper->fbdev) {
+		struct fb_info *info;
+		int ret;
+
+		info = fb_helper->fbdev;
+		ret = unregister_framebuffer(info);
+		if (ret < 0)
+			DRM_DEBUG_KMS("failed unregister_framebuffer()\n");
+
+		if (info->cmap.len)
+			fb_dealloc_cmap(&info->cmap);
+
+		framebuffer_release(info);
+	}
+
+	drm_fb_helper_fini(fb_helper);
+}
+
+void rockchip_drm_fbdev_fini(struct drm_device *dev)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+	struct rockchip_drm_fbdev *fbdev;
+
+	if (!private || !private->fb_helper)
+		return;
+
+	fbdev = to_rockchip_fbdev(private->fb_helper);
+
+	if (fbdev->rockchip_gem_obj)
+		rockchip_drm_gem_destroy(fbdev->rockchip_gem_obj);
+
+	rockchip_drm_fbdev_destroy(dev, private->fb_helper);
+	kfree(fbdev);
+	private->fb_helper = NULL;
+}
+
+void rockchip_drm_fbdev_restore_mode(struct drm_device *dev)
+{
+	struct rockchip_drm_private *private = dev->dev_private;
+
+	if (!private || !private->fb_helper)
+		return;
+
+	drm_fb_helper_restore_fbdev_mode_unlocked(private->fb_helper);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
new file mode 100644
index 0000000..d4bda37
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h
@@ -0,0 +1,26 @@
+/* rockchip_drm_fbdev.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_fbdev.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_FBDEV_H_
+#define _ROCKCHIP_DRM_FBDEV_H_
+
+int rockchip_drm_fbdev_init(struct drm_device *dev);
+int rockchip_drm_fbdev_reinit(struct drm_device *dev);
+void rockchip_drm_fbdev_fini(struct drm_device *dev);
+void rockchip_drm_fbdev_restore_mode(struct drm_device *dev);
+
+#endif /* _ROCKCHIP_DRM_FBDEV_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
new file mode 100644
index 0000000..96116d9
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -0,0 +1,738 @@
+/* rockchip_drm_gem.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_gem.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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_vma_manager.h>
+
+#include <linux/shmem_fs.h>
+#include <drm/rockchip_drm.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_buf.h"
+#include "rockchip_drm_iommu.h"
+
+static unsigned int convert_to_vm_err_msg(int msg)
+{
+	unsigned int out_msg;
+
+	switch (msg) {
+	case 0:
+	case -ERESTARTSYS:
+	case -EINTR:
+		out_msg = VM_FAULT_NOPAGE;
+		break;
+
+	case -ENOMEM:
+		out_msg = VM_FAULT_OOM;
+		break;
+	default:
+		out_msg = VM_FAULT_SIGBUS;
+		break;
+	}
+
+	return out_msg;
+}
+
+static int check_gem_flags(unsigned int flags)
+{
+	if (flags & ~(ROCKCHIP_BO_MASK)) {
+		DRM_ERROR("invalid flags.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void update_vm_cache_attr(struct rockchip_drm_gem_obj *obj,
+					struct vm_area_struct *vma)
+{
+	DRM_DEBUG_KMS("flags = 0x%x\n", obj->flags);
+
+	/* non-cachable as default. */
+	if (obj->flags & ROCKCHIP_BO_CACHABLE)
+		vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+	else if (obj->flags & ROCKCHIP_BO_WC)
+		vma->vm_page_prot =
+			pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+	else
+		vma->vm_page_prot =
+			pgprot_noncached(vm_get_page_prot(vma->vm_flags));
+}
+
+static unsigned long roundup_gem_size(unsigned long size, unsigned int flags)
+{
+	/* TODO */
+
+	return roundup(size, PAGE_SIZE);
+}
+
+static int rockchip_drm_gem_map_buf(struct drm_gem_object *obj,
+					struct vm_area_struct *vma,
+					unsigned long f_vaddr,
+					pgoff_t page_offset)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj =
+						to_rockchip_gem_obj(obj);
+	struct rockchip_drm_gem_buf *buf = rockchip_gem_obj->buffer;
+	struct scatterlist *sgl;
+	unsigned long pfn;
+	int i;
+
+	if (!buf->sgt)
+		return -EINTR;
+
+	if (page_offset >= (buf->size >> PAGE_SHIFT)) {
+		DRM_ERROR("invalid page offset\n");
+		return -EINVAL;
+	}
+
+	sgl = buf->sgt->sgl;
+	for_each_sg(buf->sgt->sgl, sgl, buf->sgt->nents, i) {
+		if (page_offset < (sgl->length >> PAGE_SHIFT))
+			break;
+		page_offset -= (sgl->length >> PAGE_SHIFT);
+	}
+
+	pfn = __phys_to_pfn(sg_phys(sgl)) + page_offset;
+
+	return vm_insert_mixed(vma, f_vaddr, pfn);
+}
+
+static int rockchip_drm_gem_handle_create(struct drm_gem_object *obj,
+					struct drm_file *file_priv,
+					unsigned int *handle)
+{
+	int ret;
+
+	/*
+	 * allocate a id of idr table where the obj is registered
+	 * and handle has the id what user can see.
+	 */
+	ret = drm_gem_handle_create(file_priv, obj, handle);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_KMS("gem handle = 0x%x\n", *handle);
+
+	/* drop reference from allocate - handle holds it now. */
+	drm_gem_object_unreference_unlocked(obj);
+
+	return 0;
+}
+
+void rockchip_drm_gem_destroy(struct rockchip_drm_gem_obj *rockchip_gem_obj)
+{
+	struct drm_gem_object *obj;
+	struct rockchip_drm_gem_buf *buf;
+
+	obj = &rockchip_gem_obj->base;
+	buf = rockchip_gem_obj->buffer;
+
+	DRM_DEBUG_KMS("handle count = %d\n", obj->handle_count);
+
+	/*
+	 * 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;
+
+	rockchip_drm_free_buf(obj->dev, rockchip_gem_obj->flags, buf);
+
+out:
+	rockchip_drm_fini_buf(obj->dev, buf);
+	rockchip_gem_obj->buffer = NULL;
+
+	drm_gem_free_mmap_offset(obj);
+
+	/* release file pointer to gem object. */
+	drm_gem_object_release(obj);
+
+	kfree(rockchip_gem_obj);
+	rockchip_gem_obj = NULL;
+}
+
+unsigned long rockchip_drm_gem_get_size(struct drm_device *dev,
+						unsigned int gem_handle,
+						struct drm_file *file_priv)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct drm_gem_object *obj;
+
+	obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		return 0;
+	}
+
+	rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	return rockchip_gem_obj->buffer->size;
+}
+
+
+struct rockchip_drm_gem_obj *rockchip_drm_gem_init(struct drm_device *dev,
+						      unsigned long size)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct drm_gem_object *obj;
+	int ret;
+
+	rockchip_gem_obj = kzalloc(sizeof(*rockchip_gem_obj), GFP_KERNEL);
+	if (!rockchip_gem_obj)
+		return NULL;
+
+	rockchip_gem_obj->size = size;
+	obj = &rockchip_gem_obj->base;
+
+	ret = drm_gem_object_init(dev, obj, size);
+	if (ret < 0) {
+		DRM_ERROR("failed to initialize gem object\n");
+		kfree(rockchip_gem_obj);
+		return NULL;
+	}
+
+	DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp);
+
+	return rockchip_gem_obj;
+}
+
+struct rockchip_drm_gem_obj *rockchip_drm_gem_create(struct drm_device *dev,
+						unsigned int flags,
+						unsigned long size)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct rockchip_drm_gem_buf *buf;
+	int ret;
+
+	if (!size) {
+		DRM_ERROR("invalid size.\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	size = roundup_gem_size(size, flags);
+
+	ret = check_gem_flags(flags);
+	if (ret < 0)
+		return ERR_PTR(ret);
+
+	buf = rockchip_drm_init_buf(dev, size);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	rockchip_gem_obj = rockchip_drm_gem_init(dev, size);
+	if (!rockchip_gem_obj) {
+		ret = -ENOMEM;
+		goto err_fini_buf;
+	}
+
+	rockchip_gem_obj->buffer = buf;
+
+	/* set memory type and cache attribute from user side. */
+	rockchip_gem_obj->flags = flags;
+
+	ret = rockchip_drm_alloc_buf(dev, buf, flags);
+	if (ret < 0)
+		goto err_gem_fini;
+
+	return rockchip_gem_obj;
+
+err_gem_fini:
+	drm_gem_object_release(&rockchip_gem_obj->base);
+	kfree(rockchip_gem_obj);
+err_fini_buf:
+	rockchip_drm_fini_buf(dev, buf);
+	return ERR_PTR(ret);
+}
+
+int rockchip_drm_gem_create_ioctl(struct drm_device *dev, void *data,
+				struct drm_file *file_priv)
+{
+	struct drm_rockchip_gem_create *args = data;
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	int ret;
+
+	rockchip_gem_obj = rockchip_drm_gem_create(dev,
+					args->flags, args->size);
+	if (IS_ERR(rockchip_gem_obj))
+		return PTR_ERR(rockchip_gem_obj);
+
+	ret = rockchip_drm_gem_handle_create(&rockchip_gem_obj->base,
+					file_priv, &args->handle);
+	if (ret) {
+		rockchip_drm_gem_destroy(rockchip_gem_obj);
+		return ret;
+	}
+
+	return 0;
+}
+
+dma_addr_t *rockchip_drm_gem_get_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *filp)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct drm_gem_object *obj;
+
+	obj = drm_gem_object_lookup(dev, filp, gem_handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+	return &rockchip_gem_obj->buffer->dma_addr;
+}
+
+void rockchip_drm_gem_put_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *filp)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct drm_gem_object *obj;
+
+	obj = drm_gem_object_lookup(dev, filp, gem_handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		return;
+	}
+
+	rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+	drm_gem_object_unreference_unlocked(obj);
+
+	/*
+	 * decrease obj->refcount one more time because we has already
+	 * increased it at rockchip_drm_gem_get_dma_addr().
+	 */
+	drm_gem_object_unreference_unlocked(obj);
+}
+
+int rockchip_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file_priv)
+{
+	struct drm_rockchip_gem_map_off *args = data;
+
+	DRM_DEBUG_KMS("handle = 0x%x, offset = 0x%lx\n",
+			args->handle, (unsigned long)args->offset);
+
+	if (!(dev->driver->driver_features & DRIVER_GEM)) {
+		DRM_ERROR("does not support GEM.\n");
+		return -ENODEV;
+	}
+
+	return rockchip_drm_gem_dumb_map_offset(file_priv, dev, args->handle,
+			&args->offset);
+}
+
+int rockchip_drm_gem_mmap_buffer(struct file *filp,
+				      struct vm_area_struct *vma)
+{
+	struct drm_gem_object *obj = filp->private_data;
+	struct rockchip_drm_gem_obj *rockchip_gem_obj =
+						to_rockchip_gem_obj(obj);
+	struct drm_device *drm_dev = obj->dev;
+	struct rockchip_drm_gem_buf *buffer;
+	unsigned long vm_size;
+	int ret;
+
+	WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
+
+	vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+	vma->vm_private_data = obj;
+	vma->vm_ops = drm_dev->driver->gem_vm_ops;
+
+	update_vm_cache_attr(rockchip_gem_obj, vma);
+
+	vm_size = vma->vm_end - vma->vm_start;
+
+	/*
+	 * a buffer contains information to physically continuous memory
+	 * allocated by user request or at framebuffer creation.
+	 */
+	buffer = rockchip_gem_obj->buffer;
+
+	/* check if user-requested size is valid. */
+	if (vm_size > buffer->size)
+		return -EINVAL;
+
+	ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->pages,
+				buffer->dma_addr, buffer->size,
+				&buffer->dma_attrs);
+	if (ret < 0) {
+		DRM_ERROR("failed to mmap.\n");
+		return ret;
+	}
+
+	/*
+	 * take a reference to this mapping of the object. And this reference
+	 * is unreferenced by the corresponding vm_close call.
+	 */
+	drm_gem_object_reference(obj);
+
+	drm_vm_open_locked(drm_dev, vma);
+
+	return 0;
+}
+
+int rockchip_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
+			      struct drm_file *file_priv)
+{
+	struct drm_rockchip_file_private *rockchip_file_priv;
+	struct drm_rockchip_gem_mmap *args = data;
+	struct drm_gem_object *obj;
+	struct file *anon_filp;
+	unsigned long addr;
+
+	if (!(dev->driver->driver_features & DRIVER_GEM)) {
+		DRM_ERROR("does not support GEM.\n");
+		return -ENODEV;
+	}
+
+	mutex_lock(&dev->struct_mutex);
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		mutex_unlock(&dev->struct_mutex);
+		return -EINVAL;
+	}
+
+	rockchip_file_priv = file_priv->driver_priv;
+	anon_filp = rockchip_file_priv->anon_filp;
+	anon_filp->private_data = obj;
+
+	addr = vm_mmap(anon_filp, 0, args->size, PROT_READ | PROT_WRITE,
+			MAP_SHARED, 0);
+
+	drm_gem_object_unreference(obj);
+
+	if (IS_ERR_VALUE(addr)) {
+		mutex_unlock(&dev->struct_mutex);
+		return (int)addr;
+	}
+
+	mutex_unlock(&dev->struct_mutex);
+
+	args->mapped = addr;
+
+	DRM_DEBUG_KMS("mapped = 0x%lx\n", (unsigned long)args->mapped);
+
+	return 0;
+}
+
+int rockchip_drm_gem_get_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *file_priv)
+{	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct drm_rockchip_gem_info *args = data;
+	struct drm_gem_object *obj;
+
+	mutex_lock(&dev->struct_mutex);
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		mutex_unlock(&dev->struct_mutex);
+		return -EINVAL;
+	}
+
+	rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+	args->flags = rockchip_gem_obj->flags;
+	args->size = rockchip_gem_obj->size;
+
+	drm_gem_object_unreference(obj);
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+struct vm_area_struct *rockchip_gem_get_vma(struct vm_area_struct *vma)
+{
+	struct vm_area_struct *vma_copy;
+
+	vma_copy = kmalloc(sizeof(*vma_copy), GFP_KERNEL);
+	if (!vma_copy)
+		return NULL;
+
+	if (vma->vm_ops && vma->vm_ops->open)
+		vma->vm_ops->open(vma);
+
+	if (vma->vm_file)
+		get_file(vma->vm_file);
+
+	memcpy(vma_copy, vma, sizeof(*vma));
+
+	vma_copy->vm_mm = NULL;
+	vma_copy->vm_next = NULL;
+	vma_copy->vm_prev = NULL;
+
+	return vma_copy;
+}
+
+void rockchip_gem_put_vma(struct vm_area_struct *vma)
+{
+	if (!vma)
+		return;
+
+	if (vma->vm_ops && vma->vm_ops->close)
+		vma->vm_ops->close(vma);
+
+	if (vma->vm_file)
+		fput(vma->vm_file);
+
+	kfree(vma);
+}
+
+int rockchip_gem_get_pages_from_userptr(unsigned long start,
+						unsigned int npages,
+						struct page **pages,
+						struct vm_area_struct *vma)
+{
+	int get_npages;
+
+	/* the memory region mmaped with VM_PFNMAP. */
+	if (vma_is_io(vma)) {
+		unsigned int i;
+
+		for (i = 0; i < npages; ++i, start += PAGE_SIZE) {
+			unsigned long pfn;
+			int ret = follow_pfn(vma, start, &pfn);
+
+			if (ret)
+				return ret;
+
+			pages[i] = pfn_to_page(pfn);
+		}
+
+		if (i != npages) {
+			DRM_ERROR("failed to get user_pages.\n");
+			return -EINVAL;
+		}
+
+		return 0;
+	}
+
+	get_npages = get_user_pages(current, current->mm, start,
+					npages, 1, 1, pages, NULL);
+	get_npages = max(get_npages, 0);
+	if (get_npages != npages) {
+		DRM_ERROR("failed to get user_pages.\n");
+		while (get_npages)
+			put_page(pages[--get_npages]);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+void rockchip_gem_put_pages_to_userptr(struct page **pages,
+					unsigned int npages,
+					struct vm_area_struct *vma)
+{
+	if (!vma_is_io(vma)) {
+		unsigned int i;
+
+		for (i = 0; i < npages; i++) {
+			set_page_dirty_lock(pages[i]);
+
+			/*
+			 * undo the reference we took when populating
+			 * the table.
+			 */
+			put_page(pages[i]);
+		}
+	}
+}
+
+int rockchip_gem_map_sgt_with_dma(struct drm_device *drm_dev,
+				struct sg_table *sgt,
+				enum dma_data_direction dir)
+{
+	int nents;
+
+	mutex_lock(&drm_dev->struct_mutex);
+
+	nents = dma_map_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir);
+	if (!nents) {
+		DRM_ERROR("failed to map sgl with dma.\n");
+		mutex_unlock(&drm_dev->struct_mutex);
+		return nents;
+	}
+
+	mutex_unlock(&drm_dev->struct_mutex);
+
+	return 0;
+}
+
+void rockchip_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
+				struct sg_table *sgt,
+				enum dma_data_direction dir)
+{
+	dma_unmap_sg(drm_dev->dev, sgt->sgl, sgt->nents, dir);
+}
+
+void rockchip_drm_gem_free_object(struct drm_gem_object *obj)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct rockchip_drm_gem_buf *buf;
+
+	rockchip_gem_obj = to_rockchip_gem_obj(obj);
+	buf = rockchip_gem_obj->buffer;
+
+	if (obj->import_attach)
+		drm_prime_gem_destroy(obj, buf->sgt);
+
+	rockchip_drm_gem_destroy(to_rockchip_gem_obj(obj));
+}
+
+int rockchip_drm_gem_dumb_create(struct drm_file *file_priv,
+			       struct drm_device *dev,
+			       struct drm_mode_create_dumb *args)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	int ret;
+
+	/*
+	 * allocate memory to be used for framebuffer.
+	 * - this callback would be called by user application
+	 * with DRM_IOCTL_MODE_CREATE_DUMB command.
+	 */
+
+	args->pitch = args->width * ((args->bpp + 7) / 8);
+	args->size = args->pitch * args->height;
+
+	if (is_drm_iommu_supported(dev)) {
+		rockchip_gem_obj = rockchip_drm_gem_create(dev,
+			ROCKCHIP_BO_NONCONTIG | ROCKCHIP_BO_WC,
+			args->size);
+	} else {
+		rockchip_gem_obj = rockchip_drm_gem_create(dev,
+			ROCKCHIP_BO_CONTIG | ROCKCHIP_BO_WC,
+			args->size);
+	}
+
+	if (IS_ERR(rockchip_gem_obj)) {
+		dev_warn(dev->dev, "FB allocation failed.\n");
+		return PTR_ERR(rockchip_gem_obj);
+	}
+
+	ret = rockchip_drm_gem_handle_create(&rockchip_gem_obj->base,
+					file_priv, &args->handle);
+	if (ret) {
+		rockchip_drm_gem_destroy(rockchip_gem_obj);
+		return ret;
+	}
+
+	return 0;
+}
+
+int rockchip_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+				   struct drm_device *dev, uint32_t handle,
+				   uint64_t *offset)
+{
+	struct drm_gem_object *obj;
+	int ret = 0;
+
+	mutex_lock(&dev->struct_mutex);
+
+	/*
+	 * get offset of memory allocated for drm framebuffer.
+	 * - this callback would be called by user application
+	 * with DRM_IOCTL_MODE_MAP_DUMB command.
+	 */
+
+	obj = drm_gem_object_lookup(dev, file_priv, handle);
+	if (!obj) {
+		DRM_ERROR("failed to lookup gem object.\n");
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	ret = drm_gem_create_mmap_offset(obj);
+	if (ret)
+		goto out;
+
+	*offset = drm_vma_node_offset_addr(&obj->vma_node);
+	DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);
+
+out:
+	drm_gem_object_unreference(obj);
+unlock:
+	mutex_unlock(&dev->struct_mutex);
+	return ret;
+}
+
+int rockchip_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+	struct drm_gem_object *obj = vma->vm_private_data;
+	struct drm_device *dev = obj->dev;
+	unsigned long f_vaddr;
+	pgoff_t page_offset;
+	int ret;
+
+	page_offset = ((unsigned long)vmf->virtual_address -
+			vma->vm_start) >> PAGE_SHIFT;
+	f_vaddr = (unsigned long)vmf->virtual_address;
+
+	mutex_lock(&dev->struct_mutex);
+
+	ret = rockchip_drm_gem_map_buf(obj, vma, f_vaddr, page_offset);
+	if (ret < 0)
+		DRM_ERROR("failed to map a buffer with user.\n");
+
+	mutex_unlock(&dev->struct_mutex);
+
+	return convert_to_vm_err_msg(ret);
+}
+
+int rockchip_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	struct rockchip_drm_gem_obj *rockchip_gem_obj;
+	struct drm_gem_object *obj;
+	int ret;
+
+	/* set vm_area_struct. */
+	ret = drm_gem_mmap(filp, vma);
+	if (ret < 0) {
+		DRM_ERROR("failed to mmap.\n");
+		return ret;
+	}
+
+	obj = vma->vm_private_data;
+	rockchip_gem_obj = to_rockchip_gem_obj(obj);
+
+	ret = check_gem_flags(rockchip_gem_obj->flags);
+	if (ret < 0) {
+		drm_gem_vm_close(vma);
+		drm_gem_free_mmap_offset(obj);
+		return ret;
+	}
+
+	vma->vm_flags &= ~VM_PFNMAP;
+	vma->vm_flags |= VM_MIXEDMAP;
+
+	update_vm_cache_attr(rockchip_gem_obj, vma);
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.h b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
new file mode 100644
index 0000000..e322c42
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.h
@@ -0,0 +1,198 @@
+/* rockchip_drm_gem.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_gem.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_GEM_H_
+#define _ROCKCHIP_DRM_GEM_H_
+
+#define to_rockchip_gem_obj(x)	container_of(x,\
+			struct rockchip_drm_gem_obj, base)
+
+#define IS_NONCONTIG_BUFFER(f)		(f & ROCKCHIP_BO_NONCONTIG)
+
+/*
+ * rockchip drm gem buffer structure.
+ *
+ * @kvaddr: kernel virtual address to allocated memory region.
+ * *userptr: user space address.
+ * @dma_addr: bus address(accessed by dma) to allocated memory region.
+ *        - this address could be physical address without IOMMU and
+ *        device address with IOMMU.
+ * @write: whether pages will be written to by the caller.
+ * @pages: Array of backing pages.
+ * @sgt: sg table to transfer page data.
+ * @size: size of allocated memory region.
+ * @pfnmap: indicate whether memory region from userptr is mmaped with
+ * VM_PFNMAP or not.
+ */
+struct rockchip_drm_gem_buf {
+	void __iomem *kvaddr;
+	unsigned long userptr;
+	dma_addr_t dma_addr;
+	struct dma_attrs dma_attrs;
+	unsigned int write;
+	struct page **pages;
+	struct sg_table *sgt;
+	unsigned long size;
+	bool pfnmap;
+};
+
+/*
+ * rockchip drm buffer structure.
+ *
+ * @base: a gem object.
+ *      - a new handle to this gem object would be created
+ *      by drm_gem_handle_create().
+ * @buffer: a pointer to rockchip_drm_gem_buffer object.
+ *      - contain the information to memory region allocated
+ *      by user request or at framebuffer creation.
+ *      continuous memory region allocated by user request
+ *      or at framebuffer creation.
+ * @size: size requested from user, in bytes and this size is aligned
+ *      in page unit.
+ * @vma: a pointer to vm_area.
+ * @flags: indicate memory type to allocated buffer and cache attruibute.
+ *
+ * P.S. this object would be transferred to user as kms_bo.handle so
+ *      user can access the buffer through kms_bo.handle.
+ */
+struct rockchip_drm_gem_obj {
+	struct drm_gem_object base;
+	struct rockchip_drm_gem_buf *buffer;
+	unsigned long size;
+	struct vm_area_struct *vma;
+	unsigned int flags;
+};
+
+struct page **rockchip_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
+
+/* destroy a buffer with gem object */
+void rockchip_drm_gem_destroy(struct rockchip_drm_gem_obj *rockchip_gem_obj);
+
+/* create a private gem object and initialize it. */
+struct rockchip_drm_gem_obj *rockchip_drm_gem_init(struct drm_device *dev,
+						      unsigned long size);
+
+/* create a new buffer with gem object */
+struct rockchip_drm_gem_obj *rockchip_drm_gem_create(struct drm_device *dev,
+						unsigned int flags,
+						unsigned long size);
+
+/*
+ * request gem object creation and buffer allocation as the size
+ * that it is calculated with framebuffer information such as width,
+ * height and bpp.
+ */
+int rockchip_drm_gem_create_ioctl(struct drm_device *dev, void *data,
+				struct drm_file *file_priv);
+
+/*
+ * get dma address from gem handle and this function could be used for
+ * other drivers such as 2d/3d acceleration drivers.
+ * with this function call, gem object reference count would be increased.
+ */
+dma_addr_t *rockchip_drm_gem_get_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *filp);
+
+/*
+ * put dma address from gem handle and this function could be used for
+ * other drivers such as 2d/3d acceleration drivers.
+ * with this function call, gem object reference count would be decreased.
+ */
+void rockchip_drm_gem_put_dma_addr(struct drm_device *dev,
+					unsigned int gem_handle,
+					struct drm_file *filp);
+
+/* get buffer offset to map to user space. */
+int rockchip_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
+				    struct drm_file *file_priv);
+
+/*
+ * mmap the physically continuous memory that a gem object contains
+ * to user space.
+ */
+int rockchip_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
+			      struct drm_file *file_priv);
+
+int rockchip_drm_gem_mmap_buffer(struct file *filp,
+				      struct vm_area_struct *vma);
+
+/* map user space allocated by malloc to pages. */
+int rockchip_drm_gem_userptr_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *file_priv);
+
+/* get buffer information to memory region allocated by gem. */
+int rockchip_drm_gem_get_ioctl(struct drm_device *dev, void *data,
+				      struct drm_file *file_priv);
+
+/* get buffer size to gem handle. */
+unsigned long rockchip_drm_gem_get_size(struct drm_device *dev,
+						unsigned int gem_handle,
+						struct drm_file *file_priv);
+
+/* free gem object. */
+void rockchip_drm_gem_free_object(struct drm_gem_object *gem_obj);
+
+/* create memory region for drm framebuffer. */
+int rockchip_drm_gem_dumb_create(struct drm_file *file_priv,
+			       struct drm_device *dev,
+			       struct drm_mode_create_dumb *args);
+
+/* map memory region for drm framebuffer to user space. */
+int rockchip_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+				   struct drm_device *dev, uint32_t handle,
+				   uint64_t *offset);
+
+/* page fault handler and mmap fault address(virtual) to physical memory. */
+int rockchip_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
+
+/* set vm_flags and we can change the vm attribute to other one at here. */
+int rockchip_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+
+static inline int vma_is_io(struct vm_area_struct *vma)
+{
+	return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
+}
+
+/* get a copy of a virtual memory region. */
+struct vm_area_struct *rockchip_gem_get_vma(struct vm_area_struct *vma);
+
+/* release a userspace virtual memory area. */
+void rockchip_gem_put_vma(struct vm_area_struct *vma);
+
+/* get pages from user space. */
+int rockchip_gem_get_pages_from_userptr(unsigned long start,
+						unsigned int npages,
+						struct page **pages,
+						struct vm_area_struct *vma);
+
+/* drop the reference to pages. */
+void rockchip_gem_put_pages_to_userptr(struct page **pages,
+					unsigned int npages,
+					struct vm_area_struct *vma);
+
+/* map sgt with dma region. */
+int rockchip_gem_map_sgt_with_dma(struct drm_device *drm_dev,
+				struct sg_table *sgt,
+				enum dma_data_direction dir);
+
+/* unmap sgt from dma region. */
+void rockchip_gem_unmap_sgt_from_dma(struct drm_device *drm_dev,
+				struct sg_table *sgt,
+				enum dma_data_direction dir);
+
+#endif
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_iommu.c b/drivers/gpu/drm/rockchip/rockchip_drm_iommu.c
new file mode 100644
index 0000000..ffc3170
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_iommu.c
@@ -0,0 +1,149 @@
+/* rockchip_drm_iommu.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_iommu.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 <drmP.h>
+#include <drm/rockchip_drm.h>
+
+#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
+#include <linux/kref.h>
+
+#include <asm/dma-iommu.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_iommu.h"
+
+/*
+ * drm_create_iommu_mapping - create a mapping structure
+ *
+ * @drm_dev: DRM device
+ */
+int drm_create_iommu_mapping(struct drm_device *drm_dev)
+{
+	struct dma_iommu_mapping *mapping = NULL;
+	struct rockchip_drm_private *priv = drm_dev->dev_private;
+	struct device *dev = drm_dev->dev;
+
+	if (!priv->da_start)
+		priv->da_start = ROCKCHIP_DEV_ADDR_START;
+	if (!priv->da_space_size)
+		priv->da_space_size = ROCKCHIP_DEV_ADDR_SIZE;
+
+	mapping = arm_iommu_create_mapping(&platform_bus_type, priv->da_start,
+						priv->da_space_size);
+
+	if (IS_ERR(mapping))
+		return PTR_ERR(mapping);
+
+	dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
+					GFP_KERNEL);
+	if (!dev->dma_parms)
+		goto error;
+
+	dma_set_max_seg_size(dev, 0xffffffffu);
+	dev->archdata.mapping = mapping;
+
+	return 0;
+error:
+	arm_iommu_release_mapping(mapping);
+	return -ENOMEM;
+}
+
+/*
+ * drm_release_iommu_mapping - release iommu mapping structure
+ *
+ * @drm_dev: DRM device
+ *
+ * if mapping->kref becomes 0 then all things related to iommu mapping
+ * will be released
+ */
+void drm_release_iommu_mapping(struct drm_device *drm_dev)
+{
+	struct device *dev = drm_dev->dev;
+
+	arm_iommu_release_mapping(dev->archdata.mapping);
+}
+
+/*
+ * drm_iommu_attach_device- attach device to iommu mapping
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be attach
+ *
+ * This function should be called by sub drivers to attach it to iommu
+ * mapping.
+ */
+int drm_iommu_attach_device(struct drm_device *drm_dev,
+				struct device *subdrv_dev)
+{
+	struct device *dev = drm_dev->dev;
+	int ret;
+
+	if (!dev->archdata.mapping) {
+		DRM_ERROR("iommu_mapping is null.\n");
+		return -EFAULT;
+	}
+
+	subdrv_dev->dma_parms = devm_kzalloc(subdrv_dev,
+					sizeof(*subdrv_dev->dma_parms),
+					GFP_KERNEL);
+	if (!subdrv_dev->dma_parms)
+		return -ENOMEM;
+
+	dma_set_max_seg_size(subdrv_dev, 0xffffffffu);
+
+	ret = arm_iommu_attach_device(subdrv_dev, dev->archdata.mapping);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("failed iommu attach.\n");
+		return ret;
+	}
+
+	/*
+	 * Set dma_ops to drm_device just one time.
+	 *
+	 * The dma mapping api needs device object and the api is used
+	 * to allocate physial memory and map it with iommu table.
+	 * If iommu attach succeeded, the sub driver would have dma_ops
+	 * for iommu and also all sub drivers have same dma_ops.
+	 */
+	if (!dev->archdata.dma_ops)
+		dev->archdata.dma_ops = subdrv_dev->archdata.dma_ops;
+
+	return 0;
+}
+
+/*
+ * drm_iommu_detach_device -detach device address space mapping from device
+ *
+ * @drm_dev: DRM device
+ * @subdrv_dev: device to be detached
+ *
+ * This function should be called by sub drivers to detach it from iommu
+ * mapping
+ */
+void drm_iommu_detach_device(struct drm_device *drm_dev,
+				struct device *subdrv_dev)
+{
+	struct device *dev = drm_dev->dev;
+	struct dma_iommu_mapping *mapping = dev->archdata.mapping;
+
+	if (!mapping || !mapping->domain)
+		return;
+
+	iommu_detach_device(mapping->domain, subdrv_dev);
+	drm_release_iommu_mapping(drm_dev);
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_iommu.h b/drivers/gpu/drm/rockchip/rockchip_drm_iommu.h
new file mode 100644
index 0000000..4fb4050
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_iommu.h
@@ -0,0 +1,76 @@
+/* rockchip_drm_iommu.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_iommu.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_IOMMU_H_
+#define _ROCKCHIP_DRM_IOMMU_H_
+
+#define ROCKCHIP_DEV_ADDR_START	0x20000000
+#define ROCKCHIP_DEV_ADDR_SIZE	0x40000000
+
+#ifdef CONFIG_DRM_ROCKCHIP_IOMMU
+
+int drm_create_iommu_mapping(struct drm_device *drm_dev);
+
+void drm_release_iommu_mapping(struct drm_device *drm_dev);
+
+int drm_iommu_attach_device(struct drm_device *drm_dev,
+				struct device *subdrv_dev);
+
+void drm_iommu_detach_device(struct drm_device *dev_dev,
+				struct device *subdrv_dev);
+
+static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
+{
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+	struct device *dev = drm_dev->dev;
+
+	return dev->archdata.mapping ? true : false;
+#else
+	return false;
+#endif
+}
+
+#else
+
+struct dma_iommu_mapping;
+static inline int drm_create_iommu_mapping(struct drm_device *drm_dev)
+{
+	return 0;
+}
+
+static inline void drm_release_iommu_mapping(struct drm_device *drm_dev)
+{
+}
+
+static inline int drm_iommu_attach_device(struct drm_device *drm_dev,
+						struct device *subdrv_dev)
+{
+	return 0;
+}
+
+static inline void drm_iommu_detach_device(struct drm_device *drm_dev,
+						struct device *subdrv_dev)
+{
+}
+
+static inline bool is_drm_iommu_supported(struct drm_device *drm_dev)
+{
+	return false;
+}
+
+#endif
+#endif /* _ROCKCHIP_DRM_IOMMU_H_ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_plane.c b/drivers/gpu/drm/rockchip/rockchip_drm_plane.c
new file mode 100644
index 0000000..230a35b
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_plane.c
@@ -0,0 +1,290 @@
+/* rockchip_drm_plane.c
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_plane.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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/rockchip_drm.h>
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_crtc.h"
+#include "rockchip_drm_fb.h"
+#include "rockchip_drm_gem.h"
+#include "rockchip_drm_plane.h"
+
+#define to_rockchip_plane(x) container_of(x, struct rockchip_plane, base)
+
+struct rockchip_plane {
+	struct rockchip_drm_overlay overlay;
+	struct drm_plane base;
+	bool enabled;
+};
+
+static const uint32_t formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_NV12,
+	DRM_FORMAT_NV12MT,
+};
+
+/*
+ * This function is to get X or Y size shown via screen. This needs length and
+ * start position of CRTC.
+ *
+ *      <--- length --->
+ * CRTC ----------------
+ *      ^ start        ^ end
+ *
+ * There are six cases from a to f.
+ *
+ *             <----- SCREEN ----->
+ *             0                 last
+ *   ----------|------------------|----------
+ * CRTCs
+ * a -------
+ *        b -------
+ *        c --------------------------
+ *                 d --------
+ *                           e -------
+ *                                  f -------
+ */
+static int rockchip_plane_get_size(int start, unsigned length, unsigned last)
+{
+	int end = start + length;
+	int size = 0;
+
+	if (start <= 0) {
+		if (end > 0)
+			size = min_t(unsigned, end, last);
+	} else if (start <= last) {
+		size = min_t(unsigned, last - start, length);
+	}
+
+	return size;
+}
+
+int rockchip_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 rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+	struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
+	unsigned int actual_w;
+	unsigned int actual_h;
+	int nr;
+	int i;
+
+	nr = rockchip_drm_fb_get_buf_cnt(fb);
+	for (i = 0; i < nr; i++) {
+		struct rockchip_drm_gem_buf *buffer =
+					rockchip_drm_fb_buffer(fb, i);
+
+		if (!buffer) {
+			DRM_DEBUG_KMS("buffer is null\n");
+			return -EFAULT;
+		}
+
+		overlay->dma_addr[i] = buffer->dma_addr;
+
+		DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
+				i, (unsigned long)overlay->dma_addr[i]);
+	}
+
+	actual_w = rockchip_plane_get_size(crtc_x,
+					crtc_w, crtc->mode.hdisplay);
+	actual_h = rockchip_plane_get_size(crtc_y,
+					crtc_h, crtc->mode.vdisplay);
+
+	if (crtc_x < 0) {
+		if (actual_w)
+			src_x -= crtc_x;
+		crtc_x = 0;
+	}
+
+	if (crtc_y < 0) {
+		if (actual_h)
+			src_y -= crtc_y;
+		crtc_y = 0;
+	}
+
+	/* 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);
+
+	rockchip_drm_crtc_plane_mode_set(crtc, overlay);
+
+	return 0;
+}
+
+void rockchip_plane_commit(struct drm_plane *plane)
+{
+	struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+	struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
+
+	rockchip_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
+}
+
+void rockchip_plane_dpms(struct drm_plane *plane, int mode)
+{
+	struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+	struct rockchip_drm_overlay *overlay = &rockchip_plane->overlay;
+
+	if (mode == DRM_MODE_DPMS_ON) {
+		if (rockchip_plane->enabled)
+			return;
+
+		rockchip_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
+		rockchip_plane->enabled = true;
+	} else {
+		if (!rockchip_plane->enabled)
+			return;
+
+		rockchip_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
+		rockchip_plane->enabled = false;
+	}
+}
+
+static int
+rockchip_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)
+{
+	int ret;
+
+	ret = rockchip_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;
+
+	plane->crtc = crtc;
+
+	rockchip_plane_commit(plane);
+	rockchip_plane_dpms(plane, DRM_MODE_DPMS_ON);
+
+	return 0;
+}
+
+static int rockchip_disable_plane(struct drm_plane *plane)
+{
+	rockchip_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+
+	return 0;
+}
+
+static void rockchip_plane_destroy(struct drm_plane *plane)
+{
+	struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+
+	rockchip_disable_plane(plane);
+	drm_plane_cleanup(plane);
+	kfree(rockchip_plane);
+}
+
+static int rockchip_plane_set_property(struct drm_plane *plane,
+				     struct drm_property *property,
+				     uint64_t val)
+{
+	struct drm_device *dev = plane->dev;
+	struct rockchip_plane *rockchip_plane = to_rockchip_plane(plane);
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+
+	if (property == dev_priv->plane_zpos_property) {
+		rockchip_plane->overlay.zpos = val;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+static struct drm_plane_funcs rockchip_plane_funcs = {
+	.update_plane = rockchip_update_plane,
+	.disable_plane = rockchip_disable_plane,
+	.destroy = rockchip_plane_destroy,
+	.set_property = rockchip_plane_set_property,
+};
+
+static void rockchip_plane_attach_zpos_property(struct drm_plane *plane)
+{
+	struct drm_device *dev = plane->dev;
+	struct rockchip_drm_private *dev_priv = dev->dev_private;
+	struct drm_property *prop;
+
+	prop = dev_priv->plane_zpos_property;
+	if (!prop) {
+		prop = drm_property_create_range(dev, 0, "zpos", 0,
+						 MAX_PLANE - 1);
+		if (!prop)
+			return;
+
+		dev_priv->plane_zpos_property = prop;
+	}
+
+	drm_object_attach_property(&plane->base, prop, 0);
+}
+
+struct drm_plane *rockchip_plane_init(struct drm_device *dev,
+				    unsigned long possible_crtcs, bool priv)
+{
+	struct rockchip_plane *rockchip_plane;
+	int err;
+
+	rockchip_plane = kzalloc(sizeof(struct rockchip_plane), GFP_KERNEL);
+	if (!rockchip_plane)
+		return NULL;
+
+	err = drm_plane_init(dev, &rockchip_plane->base, possible_crtcs,
+			      &rockchip_plane_funcs, formats,
+			      ARRAY_SIZE(formats), priv);
+	if (err) {
+		DRM_ERROR("failed to initialize plane\n");
+		kfree(rockchip_plane);
+		return NULL;
+	}
+
+	if (priv)
+		rockchip_plane->overlay.zpos = DEFAULT_ZPOS;
+	else
+		rockchip_plane_attach_zpos_property(&rockchip_plane->base);
+
+	return &rockchip_plane->base;
+}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_plane.h b/drivers/gpu/drm/rockchip/rockchip_drm_plane.h
new file mode 100644
index 0000000..3832496
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_plane.h
@@ -0,0 +1,30 @@
+/* rockchip_drm_plane.h
+ *
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author:mark yao <mark.yao at rock-chips.com>
+ *
+ * based on exynos_drm_plane.h
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#ifndef _ROCKCHIP_DRM_PLANE_H_
+#define _ROCKCHIP_DRM_PLANE_H_
+
+int rockchip_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 rockchip_plane_commit(struct drm_plane *plane);
+void rockchip_plane_dpms(struct drm_plane *plane, int mode);
+struct drm_plane *rockchip_plane_init(struct drm_device *dev,
+				    unsigned long possible_crtcs, bool priv);
+#endif /* _ROCKCHIP_DRM_PLANE_H_ */
diff --git a/include/uapi/drm/rockchip_drm.h b/include/uapi/drm/rockchip_drm.h
new file mode 100644
index 0000000..7f705f4
--- /dev/null
+++ b/include/uapi/drm/rockchip_drm.h
@@ -0,0 +1,155 @@
+/* rockchip_drm.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Authors:
+ *       mark yao<yzq at rock-chips.com>
+ *
+ * base on exynos_drm.h
+ *
+ * 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.
+ */
+
+#ifndef _UAPI_ROCKCHIP_DRM_H_
+#define _UAPI_ROCKCHIP_DRM_H_
+
+#include <drm/drm.h>
+
+/**
+ * User-desired buffer creation information structure.
+ *
+ * @size: user-desired memory allocation size.
+ *     - this size value would be page-aligned internally.
+ * @flags: user request for setting memory type or cache attributes.
+ * @handle: returned a handle to created gem object.
+ *     - this handle will be set by gem module of kernel side.
+ */
+struct drm_rockchip_gem_create {
+	uint64_t size;
+	unsigned int flags;
+	unsigned int handle;
+};
+
+/**
+ * A structure for getting buffer offset.
+ *
+ * @handle: a pointer to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @offset: relatived offset value of the memory region allocated.
+ *     - this value should be set by user.
+ */
+struct drm_rockchip_gem_map_off {
+	unsigned int handle;
+	unsigned int pad;
+	uint64_t offset;
+};
+
+/**
+ * A structure for mapping buffer.
+ *
+ * @handle: a handle to gem object created.
+ * @pad: just padding to be 64-bit aligned.
+ * @size: memory size to be mapped.
+ * @mapped: having user virtual address mmaped.
+ *      - this variable would be filled by rockchip gem module
+ *      of kernel side with user virtual address which is allocated
+ *      by do_mmap().
+ */
+struct drm_rockchip_gem_mmap {
+	unsigned int handle;
+	unsigned int pad;
+	uint64_t size;
+	uint64_t mapped;
+};
+
+/**
+ * A structure to gem information.
+ *
+ * @handle: a handle to gem object created.
+ * @flags: flag value including memory type and cache attribute and
+ *      this value would be set by driver.
+ * @size: size to memory region allocated by gem and this size would
+ *      be set by driver.
+ */
+struct drm_rockchip_gem_info {
+	unsigned int handle;
+	unsigned int flags;
+	uint64_t size;
+};
+
+/* memory type definitions. */
+enum e_drm_rockchip_gem_mem_type {
+	/* Physically Continuous memory and used as default. */
+	ROCKCHIP_BO_CONTIG = 0 << 0,
+	/* Physically Non-Continuous memory. */
+	ROCKCHIP_BO_NONCONTIG = 1 << 0,
+	/* non-cachable mapping and used as default. */
+	ROCKCHIP_BO_NONCACHABLE = 0 << 1,
+	/* cachable mapping. */
+	ROCKCHIP_BO_CACHABLE = 1 << 1,
+	/* write-combine mapping. */
+	ROCKCHIP_BO_WC = 1 << 2,
+	ROCKCHIP_BO_MASK = ROCKCHIP_BO_NONCONTIG | ROCKCHIP_BO_CACHABLE |
+					ROCKCHIP_BO_WC
+};
+
+enum drm_rockchip_ops_id {
+	ROCKCHIP_DRM_OPS_SRC,
+	ROCKCHIP_DRM_OPS_DST,
+	ROCKCHIP_DRM_OPS_MAX,
+};
+
+struct drm_rockchip_sz {
+	__u32 hsize;
+	__u32 vsize;
+};
+
+struct drm_rockchip_pos {
+	__u32 x;
+	__u32 y;
+	__u32 w;
+	__u32 h;
+};
+
+enum drm_rockchip_flip {
+	ROCKCHIP_DRM_FLIP_NONE = (0 << 0),
+	ROCKCHIP_DRM_FLIP_VERTICAL = (1 << 0),
+	ROCKCHIP_DRM_FLIP_HORIZONTAL = (1 << 1),
+	ROCKCHIP_DRM_FLIP_BOTH = ROCKCHIP_DRM_FLIP_VERTICAL |
+			ROCKCHIP_DRM_FLIP_HORIZONTAL,
+};
+
+enum drm_rockchip_degree {
+	ROCKCHIP_DRM_DEGREE_0,
+	ROCKCHIP_DRM_DEGREE_90,
+	ROCKCHIP_DRM_DEGREE_180,
+	ROCKCHIP_DRM_DEGREE_270,
+};
+
+enum drm_rockchip_planer {
+	ROCKCHIP_DRM_PLANAR_Y,
+	ROCKCHIP_DRM_PLANAR_CB,
+	ROCKCHIP_DRM_PLANAR_CR,
+	ROCKCHIP_DRM_PLANAR_MAX,
+};
+
+#define DRM_ROCKCHIP_GEM_CREATE		0x00
+#define DRM_ROCKCHIP_GEM_MAP_OFFSET	0x01
+#define DRM_ROCKCHIP_GEM_MMAP		0x02
+/* Reserved 0x03 ~ 0x05 for rockchip specific gem ioctl */
+#define DRM_ROCKCHIP_GEM_GET		0x04
+
+#define DRM_IOCTL_ROCKCHIP_GEM_CREATE		DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_ROCKCHIP_GEM_CREATE, struct drm_rockchip_gem_create)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_MAP_OFFSET	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_ROCKCHIP_GEM_MAP_OFFSET, struct drm_rockchip_gem_map_off)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_MMAP	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_ROCKCHIP_GEM_MMAP, struct drm_rockchip_gem_mmap)
+
+#define DRM_IOCTL_ROCKCHIP_GEM_GET	DRM_IOWR(DRM_COMMAND_BASE + \
+		DRM_ROCKCHIP_GEM_GET,	struct drm_rockchip_gem_info)
+#endif /* _UAPI_ROCKCHIP_DRM_H_ */
-- 
1.7.9.5




More information about the dri-devel mailing list