This patch is a DRM Driver for Mediatek SoC MT8173.
Now support one crtc with MIPI DSI interface.
We used GEM framework for buffer management and use iommu for
physically non-continuous memory.

Signed-off-by: CK Hu <ck...@mediatek.com>
---
 drivers/gpu/drm/Kconfig                           |    2 +
 drivers/gpu/drm/Makefile                          |    1 +
 drivers/gpu/drm/mediatek/Kconfig                  |   28 +
 drivers/gpu/drm/mediatek/Makefile                 |   13 +
 drivers/gpu/drm/mediatek/mediatek_drm_crtc.c      |  246 ++++
 drivers/gpu/drm/mediatek/mediatek_drm_crtc.h      |   80 ++
 drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c |  420 +++++++
 drivers/gpu/drm/mediatek/mediatek_drm_ddp.c       |  202 ++++
 drivers/gpu/drm/mediatek/mediatek_drm_ddp.h       |   23 +
 drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c  |  346 ++++++
 drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h  |   33 +
 drivers/gpu/drm/mediatek/mediatek_drm_drv.c       |  369 ++++++
 drivers/gpu/drm/mediatek/mediatek_drm_drv.h       |   37 +
 drivers/gpu/drm/mediatek/mediatek_drm_dsi.c       | 1333 +++++++++++++++++++++
 drivers/gpu/drm/mediatek/mediatek_drm_dsi.h       |   71 ++
 drivers/gpu/drm/mediatek/mediatek_drm_fb.c        |  339 ++++++
 drivers/gpu/drm/mediatek/mediatek_drm_fb.h        |   43 +
 drivers/gpu/drm/mediatek/mediatek_drm_gem.c       |  315 +++++
 drivers/gpu/drm/mediatek/mediatek_drm_gem.h       |   94 ++
 include/uapi/drm/mediatek_drm.h                   |   59 +
 20 files changed, 4054 insertions(+)
 create mode 100644 drivers/gpu/drm/mediatek/Kconfig
 create mode 100644 drivers/gpu/drm/mediatek/Makefile
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc.c
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc.h
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp.c
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp.h
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_drv.c
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_drv.h
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_dsi.c
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_dsi.h
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_fb.c
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_fb.h
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_gem.c
 create mode 100644 drivers/gpu/drm/mediatek/mediatek_drm_gem.h
 create mode 100644 include/uapi/drm/mediatek_drm.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 47f2ce8..441be2d 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -217,3 +217,5 @@ source "drivers/gpu/drm/sti/Kconfig"
 source "drivers/gpu/drm/amd/amdkfd/Kconfig"
 
 source "drivers/gpu/drm/imx/Kconfig"
+
+source "drivers/gpu/drm/mediatek/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 7d4944e..55fe66c 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_DRM_MSM) += msm/
 obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-$(CONFIG_DRM_STI) += sti/
 obj-$(CONFIG_DRM_IMX) += imx/
+obj-$(CONFIG_DRM_MEDIATEK) += mediatek/
 obj-y                  += i2c/
 obj-y                  += panel/
 obj-y                  += bridge/
diff --git a/drivers/gpu/drm/mediatek/Kconfig b/drivers/gpu/drm/mediatek/Kconfig
new file mode 100644
index 0000000..fa581fb
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/Kconfig
@@ -0,0 +1,28 @@
+config DRM_MEDIATEK
+       tristate "DRM Support for Mediatek SoCs"
+       depends on DRM
+       depends on ARCH_MEDIATEK || (ARM && COMPILE_TEST)
+       select MTK_SMI
+       select DRM_PANEL
+       select DRM_MIPI_DSI
+       select DRM_PANEL_SIMPLE
+       select DRM_KMS_HELPER
+       select IOMMU_DMA
+       help
+         Choose this option if you have a Mediatek SoCs.
+         The module will be called mediatek-drm
+         This driver provides kernel mode setting and
+         buffer management to userspace.
+
+config DRM_MEDIATEK_FBDEV
+       bool "Enable legacy fbdev support for Mediatek DRM"
+       depends on DRM_MEDIATEK
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       select DRM_KMS_FB_HELPER
+       help
+         Choose this option if you have a need for the legacy
+         fbdev support.  Note that this support also provides
+         the Linux console on top of the Mediatek DRM mode
+         setting driver.
diff --git a/drivers/gpu/drm/mediatek/Makefile 
b/drivers/gpu/drm/mediatek/Makefile
new file mode 100644
index 0000000..a566a83
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -0,0 +1,13 @@
+mediatek-drm-objs := mediatek_drm_drv.o \
+                  mediatek_drm_crtc.o \
+                  mediatek_drm_fb.o \
+                  mediatek_drm_gem.o \
+                  mediatek_drm_dsi.o \
+                  mediatek_drm_ddp.o \
+                  mediatek_drm_ddp_comp.o \
+                  mediatek_drm_crtc_main.o
+
+obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o
+
+ccflags-y += \
+ -Idrivers/gpu/drm
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_crtc.c 
b/drivers/gpu/drm/mediatek/mediatek_drm_crtc.c
new file mode 100644
index 0000000..e1437c6
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_crtc.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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_gem.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <linux/dma-buf.h>
+#include <linux/reservation.h>
+
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_crtc.h"
+#include "mediatek_drm_fb.h"
+#include "mediatek_drm_gem.h"
+
+
+void mtk_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc)
+{
+       struct drm_device *dev = mtk_crtc->base.dev;
+
+       drm_send_vblank_event(dev, mtk_crtc->event->pipe, mtk_crtc->event);
+       drm_crtc_vblank_put(&mtk_crtc->base);
+       mtk_crtc->event = NULL;
+}
+
+static void mediatek_drm_crtc_pending_ovl_config(struct mtk_drm_crtc *mtk_crtc,
+       bool enable, unsigned int addr)
+{
+       if (mtk_crtc->ops && mtk_crtc->ops->ovl_layer_config)
+               mtk_crtc->ops->ovl_layer_config(mtk_crtc, enable, addr);
+}
+
+static void mediatek_drm_crtc_pending_ovl_cursor_config(
+       struct mtk_drm_crtc *mtk_crtc,
+       bool enable, unsigned int addr)
+{
+       if (mtk_crtc->ops && mtk_crtc->ops->ovl_layer_config_cursor)
+               mtk_crtc->ops->ovl_layer_config_cursor(mtk_crtc, enable, addr);
+}
+
+static int mtk_drm_crtc_page_flip(struct drm_crtc *crtc,
+       struct drm_framebuffer *fb,
+       struct drm_pending_vblank_event *event,
+       uint32_t page_flip_flags)
+{
+       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+       struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
+       struct drm_device *dev = crtc->dev;
+       unsigned long flags;
+       bool busy;
+       int ret;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       busy = !!mtk_crtc->event;
+       if (!busy)
+               mtk_crtc->event = event;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+       if (busy)
+               return -EBUSY;
+
+       if (fb->width != crtc->mode.hdisplay ||
+               fb->height != crtc->mode.vdisplay) {
+               DRM_ERROR("mtk_drm_crtc_page_flip width/height not match !!\n");
+               return -EINVAL;
+       }
+
+       if (event) {
+               ret = drm_crtc_vblank_get(crtc);
+               if (ret) {
+                       DRM_ERROR("failed to acquire vblank events\n");
+                       return ret;
+               }
+       }
+
+       /*
+        * the values related to a buffer of the drm framebuffer
+        * to be applied should be set at here. because these values
+        * first, are set to shadow registers and then to
+        * real registers at vsync front porch period.
+        */
+       crtc->primary->fb = fb;
+       mtk_crtc->flip_buffer = to_mtk_gem_obj(mtk_fb->gem_obj[0])->buffer;
+
+       mediatek_drm_crtc_pending_ovl_config(mtk_crtc, true,
+               mtk_crtc->flip_buffer->mva_addr);
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       if (mtk_crtc->event)
+               mtk_crtc->pending_needs_vblank = true;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       return ret;
+}
+
+static void mtk_drm_crtc_destroy(struct drm_crtc *crtc)
+{
+       drm_crtc_cleanup(crtc);
+}
+
+static void mtk_drm_crtc_prepare(struct drm_crtc *crtc)
+{
+       /* drm framework doesn't check NULL. */
+}
+
+static void mtk_drm_crtc_commit(struct drm_crtc *crtc)
+{
+       /*
+        * when set_crtc is requested from user or at booting time,
+        * crtc->commit would be called without dpms call so if dpms is
+        * no power on then crtc->dpms should be called
+        * with DRM_MODE_DPMS_ON for the hardware power to be on.
+        */
+}
+
+static bool mtk_drm_crtc_mode_fixup(struct drm_crtc *crtc,
+       const struct drm_display_mode *mode,
+       struct drm_display_mode *adjusted_mode)
+{
+       /* drm framework doesn't check NULL */
+       return true;
+}
+
+static int mtk_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 mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+       struct drm_framebuffer *fb;
+       struct mtk_drm_fb *mtk_fb;
+       struct mtk_drm_gem_buf *buffer;
+
+       fb = crtc->primary->fb;
+       mtk_fb = to_mtk_fb(fb);
+
+       buffer = to_mtk_gem_obj(mtk_fb->gem_obj[0])->buffer;
+
+       mediatek_drm_crtc_pending_ovl_config(mtk_crtc, true,
+               buffer->mva_addr);
+       /*
+        * 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));
+
+       /* Take a reference to the new fb as we're using it */
+       drm_framebuffer_reference(crtc->primary->fb);
+
+       return 0;
+}
+
+int mtk_drm_crtc_enable_vblank(struct drm_device *drm, int pipe)
+{
+       struct mtk_drm_private *priv =
+               (struct mtk_drm_private *)drm->dev_private;
+       struct mtk_drm_crtc *mtk_crtc;
+
+       if (pipe >= MAX_CRTC || pipe < 0) {
+               DRM_ERROR(" - %s: invalid crtc (%d)\n", __func__, pipe);
+               return -EINVAL;
+       }
+
+       mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
+
+       if (mtk_crtc->ops->enable_vblank)
+               mtk_crtc->ops->enable_vblank(mtk_crtc);
+
+       return 0;
+}
+
+void mtk_drm_crtc_disable_vblank(struct drm_device *drm, int pipe)
+{
+       struct mtk_drm_private *priv =
+               (struct mtk_drm_private *)drm->dev_private;
+       struct mtk_drm_crtc *mtk_crtc;
+
+       if (pipe >= MAX_CRTC || pipe < 0)
+               DRM_ERROR(" - %s: invalid crtc (%d)\n", __func__, pipe);
+
+       mtk_crtc = to_mtk_crtc(priv->crtc[pipe]);
+       if (mtk_crtc->ops->disable_vblank)
+               mtk_crtc->ops->disable_vblank(mtk_crtc);
+}
+
+static void mtk_drm_crtc_disable(struct drm_crtc *crtc)
+{
+       struct mtk_drm_crtc *mtk_crtc = to_mtk_crtc(crtc);
+
+       DRM_INFO("mtk_drm_crtc_disable %d\n", crtc->base.id);
+
+       mediatek_drm_crtc_pending_ovl_config(mtk_crtc, false, 0);
+       mediatek_drm_crtc_pending_ovl_cursor_config(mtk_crtc, false, 0);
+}
+
+static struct drm_crtc_funcs mediatek_crtc_funcs = {
+       .set_config             = drm_crtc_helper_set_config,
+       .page_flip              = mtk_drm_crtc_page_flip,
+       .destroy                = mtk_drm_crtc_destroy,
+};
+
+static struct drm_crtc_helper_funcs mediatek_crtc_helper_funcs = {
+       .prepare        = mtk_drm_crtc_prepare,
+       .commit         = mtk_drm_crtc_commit,
+       .mode_fixup     = mtk_drm_crtc_mode_fixup,
+       .mode_set       = mtk_drm_crtc_mode_set,
+       .disable        = mtk_drm_crtc_disable,
+};
+
+struct mtk_drm_crtc *mtk_drm_crtc_create(
+       struct drm_device *drm_dev, int pipe,
+       struct mediatek_drm_crtc_ops *ops,
+       void *ctx)
+{
+       struct mtk_drm_private *priv =
+               (struct mtk_drm_private *)drm_dev->dev_private;
+       struct mtk_drm_crtc *mtk_crtc;
+
+       mtk_crtc = devm_kzalloc(drm_dev->dev, sizeof(*mtk_crtc), GFP_KERNEL);
+       if (!mtk_crtc) {
+               DRM_ERROR("failed to allocate mtk crtc\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       mtk_crtc->pipe = pipe;
+       mtk_crtc->ops = ops;
+       mtk_crtc->ctx = ctx;
+
+       priv->crtc[pipe] = &mtk_crtc->base;
+
+       drm_crtc_init(drm_dev, &mtk_crtc->base, &mediatek_crtc_funcs);
+       drm_crtc_helper_add(&mtk_crtc->base, &mediatek_crtc_helper_funcs);
+
+       return mtk_crtc;
+}
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_crtc.h 
b/drivers/gpu/drm/mediatek/mediatek_drm_crtc.h
new file mode 100644
index 0000000..1732927
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_crtc.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _MEDIATEL_DRM_CRTC_H_
+#define _MEDIATEL_DRM_CRTC_H_
+
+#include "mediatek_drm_ddp.h"
+
+
+#define MAX_FB_BUFFER  4
+#define DEFAULT_ZPOS   -1
+
+struct mtk_drm_crtc;
+struct mediatek_drm_crtc_ops {
+       void (*dpms)(struct mtk_drm_crtc *crtc, int mode);
+       int (*enable_vblank)(struct mtk_drm_crtc *crtc);
+       void (*disable_vblank)(struct mtk_drm_crtc *crtc);
+       void (*ovl_layer_config)(struct mtk_drm_crtc *crtc,
+               bool enable, unsigned int addr);
+       void (*ovl_layer_config_cursor)(struct mtk_drm_crtc *crtc,
+               bool enable, unsigned int addr);
+};
+
+/*
+ * MediaTek specific crtc structure.
+ *
+ * @base: crtc object.
+ * @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.
+ */
+struct mtk_drm_crtc {
+       struct drm_crtc                 base;
+
+       unsigned int                    pipe;
+       struct drm_pending_vblank_event *event;
+       struct mtk_drm_gem_buf *flip_buffer;
+       struct mediatek_drm_crtc_ops    *ops;
+       void                            *ctx;
+       bool pending_needs_vblank;
+
+       bool pending_ovl_config;
+       bool pending_ovl_enabled;
+       unsigned int pending_ovl_addr;
+       unsigned int pending_ovl_width;
+       unsigned int pending_ovl_height;
+       unsigned int pending_ovl_pitch;
+       unsigned int pending_ovl_format;
+
+};
+
+#define to_mtk_crtc(x) container_of(x, struct mtk_drm_crtc, base)
+
+struct mtk_drm_crtc *mtk_drm_crtc_create(
+       struct drm_device *drm_dev,     int pipe,
+       struct mediatek_drm_crtc_ops *ops,
+       void *ctx);
+void mtk_drm_crtc_irq(struct mtk_drm_crtc *mtk_crtc);
+
+void mtk_crtc_finish_page_flip(struct mtk_drm_crtc *mtk_crtc);
+int mtk_drm_crtc_enable_vblank(struct drm_device *drm, int pipe);
+void mtk_drm_crtc_disable_vblank(struct drm_device *drm, int pipe);
+
+#endif
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c 
b/drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c
new file mode 100644
index 0000000..4d16620
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_crtc_main.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Authors:
+ *     YT Shen <yt.s...@mediatek.com>
+ *     CK Hu <ck...@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/of_device.h>
+#include <linux/component.h>
+#include <linux/pm_runtime.h>
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_crtc.h"
+#include "mediatek_drm_gem.h"
+#include "mediatek_drm_ddp_comp.h"
+
+
+struct crtc_main_context {
+       struct device           *dev;
+       struct drm_device       *drm_dev;
+       struct mtk_drm_crtc     *crtc;
+       int     pipe;
+
+       struct device           *ddp_dev;
+       struct clk              *ovl0_disp_clk;
+       struct clk              *rdma0_disp_clk;
+       struct clk              *color0_disp_clk;
+       struct clk              *aal_disp_clk;
+       struct clk              *ufoe_disp_clk;
+       struct clk              *od_disp_clk;
+
+       void __iomem            *ovl0_regs;
+       void __iomem            *rdma0_regs;
+       void __iomem            *color0_regs;
+       void __iomem            *aal_regs;
+       void __iomem            *ufoe_regs;
+       void __iomem            *od_regs;
+
+       bool                    pending_ovl_config;
+       bool                    pending_ovl_enable;
+       unsigned int            pending_ovl_addr;
+       unsigned int            pending_ovl_width;
+       unsigned int            pending_ovl_height;
+       unsigned int            pending_ovl_pitch;
+       unsigned int            pending_ovl_format;
+};
+
+
+static int crtc_main_ctx_initialize(struct crtc_main_context *ctx,
+       struct drm_device *drm_dev)
+{
+       struct mtk_drm_private *priv;
+
+       priv = drm_dev->dev_private;
+       ctx->drm_dev = drm_dev;
+       ctx->pipe = priv->pipe++;
+
+       return 0;
+}
+
+static void crtc_main_ctx_remove(struct crtc_main_context *ctx)
+{
+}
+
+static void crtc_main_power_on(struct crtc_main_context *ctx)
+{
+       int ret;
+
+       ret = clk_prepare_enable(ctx->ovl0_disp_clk);
+       if (ret != 0)
+               DRM_ERROR("clk_prepare_enable(ctx->ovl0_disp_clk) error!\n");
+
+       ret = clk_prepare_enable(ctx->rdma0_disp_clk);
+       if (ret != 0)
+               DRM_ERROR("clk_prepare_enable(ctx->rdma0_disp_clk) error!\n");
+
+       ret = clk_prepare_enable(ctx->color0_disp_clk);
+       if (ret != 0)
+               DRM_ERROR("clk_prepare_enable(ctx->color0_disp_clk) error!\n");
+
+       ret = clk_prepare_enable(ctx->aal_disp_clk);
+       if (ret != 0)
+               DRM_ERROR("clk_prepare_enable(ctx->aal_disp_clk) error!\n");
+
+       ret = clk_prepare_enable(ctx->ufoe_disp_clk);
+       if (ret != 0)
+               DRM_ERROR("clk_prepare_enable(ctx->ufoe_disp_clk) error!\n");
+
+       ret = clk_prepare_enable(ctx->od_disp_clk);
+       if (ret != 0)
+               DRM_ERROR("clk_prepare_enable(ctx->od_disp_clk) error!\n");
+}
+
+static void crtc_main_power_off(struct crtc_main_context *ctx)
+{
+       clk_disable_unprepare(ctx->ovl0_disp_clk);
+
+       clk_disable_unprepare(ctx->rdma0_disp_clk);
+
+       clk_disable_unprepare(ctx->color0_disp_clk);
+
+       clk_disable_unprepare(ctx->aal_disp_clk);
+
+       clk_disable_unprepare(ctx->ufoe_disp_clk);
+
+       clk_disable_unprepare(ctx->od_disp_clk);
+}
+
+static void crtc_main_dpms(struct mtk_drm_crtc *crtc, int mode)
+{
+       /* DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); */
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               crtc_main_power_on(crtc->ctx);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               crtc_main_power_off(crtc->ctx);
+               break;
+       default:
+               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+               break;
+       }
+}
+
+static int crtc_main_enable_vblank(struct mtk_drm_crtc *crtc)
+{
+       struct crtc_main_context *ctx = (struct crtc_main_context *)crtc->ctx;
+
+       mediatek_od_enable_vblank(ctx->od_regs);
+
+       return 0;
+}
+
+static void crtc_main_disable_vblank(struct mtk_drm_crtc *crtc)
+{
+       struct crtc_main_context *ctx = (struct crtc_main_context *)crtc->ctx;
+
+       mediatek_od_disable_vblank(ctx->od_regs);
+}
+
+static void crtc_main_ovl_layer_config(struct mtk_drm_crtc *crtc,
+       bool enable, unsigned int addr)
+{
+       struct crtc_main_context *ctx = (struct crtc_main_context *)crtc->ctx;
+       unsigned int pitch = 0;
+
+       if (crtc->base.primary->fb && crtc->base.primary->fb->pitches[0])
+               pitch = crtc->base.primary->fb->pitches[0];
+
+       ctx->pending_ovl_enable = enable;
+       if (enable) {
+               ctx->pending_ovl_addr = addr;
+               ctx->pending_ovl_width = crtc->base.mode.hdisplay;
+               ctx->pending_ovl_height = crtc->base.mode.vdisplay;
+               ctx->pending_ovl_pitch = pitch;
+               ctx->pending_ovl_format = crtc->base.primary->fb->pixel_format;
+       }
+       ctx->pending_ovl_config = true;
+}
+
+static struct mediatek_drm_crtc_ops crtc_main_crtc_ops = {
+       .dpms = crtc_main_dpms,
+       .enable_vblank = crtc_main_enable_vblank,
+       .disable_vblank = crtc_main_disable_vblank,
+       .ovl_layer_config = crtc_main_ovl_layer_config,
+};
+
+static void crtc_main_irq(struct crtc_main_context *ctx)
+{
+       struct drm_device *dev = ctx->drm_dev;
+       struct mtk_drm_crtc *mtk_crtc = ctx->crtc;
+       unsigned long flags;
+
+       if (ctx->pending_ovl_config) {
+               ctx->pending_ovl_config = false;
+               mediatek_ovl_layer_config(ctx->ovl0_regs,
+                       ctx->pending_ovl_enable,
+                       ctx->pending_ovl_addr,
+                       ctx->pending_ovl_width,
+                       ctx->pending_ovl_height,
+                       ctx->pending_ovl_pitch,
+                       ctx->pending_ovl_format);
+       }
+
+       drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+       spin_lock_irqsave(&dev->event_lock, flags);
+       if (mtk_crtc->pending_needs_vblank) {
+               mtk_crtc_finish_page_flip(mtk_crtc);
+               mtk_crtc->pending_needs_vblank = false;
+       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+irqreturn_t crtc_main_irq_handler(int irq, void *dev_id)
+{
+       struct crtc_main_context *ctx = (struct crtc_main_context *)dev_id;
+
+       mediatek_od_clear_vblank(ctx->od_regs);
+
+       if (ctx->pipe < 0 || !ctx->drm_dev)
+               goto out;
+
+       crtc_main_irq(ctx);
+out:
+       return IRQ_HANDLED;
+}
+
+static int crtc_main_bind(struct device *dev, struct device *master, void 
*data)
+{
+       struct crtc_main_context *ctx = dev_get_drvdata(dev);
+       struct drm_device *drm_dev = data;
+       int ret;
+
+       ret = crtc_main_ctx_initialize(ctx, drm_dev);
+       if (ret) {
+               DRM_ERROR("crtc_main_ctx_initialize failed.\n");
+               return ret;
+       }
+
+       ctx->crtc = mtk_drm_crtc_create(drm_dev, ctx->pipe,
+               &crtc_main_crtc_ops, ctx);
+
+       if (IS_ERR(ctx->crtc)) {
+               crtc_main_ctx_remove(ctx);
+               return PTR_ERR(ctx->crtc);
+       }
+
+       DRM_INFO("mediatek_ddp_clock_on\n");
+       mediatek_ddp_clock_on(ctx->ddp_dev);
+
+       DRM_INFO("mediatek_ddp_main_path_setup\n");
+       mediatek_ddp_main_path_setup(ctx->ddp_dev);
+
+       DRM_INFO("main_disp_path_power_on\n");
+       main_disp_path_power_on(ctx->ovl0_regs, ctx->rdma0_regs,
+               ctx->color0_regs, ctx->ufoe_regs, ctx->od_regs);
+
+       return 0;
+
+}
+
+static void crtc_main_unbind(struct device *dev, struct device *master,
+                       void *data)
+{
+       struct crtc_main_context *ctx = dev_get_drvdata(dev);
+
+       crtc_main_ctx_remove(ctx);
+}
+
+static const struct component_ops crtc_main_component_ops = {
+       .bind   = crtc_main_bind,
+       .unbind = crtc_main_unbind,
+};
+
+static int crtc_main_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct crtc_main_context *ctx;
+       struct device_node *node;
+       struct platform_device *ddp_pdev;
+       struct resource *regs;
+       int irq;
+       int ret;
+
+       if (!dev->of_node)
+               return -ENODEV;
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       node = of_parse_phandle(dev->of_node, "ddp", 0);
+       if (!node) {
+               dev_err(dev, "crtc_main_probe: Get ddp node fail.\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ddp_pdev = of_find_device_by_node(node);
+       if (WARN_ON(!ddp_pdev)) {
+               dev_err(dev, "crtc_main_probe: Find ddp device fail.\n");
+               ret = -EINVAL;
+               goto err;
+       }
+       ctx->ddp_dev = &ddp_pdev->dev;
+
+       ctx->ovl0_disp_clk = devm_clk_get(dev, "ovl0_disp");
+       if (IS_ERR(ctx->ovl0_disp_clk)) {
+               dev_err(dev, "crtc_main_probe: Get ovl0_disp_clk fail.\n");
+               ret = PTR_ERR(ctx->ovl0_disp_clk);
+               goto err;
+       }
+
+       ctx->rdma0_disp_clk = devm_clk_get(dev, "rdma0_disp");
+       if (IS_ERR(ctx->rdma0_disp_clk)) {
+               dev_err(dev, "crtc_main_probe: Get rdma0_disp_clk.\n");
+               ret = PTR_ERR(ctx->rdma0_disp_clk);
+               goto err;
+       }
+
+       ctx->color0_disp_clk = devm_clk_get(dev, "color0_disp");
+       if (IS_ERR(ctx->color0_disp_clk)) {
+               dev_err(dev, "crtc_main_probe: Get color0_disp_clk fail.\n");
+               ret = PTR_ERR(ctx->color0_disp_clk);
+               goto err;
+       }
+
+       ctx->aal_disp_clk = devm_clk_get(dev, "aal_disp");
+       if (IS_ERR(ctx->aal_disp_clk)) {
+               dev_err(dev, "crtc_main_probe: Get aal_disp_clk fail.\n");
+               ret = PTR_ERR(ctx->aal_disp_clk);
+               goto err;
+       }
+
+       ctx->ufoe_disp_clk = devm_clk_get(dev, "ufoe_disp");
+       if (IS_ERR(ctx->ufoe_disp_clk)) {
+               dev_err(dev, "crtc_main_probe: Get ufoe_disp_clk fail.\n");
+               ret = PTR_ERR(ctx->ufoe_disp_clk);
+               goto err;
+       }
+
+       ctx->od_disp_clk = devm_clk_get(dev, "od_disp");
+       if (IS_ERR(ctx->od_disp_clk)) {
+               dev_err(dev, "crtc_main_probe: Get od_disp_clk fail.\n");
+               ret = PTR_ERR(ctx->od_disp_clk);
+               goto err;
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ctx->ovl0_regs = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(ctx->ovl0_regs))
+               return PTR_ERR(ctx->ovl0_regs);
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       ctx->rdma0_regs = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(ctx->rdma0_regs))
+               return PTR_ERR(ctx->rdma0_regs);
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       ctx->color0_regs = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(ctx->color0_regs))
+               return PTR_ERR(ctx->color0_regs);
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+       ctx->aal_regs = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(ctx->aal_regs))
+               return PTR_ERR(ctx->aal_regs);
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 4);
+       ctx->ufoe_regs = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(ctx->ufoe_regs))
+               return PTR_ERR(ctx->ufoe_regs);
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 5);
+       ctx->od_regs = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(ctx->od_regs))
+               return PTR_ERR(ctx->od_regs);
+
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_request_irq(dev, irq, crtc_main_irq_handler,
+               IRQF_TRIGGER_NONE, dev_name(dev), ctx);
+       if (ret < 0) {
+               dev_err(dev, "devm_request_irq %d fail %d\n", irq, ret);
+               ret = -ENXIO;
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, ctx);
+
+       ret = component_add(&pdev->dev, &crtc_main_component_ops);
+       if (ret)
+               goto err;
+
+       return 0;
+
+err:
+       if (node)
+               of_node_put(node);
+
+       return ret;
+}
+
+static int crtc_main_remove(struct platform_device *pdev)
+{
+       component_del(&pdev->dev, &crtc_main_component_ops);
+
+       return 0;
+}
+
+static const struct of_device_id crtc_main_driver_dt_match[] = {
+       { .compatible = "mediatek,mt8173-crtc-main" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, crtc_main_driver_dt_match);
+
+struct platform_driver mediatek_crtc_main_driver = {
+       .probe          = crtc_main_probe,
+       .remove         = crtc_main_remove,
+       .driver         = {
+               .name   = "mediatek-crtc-main",
+               .owner  = THIS_MODULE,
+               .of_match_table = crtc_main_driver_dt_match,
+       },
+};
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_ddp.c 
b/drivers/gpu/drm/mediatek/mediatek_drm_ddp.c
new file mode 100644
index 0000000..bb6959b
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_ddp.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_device.h>
+#include <linux/component.h>
+
+#include "mediatek_drm_crtc.h"
+#include "mediatek_drm_ddp.h"
+
+
+#define DISP_REG_CONFIG_DISP_OVL0_MOUT_EN      0x040
+#define DISP_REG_CONFIG_DISP_OVL1_MOUT_EN      0x044
+#define DISP_REG_CONFIG_DISP_OD_MOUT_EN                0x048
+#define DISP_REG_CONFIG_DISP_GAMMA_MOUT_EN     0x04C
+#define DISP_REG_CONFIG_DISP_UFOE_MOUT_EN      0x050
+#define DISP_REG_CONFIG_DISP_COLOR0_SEL_IN     0x084
+#define DISP_REG_CONFIG_DISP_COLOR1_SEL_IN     0x088
+#define DISP_REG_CONFIG_DPI_SEL_IN             0x0AC
+#define DISP_REG_CONFIG_DISP_PATH1_SOUT_SEL_IN 0x0C8
+#define DISP_REG_CONFIG_MMSYS_CG_CON0          0x100
+
+#define DISP_REG_CONFIG_MUTEX_EN(n)      (0x20 + 0x20 * n)
+#define DISP_REG_CONFIG_MUTEX_MOD(n)     (0x2C + 0x20 * n)
+#define DISP_REG_CONFIG_MUTEX_SOF(n)     (0x30 + 0x20 * n)
+
+
+enum {
+       MUTEX_MOD_OVL0      = 11,
+       MUTEX_MOD_RDMA0     = 13,
+       MUTEX_MOD_COLOR0    = 18,
+       MUTEX_MOD_AAL       = 20,
+       MUTEX_MOD_UFOE      = 22,
+       MUTEX_MOD_PWM0      = 23,
+       MUTEX_MOD_OD        = 25,
+};
+
+enum {
+       MUTEX_SOF_DSI0      = 1,
+};
+
+enum {
+       OVL0_MOUT_EN_COLOR0     = 0x1,
+};
+
+enum {
+       OD_MOUT_EN_RDMA0        = 0x1,
+};
+
+enum {
+       UFOE_MOUT_EN_DSI0       = 0x1,
+};
+
+enum {
+       COLOR0_SEL_IN_OVL0      = 0x1,
+};
+
+struct ddp_context {
+       struct device                   *dev;
+       struct drm_device               *drm_dev;
+       struct mediatek_drm_crtc        *crtc;
+       int                             pipe;
+
+       struct clk                      *mutex_disp_clk;
+
+       void __iomem                    *config_regs;
+       void __iomem                    *mutex_regs;
+
+       bool                            pending_ovl_config;
+       bool                            pending_ovl_enable;
+       unsigned int                    pending_ovl_addr;
+       unsigned int                    pending_ovl_width;
+       unsigned int                    pending_ovl_height;
+       unsigned int                    pending_ovl_pitch;
+       unsigned int                    pending_ovl_format;
+};
+
+
+static void disp_config_main_path_connection(void __iomem *disp_base)
+{
+       writel(OVL0_MOUT_EN_COLOR0,
+               disp_base + DISP_REG_CONFIG_DISP_OVL0_MOUT_EN);
+       writel(OD_MOUT_EN_RDMA0, disp_base + DISP_REG_CONFIG_DISP_OD_MOUT_EN);
+       writel(UFOE_MOUT_EN_DSI0,
+               disp_base + DISP_REG_CONFIG_DISP_UFOE_MOUT_EN);
+       writel(COLOR0_SEL_IN_OVL0,
+               disp_base + DISP_REG_CONFIG_DISP_COLOR0_SEL_IN);
+}
+
+static void disp_config_main_path_mutex(void __iomem *mutex_base)
+{
+       unsigned int id = 0;
+
+       writel((1 << MUTEX_MOD_OVL0 | 1 << MUTEX_MOD_RDMA0 |
+               1 << MUTEX_MOD_COLOR0 | 1 << MUTEX_MOD_AAL |
+               1 << MUTEX_MOD_UFOE | 1 << MUTEX_MOD_PWM0 |
+               1 << MUTEX_MOD_OD),
+               mutex_base + DISP_REG_CONFIG_MUTEX_MOD(id));
+
+       writel(MUTEX_SOF_DSI0, mutex_base + DISP_REG_CONFIG_MUTEX_SOF(id));
+       writel(1, mutex_base + DISP_REG_CONFIG_MUTEX_EN(id));
+}
+
+void mediatek_ddp_main_path_setup(struct device *dev)
+{
+       struct ddp_context *ddp = dev_get_drvdata(dev);
+
+       disp_config_main_path_connection(ddp->config_regs);
+       disp_config_main_path_mutex(ddp->mutex_regs);
+}
+
+void mediatek_ddp_clock_on(struct device *dev)
+{
+       struct ddp_context *ddp = dev_get_drvdata(dev);
+       int ret;
+
+       /* disp_mtcmos */
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               DRM_ERROR("failed to get_sync(%d)\n", ret);
+
+       ret = clk_prepare_enable(ddp->mutex_disp_clk);
+       if (ret != 0)
+               DRM_ERROR("clk_prepare_enable(mutex_disp_clk) error!\n");
+}
+
+static int ddp_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ddp_context *ddp;
+       struct resource *regs;
+       int ret;
+
+       if (!dev->of_node)
+               return -ENODEV;
+
+       ddp = devm_kzalloc(dev, sizeof(*ddp), GFP_KERNEL);
+       if (!ddp)
+               return -ENOMEM;
+
+       ddp->mutex_disp_clk = devm_clk_get(dev, "mutex_disp");
+       if (IS_ERR(ddp->mutex_disp_clk)) {
+               dev_err(dev, "ddp_probe: Get mutex_disp_clk fail.\n");
+               ret = PTR_ERR(ddp->mutex_disp_clk);
+               goto err;
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ddp->config_regs = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(ddp->config_regs))
+               return PTR_ERR(ddp->config_regs);
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       ddp->mutex_regs = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(ddp->mutex_regs))
+               return PTR_ERR(ddp->mutex_regs);
+
+       platform_set_drvdata(pdev, ddp);
+
+       pm_runtime_enable(dev);
+
+       return 0;
+
+err:
+
+       return ret;
+}
+
+static int ddp_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static const struct of_device_id ddp_driver_dt_match[] = {
+       { .compatible = "mediatek,mt8173-ddp" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ddp_driver_dt_match);
+
+struct platform_driver mediatek_ddp_driver = {
+       .probe          = ddp_probe,
+       .remove         = ddp_remove,
+       .driver         = {
+               .name   = "mediatek-ddp",
+               .owner  = THIS_MODULE,
+               .of_match_table = ddp_driver_dt_match,
+       },
+};
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_ddp.h 
b/drivers/gpu/drm/mediatek/mediatek_drm_ddp.h
new file mode 100644
index 0000000..07dd637
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_ddp.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _MEDIATEK_DRM_DDP_H_
+#define _MEDIATEK_DRM_DDP_H_
+
+void mediatek_ddp_main_path_setup(struct device *dev);
+
+void mediatek_ddp_clock_on(struct device *dev);
+
+
+#endif
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c 
b/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c
new file mode 100644
index 0000000..dd7ac83
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Authors:
+ *     YT Shen <yt.s...@mediatek.com>
+ *     CK Hu <ck...@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 <linux/clk.h>
+
+
+#define DISP_REG_OVL_INTEN                       0x0004
+#define DISP_REG_OVL_INTSTA                      0x0008
+#define DISP_REG_OVL_EN                          0x000C
+#define DISP_REG_OVL_RST                         0x0014
+#define DISP_REG_OVL_ROI_SIZE                    0x0020
+#define DISP_REG_OVL_ROI_BGCLR                   0x0028
+#define DISP_REG_OVL_SRC_CON                     0x002C
+#define DISP_REG_OVL_L0_CON                      0x0030
+#define DISP_REG_OVL_L0_SRCKEY                   0x0034
+#define DISP_REG_OVL_L0_SRC_SIZE                 0x0038
+#define DISP_REG_OVL_L0_OFFSET                   0x003C
+#define DISP_REG_OVL_L0_PITCH                    0x0044
+#define DISP_REG_OVL_L1_CON                      0x0050
+#define DISP_REG_OVL_L1_SRCKEY                   0x0054
+#define DISP_REG_OVL_L1_SRC_SIZE                 0x0058
+#define DISP_REG_OVL_L1_OFFSET                   0x005C
+#define DISP_REG_OVL_L1_PITCH                    0x0064
+#define DISP_REG_OVL_RDMA0_CTRL                  0x00C0
+#define DISP_REG_OVL_RDMA0_MEM_GMC_SETTING       0x00C8
+#define DISP_REG_OVL_RDMA1_CTRL                  0x00E0
+#define DISP_REG_OVL_RDMA1_MEM_GMC_SETTING       0x00E8
+#define DISP_REG_OVL_RDMA1_FIFO_CTRL             0x00F0
+#define DISP_REG_OVL_L0_ADDR                     0x0f40
+#define DISP_REG_OVL_L1_ADDR                     0x0f60
+
+#define DISP_REG_RDMA_INT_ENABLE          0x0000
+#define DISP_REG_RDMA_INT_STATUS          0x0004
+#define DISP_REG_RDMA_GLOBAL_CON          0x0010
+#define DISP_REG_RDMA_SIZE_CON_0          0x0014
+#define DISP_REG_RDMA_SIZE_CON_1          0x0018
+#define DISP_REG_RDMA_FIFO_CON            0x0040
+
+#define DISP_OD_EN                              0x000
+#define DISP_OD_INTEN                           0x008
+#define DISP_OD_INTS                            0x00C
+#define DISP_OD_CFG                             0x020
+#define DISP_OD_SIZE                            0x030
+
+#define DISP_REG_UFO_START                     0x000
+
+#define DISP_COLOR_CFG_MAIN                    0x400
+#define DISP_COLOR_START                       0xC00
+
+enum DISPLAY_PATH {
+       PRIMARY_PATH = 0,
+       EXTERNAL_PATH = 1,
+};
+
+enum RDMA_MODE {
+       RDMA_MODE_DIRECT_LINK = 0,
+       RDMA_MODE_MEMORY = 1,
+};
+
+enum RDMA_OUTPUT_FORMAT {
+       RDMA_OUTPUT_FORMAT_ARGB = 0,
+       RDMA_OUTPUT_FORMAT_YUV444 = 1,
+};
+
+#define OVL_COLOR_BASE 30
+enum OVL_INPUT_FORMAT {
+       OVL_INFMT_RGB565 = 0,
+       OVL_INFMT_RGB888 = 1,
+       OVL_INFMT_RGBA8888 = 2,
+       OVL_INFMT_ARGB8888 = 3,
+       OVL_INFMT_UYVY = 4,
+       OVL_INFMT_YUYV = 5,
+       OVL_INFMT_UNKNOWN = 16,
+
+       OVL_INFMT_BGR565 = OVL_INFMT_RGB565 + OVL_COLOR_BASE,
+       OVL_INFMT_BGR888 = OVL_INFMT_RGB888 + OVL_COLOR_BASE,
+       OVL_INFMT_BGRA8888 = OVL_INFMT_RGBA8888 + OVL_COLOR_BASE,
+       OVL_INFMT_ABGR8888 = OVL_INFMT_ARGB8888 + OVL_COLOR_BASE,
+};
+
+enum {
+       OD_RELAY_MODE           = 0x1,
+};
+
+enum {
+       UFO_BYPASS              = 0x4,
+};
+
+enum {
+       COLOR_BYPASS_ALL        = (1UL<<7),
+       COLOR_SEQ_SEL           = (1UL<<13),
+};
+
+enum {
+       OVL_LAYER_SRC_DRAM      = 0,
+};
+
+
+static void mediatek_ovl_start(void __iomem *ovl_base)
+{
+       writel(0x01, ovl_base + DISP_REG_OVL_EN);
+}
+
+static void mediatek_ovl_roi(void __iomem *ovl_base,
+       unsigned int w, unsigned int h, unsigned int bg_color)
+{
+       writel(h << 16 | w, ovl_base + DISP_REG_OVL_ROI_SIZE);
+       writel(bg_color, ovl_base + DISP_REG_OVL_ROI_BGCLR);
+}
+
+void mediatek_ovl_layer_switch(void __iomem *ovl_base,
+       unsigned layer, bool en)
+{
+       u32 reg;
+
+       reg = readl(ovl_base + DISP_REG_OVL_SRC_CON);
+       if (en)
+               reg |= (1U<<layer);
+       else
+               reg &= ~(1U<<layer);
+
+       writel(reg, ovl_base + DISP_REG_OVL_SRC_CON);
+       writel(0x1, ovl_base + DISP_REG_OVL_RST);
+       writel(0x0, ovl_base + DISP_REG_OVL_RST);
+}
+
+static unsigned int ovl_fmt_convert(unsigned int fmt)
+{
+       switch (fmt) {
+       case DRM_FORMAT_RGB888:
+               return OVL_INFMT_RGB888;
+       case DRM_FORMAT_RGB565:
+               return OVL_INFMT_RGB565;
+       case DRM_FORMAT_ARGB8888:
+               return OVL_INFMT_ARGB8888;
+       case DRM_FORMAT_RGBA8888:
+               return OVL_INFMT_RGBA8888;
+       case DRM_FORMAT_BGR888:
+               return OVL_INFMT_BGR888;
+       case DRM_FORMAT_BGR565:
+               return OVL_INFMT_BGR565;
+       case DRM_FORMAT_ABGR8888:
+               return OVL_INFMT_ABGR8888;
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_BGRA8888:
+               return OVL_INFMT_BGRA8888;
+       case DRM_FORMAT_YUYV:
+               return OVL_INFMT_YUYV;
+       case DRM_FORMAT_UYVY:
+               return OVL_INFMT_UYVY;
+       default:
+               return OVL_INFMT_UNKNOWN;
+       }
+}
+
+void mediatek_ovl_layer_config(void __iomem *ovl_base, bool enabled,
+       unsigned int addr, unsigned int width, unsigned int height,
+       unsigned int pitch,     unsigned int format)
+{
+       unsigned int reg;
+       unsigned int dst_x = 0;
+       unsigned int dst_y = 0;
+       bool color_key_en = 1;
+       unsigned int color_key = 0xFF000000;
+       bool alpha_en = 0;
+       unsigned char alpha = 0x0;
+       unsigned int src_con, new_set;
+
+       unsigned int rgb_swap, bpp;
+       unsigned int fmt = ovl_fmt_convert(format);
+
+       if (fmt == OVL_INFMT_BGR888 || fmt == OVL_INFMT_BGR565 ||
+               fmt == OVL_INFMT_ABGR8888 || fmt == OVL_INFMT_BGRA8888) {
+               fmt -= OVL_COLOR_BASE;
+               rgb_swap = 1;
+       } else {
+               rgb_swap = 0;
+       }
+
+       switch (fmt) {
+       case OVL_INFMT_ARGB8888:
+       case OVL_INFMT_RGBA8888:
+               bpp = 4;
+               break;
+       case OVL_INFMT_RGB888:
+               bpp = 3;
+               break;
+       case OVL_INFMT_RGB565:
+       case OVL_INFMT_YUYV:
+       case OVL_INFMT_UYVY:
+               bpp = 2;
+               break;
+       default:
+               bpp = 1;
+       }
+
+       if (pitch == 0)
+               pitch = width * bpp;
+
+       src_con = readl(ovl_base + DISP_REG_OVL_SRC_CON);
+       if (enabled == true)
+               new_set = src_con | 0x1;
+       else
+               new_set = src_con & ~(0x1);
+
+       writel(0x1, ovl_base + DISP_REG_OVL_RST);
+       writel(0x0, ovl_base + DISP_REG_OVL_RST);
+
+       writel(new_set, ovl_base + DISP_REG_OVL_SRC_CON);
+
+       writel(0x00000001, ovl_base + DISP_REG_OVL_RDMA0_CTRL);
+       writel(0x40402020, ovl_base + DISP_REG_OVL_RDMA0_MEM_GMC_SETTING);
+
+       reg = color_key_en << 30 | OVL_LAYER_SRC_DRAM << 28 |
+               rgb_swap << 25 | fmt << 12 | alpha_en << 8 | alpha;
+       writel(reg, ovl_base + DISP_REG_OVL_L0_CON);
+       writel(color_key, ovl_base + DISP_REG_OVL_L0_SRCKEY);
+       writel(height << 16 | width, ovl_base + DISP_REG_OVL_L0_SRC_SIZE);
+       writel(dst_y << 16 | dst_x, ovl_base + DISP_REG_OVL_L0_OFFSET);
+       writel(addr, ovl_base + DISP_REG_OVL_L0_ADDR);
+       writel(pitch & 0xFFFF, ovl_base + DISP_REG_OVL_L0_PITCH);
+}
+
+static void mediatek_rdma_start(void __iomem *rdma_base)
+{
+       unsigned int reg;
+
+       writel(0x4, rdma_base + DISP_REG_RDMA_INT_ENABLE);
+       reg = readl(rdma_base + DISP_REG_RDMA_GLOBAL_CON);
+       reg |= 1;
+       writel(reg, rdma_base + DISP_REG_RDMA_GLOBAL_CON);
+}
+
+static void mediatek_rdma_config_direct_link(void __iomem *rdma_base,
+       unsigned width, unsigned height)
+{
+       unsigned int reg;
+       enum RDMA_MODE mode = RDMA_MODE_DIRECT_LINK;
+       enum RDMA_OUTPUT_FORMAT output_format = RDMA_OUTPUT_FORMAT_ARGB;
+
+       reg = readl(rdma_base + DISP_REG_RDMA_GLOBAL_CON);
+       if (mode == RDMA_MODE_DIRECT_LINK)
+               reg &= ~(0x2U);
+       writel(reg, rdma_base + DISP_REG_RDMA_GLOBAL_CON);
+
+       reg = readl(rdma_base + DISP_REG_RDMA_SIZE_CON_0);
+       if (output_format == RDMA_OUTPUT_FORMAT_ARGB)
+               reg &= ~(0x20000000U);
+       else
+               reg |= 0x20000000U;
+       writel(reg, rdma_base + DISP_REG_RDMA_SIZE_CON_0);
+
+       reg = readl(rdma_base + DISP_REG_RDMA_SIZE_CON_0);
+       reg = (reg & ~(0xFFFU)) | (width & 0xFFFU);
+       writel(reg, rdma_base + DISP_REG_RDMA_SIZE_CON_0);
+
+       reg = readl(rdma_base + DISP_REG_RDMA_SIZE_CON_1);
+       reg = (reg & ~(0xFFFFFU)) | (height & 0xFFFFFU);
+       writel(reg, rdma_base + DISP_REG_RDMA_SIZE_CON_1);
+
+       writel(0x80F00008, rdma_base + DISP_REG_RDMA_FIFO_CON);
+}
+
+void mediatek_od_enable_vblank(void __iomem *disp_base)
+{
+       writel(0x1, disp_base + DISP_OD_INTEN);
+}
+
+void mediatek_od_disable_vblank(void __iomem *disp_base)
+{
+       writel(0x0, disp_base + DISP_OD_INTEN);
+}
+
+void mediatek_od_clear_vblank(void __iomem *disp_base)
+{
+       writel(0x0, disp_base + DISP_OD_INTS);
+}
+
+static void mediatek_od_start(void __iomem *od_base, unsigned int w,
+       unsigned int h)
+{
+       writel(w << 16 | h, od_base + DISP_OD_SIZE);
+       writel(OD_RELAY_MODE, od_base + DISP_OD_CFG);
+       writel(1, od_base + DISP_OD_EN);
+}
+
+static void mediatek_ufoe_start(void __iomem *ufoe_base)
+{
+       writel(UFO_BYPASS, ufoe_base + DISP_REG_UFO_START);
+}
+
+static void mediatek_color_start(void __iomem *color_base)
+{
+       writel(COLOR_BYPASS_ALL | COLOR_SEQ_SEL,
+               color_base + DISP_COLOR_CFG_MAIN);
+       writel(0x1, color_base + DISP_COLOR_START);
+}
+
+void main_disp_path_power_on(void __iomem *ovl_base,
+       void __iomem *rdma_base,
+       void __iomem *color_base,
+       void __iomem *ufoe_base,
+       void __iomem *od_base)
+{
+       struct device_node *node;
+       unsigned int width, height;
+       int err;
+
+       node = of_find_compatible_node(NULL, NULL, "mediatek,mt8173-dsi");
+
+       err = of_property_read_u32(node, "mediatek,width", &width);
+       if (err < 0)
+               return;
+
+       err = of_property_read_u32(node, "mediatek,height", &height);
+       if (err < 0)
+               return;
+
+       width = ((width + 3)>>2)<<2;
+
+       mediatek_ovl_start(ovl_base);
+       mediatek_rdma_start(rdma_base);
+
+       mediatek_ovl_roi(ovl_base, width, height, 0x00000000);
+       mediatek_ovl_layer_switch(ovl_base, 0, 1);
+       mediatek_rdma_config_direct_link(rdma_base, width, height);
+       mediatek_od_start(od_base, width, height);
+       mediatek_ufoe_start(ufoe_base);
+       mediatek_color_start(color_base);
+}
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h 
b/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h
new file mode 100644
index 0000000..d3ed3e1
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_ddp_comp.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _MEDIATEK_DRM_DDP_COMP_H_
+#define _MEDIATEK_DRM_DDP_COMP_H_
+
+
+void mediatek_od_enable_vblank(void __iomem *drm_disp_base);
+void mediatek_od_disable_vblank(void __iomem *drm_disp_base);
+void mediatek_od_clear_vblank(void __iomem *drm_disp_base);
+void mediatek_ovl_layer_config(void __iomem *ovl_base, bool enabled,
+       unsigned int addr, unsigned int width, unsigned int height,
+       unsigned int pitch,     unsigned int format);
+
+void main_disp_path_power_on(void __iomem *ovl_base,
+       void __iomem *rdma_base, void __iomem *color_base,
+       void __iomem *ufoe_base, void __iomem *od_base);
+
+void mediatek_ovl_layer_switch(void __iomem *ovl_base,
+       unsigned layer, bool en);
+
+#endif
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_drv.c 
b/drivers/gpu/drm/mediatek/mediatek_drm_drv.c
new file mode 100644
index 0000000..dfd816f
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_drv.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: YT SHEN <yt.s...@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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_gem.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/of_platform.h>
+#include <linux/component.h>
+#include <linux/mtk-smi.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-iommu.h>
+
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_crtc.h"
+#include "mediatek_drm_fb.h"
+#include "mediatek_drm_gem.h"
+
+#include "drm/mediatek_drm.h"
+
+#define DRIVER_NAME "mediatek"
+#define DRIVER_DESC "Mediatek SoC DRM"
+#define DRIVER_DATE "20150513"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+static struct drm_mode_config_funcs mediatek_drm_mode_config_funcs = {
+       .fb_create = mtk_drm_mode_fb_create,
+       .output_poll_changed = mtk_drm_mode_output_poll_changed,
+};
+
+static int mtk_drm_kms_init(struct drm_device *dev)
+{
+       struct device_node *node;
+       struct platform_device *pdev;
+       int err;
+
+       drm_mode_config_init(dev);
+
+       dev->mode_config.min_width = 640;
+       dev->mode_config.min_height = 480;
+
+       /*
+        * 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 = &mediatek_drm_mode_config_funcs;
+
+       err = component_bind_all(dev->dev, dev);
+       if (err)
+               goto err_crtc;
+
+       /*
+        * We don't use the drm_irq_install() helpers provided by the DRM
+        * core, so we need to set this manually in order to allow the
+        * DRM_IOCTL_WAIT_VBLANK to operate correctly.
+        */
+       dev->irq_enabled = true;
+       err = drm_vblank_init(dev, MAX_CRTC);
+       if (err < 0)
+               goto err_crtc;
+
+       drm_kms_helper_poll_init(dev);
+
+       node = of_parse_phandle(dev->dev->of_node, "iommus", 0);
+       if (!node)
+               return 0;
+
+       pdev = of_find_device_by_node(node);
+       if (WARN_ON(!pdev)) {
+               of_node_put(node);
+               return -EINVAL;
+       }
+       err = iommu_dma_attach_device(dev->dev,
+                       arch_get_dma_domain(&pdev->dev));
+       if (err)
+               DRM_ERROR("iommu_dma_attach_device fail %d\n", err);
+
+       node = of_parse_phandle(dev->dev->of_node, "larb", 0);
+       if (!node)
+               return 0;
+
+       pdev = of_find_device_by_node(node);
+       if (WARN_ON(!pdev)) {
+               of_node_put(node);
+               return -EINVAL;
+       }
+
+       err = mtk_smi_larb_get(&pdev->dev);
+       if (err)
+               DRM_ERROR("mtk_smi_larb_get fail %d\n", err);
+
+       node = of_parse_phandle(dev->dev->of_node, "larb", 1);
+       if (!node)
+               return 0;
+
+       pdev = of_find_device_by_node(node);
+       if (WARN_ON(!pdev)) {
+               of_node_put(node);
+               return -EINVAL;
+       }
+
+       err = mtk_smi_larb_get(&pdev->dev);
+       if (err)
+               DRM_ERROR("mtk_smi_larb_get fail %d\n", err);
+
+       mtk_fbdev_create(dev);
+
+       return 0;
+err_crtc:
+       drm_mode_config_cleanup(dev);
+
+       return err;
+}
+
+static int mtk_drm_load(struct drm_device *dev, unsigned long flags)
+{
+       struct mtk_drm_private *priv;
+
+       priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       dev->dev_private = priv;
+       platform_set_drvdata(dev->platformdev, dev);
+
+       return mtk_drm_kms_init(dev);
+}
+
+static void mtk_drm_kms_deinit(struct drm_device *dev)
+{
+       drm_kms_helper_poll_fini(dev);
+
+       mtk_fbdev_destroy(dev);
+
+       drm_vblank_cleanup(dev);
+       drm_mode_config_cleanup(dev);
+
+       pm_runtime_disable(dev->dev);
+}
+
+static int mtk_drm_unload(struct drm_device *dev)
+{
+       mtk_drm_kms_deinit(dev);
+       dev->dev_private = NULL;
+
+       return 0;
+}
+
+static int mtk_drm_open(struct drm_device *drm, struct drm_file *filp)
+{
+       return 0;
+}
+
+static void mediatek_drm_preclose(struct drm_device *drm, struct drm_file 
*file)
+{
+}
+
+static void mediatek_drm_lastclose(struct drm_device *drm)
+{
+}
+
+static const struct vm_operations_struct mediatek_drm_gem_vm_ops = {
+       .open = drm_gem_vm_open,
+       .close = drm_gem_vm_close,
+};
+
+static const struct drm_ioctl_desc mtk_ioctls[] = {
+       DRM_IOCTL_DEF_DRV(MTK_GEM_CREATE, mediatek_gem_create_ioctl,
+                         DRM_UNLOCKED | DRM_AUTH),
+       DRM_IOCTL_DEF_DRV(MTK_GEM_MAP_OFFSET,
+                         mediatek_gem_map_offset_ioctl,
+                         DRM_UNLOCKED | DRM_AUTH),
+};
+
+static const struct file_operations mediatek_drm_fops = {
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .release = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+       .mmap = mtk_drm_gem_mmap,
+       .poll = drm_poll,
+       .read = drm_read,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = drm_compat_ioctl,
+#endif
+};
+
+static struct drm_driver mediatek_drm_driver = {
+       .driver_features = DRIVER_MODESET | DRIVER_GEM,
+       .load = mtk_drm_load,
+       .unload = mtk_drm_unload,
+       .open = mtk_drm_open,
+       .preclose = mediatek_drm_preclose,
+       .lastclose = mediatek_drm_lastclose,
+       .set_busid = drm_platform_set_busid,
+
+       .get_vblank_counter = drm_vblank_count,
+       .enable_vblank = mtk_drm_crtc_enable_vblank,
+       .disable_vblank = mtk_drm_crtc_disable_vblank,
+
+       .gem_free_object = mtk_drm_gem_free_object,
+       .gem_vm_ops = &mediatek_drm_gem_vm_ops,
+       .dumb_create = mtk_drm_gem_dumb_create,
+       .dumb_map_offset = mtk_drm_gem_dumb_map_offset,
+       .dumb_destroy = drm_gem_dumb_destroy,
+
+       .num_ioctls = 0,
+       .fops = &mediatek_drm_fops,
+
+       .set_busid = drm_platform_set_busid,
+
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+       return dev->of_node == data;
+}
+
+static int mtk_drm_add_components(struct device *master, struct master *m)
+{
+       struct device_node *np = master->of_node;
+       unsigned i;
+       int ret;
+
+       for (i = 0; ; i++) {
+               struct device_node *node;
+
+               node = of_parse_phandle(np, "connectors", i);
+               if (!node)
+                       break;
+
+               ret = component_master_add_child(m, compare_of, node);
+               of_node_put(node);
+               if (ret) {
+                       dev_err(master, "component_master_add_child %s fail.\n",
+                               node->full_name);
+                       return ret;
+               }
+       }
+
+       for (i = 0; ; i++) {
+               struct device_node *node;
+
+               node = of_parse_phandle(np, "crtcs", i);
+               if (!node)
+                       break;
+
+               ret = component_master_add_child(m, compare_of, node);
+               of_node_put(node);
+               if (ret) {
+                       dev_err(master, "component_master_add_child %s fail.\n",
+                               node->full_name);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int mtk_drm_bind(struct device *dev)
+{
+       return drm_platform_init(&mediatek_drm_driver, to_platform_device(dev));
+}
+
+static void mtk_drm_unbind(struct device *dev)
+{
+       drm_put_dev(platform_get_drvdata(to_platform_device(dev)));
+}
+
+static const struct component_master_ops mtk_drm_ops = {
+       .add_components = mtk_drm_add_components,
+       .bind           = mtk_drm_bind,
+       .unbind         = mtk_drm_unbind,
+};
+
+static int mtk_drm_probe(struct platform_device *pdev)
+{
+       component_master_add(&pdev->dev, &mtk_drm_ops);
+
+       return 0;
+}
+
+static int mtk_drm_remove(struct platform_device *pdev)
+{
+       drm_put_dev(platform_get_drvdata(pdev));
+
+       return 0;
+}
+
+static const struct of_device_id mediatek_drm_of_ids[] = {
+       { .compatible = "mediatek,mt8173-drm", },
+       { }
+};
+
+static struct platform_driver mediatek_drm_platform_driver = {
+       .probe  = mtk_drm_probe,
+       .remove = mtk_drm_remove,
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "mediatek-drm",
+               .of_match_table = mediatek_drm_of_ids,
+               /*.pm     = &mtk_pm_ops, */
+       },
+       /* .id_table = mtk_drm_platform_ids, */
+};
+
+static int mediatek_drm_init(void)
+{
+       int err;
+
+       err = platform_driver_register(&mediatek_ddp_driver);
+       if (err < 0) {
+               DRM_DEBUG_DRIVER("register ddp driver fail.\n");
+               return err;
+       }
+
+       err = platform_driver_register(&mtk_dsi_driver);
+       if (err < 0) {
+               DRM_DEBUG_DRIVER("register dsi driver fail.\n");
+               return err;
+       }
+
+       err = platform_driver_register(&mediatek_crtc_main_driver);
+       if (err < 0) {
+               DRM_DEBUG_DRIVER("register crtc_main driver fail.\n");
+               return err;
+       }
+
+       err = platform_driver_register(&mediatek_drm_platform_driver);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static void mediatek_drm_exit(void)
+{
+       platform_driver_unregister(&mediatek_drm_platform_driver);
+       platform_driver_unregister(&mtk_dsi_driver);
+}
+
+late_initcall(mediatek_drm_init);
+module_exit(mediatek_drm_exit);
+
+MODULE_AUTHOR("YT SHEN <yt.s...@mediatek.com>");
+MODULE_DESCRIPTION("Mediatek SoC DRM driver");
+MODULE_LICENSE("GPL");
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_drv.h 
b/drivers/gpu/drm/mediatek/mediatek_drm_drv.h
new file mode 100644
index 0000000..10ee4c4
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_drv.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _MEDIATEK_DRM_DRV_H_
+#define _MEDIATEK_DRM_DRV_H_
+
+#define MAX_CRTC       2
+#define MAX_PLANE      4
+
+extern struct platform_driver mediatek_ddp_driver;
+extern struct platform_driver mtk_dsi_driver;
+extern struct platform_driver mediatek_crtc_main_driver;
+
+struct mtk_drm_private {
+       struct drm_fb_helper *fb_helper;
+
+       /*
+        * 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];
+       unsigned int pipe;
+};
+
+
+#endif
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_dsi.c 
b/drivers/gpu/drm/mediatek/mediatek_drm_dsi.c
new file mode 100644
index 0000000..199ff9d
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_dsi.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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_gem.h>
+#include <drm/drm_crtc_helper.h>
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_graph.h>
+#include <linux/component.h>
+
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+#include <video/videomode.h>
+
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_crtc.h"
+
+#include "mediatek_drm_ddp.h"
+
+#include "mediatek_drm_gem.h"
+#include "mediatek_drm_dsi.h"
+
+
+#define DSI_VIDEO_FIFO_DEPTH (1920 / 4)
+#define DSI_HOST_FIFO_DEPTH 64
+
+
+#define DSI_START              0x00
+
+#define        DSI_CON_CTRL    0x10
+       #define DSI_RESET               (1)
+
+#define DSI_MODE_CTRL  0x14
+       #define  MODE           2
+               #define CMD_MODE                  0
+               #define SYNC_PULSE_MODE    1
+               #define SYNC_EVENT_MODE    2
+               #define BURST_MODE              3
+       #define  FRM_MODE    (1<<16)
+       #define  MIX_MODE     (1<<17)
+
+#define DSI_TXRX_CTRL  0x18
+       #define VC_NUM  (2<<0)
+       #define LANE_NUM        (0xf<<2)
+       #define DIS_EOT         (1<<6)
+       #define NULL_EN         (1<<7)
+       #define TE_FREERUN              (1<<8)
+       #define EXT_TE_EN               (1<<9)
+       #define EXT_TE_EDGE             (1<<10)
+       #define MAX_RTN_SIZE            (0xf<<12)
+       #define HSTX_CKLP_EN            (1<<16)
+
+#define DSI_PSCTRL             0x1c
+       #define DSI_PS_WC               0x3fff
+       #define DSI_PS_SEL       (2<<16)
+               #define PACKED_PS_16BIT_RGB565          (0<<16)
+               #define LOOSELY_PS_18BIT_RGB666         (1<<16)
+               #define PACKED_PS_18BIT_RGB666          (2<<16)
+               #define PACKED_PS_24BIT_RGB888          (3<<16)
+
+#define DSI_VSA_NL             0x20
+#define DSI_VBP_NL             0x24
+#define DSI_VFP_NL             0x28
+
+#define DSI_VACT_NL            0x2C
+
+#define DSI_HSA_WC             0x50
+#define DSI_HBP_WC             0x54
+#define DSI_HFP_WC             0x58
+
+#define        DSI_HSTX_CKL_WC 0x64
+
+#define DSI_PHY_LCCON  0x104
+       #define LC_HS_TX_EN                                     (1)
+       #define LC_ULPM_EN                                      (1<<1)
+       #define LC_WAKEUP_EN                            (1<<2)
+
+#define DSI_PHY_LD0CON 0x108
+       #define LD0_HS_TX_EN                            (1)
+       #define LD0_ULPM_EN                                     (1<<1)
+       #define LD0_WAKEUP_EN                           (1<<2)
+
+#define        DSI_PHY_TIMECON0                        0x0110
+       #define LPX                     (0xff<<0)
+       #define HS_PRPR         (0xff<<8)
+       #define HS_ZERO         (0xff<<16)
+       #define HS_TRAIL                (0xff<<24)
+
+#define        DSI_PHY_TIMECON1                        0x0114
+       #define TA_GO                   (0xff<<0)
+       #define TA_SURE                 (0xff<<8)
+       #define TA_GET                  (0xff<<16)
+       #define DA_HS_EXIT              (0xff<<24)
+
+#define        DSI_PHY_TIMECON2                        0x0118
+       #define CONT_DET                (0xff<<0)
+       #define CLK_ZERO                (0xff<<16)
+       #define CLK_TRAIL               (0xff<<24)
+
+#define        DSI_PHY_TIMECON3                        0x011c
+       #define CLK_HS_PRPR             (0xff<<0)
+       #define CLK_HS_POST             (0xff<<8)
+       #define CLK_HS_EXIT             (0xff<<16)
+
+#define                MIPITX_DSI0_CON                 0x00
+    #define RG_DSI0_LDOCORE_EN                                 (1)
+    #define RG_DSI0_CKG_LDOOUT_EN                              (1<<1)
+    #define RG_DSI0_BCLK_SEL                                   (3<<2)
+    #define RG_DSI0_LD_IDX_SEL                                 (7<<4)
+    #define RG_DSI0_PHYCLK_SEL                                 (2<<8)
+    #define RG_DSI0_DSICLK_FREQ_SEL                            (1<<10)
+    #define RG_DSI0_LPTX_CLMP_EN                               (1<<11)
+
+#define                MIPITX_DSI0_CLOCK_LANE  0x04
+    #define RG_DSI0_LNTC_LDOOUT_EN                             (1)
+    #define RG_DSI0_LNTC_CKLANE_EN                             (1<<1)
+    #define RG_DSI0_LNTC_LPTX_IPLUS1                   (1<<2)
+    #define RG_DSI0_LNTC_LPTX_IPLUS2                   (1<<3)
+    #define RG_DSI0_LNTC_LPTX_IMINUS                   (1<<4)
+    #define RG_DSI0_LNTC_LPCD_IPLUS                            (1<<5)
+    #define RG_DSI0_LNTC_LPCD_IMLUS                            (1<<6)
+    #define RG_DSI0_LNTC_RT_CODE                               (0xf<<8)
+
+#define                MIPITX_DSI0_DATA_LANE0  0x08
+    #define RG_DSI0_LNT0_LDOOUT_EN                             (1)
+    #define RG_DSI0_LNT0_CKLANE_EN                             (1<<1)
+    #define RG_DSI0_LNT0_LPTX_IPLUS1                   (1<<2)
+    #define RG_DSI0_LNT0_LPTX_IPLUS2                   (1<<3)
+    #define RG_DSI0_LNT0_LPTX_IMINUS                   (1<<4)
+    #define RG_DSI0_LNT0_LPCD_IPLUS                            (1<<5)
+    #define RG_DSI0_LNT0_LPCD_IMINUS                   (1<<6)
+    #define RG_DSI0_LNT0_RT_CODE                               (0xf<<8)
+
+#define                MIPITX_DSI0_DATA_LANE1  0x0c
+    #define RG_DSI0_LNT1_LDOOUT_EN                             (1)
+       #define RG_DSI0_LNT1_CKLANE_EN                          (1<<1)
+       #define RG_DSI0_LNT1_LPTX_IPLUS1                        (1<<2)
+       #define RG_DSI0_LNT1_LPTX_IPLUS2                        (1<<3)
+       #define RG_DSI0_LNT1_LPTX_IMINUS                        (1<<4)
+       #define RG_DSI0_LNT1_LPCD_IPLUS                         (1<<5)
+       #define RG_DSI0_LNT1_LPCD_IMINUS                        (1<<6)
+       #define RG_DSI0_LNT1_RT_CODE                            (0xf<<8)
+
+#define                MIPITX_DSI0_DATA_LANE2  0x10
+    #define RG_DSI0_LNT2_LDOOUT_EN                             (1)
+       #define RG_DSI0_LNT2_CKLANE_EN                          (1<<1)
+       #define RG_DSI0_LNT2_LPTX_IPLUS1                        (1<<2)
+       #define RG_DSI0_LNT2_LPTX_IPLUS2                        (1<<3)
+       #define RG_DSI0_LNT2_LPTX_IMINUS                        (1<<4)
+       #define RG_DSI0_LNT2_LPCD_IPLUS                         (1<<5)
+       #define RG_DSI0_LNT2_LPCD_IMINUS                        (1<<6)
+       #define RG_DSI0_LNT2_RT_CODE                            (0xf<<8)
+
+#define                MIPITX_DSI0_DATA_LANE3  0x14
+       #define RG_DSI0_LNT3_LDOOUT_EN                          (1)
+       #define RG_DSI0_LNT3_CKLANE_EN                          (1<<1)
+       #define RG_DSI0_LNT3_LPTX_IPLUS1                        (1<<2)
+       #define RG_DSI0_LNT3_LPTX_IPLUS2                        (1<<3)
+       #define RG_DSI0_LNT3_LPTX_IMINUS                        (1<<4)
+       #define RG_DSI0_LNT3_LPCD_IPLUS                         (1<<5)
+       #define RG_DSI0_LNT3_LPCD_IMINUS                        (1<<6)
+       #define RG_DSI0_LNT3_RT_CODE                            (0xf<<8)
+
+#define                MIPITX_DSI_TOP_CON      0x40
+       #define RG_DSI_LNT_INTR_EN                      (1)
+       #define RG_DSI_LNT_HS_BIAS_EN                   (1<<1)
+       #define RG_DSI_LNT_IMP_CAL_EN                   (1<<2)
+       #define RG_DSI_LNT_TESTMODE_EN          (1<<3)
+       #define RG_DSI_LNT_IMP_CAL_CODE         (0xf<<4)
+       #define RG_DSI_LNT_AIO_SEL                              (7<<8)
+       #define RG_DSI_PAD_TIE_LOW_EN                   (1<<11)
+       #define RG_DSI_DEBUG_INPUT_EN                   (1<<12)
+       #define RG_DSI_PRESERVE                        (7<<13)
+
+#define                MIPITX_DSI_BG_CON               0x44
+       #define RG_DSI_BG_CORE_EN               1
+       #define RG_DSI_BG_CKEN                  (1<<1)
+       #define RG_DSI_BG_DIV                   (0x3<<2)
+       #define RG_DSI_BG_FAST_CHARGE           (1<<4)
+       #define RG_DSI_V12_SEL                   (7<<5)
+       #define RG_DSI_V10_SEL                   (7<<8)
+       #define RG_DSI_V072_SEL                  (7<<11)
+       #define RG_DSI_V04_SEL                   (7<<14)
+       #define RG_DSI_V032_SEL                  (7<<17)
+       #define RG_DSI_V02_SEL                   (7<<20)
+       #define rsv_23                                   (1<<)
+       #define RG_DSI_BG_R1_TRIM                (0xf<<24)
+       #define RG_DSI_BG_R2_TRIM                (0xf<<28)
+
+#define                MIPITX_DSI_PLL_CON0             0x50
+    #define RG_DSI0_MPPLL_PLL_EN                       (1<<0)
+    #define RG_DSI0_MPPLL_PREDIV                       (3<<1)
+    #define RG_DSI0_MPPLL_TXDIV0                       (3<<3)
+    #define RG_DSI0_MPPLL_TXDIV1                       (3<<5)
+    #define RG_DSI0_MPPLL_POSDIV               (7<<7)
+    #define RG_DSI0_MPPLL_MONVC_EN             (1<<10)
+    #define RG_DSI0_MPPLL_MONREF_EN            (1<<11)
+       #define RG_DSI0_MPPLL_VOD_EN            (1<<12)
+
+#define                MIPITX_DSI_PLL_CON1             0x54
+    #define RG_DSI0_MPPLL_SDM_FRA_EN                   (1)
+    #define RG_DSI0_MPPLL_SDM_SSC_PH_INIT                      (1<<1)
+    #define RG_DSI0_MPPLL_SDM_SSC_EN                   (1<<2)
+    #define RG_DSI0_MPPLL_SDM_SSC_PRD                  (0xffff<<16)
+
+#define                MIPITX_DSI_PLL_CON2     0x58
+
+#define                MIPITX_DSI_PLL_PWR              0x68
+       #define RG_DSI_MPPLL_SDM_PWR_ON                 (1<<0)
+       #define RG_DSI_MPPLL_SDM_ISO_EN                 (1<<1)
+       #define RG_DSI_MPPLL_SDM_PWR_ACK                (1<<8)
+
+#define                MIPITX_DSI_SW_CTRL              0x80
+       #define SW_CTRL_EN              (1<<0)
+
+#define                MIPITX_DSI_SW_CTRL_CON0 0x84
+    #define SW_LNTC_LPTX_PRE_OE                (1<<0)
+    #define SW_LNTC_LPTX_OE                    (1<<1)
+    #define SW_LNTC_LPTX_P                     (1<<2)
+    #define SW_LNTC_LPTX_N                     (1<<3)
+    #define SW_LNTC_HSTX_PRE_OE                (1<<4)
+    #define SW_LNTC_HSTX_OE                    (1<<5)
+    #define SW_LNTC_HSTX_ZEROCLK       (1<<6)
+    #define SW_LNT0_LPTX_PRE_OE                (1<<7)
+    #define SW_LNT0_LPTX_OE                    (1<<8)
+    #define SW_LNT0_LPTX_P                     (1<<9)
+    #define SW_LNT0_LPTX_N                     (1<<10)
+    #define SW_LNT0_HSTX_PRE_OE                (1<<11)
+    #define SW_LNT0_HSTX_OE                    (1<<12)
+    #define SW_LNT0_LPRX_EN                    (1<<13)
+    #define SW_LNT1_LPTX_PRE_OE                (1<<14)
+    #define SW_LNT1_LPTX_OE                    (1<<15)
+    #define SW_LNT1_LPTX_P                     (1<<16)
+    #define SW_LNT1_LPTX_N                     (1<<17)
+    #define SW_LNT1_HSTX_PRE_OE                (1<<18)
+    #define SW_LNT1_HSTX_OE                    (1<<19)
+    #define SW_LNT2_LPTX_PRE_OE                (1<<20)
+    #define SW_LNT2_LPTX_OE                    (1<<21)
+    #define SW_LNT2_LPTX_P                     (1<<22)
+    #define SW_LNT2_LPTX_N                     (1<<23)
+    #define SW_LNT2_HSTX_PRE_OE                (1<<24)
+    #define SW_LNT2_HSTX_OE                    (1<<25)
+
+#define NS_TO_CYCLE(n, c)    ((n) / c + (((n) % c) ? 1 : 0))
+
+
+static inline unsigned long mtk_dsi_readl(struct mtk_dsi *dsi,
+       unsigned long reg)
+{
+       return readl(dsi->dsi_reg_base + (reg << 2));
+}
+
+static inline void mtk_dsi_writel(struct mtk_dsi *dsi, unsigned long value,
+                                   unsigned long reg)
+{
+       writel(value, dsi->dsi_reg_base + (reg << 2));
+}
+
+static int mtk_dsi_of_read_u32(const struct device_node *np,
+                                 const char *propname, u32 *out_value)
+{
+       int ret = of_property_read_u32(np, propname, out_value);
+
+       if (ret < 0)
+               DRM_ERROR("%s: failed to get '%s' property\n", np->full_name,
+                      propname);
+
+       return ret;
+}
+
+static void dsi_phy_clk_switch_off(struct mtk_dsi *dsi)
+{
+       u32 tmp_reg;
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_SW_CTRL_CON0);
+
+       tmp_reg = tmp_reg  | (SW_LNTC_LPTX_PRE_OE | SW_LNTC_LPTX_OE |
+               SW_LNTC_HSTX_PRE_OE | SW_LNTC_HSTX_OE |
+               SW_LNT0_LPTX_PRE_OE | SW_LNT0_LPTX_OE |
+               SW_LNT0_HSTX_PRE_OE | SW_LNT0_HSTX_OE |
+               SW_LNT1_LPTX_PRE_OE | SW_LNT1_LPTX_OE |
+               SW_LNT1_HSTX_PRE_OE | SW_LNT1_HSTX_OE |
+               SW_LNT2_LPTX_PRE_OE | SW_LNT2_LPTX_OE |
+               SW_LNT2_HSTX_PRE_OE | SW_LNT2_HSTX_OE);
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_SW_CTRL_CON0);
+
+
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_SW_CTRL);
+       tmp_reg = (tmp_reg | SW_CTRL_EN);
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_SW_CTRL);
+
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+       tmp_reg = (tmp_reg & (~RG_DSI0_MPPLL_PLL_EN));
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+
+       udelay(100);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+       tmp_reg = (tmp_reg & (~(RG_DSI_LNT_HS_BIAS_EN |
+               RG_DSI_LNT_IMP_CAL_EN |
+               RG_DSI_LNT_TESTMODE_EN)));
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_CLOCK_LANE);
+       tmp_reg = tmp_reg & (~RG_DSI0_LNTC_LDOOUT_EN);
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_CLOCK_LANE);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE0);
+       tmp_reg = tmp_reg & (~RG_DSI0_LNT0_LDOOUT_EN);
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE0);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE1);
+       tmp_reg = tmp_reg & (~RG_DSI0_LNT1_LDOOUT_EN);
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE1);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE2);
+       tmp_reg = tmp_reg & (~RG_DSI0_LNT2_LDOOUT_EN);
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE2);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE3);
+       tmp_reg = tmp_reg & (~RG_DSI0_LNT3_LDOOUT_EN);
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE3);
+
+
+       udelay(100);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_CON);
+       tmp_reg = tmp_reg & (~(RG_DSI0_CKG_LDOOUT_EN |
+               RG_DSI0_LDOCORE_EN));
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_CON);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_BG_CON);
+       tmp_reg = tmp_reg & (~(RG_DSI_BG_CKEN | RG_DSI_BG_CORE_EN));
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_BG_CON);
+
+
+       udelay(100);
+
+       tmp_reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+       tmp_reg = (tmp_reg & (~RG_DSI0_MPPLL_PLL_EN));
+       writel(tmp_reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+}
+
+static void dsi_phy_clk_setting(struct mtk_dsi *dsi)
+{
+       unsigned int data_Rate = dsi->pll_clk_rate * 2;
+       unsigned int txdiv = 0;
+       unsigned int txdiv0 = 0;
+       unsigned int txdiv1 = 0;
+       unsigned int pcw = 0;
+       u32 reg;
+       u32 temp;
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_BG_CON);
+       reg = (reg & (~RG_DSI_V032_SEL)) | (4<<17);
+       reg = (reg & (~RG_DSI_V04_SEL)) | (4<<14);
+       reg = (reg & (~RG_DSI_V072_SEL)) | (4<<11);
+       reg = (reg & (~RG_DSI_V10_SEL)) | (4<<8);
+       reg = (reg & (~RG_DSI_V12_SEL)) | (4<<5);
+       reg = (reg & (~RG_DSI_BG_CKEN)) | (1<<1);
+       reg = (reg & (~RG_DSI_BG_CORE_EN)) | (1);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_BG_CON);
+
+       udelay(1000);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+       reg = (reg & (~RG_DSI_LNT_IMP_CAL_CODE)) | (8<<4);
+       reg = (reg & (~RG_DSI_LNT_HS_BIAS_EN)) | (1<<1);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_CON);
+       reg = (reg & (~RG_DSI0_CKG_LDOOUT_EN)) | (1<<1);
+       reg = (reg & (~RG_DSI0_LDOCORE_EN)) | (1);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_CON);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_PWR);
+       reg = (reg & (~RG_DSI_MPPLL_SDM_PWR_ON)) | (1<<0);
+       reg = (reg & (~RG_DSI_MPPLL_SDM_ISO_EN));
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_PWR);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+       reg = (reg & (~RG_DSI0_MPPLL_PLL_EN));
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+       udelay(1000);
+
+       if (data_Rate > 1250) {
+               txdiv = 1;
+               txdiv0 = 0;
+               txdiv1 = 0;
+       } else if (data_Rate >= 500) {
+               txdiv = 1;
+               txdiv0 = 0;
+               txdiv1 = 0;
+       } else if (data_Rate >= 250) {
+               txdiv = 2;
+               txdiv0 = 1;
+               txdiv1 = 0;
+       } else if (data_Rate >= 125) {
+               txdiv = 4;
+               txdiv0 = 2;
+               txdiv1 = 0;
+       } else if (data_Rate > 62) {
+               txdiv = 8;
+               txdiv0 = 2;
+               txdiv1 = 1;
+       } else if (data_Rate >= 50) {
+               txdiv = 16;
+               txdiv0 = 2;
+               txdiv1 = 2;
+       } else {
+       }
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+       switch (txdiv) {
+       case 1:
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (0<<3);
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (0<<5);
+
+               break;
+       case 2:
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (1<<3);
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (0<<5);
+               break;
+       case 4:
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (2<<3);
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (0<<5);
+               break;
+       case 8:
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (2<<3);
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (1<<5);
+               break;
+       case 16:
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV0)) | (2<<3);
+               reg = (reg & (~RG_DSI0_MPPLL_TXDIV1)) | (2<<5);
+               break;
+
+       default:
+               break;
+       }
+       reg = (reg & (~RG_DSI0_MPPLL_PREDIV));
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+       pcw = data_Rate * txdiv / 13;
+       temp = data_Rate * txdiv % 13;
+       reg = ((pcw & 0x7f)<<24) + (((256 * temp / 13) & 0xff)<<16)
+               + (((256 * (256 * temp % 13)/13) & 0xff)<<8)
+               + ((256 * (256 * (256 * temp % 13) % 13) / 13) & 0xff);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON2);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON1);
+       reg = (reg & (~RG_DSI0_MPPLL_SDM_FRA_EN)) | (1<<0);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON1);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_CLOCK_LANE);
+       reg = (reg & (~RG_DSI0_LNTC_LDOOUT_EN)) | (1<<0);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_CLOCK_LANE);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE0);
+       reg = (reg & (~RG_DSI0_LNT0_LDOOUT_EN)) | (1<<0);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE0);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE1);
+       reg = (reg & (~RG_DSI0_LNT1_LDOOUT_EN)) | (1<<0);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE1);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE2);
+       reg = (reg & (~RG_DSI0_LNT2_LDOOUT_EN)) | (1<<0);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE2);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE3);
+       reg = (reg & (~RG_DSI0_LNT3_LDOOUT_EN)) | (1<<0);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI0_DATA_LANE3);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+       reg = (reg & (~RG_DSI0_MPPLL_PLL_EN)) | (1<<0);
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON0);
+
+       udelay(1000);
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON1);
+       reg = (reg & (~RG_DSI0_MPPLL_SDM_SSC_EN));
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_PLL_CON1);
+
+       reg = readl(dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+       reg = (reg & (~RG_DSI_PAD_TIE_LOW_EN));
+       writel(reg, dsi->dsi_tx_reg_base + MIPITX_DSI_TOP_CON);
+}
+
+static void dsi_phy_timconfig(struct mtk_dsi *dsi)
+{
+       u32 timcon0 = 0;
+       u32 timcon1 = 0;
+       u32 timcon2 = 0;
+       u32 timcon3 = 0;
+       unsigned int lane_no = dsi->lanes;
+       unsigned int cycle_time;
+       unsigned int ui;
+       unsigned int hs_trail_m, hs_trail_n;
+
+       ui = 1000/(250 * 2) + 0x01;
+       cycle_time = 8000/(250 * 2) + 0x01;
+
+       hs_trail_m = lane_no;
+       hs_trail_n =  NS_TO_CYCLE(((lane_no * 4 * ui) + 60), cycle_time);
+
+       timcon0 = (timcon0 & (~HS_TRAIL)) | (8<<24);
+       timcon0 = (timcon0 & (~HS_PRPR)) | 0x6<<8;
+
+       if ((timcon0 & HS_PRPR) == 0)
+               timcon0 = (timcon0 & (~HS_PRPR)) | 1<<8;
+
+       timcon0 =  (timcon0 & (~HS_ZERO)) | 0xA<<16;
+       timcon0 =  (timcon0 & (~LPX)) | 5;
+
+       if ((timcon0 & LPX) == 0)
+               timcon0 =  (timcon0 & (~LPX)) | 1;
+
+       timcon1 = (timcon1 & (~TA_GET)) | (5 * (timcon0 & LPX)<<16);
+       timcon1 = (timcon1 & (~TA_SURE)) | ((3 * (timcon0 & LPX) / 2) << 8);
+       timcon1 =  (timcon1 & (~TA_GO)) | (4 * (timcon0 & LPX));
+       timcon1 = (timcon1 & (~DA_HS_EXIT)) | (7<<24);
+       timcon2 = (timcon2 & (~CLK_TRAIL)) | ((NS_TO_CYCLE(0x64, cycle_time) +
+               0x0a)<<24);
+
+       if (((timcon2 & CLK_TRAIL)>>24) < 2)
+               timcon2 = (timcon2 & (~CLK_TRAIL)) | (2<<24);
+
+       timcon2 = (timcon2 & (~CONT_DET));
+       timcon3 =  (timcon3 & (~CLK_HS_PRPR)) | NS_TO_CYCLE(0x40, cycle_time);
+       if ((timcon3 & CLK_HS_PRPR) == 0)
+               timcon3 = (timcon3 & (~CLK_HS_PRPR)) | 1;
+
+       timcon2 = (timcon2 & (~CLK_ZERO)) |
+               (NS_TO_CYCLE(0x190 - (timcon3 & CLK_HS_PRPR) * cycle_time,
+               cycle_time)<<16);
+
+       timcon3 =  (timcon3 & (~CLK_HS_EXIT)) | ((2 * (timcon0 & LPX))<<16);
+       timcon3 =  (timcon3 & (~CLK_HS_POST)) | (NS_TO_CYCLE((80 + 52 * ui),
+               cycle_time)<<8);
+
+       writel(timcon0, dsi->dsi_reg_base + DSI_PHY_TIMECON0);
+       writel(timcon1, dsi->dsi_reg_base + DSI_PHY_TIMECON1);
+       writel(timcon2, dsi->dsi_reg_base + DSI_PHY_TIMECON2);
+       writel(timcon3, dsi->dsi_reg_base + DSI_PHY_TIMECON3);
+}
+
+static void mtk_dsi_reset(struct mtk_dsi *dsi)
+{
+       writel(3, dsi->dsi_reg_base + DSI_CON_CTRL);
+       writel(2, dsi->dsi_reg_base + DSI_CON_CTRL);
+}
+
+static int mtk_dsi_poweron(struct mtk_dsi *dsi)
+{
+       int ret;
+       struct drm_device *dev = dsi->drm_dev;
+
+       dsi_phy_clk_setting(dsi);
+
+       ret = clk_prepare_enable(dsi->dsi0_engine_clk_cg);
+       if (ret < 0) {
+               dev_err(dev->dev, "can't enable dsi0_engine_clk_cg %d\n", ret);
+               goto err_dsi0_engine_clk_cg;
+       }
+
+       ret = clk_prepare_enable(dsi->dsi0_digital_clk_cg);
+       if (ret < 0) {
+               dev_err(dev->dev, "can't enable dsi0_digital_clk_cg %d\n", ret);
+               goto err_dsi0_digital_clk_cg;
+       }
+
+       mtk_dsi_reset((dsi));
+       dsi_phy_timconfig(dsi);
+
+       return 0;
+
+err_dsi0_digital_clk_cg:
+       clk_disable_unprepare(dsi->dsi0_engine_clk_cg);
+
+err_dsi0_engine_clk_cg:
+
+       return ret;
+}
+
+static void dsi_clk_ulp_mode_enter(struct mtk_dsi *dsi)
+{
+       u32 tmp_reg1;
+
+       tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LCCON);
+       tmp_reg1 = tmp_reg1 & (~LC_HS_TX_EN);
+       writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+       udelay(100);
+       tmp_reg1 = tmp_reg1 & (~LC_ULPM_EN);
+       writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+       udelay(100);
+}
+
+static void dsi_clk_ulp_mode_leave(struct mtk_dsi *dsi)
+{
+       u32 tmp_reg1;
+
+       tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LCCON);
+       tmp_reg1 = tmp_reg1 & (~LC_ULPM_EN);
+       writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+       udelay(100);
+       tmp_reg1 = tmp_reg1 | LC_WAKEUP_EN;
+       writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+       udelay(100);
+       tmp_reg1 = tmp_reg1 & (~LC_WAKEUP_EN);
+       writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+       udelay(100);
+}
+
+static void dsi_lane0_ulp_mode(struct mtk_dsi *dsi, bool enter)
+{
+       u32 tmp_reg1;
+
+       tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LD0CON);
+
+       if (enter) {
+               tmp_reg1 = tmp_reg1 & (~LD0_HS_TX_EN);
+               writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+               udelay(100);
+               tmp_reg1 = tmp_reg1 & (~LD0_ULPM_EN);
+               writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+               udelay(100);
+       } else {
+               tmp_reg1 = tmp_reg1 & (~LD0_ULPM_EN);
+               writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+               udelay(100);
+               tmp_reg1 = tmp_reg1 | LD0_WAKEUP_EN;
+               writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+               udelay(100);
+               tmp_reg1 = tmp_reg1 & (~LD0_WAKEUP_EN);
+               writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LD0CON);
+               udelay(100);
+       }
+}
+
+static bool dsi_clk_hs_state(struct mtk_dsi *dsi)
+{
+       u32 tmp_reg1;
+
+       tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LCCON);
+
+       return ((tmp_reg1 & LC_HS_TX_EN) == 1) ? true : false;
+}
+
+static void dsi_clk_hs_mode(struct mtk_dsi *dsi, bool enter)
+{
+       u32 tmp_reg1;
+
+       tmp_reg1 = readl(dsi->dsi_reg_base + DSI_PHY_LCCON);
+
+       if (enter && !dsi_clk_hs_state(dsi)) {
+               tmp_reg1 = tmp_reg1 | LC_HS_TX_EN;
+               writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+       } else if (!enter && dsi_clk_hs_state(dsi)) {
+               tmp_reg1 = tmp_reg1 & (~LC_HS_TX_EN);
+               writel(tmp_reg1, dsi->dsi_reg_base + DSI_PHY_LCCON);
+       }
+}
+
+static void  dsi_set_mode(struct mtk_dsi *dsi)
+{
+       u32 tmp_reg1;
+
+       tmp_reg1 = 0;
+
+       if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+               tmp_reg1 = SYNC_PULSE_MODE;
+
+               if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+                       tmp_reg1 = BURST_MODE;
+
+               if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+                       tmp_reg1 = SYNC_PULSE_MODE;
+       }
+
+       writel(tmp_reg1, dsi->dsi_reg_base + DSI_MODE_CTRL);
+}
+
+static void dsi_ps_control_vact(struct mtk_dsi *dsi)
+{
+       struct videomode *vm = &dsi->vm;
+       u32 dsiTmpBufBpp, ps_wc;
+       u32 tmp_reg;
+       u32 tmp_hstx_cklp_wc;
+
+       tmp_reg = 0;
+
+       if (dsi->format == MIPI_DSI_FMT_RGB565)
+               dsiTmpBufBpp = 2;
+       else
+               dsiTmpBufBpp = 3;
+
+       ps_wc = vm->vactive * dsiTmpBufBpp;
+
+       tmp_reg = ps_wc;
+
+       switch (dsi->format) {
+       case MIPI_DSI_FMT_RGB888:
+               tmp_reg |= PACKED_PS_24BIT_RGB888;
+               break;
+       case MIPI_DSI_FMT_RGB666:
+               tmp_reg |= PACKED_PS_18BIT_RGB666;
+               break;
+       case MIPI_DSI_FMT_RGB666_PACKED:
+               tmp_reg |= LOOSELY_PS_18BIT_RGB666;
+               break;
+       case MIPI_DSI_FMT_RGB565:
+               tmp_reg |= PACKED_PS_16BIT_RGB565;
+               break;
+       }
+
+       tmp_hstx_cklp_wc = ps_wc;
+
+       writel(vm->vactive, dsi->dsi_reg_base + DSI_VACT_NL);
+       writel(tmp_reg, dsi->dsi_reg_base + DSI_PSCTRL);
+       writel(tmp_hstx_cklp_wc, dsi->dsi_reg_base + DSI_HSTX_CKL_WC);
+}
+
+static void dsi_rxtx_control(struct mtk_dsi *dsi)
+{
+       u32 tmp_reg = 0;
+
+       switch (dsi->lanes) {
+       case 1:
+               tmp_reg = 1<<2;
+               break;
+       case 2:
+               tmp_reg = 3<<2;
+               break;
+       case 3:
+               tmp_reg = 7<<2;
+               break;
+       case 4:
+               tmp_reg = 0xF<<2;
+               break;
+       default:
+               tmp_reg = 0xF<<2;
+               break;
+       }
+
+       writel(tmp_reg, dsi->dsi_reg_base + DSI_TXRX_CTRL);
+}
+
+void dsi_ps_control(struct mtk_dsi *dsi)
+{
+       unsigned int dsi_tmp_buf_bpp;
+       u32 tmp_reg1 = 0;
+
+       switch (dsi->format) {
+       case MIPI_DSI_FMT_RGB888:
+               tmp_reg1 = PACKED_PS_24BIT_RGB888;
+               dsi_tmp_buf_bpp = 3;
+               break;
+       case MIPI_DSI_FMT_RGB666:
+               tmp_reg1 = LOOSELY_PS_18BIT_RGB666;
+               dsi_tmp_buf_bpp = 3;
+               break;
+       case MIPI_DSI_FMT_RGB666_PACKED:
+               tmp_reg1 = PACKED_PS_18BIT_RGB666;
+               dsi_tmp_buf_bpp = 3;
+               break;
+       case MIPI_DSI_FMT_RGB565:
+               tmp_reg1 = PACKED_PS_16BIT_RGB565;
+               dsi_tmp_buf_bpp = 2;
+               break;
+       default:
+               tmp_reg1 = PACKED_PS_24BIT_RGB888;
+               dsi_tmp_buf_bpp = 3;
+               break;
+       }
+
+       tmp_reg1 = tmp_reg1 + ((dsi->vm.hactive * dsi_tmp_buf_bpp) & DSI_PS_WC);
+
+       writel(tmp_reg1, dsi->dsi_reg_base + DSI_PSCTRL);
+}
+
+static void dsi_config_vdo_timing(struct mtk_dsi *dsi)
+{
+       unsigned int horizontal_sync_active_byte;
+       unsigned int horizontal_backporch_byte;
+       unsigned int horizontal_frontporch_byte;
+       unsigned int dsi_tmp_buf_bpp;
+
+       struct videomode *vm = &dsi->vm;
+
+       if (dsi->format == MIPI_DSI_FMT_RGB565)
+               dsi_tmp_buf_bpp = 2;
+       else
+               dsi_tmp_buf_bpp = 3;
+
+       writel(vm->vsync_len, dsi->dsi_reg_base + DSI_VSA_NL);
+       writel(vm->vback_porch, dsi->dsi_reg_base + DSI_VBP_NL);
+       writel(vm->vfront_porch, dsi->dsi_reg_base + DSI_VFP_NL);
+       writel(vm->vactive, dsi->dsi_reg_base + DSI_VACT_NL);
+
+       horizontal_sync_active_byte = (vm->hsync_len * dsi_tmp_buf_bpp - 10);
+
+       if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+               horizontal_backporch_byte =
+                       (vm->hback_porch * dsi_tmp_buf_bpp - 10);
+       else
+               horizontal_backporch_byte = ((vm->hback_porch + vm->hsync_len) *
+                       dsi_tmp_buf_bpp - 10);
+
+       horizontal_frontporch_byte = (vm->vfront_porch * dsi_tmp_buf_bpp - 12);
+
+       writel(vm->hsync_len, dsi->dsi_reg_base + DSI_HSA_WC);
+       writel(vm->hback_porch, dsi->dsi_reg_base + DSI_HBP_WC);
+       writel(vm->hfront_porch, dsi->dsi_reg_base + DSI_HFP_WC);
+
+       dsi_ps_control(dsi);
+}
+
+static void mtk_dsi_start(struct mtk_dsi *dsi)
+{
+       writel(0, dsi->dsi_reg_base + DSI_START);
+       writel(1, dsi->dsi_reg_base + DSI_START);
+}
+
+static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
+{
+       clk_disable_unprepare(dsi->dsi0_engine_clk_cg);
+       clk_disable_unprepare(dsi->dsi0_digital_clk_cg);
+
+       usleep_range(10000, 20000);
+
+       dsi_phy_clk_switch_off(dsi);
+}
+
+static int mtk_output_dsi_enable(struct mtk_dsi *dsi)
+{
+       int ret;
+
+       if (dsi->enabled == true)
+               return 0;
+
+       ret = mtk_dsi_poweron(dsi);
+       if (ret < 0)
+               return ret;
+
+       dsi_rxtx_control(dsi);
+
+       dsi_clk_ulp_mode_leave(dsi);
+       dsi_lane0_ulp_mode(dsi, 0);
+       dsi_clk_hs_mode(dsi, 0);
+       dsi_set_mode(dsi);
+
+       dsi_ps_control_vact(dsi);
+       dsi_config_vdo_timing(dsi);
+
+       dsi_set_mode(dsi);
+       dsi_clk_hs_mode(dsi, 1);
+
+       mtk_dsi_start(dsi);
+
+       dsi->enabled = true;
+
+       return 0;
+}
+
+static int mtk_output_dsi_disable(struct mtk_dsi *dsi)
+{
+       if (dsi->enabled == false)
+               return 0;
+
+       dsi_lane0_ulp_mode(dsi, 1);
+       dsi_clk_ulp_mode_enter(dsi);
+       mtk_dsi_poweroff(dsi);
+       dsi_phy_clk_switch_off(dsi);
+
+       dsi->enabled = false;
+
+       return 0;
+}
+
+static void mtk_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs mtk_dsi_encoder_funcs = {
+       .destroy        = mtk_dsi_encoder_destroy,
+};
+
+static void mtk_dsi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct mtk_dsi *dsi = encoder_to_dsi(encoder);
+       struct drm_panel *panel = dsi->panel;
+
+       mtk_dsi_info("%s dpms mode = %d !\n", __func__, mode);
+
+       if (mode != DRM_MODE_DPMS_ON) {
+               drm_panel_disable(panel);
+               mtk_output_dsi_disable(dsi);
+       } else {
+               mtk_output_dsi_enable(dsi);
+               drm_panel_enable(panel);
+       }
+}
+
+static bool mtk_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
+                              const struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void mtk_dsi_encoder_prepare(struct drm_encoder *encoder)
+{
+       /* drm framework doesn't check NULL. */
+}
+
+static void mtk_dsi_encoder_mode_set(struct drm_encoder *encoder,
+       struct drm_display_mode *mode, struct drm_display_mode *adjusted)
+{
+}
+
+static void mtk_dsi_encoder_commit(struct drm_encoder *encoder)
+{
+       /* DRM_MODE_DPMS_ON? */
+}
+
+static enum drm_connector_status mtk_dsi_connector_detect(
+       struct drm_connector *connector, bool force)
+{
+       enum drm_connector_status status = connector_status_unknown;
+
+       status = connector_status_connected; /* FIXME? */
+
+       return status;
+}
+
+static void mtk_dsi_connector_destroy(struct drm_connector *connector)
+{
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+}
+
+static const struct drm_display_mode default_modes[] = {
+       /* 1368x768@60Hz */
+       { DRM_MODE("1368x768", DRM_MODE_TYPE_DRIVER, 72070,
+       1368, 1368 + 58, 1368 + 58 + 58, 1368 + 58 + 58 + 58, 0,
+       768, 768 + 4, 768 + 4 + 4, 768 + 4 + 4 + 4, 0, 0) },
+};
+
+static int mtk_dsi_connector_get_modes(struct drm_connector *connector)
+{
+       const struct drm_display_mode *ptr = &default_modes[0];
+       struct drm_display_mode *mode;
+       int count = 0;
+
+       mode = drm_mode_duplicate(connector->dev, ptr);
+       if (mode) {
+               drm_mode_probed_add(connector, mode);
+               count++;
+       }
+
+       connector->display_info.width_mm = mode->hdisplay;
+       connector->display_info.height_mm = mode->vdisplay;
+
+       return 1;
+}
+
+static struct drm_encoder *
+mtk_dsi_connector_best_encoder(struct drm_connector *connector)
+{
+       struct mtk_dsi *dsi = connector_to_dsi(connector);
+
+       return &dsi->encoder;
+}
+
+static const struct drm_encoder_helper_funcs mtk_dsi_encoder_helper_funcs = {
+       .dpms = mtk_dsi_encoder_dpms,
+       .mode_fixup = mtk_dsi_encoder_mode_fixup,
+       .prepare = mtk_dsi_encoder_prepare,
+       .mode_set = mtk_dsi_encoder_mode_set,
+       .commit = mtk_dsi_encoder_commit,
+};
+
+static const struct drm_connector_funcs mtk_dsi_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = mtk_dsi_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = mtk_dsi_connector_destroy,
+};
+
+static const struct drm_connector_helper_funcs
+       mtk_dsi_connector_helper_funcs = {
+       .get_modes = mtk_dsi_connector_get_modes,
+       .best_encoder = mtk_dsi_connector_best_encoder,
+};
+
+struct bridge_init {
+       struct i2c_client *mipirx_client;
+       struct i2c_client *dptx_client;
+       struct device_node *node_mipirx;
+       struct device_node *node_dptx;
+};
+
+static int mtk_drm_attach_lcm_bridge(struct drm_bridge *bridge,
+       struct drm_encoder *encoder)
+{
+       int ret;
+
+       encoder->bridge = bridge;
+       bridge->encoder = encoder;
+       ret = drm_bridge_attach(encoder->dev, bridge);
+       if (ret) {
+               DRM_ERROR("Failed to attach bridge to drm\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int mtk_dsi_create_conn_enc(struct mtk_dsi *dsi)
+{
+       int ret;
+
+       ret = drm_encoder_init(dsi->drm_dev, &dsi->encoder,
+                       &mtk_dsi_encoder_funcs, DRM_MODE_ENCODER_DSI);
+
+       if (ret)
+               goto errcode;
+
+       drm_encoder_helper_add(&dsi->encoder, &mtk_dsi_encoder_helper_funcs);
+
+       dsi->encoder.possible_crtcs = 1;
+
+       /* Pre-empt DP connector creation if there's a bridge */
+       ret = mtk_drm_attach_lcm_bridge(dsi->bridge, &dsi->encoder);
+       if (!ret)
+               return 0;
+
+       ret = drm_connector_init(dsi->drm_dev, &dsi->conn,
+               &mtk_dsi_connector_funcs, DRM_MODE_CONNECTOR_DSI);
+       if (ret)
+               goto errcode;
+
+       drm_connector_helper_add(&dsi->conn, &mtk_dsi_connector_helper_funcs);
+
+       ret = drm_connector_register(&dsi->conn);
+       if (ret)
+               goto errcode;
+
+       dsi->conn.dpms = DRM_MODE_DPMS_OFF;
+       dsi->conn.encoder = &dsi->encoder;
+
+       drm_mode_connector_attach_encoder(&dsi->conn, &dsi->encoder);
+
+       if (dsi->panel)
+               ret = drm_panel_attach(dsi->panel, &dsi->conn);
+
+       return 0;
+
+errcode:
+       drm_encoder_cleanup(&dsi->encoder);
+       drm_connector_unregister(&dsi->conn);
+       drm_connector_cleanup(&dsi->conn);
+
+       return ret;
+}
+
+static void mtk_dsi_destroy_conn_enc(struct mtk_dsi *dsi)
+{
+       drm_encoder_cleanup(&dsi->encoder);
+       drm_connector_unregister(&dsi->conn);
+       drm_connector_cleanup(&dsi->conn);
+}
+
+static int mtk_dsi_bind(struct device *dev, struct device *master,
+       void *data)
+{
+       int ret;
+       struct mtk_dsi *dsi = NULL;
+
+       dsi = platform_get_drvdata(to_platform_device(dev));
+       if (!dsi) {
+               ret = -EFAULT;
+               goto errcode;
+       }
+
+       dsi->drm_dev = data;
+
+       ret = mtk_dsi_create_conn_enc(dsi);
+       if (ret) {
+               DRM_ERROR("Encoder create  failed with %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+
+errcode:
+       return ret;
+
+}
+
+static void mtk_dsi_unbind(struct device *dev, struct device *master,
+       void *data)
+{
+       struct mtk_dsi *dsi = NULL;
+
+       dsi = platform_get_drvdata(to_platform_device(dev));
+       mtk_dsi_destroy_conn_enc(dsi);
+
+       dsi->drm_dev = NULL;
+}
+
+static const struct component_ops mtk_dsi_component_ops = {
+       .bind   = mtk_dsi_bind,
+       .unbind = mtk_dsi_unbind,
+};
+
+static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
+       struct mipi_dsi_device *device)
+{
+       struct mtk_dsi *dsi = host_to_mtk(host);
+
+       dsi->mode_flags = device->mode_flags;
+       dsi->format = device->format;
+       dsi->lanes = device->lanes;
+
+       dsi->panel = of_drm_find_panel(device->dev.of_node);
+       if (dsi->panel) {
+               if (dsi->conn.dev)
+                       drm_helper_hpd_irq_event(dsi->conn.dev);
+       }
+
+       return 0;
+}
+
+static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
+       struct mipi_dsi_device *device)
+{
+       struct mtk_dsi *dsi = host_to_mtk(host);
+
+       if (dsi->panel && &device->dev == dsi->panel->dev) {
+               if (dsi->conn.dev)
+                       drm_helper_hpd_irq_event(dsi->conn.dev);
+
+               dsi->panel = NULL;
+       }
+
+       return 0;
+}
+
+static const struct mipi_dsi_host_ops mtk_dsi_host_ops = {
+       .attach = mtk_dsi_host_attach,
+       .detach = mtk_dsi_host_detach,
+};
+
+static int mtk_dsi_probe(struct platform_device *pdev)
+{
+       struct mtk_dsi *dsi = NULL;
+       struct device *dev = &pdev->dev;
+       struct device_node *panel_node, *bridge_node, *endpoint;
+       struct resource *regs;
+       int err;
+       int ret;
+
+       dsi = kzalloc(sizeof(struct mtk_dsi), GFP_KERNEL);
+
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->lanes = 4;
+
+       dsi->vm.pixelclock = 76000;
+       dsi->vm.hactive  = 1368;
+       dsi->vm.hback_porch = 100;
+       dsi->vm.hfront_porch = 106;
+       dsi->vm.hsync_len = 26;
+       dsi->vm.vactive   = 768;
+       dsi->vm.vback_porch = 10;
+       dsi->vm.vfront_porch = 10;
+       dsi->vm.vsync_len = 12;
+
+       err = mtk_dsi_of_read_u32(dev->of_node, "mediatek,width",
+                                    &dsi->vm.hactive);
+       if (err < 0)
+               return err;
+
+       err = mtk_dsi_of_read_u32(dev->of_node, "mediatek,height",
+                                    &dsi->vm.vactive);
+       if (err < 0)
+               return err;
+
+       err = mtk_dsi_of_read_u32(dev->of_node, "mediatek,mipi-tx-burst-freq",
+                                    &dsi->pll_clk_rate);
+
+       if (err < 0)
+               return err;
+
+       endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+       if (endpoint) {
+               bridge_node = of_graph_get_remote_port_parent(endpoint);
+               if (!bridge_node)
+                       return -EPROBE_DEFER;
+
+               dsi->bridge = of_drm_find_bridge(bridge_node);
+               of_node_put(bridge_node);
+               if (!dsi->bridge)
+                       return -EPROBE_DEFER;
+       }
+
+       dsi->dsi0_engine_clk_cg = devm_clk_get(dev, "dsi0_engine_disp_ck");
+       if (IS_ERR(dsi->dsi0_engine_clk_cg)) {
+               dev_err(dev, "cannot get dsi0_engine_clk_cg\n");
+               return PTR_ERR(dsi->dsi0_engine_clk_cg);
+       }
+
+       dsi->dsi0_digital_clk_cg = devm_clk_get(dev, "dsi0_digital_disp_ck");
+       if (IS_ERR(dsi->dsi0_digital_clk_cg)) {
+               dev_err(dev, "cannot get dsi0_digital_disp_ck\n");
+               return PTR_ERR(dsi->dsi0_digital_clk_cg);
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dsi->dsi_reg_base = devm_ioremap_resource(dev, regs);
+
+       if (IS_ERR(dsi->dsi_reg_base)) {
+               dev_err(dev, "cannot get dsi->dsi_reg_base\n");
+               return PTR_ERR(dsi->dsi_reg_base);
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       dsi->dsi_tx_reg_base = devm_ioremap_resource(dev, regs);
+       if (IS_ERR(dsi->dsi_tx_reg_base)) {
+               dev_err(dev, "cannot get dsi->dsi_tx_reg_base\n");
+               return PTR_ERR(dsi->dsi_tx_reg_base);
+       }
+
+       dsi->disp_supplies = devm_regulator_get(&pdev->dev, "disp-bdg");
+       if (IS_ERR(dsi->disp_supplies)) {
+               dev_err(dev, "cannot get dsi->disp_supplies\n");
+               return PTR_ERR(dsi->disp_supplies);
+       }
+
+       ret = regulator_set_voltage(dsi->disp_supplies, 1800000, 1800000);
+       if (ret != 0)   {
+               dev_err(dev, "lcm failed to set lcm_vgp voltage:  %d\n", ret);
+               return PTR_ERR(dsi->disp_supplies);
+       }
+
+       ret = regulator_enable(dsi->disp_supplies);
+       if (ret != 0) {
+               dev_err(dev, "Failed to enable lcm_vgp: %d\n", ret);
+               return PTR_ERR(dsi->disp_supplies);
+       }
+
+       panel_node = of_parse_phandle(dev->of_node, "mediatek,panel", 0);
+       if (panel_node) {
+               dsi->panel = of_drm_find_panel(panel_node);
+               of_node_put(panel_node);
+               if (!dsi->panel)
+                       return -EPROBE_DEFER;
+       } else
+               return -EPROBE_DEFER;
+
+       platform_set_drvdata(pdev, dsi);
+
+       ret = component_add(&pdev->dev, &mtk_dsi_component_ops);
+       if (ret)
+               goto err_del_component;
+
+       return 0;
+
+err_del_component:
+       component_del(&pdev->dev, &mtk_dsi_component_ops);
+       return -EPROBE_DEFER;
+
+}
+
+static int mtk_dsi_remove(struct platform_device *pdev)
+{
+       struct mtk_dsi *dsi = platform_get_drvdata(pdev);
+
+       mtk_output_dsi_disable(dsi);
+       component_del(&pdev->dev, &mtk_dsi_component_ops);
+
+       return 0;
+}
+
+static const struct of_device_id mtk_dsi_of_match[] = {
+       { .compatible = "mediatek,mt8173-dsi" },
+       { },
+};
+
+struct platform_driver mtk_dsi_driver = {
+       .probe = mtk_dsi_probe,
+       .remove = mtk_dsi_remove,
+       .driver = {
+               .name = "mtk-dsi",
+               .of_match_table = mtk_dsi_of_match,
+               .owner  = THIS_MODULE,
+       },
+};
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_dsi.h 
b/drivers/gpu/drm/mediatek/mediatek_drm_dsi.h
new file mode 100644
index 0000000..7b7b93b
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_dsi.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _MEDIATEK_DRM_DSI_H_
+#define _MEDIATEK_DRM_DSI_H_
+
+
+struct mtk_dsi {
+       struct drm_device *drm_dev;
+       struct drm_encoder encoder;
+       struct drm_connector conn;
+       struct drm_panel *panel;
+       struct drm_bridge *bridge;
+       struct mipi_dsi_host host;
+       struct regulator *disp_supplies;
+
+       void __iomem *dsi_reg_base;
+       void __iomem *dsi_tx_reg_base;
+
+       struct clk *dsi_disp_clk_cg;
+       struct clk *dsi_dsi_clk_cg;
+       struct clk *dsi_div2_clk_cg;
+
+       struct clk *dsi0_engine_clk_cg;
+       struct clk *dsi0_digital_clk_cg;
+
+       u32 pll_clk_rate;
+
+       unsigned long mode_flags;
+       enum mipi_dsi_pixel_format format;
+       unsigned int lanes;
+       struct videomode vm;
+       bool enabled;
+};
+
+
+static inline struct mtk_dsi *host_to_mtk(struct mipi_dsi_host *host)
+{
+       return container_of(host, struct mtk_dsi, host);
+}
+
+static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e)
+{
+       return container_of(e, struct mtk_dsi, encoder);
+}
+
+#define connector_to_dsi(c) container_of(c, struct mtk_dsi, conn)
+
+
+#define mtk_dsi_err(fmt, ...) \
+       pr_err("[mediatek drm dsi] ERROR!!! fun:%s, line:%d  " \
+       fmt, __func__, __LINE__,  ##__VA_ARGS__)
+#define mtk_dsi_info(fmt, ...) \
+       pr_info("[mediatek drm dsi] INFO fun:%s, line:%d  " \
+       fmt, __func__, __LINE__,  ##__VA_ARGS__)
+#define mtk_dsi_output(fmt, ...) \
+               pr_info(fmt, ##__VA_ARGS__)
+
+#endif
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_fb.c 
b/drivers/gpu/drm/mediatek/mediatek_drm_fb.c
new file mode 100644
index 0000000..fbaba95
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_fb.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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_gem.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include "mediatek_drm_drv.h"
+#include "mediatek_drm_fb.h"
+#include "mediatek_drm_gem.h"
+
+
+static int mtk_drm_fb_create_handle(struct drm_framebuffer *fb,
+                                       struct drm_file *file_priv,
+                                       unsigned int *handle)
+{
+       struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
+
+       return drm_gem_handle_create(file_priv, mtk_fb->gem_obj[0], handle);
+}
+
+static void mtk_drm_fb_destroy(struct drm_framebuffer *fb)
+{
+       unsigned int i;
+       struct mtk_drm_fb *mtk_fb = to_mtk_fb(fb);
+       struct drm_gem_object *gem;
+       int nr = drm_format_num_planes(fb->pixel_format);
+
+       drm_framebuffer_cleanup(fb);
+
+       for (i = 0; i < nr; i++) {
+               gem = mtk_fb->gem_obj[i];
+               drm_gem_object_unreference_unlocked(gem);
+       }
+}
+
+static struct drm_framebuffer_funcs mediatek_drm_fb_funcs = {
+       .create_handle = mtk_drm_fb_create_handle,
+       .destroy = mtk_drm_fb_destroy,
+};
+
+static struct mtk_drm_fb *mtk_drm_framebuffer_init(struct drm_device *dev,
+                           struct drm_mode_fb_cmd2 *mode,
+                           struct drm_gem_object **obj)
+{
+       struct mtk_drm_fb *mtk_fb;
+       unsigned int i;
+       int ret;
+
+       mtk_fb = devm_kzalloc(dev->dev, sizeof(*mtk_fb), GFP_KERNEL);
+       if (!mtk_fb)
+               return ERR_PTR(-ENOMEM);
+
+       drm_helper_mode_fill_fb_struct(&mtk_fb->base, mode);
+
+       for (i = 0; i < drm_format_num_planes(mode->pixel_format); i++)
+               mtk_fb->gem_obj[i] = obj[i];
+
+       ret = drm_framebuffer_init(dev, &mtk_fb->base, &mediatek_drm_fb_funcs);
+       if (ret) {
+               DRM_ERROR("failed to initialize framebuffer\n");
+               return ERR_PTR(ret);
+       }
+
+       return mtk_fb;
+}
+
+static int mtk_drm_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       struct drm_fb_helper *helper = info->par;
+       struct device *dev = ((struct drm_device *)helper->dev)->dev;
+       struct mtk_drm_fb *mtk_fb = to_mtk_fb(helper->fb);
+       struct mtk_drm_gem_buf *buffer =
+               to_mtk_gem_obj(mtk_fb->gem_obj[0])->buffer;
+       int ret;
+
+       vma->vm_flags |= VM_MIXEDMAP;
+
+       if (dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buffer->dma_attrs)) {
+               ret = dma_mmap_attrs(dev, vma, buffer->pages,
+                       buffer->mva_addr, buffer->size, &buffer->dma_attrs);
+       } else {
+               ret = dma_mmap_attrs(dev, vma, buffer->kvaddr,
+                       buffer->mva_addr, buffer->size, &buffer->dma_attrs);
+       }
+
+       if (ret) {
+               DRM_ERROR("failed to fb_mmap %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct fb_ops mediatek_fb_ops = {
+       .owner = THIS_MODULE,
+       .fb_fillrect = sys_fillrect,
+       .fb_copyarea = sys_copyarea,
+       .fb_imageblit = sys_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,
+       .fb_mmap = mtk_drm_fb_mmap,
+};
+
+static int mtk_fbdev_probe(struct drm_fb_helper *helper,
+                            struct drm_fb_helper_surface_size *sizes)
+{
+       struct drm_device *dev = helper->dev;
+       struct drm_mode_fb_cmd2 mode = { 0 };
+       struct mtk_drm_fb *mtk_fb;
+       struct mtk_drm_gem_buf *buffer;
+       struct mtk_drm_gem_obj *mtk_gem;
+       struct drm_gem_object *gem;
+       struct fb_info *info;
+       struct drm_framebuffer *fb;
+       unsigned long offset;
+       size_t size;
+       int err;
+
+       mode.width = sizes->surface_width;
+       mode.height = sizes->surface_height;
+       mode.pitches[0] = sizes->surface_width * ((sizes->surface_bpp + 7) / 8);
+       mode.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+                                                       sizes->surface_depth);
+
+       mode.height = mode.height;/* << 1; for fb use? */
+       size = mode.pitches[0] * mode.height;
+       dev_info(dev->dev, "mtk_fbdev_probe %dx%d bpp %d pitch %d size %zu\n",
+               mode.width, mode.height, sizes->surface_bpp, mode.pitches[0],
+               size);
+
+       mtk_gem = mtk_drm_gem_create(dev, 3, size);
+       if (IS_ERR(mtk_gem)) {
+               err = PTR_ERR(mtk_gem);
+               goto fini;
+       }
+
+       gem = &mtk_gem->base;
+       buffer = mtk_gem->buffer;
+
+       mtk_fb = mtk_drm_framebuffer_init(dev, &mode, &gem);
+       if (IS_ERR(mtk_fb)) {
+               dev_err(dev->dev, "failed to allocate DRM framebuffer\n");
+               err = PTR_ERR(mtk_fb);
+               goto free;
+       }
+       fb = &mtk_fb->base;
+
+       info = framebuffer_alloc(0, dev->dev);
+       if (!info) {
+               dev_err(dev->dev, "failed to allocate framebuffer info\n");
+               err = PTR_ERR(info);
+               goto release;
+       }
+
+       helper->fb = fb;
+       helper->fbdev = info;
+
+       info->par = helper;
+       info->flags = FBINFO_FLAG_DEFAULT;
+       info->fbops = &mediatek_fb_ops;
+
+       err = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (err < 0) {
+               dev_err(dev->dev, "failed to allocate color map: %d\n", err);
+               goto destroy;
+       }
+
+       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+       drm_fb_helper_fill_var(info, helper, fb->width, fb->height);
+
+       offset = info->var.xoffset * (fb->bits_per_pixel + 7) / 8;
+       offset += info->var.yoffset * fb->pitches[0];
+
+       strcpy(info->fix.id, "mtk");
+       /* dev->mode_config.fb_base = (resource_size_t)bo->paddr; */
+       info->var.yres = info->var.yres_virtual;/* >> 1; for fb use? */
+       info->fix.smem_start = buffer->mva_addr + offset;
+       info->fix.smem_len = size;
+       info->screen_base = buffer->kvaddr + offset;
+       info->screen_size = size;
+
+       return 0;
+
+destroy:
+       drm_framebuffer_unregister_private(fb);
+       mtk_drm_fb_destroy(fb);
+release:
+       framebuffer_release(info);
+free:
+       mtk_drm_gem_free_object(&mtk_gem->base);
+fini:
+       dev_err(dev->dev, "mtk_fbdev_probe fail\n");
+       return err;
+}
+
+static struct drm_fb_helper_funcs mediatek_drm_fb_helper_funcs = {
+       .fb_probe = mtk_fbdev_probe,
+};
+
+int mtk_fbdev_create(struct drm_device *dev)
+{
+       struct mtk_drm_private *priv =
+               (struct mtk_drm_private *)dev->dev_private;
+       struct drm_fb_helper *fbdev;
+       int ret;
+
+       fbdev = devm_kzalloc(dev->dev, sizeof(*fbdev), GFP_KERNEL);
+       if (!fbdev)
+               return -ENOMEM;
+
+       drm_fb_helper_prepare(dev, fbdev, &mediatek_drm_fb_helper_funcs);
+
+       ret = drm_fb_helper_init(dev, fbdev, dev->mode_config.num_crtc,
+                                               dev->mode_config.num_connector);
+       if (ret) {
+               dev_err(dev->dev, "failed to initialize DRM FB helper\n");
+               goto fini;
+       }
+
+       ret = drm_fb_helper_single_add_all_connectors(fbdev);
+       if (ret) {
+               dev_err(dev->dev, "failed to add connectors\n");
+               goto fini;
+       }
+
+       drm_helper_disable_unused_functions(dev);
+
+       ret = drm_fb_helper_initial_config(fbdev, FBDEV_BPP);
+       if (ret) {
+               dev_err(dev->dev, "failed to set initial configuration\n");
+               goto fini;
+       }
+       priv->fb_helper = fbdev;
+
+       return 0;
+
+fini:
+       drm_fb_helper_fini(fbdev);
+
+       return ret;
+}
+
+void mtk_fbdev_destroy(struct drm_device *dev)
+{
+       struct mtk_drm_private *priv =
+               (struct mtk_drm_private *)dev->dev_private;
+       struct drm_fb_helper *fbdev = priv->fb_helper;
+       struct fb_info *info = priv->fb_helper->fbdev;
+
+       if (info) {
+               int err;
+
+               err = unregister_framebuffer(info);
+               if (err < 0)
+                       DRM_DEBUG_KMS("failed to unregister framebuffer\n");
+
+               if (info->cmap.len)
+                       fb_dealloc_cmap(&info->cmap);
+
+               framebuffer_release(info);
+       }
+
+       if (fbdev->fb) {
+               drm_framebuffer_unregister_private(fbdev->fb);
+               mtk_drm_fb_destroy(fbdev->fb);
+       }
+
+       drm_fb_helper_fini(fbdev);
+       kfree(fbdev);
+}
+
+void mtk_drm_mode_output_poll_changed(struct drm_device *dev)
+{
+       struct mtk_drm_private *priv =
+               (struct mtk_drm_private *)dev->dev_private;
+
+       if (priv->fb_helper)
+               drm_fb_helper_hotplug_event(priv->fb_helper);
+}
+
+struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
+                                              struct drm_file *file,
+                                              struct drm_mode_fb_cmd2 *cmd)
+{
+       unsigned int hsub, vsub, i;
+       struct mtk_drm_fb *mtk_fb;
+       struct drm_gem_object *gem[MAX_FB_OBJ];
+       int err;
+
+       hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format);
+       vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format);
+       for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) {
+               unsigned int width = cmd->width / (i ? hsub : 1);
+               unsigned int height = cmd->height / (i ? vsub : 1);
+               unsigned int size, bpp;
+
+               gem[i] = drm_gem_object_lookup(dev, file, cmd->handles[i]);
+               if (!gem[i]) {
+                       err = -ENOENT;
+                       goto unreference;
+               }
+
+               bpp = drm_format_plane_cpp(cmd->pixel_format, i);
+               size = (height - 1) * cmd->pitches[i] + width * bpp;
+               size += cmd->offsets[i];
+
+               if (gem[i]->size < size) {
+                       err = -EINVAL;
+                       goto unreference;
+               }
+       }
+
+       mtk_fb = mtk_drm_framebuffer_init(dev, cmd, gem);
+
+       return &mtk_fb->base;
+
+unreference:
+       while (i--)
+               drm_gem_object_unreference_unlocked(gem[i]);
+
+       return ERR_PTR(err);
+}
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_fb.h 
b/drivers/gpu/drm/mediatek/mediatek_drm_fb.h
new file mode 100644
index 0000000..ee8b6a6
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_fb.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _MEDIATEK_DRM_FB_H_
+#define _MEDIATEK_DRM_FB_H_
+
+#define MAX_FB_OBJ     4
+#define FBDEV_BPP      16
+
+/*
+ * mtk specific framebuffer structure.
+ *
+ * @fb: drm framebuffer object.
+ * @mtk_gem_obj: array of mtk specific gem object containing a gem object.
+ */
+struct mtk_drm_fb {
+       struct drm_framebuffer  base;
+       struct drm_gem_object   *gem_obj[MAX_FB_OBJ]; /* FIXME? mtk_gem_obj? */
+};
+
+#define to_mtk_fb(x) container_of(x, struct mtk_drm_fb, base)
+
+void mtk_drm_mode_output_poll_changed(struct drm_device *dev);
+struct drm_framebuffer *mtk_drm_mode_fb_create(struct drm_device *dev,
+                                              struct drm_file *file,
+                                              struct drm_mode_fb_cmd2 *cmd);
+
+int mtk_fbdev_create(struct drm_device *dev);
+void mtk_fbdev_destroy(struct drm_device *dev);
+
+#endif
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_gem.c 
b/drivers/gpu/drm/mediatek/mediatek_drm_gem.c
new file mode 100644
index 0000000..3df3f4f
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_gem.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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_gem.h>
+
+#include "mediatek_drm_gem.h"
+#include "drm/mediatek_drm.h"
+
+
+struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
+                                                     unsigned long size)
+{
+       struct mtk_drm_gem_obj *mtk_gem_obj;
+       struct drm_gem_object *obj;
+       int ret;
+
+       mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL);
+       if (!mtk_gem_obj)
+               return NULL;
+
+       mtk_gem_obj->size = size;
+       obj = &mtk_gem_obj->base;
+
+       ret = drm_gem_object_init(dev, obj, size);
+       if (ret < 0) {
+               DRM_ERROR("failed to initialize gem object\n");
+               kfree(mtk_gem_obj);
+               return NULL;
+       }
+
+       DRM_DEBUG_KMS("created file object = 0x%p\n", obj->filp);
+
+       return mtk_gem_obj;
+}
+
+struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev,
+                               unsigned int flags, unsigned long size)
+{
+       struct mtk_drm_gem_obj *mtk_gem;
+       struct mtk_drm_gem_buf *mtk_buf;
+       int ret;
+
+       if (!size) {
+               DRM_ERROR("invalid size.\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       mtk_gem = kzalloc(sizeof(*mtk_gem), GFP_KERNEL);
+       if (!mtk_gem) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       mtk_buf = kzalloc(sizeof(*mtk_buf), GFP_KERNEL);
+       if (!mtk_buf) {
+               ret = -ENOMEM;
+               goto err_buf;
+       }
+       mtk_gem->buffer = mtk_buf;
+
+       if (flags == 0) {
+               size = round_up(size, PAGE_SIZE);
+               mtk_buf->kvaddr = kzalloc(size, GFP_KERNEL);
+               if (!mtk_buf->kvaddr) {
+                       ret = -ENOMEM;
+                       goto err_size;
+               }
+
+               mtk_buf->paddr = virt_to_phys(mtk_buf->kvaddr);
+               mtk_buf->size = size;
+               mtk_buf->mva_addr = mtk_buf->paddr;
+       } else {
+               struct page **pages;
+               int npages, size_pages;
+               int offset, index;
+
+               size = PAGE_ALIGN(size);
+               npages = size >> PAGE_SHIFT;
+               size_pages = npages * sizeof(*pages);
+               pages = kmalloc(size_pages, GFP_KERNEL);
+               if (!pages) {
+                       ret = -ENOMEM;
+                       goto err_size;
+               }
+               mtk_buf->pages = pages;
+
+               init_dma_attrs(&mtk_buf->dma_attrs);
+
+               mtk_buf->kvaddr = dma_alloc_attrs(dev->dev, size,
+                       (dma_addr_t *)&mtk_buf->mva_addr, GFP_KERNEL,
+                       &mtk_buf->dma_attrs);
+               if (!mtk_buf->kvaddr) {
+                       ret = -ENOMEM;
+                       goto err_mem;
+               }
+
+               mtk_buf->paddr = 0;
+               mtk_buf->size = size;
+
+               for (offset = 0, index = 0;
+                       offset < size; offset += PAGE_SIZE, index++)
+                       mtk_buf->pages[index] =
+                               vmalloc_to_page(mtk_buf->kvaddr + offset);
+
+               mtk_buf->sgt = drm_prime_pages_to_sg(mtk_buf->pages, npages);
+       }
+       mtk_gem->flags = flags;
+
+       DRM_INFO("kvaddr = %p mva_addr = %X\n",
+               mtk_buf->kvaddr, mtk_buf->mva_addr);
+       ret = drm_gem_object_init(dev, &mtk_gem->base, size);
+       if (ret)
+               goto err_mem;
+
+       return mtk_gem;
+
+err_mem:
+       if (mtk_buf->paddr)
+               kfree(mtk_buf->kvaddr);
+       else
+               dma_free_attrs(dev->dev, size, mtk_buf->kvaddr,
+                       mtk_buf->mva_addr, &mtk_buf->dma_attrs);
+
+       kfree(mtk_buf->pages);
+
+err_size:
+       kfree(mtk_buf);
+err_buf:
+       kfree(mtk_gem);
+err:
+       return ERR_PTR(ret);
+}
+
+void mtk_drm_gem_free_object(struct drm_gem_object *gem)
+{
+       struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(gem);
+
+       DRM_DEBUG_KMS("handle count = %d\n", gem->handle_count);
+
+       drm_gem_free_mmap_offset(gem);
+
+       /* release file pointer to gem object. */
+       drm_gem_object_release(gem);
+
+       if (mtk_gem->flags == 0)
+               kfree(mtk_gem->buffer->kvaddr);
+       else
+               dma_free_attrs(gem->dev->dev, mtk_gem->buffer->size,
+                       mtk_gem->buffer->kvaddr, mtk_gem->buffer->mva_addr,
+                       &mtk_gem->buffer->dma_attrs);
+
+       kfree(mtk_gem->buffer->pages);
+       kfree(mtk_gem->buffer);
+       kfree(mtk_gem);
+}
+
+int mtk_drm_gem_dumb_create(struct drm_file *file_priv,
+                              struct drm_device *dev,
+                              struct drm_mode_create_dumb *args)
+
+{
+       struct mtk_drm_gem_obj *mtk_gem;
+       unsigned int min_pitch = args->width * ((args->bpp + 7) / 8);
+       int ret;
+
+       args->pitch = min_pitch;
+       args->size = args->pitch * args->height;
+
+       mtk_gem = mtk_drm_gem_create(dev, 3, args->size);
+       if (IS_ERR(mtk_gem))
+               return PTR_ERR(mtk_gem);
+
+       /*
+        * 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, &mtk_gem->base, &args->handle);
+       if (ret)
+               return ret;
+
+       /* drop reference from allocate - handle holds it now. */
+       drm_gem_object_unreference_unlocked(&mtk_gem->base);
+
+       return 0;
+}
+
+int mtk_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 mtk_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct mtk_drm_gem_obj *mtk_gem;
+       struct drm_gem_object *gem;
+       int ret;
+
+       /* set vm_area_struct. */
+       ret = drm_gem_mmap(filp, vma);
+       if (ret) {
+               DRM_ERROR("failed to mmap.\n");
+               return ret;
+       }
+
+       gem = vma->vm_private_data;
+       mtk_gem = to_mtk_gem_obj(gem);
+
+       if (mtk_gem->flags == 0) {
+               /*
+                * get page frame number to physical memory to be mapped
+                * to user space.
+                */
+               ret = remap_pfn_range(vma, vma->vm_start,
+                       mtk_gem->buffer->paddr >> PAGE_SHIFT,
+                       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+       } else {
+               struct drm_file *file_priv = filp->private_data;
+               struct drm_device *dev = file_priv->minor->dev;
+               struct mtk_drm_gem_buf *buffer = mtk_gem->buffer;
+
+               vma->vm_flags |= VM_MIXEDMAP;
+
+               ret = dma_mmap_attrs(dev->dev, vma, buffer->kvaddr,
+                       buffer->mva_addr, buffer->size, &buffer->dma_attrs);
+               if (ret) {
+                       DRM_ERROR("failed to remap dma %d\n", ret);
+                       return ret;
+               }
+       }
+
+       if (ret)
+               drm_gem_vm_close(vma);
+
+       return ret;
+}
+
+int mediatek_gem_map_offset_ioctl(struct drm_device *drm, void *data,
+                                 struct drm_file *file_priv)
+{
+       struct drm_mtk_gem_map_off *args = data;
+
+       return mtk_drm_gem_dumb_map_offset(file_priv, drm, args->handle,
+                                               &args->offset);
+}
+
+int mediatek_gem_create_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct mtk_drm_gem_obj *mtk_gem;
+       struct drm_mtk_gem_create *args = data;
+       int ret;
+
+       mtk_gem = mtk_drm_gem_create(dev, 3, args->size);
+
+       if (IS_ERR(mtk_gem))
+               return PTR_ERR(mtk_gem);
+
+       /*
+        * 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, &mtk_gem->base, &args->handle);
+       if (ret)
+               return ret;
+
+       /* drop reference from allocate - handle holds it now. */
+       drm_gem_object_unreference_unlocked(&mtk_gem->base);
+
+       return 0;
+}
+
+
diff --git a/drivers/gpu/drm/mediatek/mediatek_drm_gem.h 
b/drivers/gpu/drm/mediatek/mediatek_drm_gem.h
new file mode 100644
index 0000000..1529481
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mediatek_drm_gem.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _MEDIATEK_DRM_GEM_H_
+#define _MEDIATEK_DRM_GEM_H_
+
+#include <drm/drm_gem.h>
+
+struct drm_gem_object;
+
+/*
+ * mtk drm gem buffer structure.
+ *
+ * @kvaddr: kernel virtual address to allocated memory region.
+ * @dma_addr: bus address(accessed by dma) to allocated memory region.
+ *     - this address could be physical address without IOMMU and
+ *     device address with IOMMU.
+ * @sgt: sg table to transfer page data.
+ * @pages: contain all pages to allocated memory region.
+ * @size: size of allocated memory region.
+ */
+struct mtk_drm_gem_buf {
+       void __iomem    *kvaddr;
+       dma_addr_t              dma_addr;
+       struct dma_attrs        dma_attrs;
+       struct sg_table *sgt;
+       struct page             **pages;
+       unsigned long   size;
+       unsigned int    mva_addr;
+       unsigned int    paddr;
+};
+
+/*
+ * mtk 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 mtk_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: total memory size to physically non-continuous memory region.
+ * @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 mtk_drm_gem_obj {
+       struct drm_gem_object   base;
+       struct mtk_drm_gem_buf  *buffer;
+       unsigned long                   size;
+       unsigned int                    flags;
+};
+
+#define to_mtk_gem_obj(x)      container_of(x, struct mtk_drm_gem_obj, base)
+
+struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
+                                                     unsigned long size);
+void mtk_drm_gem_free_object(struct drm_gem_object *gem);
+struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev,
+                               unsigned int flags,     unsigned long size);
+int mtk_drm_gem_dumb_create(struct drm_file *file_priv,
+               struct drm_device *dev, struct drm_mode_create_dumb *args);
+int mtk_drm_gem_dumb_map_offset(struct drm_file *file_priv,
+               struct drm_device *dev, uint32_t handle, uint64_t *offset);
+int mtk_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/*
+ * request gem object creation and buffer allocation as the size
+ * that it is calculated with framebuffer information such as width,
+ * height and bpp.
+ */
+int mediatek_gem_create_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv);
+
+/* get buffer offset to map to user space. */
+int mediatek_gem_map_offset_ioctl(struct drm_device *dev, void *data,
+                                 struct drm_file *file_priv);
+
+
+#endif
+
diff --git a/include/uapi/drm/mediatek_drm.h b/include/uapi/drm/mediatek_drm.h
new file mode 100644
index 0000000..19ea357
--- /dev/null
+++ b/include/uapi/drm/mediatek_drm.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015 MediaTek Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 _UAPI_MEDIATEK_DRM_H
+#define _UAPI_MEDIATEK_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_mtk_gem_create {
+       uint64_t size;
+       uint32_t flags;
+       uint32_t 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_mtk_gem_map_off {
+       uint32_t handle;
+       uint32_t pad;
+       uint64_t offset;
+};
+
+#define DRM_MTK_GEM_CREATE             0x00
+#define DRM_MTK_GEM_MAP_OFFSET         0x01
+
+#define DRM_IOCTL_MTK_GEM_CREATE       DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_MTK_GEM_CREATE, struct drm_mtk_gem_create)
+
+#define DRM_IOCTL_MTK_GEM_MAP_OFFSET   DRM_IOWR(DRM_COMMAND_BASE + \
+               DRM_MTK_GEM_MAP_OFFSET, struct drm_mtk_gem_map_off)
+
+
+#endif /* _UAPI_MEDIATEK_DRM_H */
-- 
1.8.1.1.dirty

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to