diff --git a/arch/arm64/configs/hikey_defconfig b/arch/arm64/configs/hikey_defconfig
index 2fbdfd4..c14ca1c 100644
--- a/arch/arm64/configs/hikey_defconfig
+++ b/arch/arm64/configs/hikey_defconfig
@@ -306,6 +306,8 @@ CONFIG_DRM=y
 CONFIG_DRM_CMA_FBDEV_BUFFER_NUM=2
 CONFIG_DRM_I2C_ADV7511=y
 CONFIG_DRM_HISI=y
+CONFIG_DRM_HISI_KIRIN=y
+CONFIG_HISI_KIRIN_DW_DSI=y
 CONFIG_FB_ARMCLCD=y
 CONFIG_FB_SIMPLE=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
index f1c33c2..7503981 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -8,3 +8,8 @@ config DRM_HISI
 	help
 	  Choose this option if you have a hisilicon chipsets(hi6220).
 	  If M is selected the module will be called hisi-drm.
+#
+# hisilicon drm device configuration.
+# Please keep this list sorted alphabetically
+
+source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index 5083c1f..e3f6d49 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -1,5 +1,5 @@
-hisi-drm-y := hisi_drm_drv.o \
-	      hisi_drm_ade.o \
-	      hisi_drm_dsi.o
+#
+# Makefile for hisilicon drm drivers.
+# Please keep this list sorted alphabetically
 
-obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
+obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
diff --git a/drivers/gpu/drm/hisilicon/hisi_ade_reg.h b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
deleted file mode 100644
index 1055cce..0000000
--- a/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * 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.
- *
- */
-
-#ifndef __HISI_ADE_REG_H__
-#define __HISI_ADE_REG_H__
-
-/*
- * ADE Registers Offset
- */
-#define ADE_CTRL			(0x4)
-#define ADE_CTRL1			(0x8C)
-#define ADE_ROT_SRC_CFG			(0x10)
-#define ADE_DISP_SRC_CFG		(0x18)
-#define ADE_WDMA2_SRC_CFG		(0x1C)
-#define ADE_SEC_OVLY_SRC_CFG		(0x20)
-#define ADE_WDMA3_SRC_CFG		(0x24)
-#define ADE_OVLY1_TRANS_CFG		(0x2C)
-#define ADE_EN				(0x100)
-#define INTR_MASK_CPU_0			(0xC10)
-#define INTR_MASK_CPU_1			(0xC14)
-#define ADE_FRM_DISGARD_CTRL		(0xA4)
-/* reset and reload regs */
-#define ADE_SOFT_RST_SEL0		(0x78)
-#define ADE_SOFT_RST_SEL1		(0x7C)
-#define ADE_RELOAD_DIS0			(0xAC)
-#define ADE_RELOAD_DIS1			(0xB0)
-#define ADE_CH_RDMA_BIT_OFST		(0)
-#define ADE_CLIP_BIT_OFST		(15)
-#define ADE_SCL_BIT_OFST		(21)
-#define ADE_CTRAN_BIT_OFST		(24)
-#define ADE_OVLY_BIT_OFST		(37) /* 32+5 */
-/* channel regs */
-#define RD_CH_PE(x)			(0x1000 + (x) * 0x80)
-#define RD_CH_CTRL(x)			(0x1004 + (x) * 0x80)
-#define RD_CH_ADDR(x)			(0x1008 + (x) * 0x80)
-#define RD_CH_SIZE(x)			(0x100C + (x) * 0x80)
-#define RD_CH_STRIDE(x)			(0x1010 + (x) * 0x80)
-#define RD_CH_SPACE(x)			(0x1014 + (x) * 0x80)
-#define RD_CH_PARTIAL_SIZE(x)		(0x1018 + (x) * 0x80)
-#define RD_CH_PARTIAL_SPACE(x)		(0x101C + (x) * 0x80)
-#define RD_CH_EN(x)			(0x1020 + (x) * 0x80)
-#define RD_CH_STATUS(x)			(0x1024 + (x) * 0x80)
-#define RD_CH_DISP_CTRL			(0x1404)
-#define RD_CH_DISP_ADDR			(0x1408)
-#define RD_CH_DISP_SIZE			(0x140C)
-#define RD_CH_DISP_STRIDE		(0x1410)
-#define RD_CH_DISP_SPACE		(0x1414)
-#define RD_CH_DISP_EN			(0x142C)
-/* clip regs */
-#define ADE_CLIP_DISABLE(x)		(0x6800 + (x) * 0x100)
-#define ADE_CLIP_SIZE0(x)		(0x6804 + (x) * 0x100)
-#define ADE_CLIP_SIZE1(x)		(0x6808 + (x) * 0x100)
-#define ADE_CLIP_SIZE2(x)		(0x680C + (x) * 0x100)
-#define ADE_CLIP_CFG_OK(x)		(0x6810 + (x) * 0x100)
-/* scale regs */
-#define ADE_SCL1_MUX_CFG		(0xC)
-#define ADE_SCL2_SRC_CFG		(0x14)
-#define ADE_SCL3_MUX_CFG		(0x8)
-#define ADE_SCL_CTRL(x)			(0x3000 + (x) * 0x800)
-#define ADE_SCL_HSP(x)			(0x3004 + (x) * 0x800)
-#define ADE_SCL_UV_HSP(x)		(0x3008 + (x) * 0x800)
-#define ADE_SCL_VSP(x)			(0x300C + (x) * 0x800)
-#define ADE_SCL_UV_VSP(x)		(0x3010 + (x) * 0x800)
-#define ADE_SCL_ORES(x)			(0x3014 + (x) * 0x800)
-#define ADE_SCL_IRES(x)			(0x3018 + (x) * 0x800)
-#define ADE_SCL_START(x)		(0x301C + (x) * 0x800)
-#define ADE_SCL_ERR(x)			(0x3020 + (x) * 0x800)
-#define ADE_SCL_PIX_OFST(x)		(0x3024 + (x) * 0x800)
-#define ADE_SCL_UV_PIX_OFST(x)		(0x3028 + (x) * 0x800)
-#define ADE_SCL_COEF_CLR(x)		(0x3030 + (x) * 0x800)
-#define ADE_SCL_HCOEF(x, m, n)		(0x3100 + (x) * 0x800 + \
-					12 * (m) + 4 * (n))
-#define ADE_SCL_VCOEF(x, i, j)		(0x340C + (x) * 0x800 + \
-					12 * (i) + 4 * (j))
-/* ctran regs */
-#define ADE_CTRAN5_TRANS_CFG		(0x40)
-#define ADE_CTRAN_DIS(x)		(0x5004 + (x) * 0x100)
-#define ADE_CTRAN_MODE_CHOOSE(x)	(0x5008 + (x) * 0x100)
-#define ADE_CTRAN_STAT(x)		(0x500C + (x) * 0x100)
-#define ADE_CTRAN_CHDC0(x)		(0x5010 + (x) * 0x100)
-#define ADE_CTRAN_CHDC1(x)		(0x5014 + (x) * 0x100)
-#define ADE_CTRAN_CHDC2(x)		(0x5018 + (x) * 0x100)
-#define ADE_CTRAN_CHDC3(x)		(0x501C + (x) * 0x100)
-#define ADE_CTRAN_CHDC4(x)		(0x5020 + (x) * 0x100)
-#define ADE_CTRAN_CHDC5(x)		(0x5024 + (x) * 0x100)
-#define ADE_CTRAN_CSC0(x)		(0x5028 + (x) * 0x100)
-#define ADE_CTRAN_CSC1(x)		(0x502C + (x) * 0x100)
-#define ADE_CTRAN_CSC2(x)		(0x5030 + (x) * 0x100)
-#define ADE_CTRAN_CSC3(x)		(0x5034 + (x) * 0x100)
-#define ADE_CTRAN_CSC4(x)		(0x5038 + (x) * 0x100)
-#define ADE_CTRAN_IMAGE_SIZE(x)		(0x503C + (x) * 0x100)
-#define ADE_CTRAN_CFG_OK(x)		(0x5040 + (x) * 0x100)
-/* overlay regs */
-#define ADE_OVLY_ALPHA_ST		(0x2000)
-#define ADE_OVLY_CH_XY0(x)		(0x2004 + (x) * 4)
-#define ADE_OVLY_CH_XY1(x)		(0x2024 + (x) * 4)
-#define ADE_OVLY_CH_CTL(x)		(0x204C + (x) * 4)
-#define ADE_OVLY_OUTPUT_SIZE(x)		(0x2070 + (x) * 8)
-#define ADE_OVLY_BASE_COLOR(x)		(0x2074 + (x) * 8)
-#define ADE_OVLYX_CTL(x)		(0x209C + (x) * 4)
-#define ADE_OVLY_CTL			(0x98)
-#define ADE_OVLY_CH_ALP_MODE_OFST	(0)
-#define ADE_OVLY_CH_ALP_SEL_OFST	(2)
-#define ADE_OVLY_CH_UNDER_ALP_SEL_OFST	(4)
-#define ADE_OVLY_CH_EN_OFST		(6)
-#define ADE_OVLY_CH_ALP_GBL_OFST	(15)
-#define ADE_OVLY_CH_SEL_OFST		(28)
-
-/*
- * media regs
- */
-#define SC_MEDIA_RSTDIS			(0x530)
-#define SC_MEDIA_RSTEN			(0x52C)
-#define NOC_ADE0_QOSGENERATOR_MODE       0x010C
-#define NOC_ADE0_QOSGENERATOR_EXTCONTROL 0x0118
-#define NOC_ADE1_QOSGENERATOR_MODE       0x020C
-#define NOC_ADE1_QOSGENERATOR_EXTCONTROL 0x0218
-
-/*
- * regs relevant enum
- */
-enum {
-	LDI_TEST = 0,
-	LDI_WORK
-};
-
-enum {
-	LDI_ISR_FRAME_END_INT = 0x2,
-	LDI_ISR_UNDER_FLOW_INT = 0x4
-};
-
-enum {
-	ADE_ISR1_RES_SWITCH_CMPL = 0x80000000
-};
-
-enum {
-	LDI_DISP_MODE_NOT_3D_FBF = 0,
-	LDI_DISP_MODE_3D_FBF
-};
-
-enum {
-	ADE_RGB = 0,
-	ADE_BGR
-};
-
-enum {
-	ADE_DISABLE = 0,
-	ADE_ENABLE
-};
-
-enum {
-	ADE_OUT_RGB_565 = 0,
-	ADE_OUT_RGB_666,
-	ADE_OUT_RGB_888
-};
-
-/*
- * ADE read as big-endian, so revert the
- * rgb order described in the SoC datasheet
- */
-enum ADE_FORMAT {
-	ADE_RGB_565 = 0,
-	ADE_BGR_565,
-	ADE_XRGB_8888,
-	ADE_XBGR_8888,
-	ADE_ARGB_8888,
-	ADE_ABGR_8888,
-	ADE_RGBA_8888,
-	ADE_BGRA_8888,
-	ADE_RGB_888,
-	ADE_BGR_888 = 9,
-	ADE_FORMAT_NOT_SUPPORT = 800
-};
-
-/* ldi src cfg */
-enum {
-	TOP_DISP_SRC_NONE = 0,
-	TOP_DISP_SRC_OVLY2,
-	TOP_DISP_SRC_DISP,
-	TOP_DISP_SRC_ROT,
-	TOP_DISP_SRC_SCL2
-};
-
-enum {
-	ADE_ISR_DMA_ERROR = 0x2000000
-};
-
-enum ade_channel {
-	ADE_CH1 = 0,	/* channel 1 for primary plane */
-	ADE_CH_NUM
-};
-
-enum ade_scale {
-	ADE_SCL1 = 0,
-	ADE_SCL2,
-	ADE_SCL3,
-	ADE_SCL_NUM
-};
-
-enum ade_ctran {
-	ADE_CTRAN1 = 0,
-	ADE_CTRAN2,
-	ADE_CTRAN3,
-	ADE_CTRAN4,
-	ADE_CTRAN5,
-	ADE_CTRAN6,
-	ADE_CTRAN_NUM
-};
-
-enum ade_overlay {
-	ADE_OVLY1 = 0,
-	ADE_OVLY2,
-	ADE_OVLY3,
-	ADE_OVLY_NUM
-};
-
-enum {
-	ADE_ALP_GLOBAL = 0,
-	ADE_ALP_PIXEL,
-	ADE_ALP_PIXEL_AND_GLB
-};
-
-enum {
-	ADE_ALP_MUL_COEFF_0 = 0,	/* alpha */
-	ADE_ALP_MUL_COEFF_1,		/* 1-alpha */
-	ADE_ALP_MUL_COEFF_2,		/* 0 */
-	ADE_ALP_MUL_COEFF_3		/* 1 */
-};
-
-/*
- * ADE Register Union Struct
- */
-union U_ADE_CTRL1 {
-struct {
-	unsigned int	auto_clk_gate_en	:1;
-	unsigned int	rot_buf_shr_out		:1;
-	unsigned int	reserved_44		:30;
-	} bits;
-	unsigned int	u32;
-};
-
-union U_ADE_SOFT_RST_SEL0 {
-struct {
-	unsigned int    ch1_rdma_srst_sel     :1;
-	unsigned int    ch2_rdma_srst_sel     :1;
-	unsigned int    ch3_rdma_srst_sel     :1;
-	unsigned int    ch4_rdma_srst_sel     :1;
-	unsigned int    ch5_rdma_srst_sel     :1;
-	unsigned int    ch6_rdma_srst_sel     :1;
-	unsigned int    disp_rdma_srst_sel    :1;
-	unsigned int    cmdq1_rdma_srst_sel   :1;
-	unsigned int    cmdq2_rdma_srst_sel   :1;
-	unsigned int    reserved_29           :1;
-	unsigned int    ch1_wdma_srst_sel     :1;
-	unsigned int    ch2_wdma_srst_sel     :1;
-	unsigned int    ch3_wdma_srst_sel     :1;
-	unsigned int    reserved_28           :1;
-	unsigned int    cmdq_wdma_srst_sel    :1;
-	unsigned int    clip1_srst_sel        :1;
-	unsigned int    clip2_srst_sel        :1;
-	unsigned int    clip3_srst_sel        :1;
-	unsigned int    clip4_srst_sel        :1;
-	unsigned int    clip5_srst_sel        :1;
-	unsigned int    clip6_srst_sel        :1;
-	unsigned int    scl1_srst_sel         :1;
-	unsigned int    scl2_srst_sel         :1;
-	unsigned int    scl3_srst_sel         :1;
-	unsigned int    ctran1_srst_sel       :1;
-	unsigned int    ctran2_srst_sel       :1;
-	unsigned int    ctran3_srst_sel       :1;
-	unsigned int    ctran4_srst_sel       :1;
-	unsigned int    ctran5_srst_sel       :1;
-	unsigned int    ctran6_srst_sel       :1;
-	unsigned int    rot_srst_sel          :1;
-	unsigned int    reserved_27           :1;
-	} bits;
-	unsigned int	u32;
-};
-
-union U_ADE_CTRL {
-struct {
-	unsigned int    frm_end_start         :2;
-	unsigned int    dfs_buf_cfg           :1;
-	unsigned int    rot_buf_cfg           :3;
-	unsigned int    rd_ch5_nv             :1;
-	unsigned int    rd_ch6_nv             :1;
-	unsigned int    dfs_buf_unflow_lev1   :13;
-	unsigned int    dfs_buf_unflow_lev2   :11;
-	} bits;
-	unsigned int	u32;
-};
-
-/*
- * ADE Register Write/Read functions
- */
-static inline void set_TOP_CTL_clk_gate_en(u8 *base, u32 val)
-{
-	union U_ADE_CTRL1   ade_ctrl1;
-	u8 *reg_addr = base + ADE_CTRL1;
-
-	ade_ctrl1.u32 = readl(reg_addr);
-	ade_ctrl1.bits.auto_clk_gate_en = val;
-	writel(ade_ctrl1.u32, reg_addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_disp_rdma(u8 *base, u32 val)
-{
-	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
-	u8 *addr = base + ADE_SOFT_RST_SEL0;
-
-	ade_soft_rst.u32 = readl(addr);
-	ade_soft_rst.bits.disp_rdma_srst_sel = val;
-	writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_ctran5(u8 *base, u32 val)
-{
-	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
-	u8 *addr = base + ADE_SOFT_RST_SEL0;
-
-	ade_soft_rst.u32 = readl(addr);
-	ade_soft_rst.bits.ctran5_srst_sel = val;
-	writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_SOFT_RST_SEL0_ctran6(u8 *base, u32 val)
-{
-	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
-	u8 *addr = base + ADE_SOFT_RST_SEL0;
-
-	ade_soft_rst.u32 = readl(addr);
-	ade_soft_rst.bits.ctran6_srst_sel = val;
-	writel(ade_soft_rst.u32, addr);
-}
-
-static inline void set_TOP_CTL_frm_end_start(u8 *base, u32 val)
-{
-	union U_ADE_CTRL  ade_ctrl;
-	u8 *reg_addr = base + ADE_CTRL;
-
-	ade_ctrl.u32 = readl(reg_addr);
-	ade_ctrl.bits.frm_end_start = val;
-	writel(ade_ctrl.u32, reg_addr);
-}
-
-/*
- * LDI Registers Offset
- */
-#define LDI_HRZ_CTRL0		(0x7400)
-#define LDI_HRZ_CTRL1		(0x7404)
-#define LDI_VRT_CTRL0		(0x7408)
-#define LDI_VRT_CTRL1		(0x740C)
-#define LDI_PLR_CTRL		(0x7410)
-#define LDI_DSP_SIZE		(0x7414)
-#define LDI_INT_EN		(0x741C)
-#define LDI_CTRL		(0x7420)
-#define LDI_ORG_INT		(0x7424)
-#define LDI_MSK_INT		(0x7428)
-#define LDI_INT_CLR		(0x742C)
-#define LDI_WORK_MODE		(0x7430)
-#define LDI_DE_SPACE_LOW	(0x7438)
-#define LDI_MCU_INTS		(0x7450)
-#define LDI_MCU_INTE		(0x7454)
-#define LDI_MCU_INTC		(0x7458)
-#define LDI_HDMI_DSI_GT		(0x7434)
-
-/*
- * LDI Timing Polarity defines
- */
-#define HISI_LDI_FLAG_NVSYNC	BIT(0)
-#define HISI_LDI_FLAG_NHSYNC	BIT(1)
-#define HISI_LDI_FLAG_NPIXCLK	BIT(2)
-#define HISI_LDI_FLAG_NDE	BIT(3)
-
-/*
- * LDI Register Union Struct
- */
-union U_LDI_CTRL {
-struct {
-	unsigned int    ldi_en                :1;
-	unsigned int    disp_mode_buf         :1;
-	unsigned int    date_gate_en          :1;
-	unsigned int    bpp                   :2;
-	unsigned int    wait_vsync_en         :1;
-	unsigned int    corlorbar_width       :7;
-	unsigned int    bgr                   :1;
-	unsigned int    color_mode            :1;
-	unsigned int    shutdown              :1;
-	unsigned int    vactive_line          :12;
-	unsigned int    ldi_en_self_clr       :1;
-	unsigned int    reserved_573          :3;
-	} bits;
-	unsigned int    u32;
-};
-
-union U_LDI_WORK_MODE {
-struct {
-	unsigned int    work_mode             :1;
-	unsigned int    wback_en              :1;
-	unsigned int    colorbar_en           :1;
-	unsigned int    reserved_577          :29;
-	} bits;
-	unsigned int    u32;
-};
-
-/*
- * LDI Register Write/Read Helper functions
- */
-static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs)
-{
-	u32 mask = (1 << bw) - 1;
-	u32 tmp = readl(addr);
-
-	tmp &= ~(mask << bs);
-	writel(tmp | ((val & mask) << bs), addr);
-}
-
-static inline void set_LDI_CTRL_ldi_en(u8 *base, u32 val)
-{
-	union U_LDI_CTRL ldi_ctrl;
-	u8 *addr = base + LDI_CTRL;
-
-	ldi_ctrl.u32 = readl(addr);
-	ldi_ctrl.bits.ldi_en = val;
-	writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_disp_mode(u8 *base, u32 val)
-{
-	union U_LDI_CTRL ldi_ctrl;
-	u8 *addr = base + LDI_CTRL;
-
-	ldi_ctrl.u32 = readl(addr);
-	ldi_ctrl.bits.disp_mode_buf = val;
-	writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_bpp(u8 *base, u32 val)
-{
-	union U_LDI_CTRL ldi_ctrl;
-	u8 *addr = base + LDI_CTRL;
-
-	ldi_ctrl.u32 = readl(addr);
-	ldi_ctrl.bits.bpp = val;
-	writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_corlorbar_width(u8 *base, u32 val)
-{
-	union U_LDI_CTRL ldi_ctrl;
-	u8 *addr = base + LDI_CTRL;
-
-	ldi_ctrl.u32 = readl(addr);
-	ldi_ctrl.bits.corlorbar_width = (val > 0) ? val - 1 : 0;
-	writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_CTRL_bgr(u8 *base, u32 val)
-{
-	union U_LDI_CTRL ldi_ctrl;
-	u8 *addr = base + LDI_CTRL;
-
-	ldi_ctrl.u32 = readl(addr);
-	ldi_ctrl.bits.bgr = val;
-	writel(ldi_ctrl.u32, addr);
-}
-
-static inline void set_LDI_WORK_MODE_work_mode(u8 *base, u32 val)
-{
-	union U_LDI_WORK_MODE ldi_work_mode;
-	u8 *addr = base + LDI_WORK_MODE;
-
-	ldi_work_mode.u32 = readl(addr);
-	ldi_work_mode.bits.work_mode = val;
-	writel(ldi_work_mode.u32, addr);
-}
-
-static inline void set_LDI_WORK_MODE_colorbar_en(u8 *base, u32 val)
-{
-	union U_LDI_WORK_MODE ldi_work_mode;
-	u8 *addr = base + LDI_WORK_MODE;
-
-	ldi_work_mode.u32 = readl(addr);
-	ldi_work_mode.bits.colorbar_en = val;
-	writel(ldi_work_mode.u32, addr);
-}
-
-#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
deleted file mode 100644
index 64365f5..0000000
--- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
+++ /dev/null
@@ -1,1100 +0,0 @@
-/*
- * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
- *
- * Copyright (c) 2014-2015 Hisilicon Limited.
- * Author:
- *	Xinliang Liu <xinliang.liu@linaro.org>
- *	Xinliang Liu <z.liuxinliang@hisilicon.com>
- *	Xinwei Kong <kong.kongxinwei@hisilicon.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.
- *
- */
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/component.h>
-#include <video/display_timing.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_atomic.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_plane_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "hisi_drm_drv.h"
-#include "hisi_ade_reg.h"
-
-#define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
-#define PRIMARY_CH	(ADE_CH1)
-
-#define to_ade_crtc(crtc) \
-	container_of(crtc, struct ade_crtc, base)
-
-#define to_ade_plane(plane) \
-	container_of(plane, struct ade_plane, base)
-
-struct ade_hw_ctx {
-	void __iomem  *base;
-	void __iomem  *media_base;
-	void __iomem  *media_noc_base;
-
-	int irq;
-	u32 ade_core_rate;
-	u32 media_noc_rate;
-
-	struct clk *ade_core_clk;
-	struct clk *media_noc_clk;
-	struct clk *ade_pix_clk;
-	bool power_on;
-};
-
-struct ade_crtc {
-	struct drm_crtc base;
-	struct ade_hw_ctx *ctx;
-	bool enable;
-	u64 use_mask;
-};
-
-struct ade_plane {
-	struct drm_plane base;
-	void *ctx;
-	u8 ch; /* channel */
-};
-
-struct ade_data {
-	struct ade_crtc acrtc;
-	struct ade_plane aplane[ADE_CH_NUM];
-	struct ade_hw_ctx ctx;
-};
-
-/* ade-format info: */
-struct ade_format {
-	u32 pixel_format;
-	enum ADE_FORMAT ade_format;
-};
-
-static const struct ade_format ade_formats[] = {
-	/* 16bpp RGB: */
-	{ DRM_FORMAT_RGB565, ADE_RGB_565 },
-	{ DRM_FORMAT_BGR565, ADE_BGR_565 },
-	/* 24bpp RGB: */
-	{ DRM_FORMAT_RGB888, ADE_RGB_888 },
-	{ DRM_FORMAT_BGR888, ADE_BGR_888 },
-	/* 32bpp [A]RGB: */
-	{ DRM_FORMAT_XRGB8888, ADE_XRGB_8888 },
-	{ DRM_FORMAT_XBGR8888, ADE_XBGR_8888 },
-	{ DRM_FORMAT_RGBA8888, ADE_RGBA_8888 },
-	{ DRM_FORMAT_BGRA8888, ADE_BGRA_8888 },
-	{ DRM_FORMAT_ARGB8888, ADE_ARGB_8888 },
-	{ DRM_FORMAT_ABGR8888, ADE_ABGR_8888 },
-};
-
-static const u32 channel_formats1[] = {
-	/* channel 1,2,3,4 */
-	DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
-	DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
-	DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
-	DRM_FORMAT_ABGR8888
-};
-
-u32 ade_get_channel_formats(u8 ch, const u32 **formats)
-{
-	switch (ch) {
-	case ADE_CH1:
-		*formats = channel_formats1;
-		return ARRAY_SIZE(channel_formats1);
-	default:
-		DRM_ERROR("no this channel %d\n", ch);
-		*formats = NULL;
-		return 0;
-	}
-}
-
-/* convert from fourcc format to ade format */
-static u32 ade_get_format(u32 pixel_format)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ade_formats); i++)
-		if (ade_formats[i].pixel_format == pixel_format)
-			return ade_formats[i].ade_format;
-
-	/* not found */
-	DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", pixel_format);
-	return ADE_FORMAT_NOT_SUPPORT;
-}
-
-static void ade_init(struct ade_hw_ctx *ctx)
-{
-	void __iomem *base = ctx->base;
-
-	/* enable clk gate */
-	set_TOP_CTL_clk_gate_en(base, 1);
-	/* clear overlay */
-	writel(0, base + ADE_OVLY1_TRANS_CFG);
-	writel(0, base + ADE_OVLY_CTL);
-	writel(0, base + ADE_OVLYX_CTL(ADE_OVLY2));
-	/* clear reset and reload regs */
-	writel(0, base + ADE_SOFT_RST_SEL0);
-	writel(0, base + ADE_SOFT_RST_SEL1);
-	writel(0xFFFFFFFF, base + ADE_RELOAD_DIS0);
-	writel(0xFFFFFFFF, base + ADE_RELOAD_DIS1);
-	/* for video set to 1, means that ade registers
-	 * became effective at frame end
-	 */
-	set_TOP_CTL_frm_end_start(base, 1);
-}
-
-static void ade_ldi_set_mode(struct ade_crtc *acrtc,
-			     struct drm_display_mode *mode,
-			     struct drm_display_mode *adj_mode)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u32 out_w = mode->hdisplay;
-	u32 out_h = mode->vdisplay;
-	u32 hfp, hbp, hsw, vfp, vbp, vsw;
-	u32 plr_flags;
-	int ret;
-
-	plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
-			? HISI_LDI_FLAG_NVSYNC : 0;
-	plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
-			? HISI_LDI_FLAG_NHSYNC : 0;
-	hfp = mode->hsync_start - mode->hdisplay;
-	hbp = mode->htotal - mode->hsync_end;
-	hsw = mode->hsync_end - mode->hsync_start;
-	vfp = mode->vsync_start - mode->vdisplay;
-	vbp = mode->vtotal - mode->vsync_end;
-	vsw = mode->vsync_end - mode->vsync_start;
-	if (vsw > 15) {
-		DRM_INFO("vsw exceeded 15\n");
-		vsw = 15;
-	}
-
-	writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
-	/* p3-73 6220V100 pdf:
-	 *  "The configured value is the actual width - 1"
-	 */
-	writel(hsw - 1, base + LDI_HRZ_CTRL1);
-	writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
-	/* p3-74 6220V100 pdf:
-	 *  "The configured value is the actual width - 1"
-	 */
-	writel(vsw - 1, base + LDI_VRT_CTRL1);
-
-	/* p3-75 6220V100 pdf:
-	 *  "The configured value is the actual width - 1"
-	 */
-	writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
-	       base + LDI_DSP_SIZE);
-	writel(plr_flags, base + LDI_PLR_CTRL);
-
-	ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
-	/* Success should be guaranteed in aotomic_check
-	 * failer shouldn't happen here
-	 */
-	if (ret)
-		DRM_ERROR("set ade_pixel_clk_rate fail\n");
-	adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
-
-	/* ctran6 setting */
-	writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
-	writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
-	acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
-	DRM_INFO("set mode: %dx%d\n", out_w, out_h);
-
-	/*
-	 * other parameters setting
-	 */
-	writel(BIT(0), base + LDI_WORK_MODE);
-	writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
-	       base + LDI_CTRL);
-	set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
-}
-
-static int ade_power_up(struct ade_hw_ctx *ctx)
-{
-	void __iomem *media_base = ctx->media_base;
-	int ret;
-
-	ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
-	if (ret) {
-		DRM_ERROR("clk_set_rate ade_core_rate error\n");
-		return ret;
-	}
-	ret = clk_set_rate(ctx->media_noc_clk, ctx->media_noc_rate);
-	if (ret) {
-		DRM_ERROR("media_noc_clk media_noc_rate error\n");
-		return ret;
-	}
-	ret = clk_prepare_enable(ctx->media_noc_clk);
-	if (ret) {
-		DRM_ERROR("fail to clk_prepare_enable media_noc_clk\n");
-		return ret;
-	}
-
-	writel(0x20, media_base + SC_MEDIA_RSTDIS);
-
-	ret = clk_prepare_enable(ctx->ade_core_clk);
-	if (ret) {
-		DRM_ERROR("fail to clk_prepare_enable ade_core_clk\n");
-		return ret;
-	}
-
-	ade_init(ctx);
-	ctx->power_on = true;
-	return 0;
-}
-
-static void ade_power_down(struct ade_hw_ctx *ctx)
-{
-	void __iomem *base = ctx->base;
-	void __iomem *media_base = ctx->media_base;
-
-	set_LDI_CTRL_ldi_en(base, ADE_DISABLE);
-	/* dsi pixel off */
-	set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
-
-	clk_disable_unprepare(ctx->ade_core_clk);
-	writel(0x20, media_base + SC_MEDIA_RSTEN);
-	clk_disable_unprepare(ctx->media_noc_clk);
-	ctx->power_on = false;
-}
-
-static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
-						 unsigned int index)
-{
-	unsigned int index_tmp = 0;
-	struct drm_crtc *crtc;
-
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (index_tmp == index)
-			return crtc;
-
-		index_tmp++;
-	}
-
-	WARN_ON(true);
-	return NULL;
-}
-
-int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
-{
-	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
-	struct ade_crtc *acrtc = to_ade_crtc(crtc);
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u32 intr_en;
-
-	DRM_INFO("enable_vblank enter.\n");
-	if (!ctx->power_on)
-		(void)ade_power_up(ctx);
-
-	intr_en = readl(base + LDI_INT_EN);
-	intr_en |= LDI_ISR_FRAME_END_INT;
-	writel(intr_en, base + LDI_INT_EN);
-
-	return 0;
-}
-
-void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
-{
-	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
-	struct ade_crtc *acrtc = to_ade_crtc(crtc);
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u32 intr_en;
-
-	DRM_INFO("disable_vblank enter.\n");
-	if (!ctx->power_on) {
-		DRM_ERROR("power is down! vblank disable fail\n");
-		return;
-	}
-	intr_en = readl(base + LDI_INT_EN);
-	intr_en &= ~LDI_ISR_FRAME_END_INT;
-	writel(intr_en, base + LDI_INT_EN);
-}
-
-static irqreturn_t ade_irq_handler(int irq, void *data)
-{
-	struct ade_crtc *acrtc = data;
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	struct drm_crtc *crtc = &acrtc->base;
-	struct drm_device *dev = crtc->dev;
-	void __iomem *base = ctx->base;
-	u32 status;
-
-	status = readl(base + LDI_MSK_INT);
-	/* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
-
-	/* vblank irq */
-	if (status & LDI_ISR_FRAME_END_INT) {
-		writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
-		drm_handle_vblank(dev, drm_crtc_index(crtc));
-	}
-
-	return IRQ_HANDLED;
-}
-
-/*
- * set modules' reset mode: by software or hardware
- * set modules' reload enable/disable
- */
-static void ade_set_reset_and_reload(struct ade_crtc *acrtc)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u32 mask0 = (u32)acrtc->use_mask;
-	u32 mask1 = (u32)(acrtc->use_mask >> 32);
-
-	DRM_DEBUG_DRIVER("mask=0x%llX, mask0=0x%X, mask1=0x%X\n",
-			 acrtc->use_mask, mask0, mask1);
-
-	writel(mask0, base + ADE_SOFT_RST_SEL0);
-	writel(mask1, base + ADE_SOFT_RST_SEL1);
-	writel(~mask0, base + ADE_RELOAD_DIS0);
-	writel(~mask1, base + ADE_RELOAD_DIS1);
-}
-
-void ade_set_medianoc_qos(struct ade_crtc *acrtc)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->media_noc_base;
-	void __iomem *reg;
-	u32 val;
-
-	reg = base + NOC_ADE0_QOSGENERATOR_MODE;
-	val = (readl(reg) & 0xfffffffc) | 0x2;
-	writel(val, reg);
-
-	reg = base + NOC_ADE0_QOSGENERATOR_EXTCONTROL;
-	val = readl(reg) | 0x1;
-	writel(val, reg);
-
-	reg = base + NOC_ADE1_QOSGENERATOR_MODE;
-	val = (readl(reg) & 0xfffffffc) | 0x2;
-	writel(val, reg);
-
-	reg = base + NOC_ADE1_QOSGENERATOR_EXTCONTROL;
-	val = readl(reg) | 0x1;
-	writel(val, reg);
-}
-
-/*
- * commit to ldi to display
- */
-static void ade_display_commit(struct ade_crtc *acrtc)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-
-	/* TODO: set rotator after overlay */
-
-	/* TODO: set scale after overlay */
-
-	/* display source setting */
-	writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
-
-	/* set reset mode:soft or hw, and reload modules */
-	ade_set_reset_and_reload(acrtc);
-
-	DRM_INFO("ADE GO\n");
-	/* enable ade */
-	wmb();
-	writel(ADE_ENABLE, base + ADE_EN);
-	/* enable ldi */
-	wmb();
-	set_LDI_CTRL_ldi_en(base, ADE_ENABLE);
-	/* dsi pixel on */
-	set_reg(base + LDI_HDMI_DSI_GT, 0x0, 1, 0);
-}
-
-static void ade_crtc_enable(struct drm_crtc *crtc)
-{
-	struct ade_crtc *acrtc = to_ade_crtc(crtc);
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	int ret;
-
-	DRM_DEBUG_DRIVER("enter.\n");
-	if (acrtc->enable)
-		return;
-
-	if (!ctx->power_on) {
-		ret = ade_power_up(ctx);
-		if (ret) {
-			DRM_ERROR("failed to initialize ade clk\n");
-			return;
-		}
-	}
-
-	ade_set_medianoc_qos(acrtc);
-	ade_display_commit(acrtc);
-	acrtc->enable = true;
-
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void ade_crtc_disable(struct drm_crtc *crtc)
-{
-	struct ade_crtc *acrtc = to_ade_crtc(crtc);
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-
-	DRM_DEBUG_DRIVER("enter.\n");
-
-	if (!acrtc->enable)
-		return;
-
-	ade_power_down(ctx);
-	acrtc->use_mask = 0;
-	acrtc->enable = false;
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-int ade_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
-{
-	DRM_DEBUG_DRIVER("enter.\n");
-	DRM_DEBUG_DRIVER("exit success.\n");
-	/* do nothing */
-	return 0;
-}
-
-static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
-{
-	struct ade_crtc *acrtc = to_ade_crtc(crtc);
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	struct drm_display_mode *mode = &crtc->state->mode;
-	struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
-
-	DRM_DEBUG_DRIVER("enter.\n");
-	if (!ctx->power_on)
-		(void)ade_power_up(ctx);
-	ade_ldi_set_mode(acrtc, mode, adj_mode);
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_state)
-{
-	struct ade_crtc *acrtc = to_ade_crtc(crtc);
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-
-	DRM_DEBUG_DRIVER("enter.\n");
-	if (!ctx->power_on)
-		(void)ade_power_up(ctx);
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
-				  struct drm_crtc_state *old_state)
-
-{
-	struct ade_crtc *acrtc = to_ade_crtc(crtc);
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-
-	DRM_DEBUG_DRIVER("enter.\n");
-	/* commit to  display: LDI input setting */
-	if (acrtc->enable) {
-		/* set reset and reload */
-		ade_set_reset_and_reload(acrtc);
-		/* flush ade regitsters */
-		wmb();
-		writel(ADE_ENABLE, base + ADE_EN);
-	}
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
-	.enable		= ade_crtc_enable,
-	.disable	= ade_crtc_disable,
-	.atomic_check	= ade_crtc_atomic_check,
-	.mode_set_nofb	= ade_crtc_mode_set_nofb,
-	.atomic_begin	= ade_crtc_atomic_begin,
-	.atomic_flush	= ade_crtc_atomic_flush,
-};
-
-static const struct drm_crtc_funcs ade_crtc_funcs = {
-	.destroy	= drm_crtc_cleanup,
-	.set_config	= drm_atomic_helper_set_config,
-	.page_flip	= drm_atomic_helper_page_flip,
-	.reset		= drm_atomic_helper_crtc_reset,
-	.set_property = drm_atomic_helper_crtc_set_property,
-	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,
-	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
-};
-
-static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
-			 struct drm_plane *plane)
-{
-	int ret;
-
-	ret = drm_crtc_init_with_planes(dev, crtc, plane,
-					NULL, &ade_crtc_funcs);
-	if (ret) {
-		DRM_ERROR("failed to init crtc.\n");
-		return ret;
-	}
-
-	drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
-
-	return 0;
-}
-
-static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
-			 u32 ch, u32 y, u32 in_h, u32 fmt)
-{
-	u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
-	struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u32 stride = fb->pitches[0];
-	u32 addr = (u32)obj->paddr + y * stride;
-
-	DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x, \
-			 addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
-			 ch + 1, y, in_h, stride, (u32)obj->paddr,
-			 addr, fb->width, fb->height,
-			 fmt, drm_get_format_name(fb->pixel_format));
-
-	/* get reg offset */
-	reg_ctrl = RD_CH_CTRL(ch);
-	reg_addr = RD_CH_ADDR(ch);
-	reg_size = RD_CH_SIZE(ch);
-	reg_stride = RD_CH_STRIDE(ch);
-	reg_space = RD_CH_SPACE(ch);
-	reg_en = RD_CH_EN(ch);
-
-	/*
-	 * TODO: set rotation
-	 */
-	writel((fmt << 16) & 0x1f0000, base + reg_ctrl);
-	writel(addr, base + reg_addr);
-	writel((in_h << 16) | stride, base + reg_size);
-	writel(stride, base + reg_stride);
-	writel(in_h * stride, base + reg_space);
-	writel(1, base + reg_en);
-
-	acrtc->use_mask |= BIT(ADE_CH_RDMA_BIT_OFST + ch);
-}
-
-static void ade_rdma_disable(struct ade_crtc *acrtc, u32 ch)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u32 reg_en;
-
-	/* get reg offset */
-	reg_en = RD_CH_EN(ch);
-
-	writel(0, base + reg_en);
-	acrtc->use_mask &= ~BIT(ADE_CH_RDMA_BIT_OFST + ch);
-}
-
-static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
-			 u32 in_w, u32 in_h)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u32 disable_val;
-	u32 clip_left;
-	u32 clip_right;
-
-	/*
-	 * clip width, no need to clip height
-	 */
-	if (fb_w == in_w) { /* bypass */
-		disable_val = 1;
-		clip_left = 0;
-		clip_right = 0;
-	} else {
-		disable_val = 0;
-		clip_left = x;
-		clip_right = fb_w - (x + in_w) - 1;
-	}
-
-	DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n",
-			 ch + 1, clip_left, clip_right);
-
-	writel(disable_val, base + ADE_CLIP_DISABLE(ch));
-	writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
-	writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
-
-	acrtc->use_mask |= BIT(ADE_CLIP_BIT_OFST + ch);
-}
-
-static void ade_clip_disable(struct ade_crtc *acrtc, u32 ch)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-
-	writel(1, base + ADE_CLIP_DISABLE(ch));
-	acrtc->use_mask &= ~BIT(ADE_CLIP_BIT_OFST + ch);
-}
-
-static bool has_Alpha_channel(int format)
-{
-	switch (format) {
-	case ADE_ARGB_8888:
-	case ADE_ABGR_8888:
-	case ADE_RGBA_8888:
-	case ADE_BGRA_8888:
-		return true;
-	default:
-		return false;
-	}
-}
-
-static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
-				    u8 *alp_sel, u8 *under_alp_sel)
-{
-	bool has_alpha = has_Alpha_channel(fmt);
-
-	/*
-	 * get alp_mode
-	 */
-	if (has_alpha && glb_alpha < 255)
-		*alp_mode = ADE_ALP_PIXEL_AND_GLB;
-	else if (has_alpha)
-		*alp_mode = ADE_ALP_PIXEL;
-	else
-		*alp_mode = ADE_ALP_GLOBAL;
-
-	/*
-	 * get alp sel
-	 */
-	*alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */
-	*under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
-}
-
-static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
-			    u32 in_w, u32 in_h, u32 fmt)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u8 ovly_ch = 0;
-	u8 x = ADE_OVLY2;
-	u8 glb_alpha = 255;
-	u32 x1 = x0 + in_w - 1;
-	u32 y1 = y0 + in_h - 1;
-	u32 val;
-	u8 alp_sel;
-	u8 under_alp_sel;
-	u8 alp_mode;
-
-	ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
-				&under_alp_sel);
-
-	/* overlay routing setting */
-	writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
-	writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
-	val = (ch + 1) << ADE_OVLY_CH_SEL_OFST | BIT(ADE_OVLY_CH_EN_OFST) |
-		alp_sel << ADE_OVLY_CH_ALP_SEL_OFST |
-		under_alp_sel << ADE_OVLY_CH_UNDER_ALP_SEL_OFST |
-		glb_alpha << ADE_OVLY_CH_ALP_GBL_OFST |
-		alp_mode << ADE_OVLY_CH_ALP_MODE_OFST;
-	DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
-	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
-	val = (x + 1) << (ovly_ch * 4) | readl(base + ADE_OVLY_CTL);
-	DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
-	writel(val, base + ADE_OVLY_CTL);
-
-	/* when primary is enable, indicate that it's ready to output. */
-	if (ch == PRIMARY_CH) {
-		val = (in_w - 1) << 16 | (in_h - 1);
-		writel(val, base + ADE_OVLY_OUTPUT_SIZE(x));
-		writel(1, base + ADE_OVLYX_CTL(x));
-		acrtc->use_mask |= BIT(ADE_OVLY_BIT_OFST + x);
-	}
-}
-
-static void ade_overlay_disable(struct ade_crtc *acrtc, u32 ch)
-{
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
-	u8 ovly_ch = 0;
-	u32 val;
-
-	val = ~BIT(6) & readl(base + ADE_OVLY_CH_CTL(ovly_ch));
-	DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
-	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
-	val = ~(0x3 << (ovly_ch * 4)) & readl(base + ADE_OVLY_CTL);
-
-	DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
-	writel(val, base + ADE_OVLY_CTL);
-}
-
-/*
- * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
- */
-static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
-			       struct drm_framebuffer *fb, int crtc_x,
-			       int crtc_y, unsigned int crtc_w,
-			       unsigned int crtc_h, u32 src_x,
-			       u32 src_y, u32 src_w, u32 src_h)
-{
-	u8 ch = aplane->ch;
-	u32 fmt = ade_get_format(fb->pixel_format);
-	u32 in_w;
-	u32 in_h;
-
-	DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d",
-			 ch + 1, src_x, src_y, src_w, src_h,
-			 crtc_x, crtc_y, crtc_w, crtc_h);
-
-	/* 1) DMA setting */
-	in_w = src_w;
-	in_h = src_h;
-	ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt);
-
-	/* 2) clip setting */
-	ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
-
-	/* 3) TODO: scale setting for overlay planes */
-
-	/* 4) TODO: ctran/csc setting for overlay planes */
-
-	/* 5) overlay/compositor routing setting */
-	ade_overlay_set(acrtc, ch, crtc_x, crtc_y, in_w, in_h, fmt);
-
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void ade_disable_channel(struct ade_plane *aplane,
-				struct ade_crtc *acrtc)
-{
-	u32 ch = aplane->ch;
-
-	DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
-
-	/*
-	 * when primary is disable, power is down
-	 * so no need to disable this channel.
-	 */
-	if (ch == PRIMARY_CH)
-		return;
-
-	/* disable read DMA */
-	ade_rdma_disable(acrtc, ch);
-
-	/* disable clip */
-	ade_clip_disable(acrtc, ch);
-
-	/* disable overlay routing */
-	ade_overlay_disable(acrtc, ch);
-
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static int ade_plane_prepare_fb(struct drm_plane *plane,
-				const struct drm_plane_state *new_state)
-{
-	DRM_DEBUG_DRIVER("enter.\n");
-	DRM_DEBUG_DRIVER("exit success.\n");
-	return 0;
-}
-
-static void ade_plane_cleanup_fb(struct drm_plane *plane,
-				 const struct drm_plane_state *old_state)
-{
-	DRM_DEBUG_DRIVER("enter.\n");
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static int ade_plane_atomic_check(struct drm_plane *plane,
-				  struct drm_plane_state *state)
-{
-	struct drm_framebuffer *fb = state->fb;
-	struct drm_crtc *crtc = state->crtc;
-	struct drm_crtc_state *crtc_state;
-	u32 src_x = state->src_x >> 16;
-	u32 src_y = state->src_y >> 16;
-	u32 src_w = state->src_w >> 16;
-	u32 src_h = state->src_h >> 16;
-	int crtc_x = state->crtc_x;
-	int crtc_y = state->crtc_y;
-	u32 crtc_w = state->crtc_w;
-	u32 crtc_h = state->crtc_h;
-
-	if (!crtc || !fb)
-		return 0;
-
-	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
-	if (IS_ERR(crtc_state))
-		return PTR_ERR(crtc_state);
-
-	if (src_w != crtc_w || src_h != crtc_h) {
-		DRM_ERROR("Scale not support!!!\n");
-		return -EINVAL;
-	}
-
-	if (src_x + src_w > fb->width ||
-	    src_y + src_h > fb->height)
-		return -EINVAL;
-
-	if (crtc_x < 0 || crtc_y < 0)
-		return -EINVAL;
-
-	if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
-	    crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
-		return -EINVAL;
-
-	return 0;
-}
-
-static void ade_plane_atomic_update(struct drm_plane *plane,
-				    struct drm_plane_state *old_state)
-{
-	struct drm_plane_state	*state	= plane->state;
-	struct ade_plane *aplane = to_ade_plane(plane);
-	struct ade_crtc *acrtc;
-
-	if (!state->crtc)
-		return;
-
-	acrtc = to_ade_crtc(state->crtc);
-	ade_update_channel(aplane, acrtc, state->fb,
-			   state->crtc_x, state->crtc_y,
-			   state->crtc_w, state->crtc_h,
-			   state->src_x >> 16, state->src_y >> 16,
-			   state->src_w >> 16, state->src_h >> 16);
-}
-
-static void ade_plane_atomic_disable(struct drm_plane *plane,
-				     struct drm_plane_state *old_state)
-{
-	struct ade_plane *aplane = to_ade_plane(plane);
-	struct ade_crtc *acrtc;
-
-	if (!old_state->crtc)
-		return;
-	acrtc = to_ade_crtc(old_state->crtc);
-	ade_disable_channel(aplane, acrtc);
-}
-
-static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
-	.prepare_fb = ade_plane_prepare_fb,
-	.cleanup_fb = ade_plane_cleanup_fb,
-	.atomic_check = ade_plane_atomic_check,
-	.atomic_update = ade_plane_atomic_update,
-	.atomic_disable = ade_plane_atomic_disable,
-};
-
-static struct drm_plane_funcs ade_plane_funcs = {
-	.update_plane	= drm_atomic_helper_update_plane,
-	.disable_plane	= drm_atomic_helper_disable_plane,
-	.set_property = drm_atomic_helper_plane_set_property,
-	.destroy = drm_plane_cleanup,
-	.reset = drm_atomic_helper_plane_reset,
-	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
-};
-
-static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
-			  enum drm_plane_type type)
-{
-	const u32 *fmts;
-	u32 fmts_cnt;
-	int ret = 0;
-
-	/* get  properties */
-	fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts);
-	if (ret)
-		return ret;
-
-	ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
-				       fmts, fmts_cnt, type);
-	if (ret) {
-		DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
-		return ret;
-	}
-
-	drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs);
-
-	return 0;
-}
-
-static int ade_bind(struct device *dev, struct device *master, void *data)
-{
-	struct ade_data *ade = dev_get_drvdata(dev);
-	struct ade_hw_ctx *ctx = &ade->ctx;
-	struct ade_crtc *acrtc = &ade->acrtc;
-	struct drm_device *drm_dev = (struct drm_device *)data;
-	struct ade_plane *aplane;
-	enum drm_plane_type type;
-	int ret;
-	int i;
-
-	/*
-	 * plane init
-	 * TODO: Now only support primary plane, overlay planes
-	 * need to do.
-	 */
-	for (i = 0; i < ADE_CH_NUM; i++) {
-		aplane = &ade->aplane[i];
-		aplane->ch = i;
-		aplane->ctx = ctx;
-		type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
-			DRM_PLANE_TYPE_OVERLAY;
-
-		ret = ade_plane_init(drm_dev, aplane, type);
-		if (ret)
-			return ret;
-	}
-
-	/* crtc init */
-	acrtc->ctx = ctx;
-	ret = ade_crtc_init(drm_dev, &acrtc->base,
-			    &ade->aplane[PRIMARY_CH].base);
-	if (ret)
-		return ret;
-
-	/* vblank irq init */
-	ret = request_irq(ctx->irq, ade_irq_handler, DRIVER_IRQ_SHARED,
-			  drm_dev->driver->name, acrtc);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static void ade_unbind(struct device *dev, struct device *master, void *data)
-{
-	/* do nothing */
-}
-
-static const struct component_ops ade_ops = {
-	.bind	= ade_bind,
-	.unbind	= ade_unbind,
-};
-
-static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx)
-{
-	struct resource *res;
-	struct device *dev;
-	struct device_node *np;
-	int ret;
-
-	dev = &pdev->dev;
-	np  = dev->of_node;
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ade_base");
-	ctx->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(ctx->base)) {
-		DRM_ERROR("failed to remap ade io base\n");
-		return  PTR_ERR(ctx->base);
-	}
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_base");
-	ctx->media_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(ctx->media_base)) {
-		DRM_ERROR("failed to remap media io base\n");
-		return PTR_ERR(ctx->media_base);
-	}
-
-	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_noc_base");
-	ctx->media_noc_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(ctx->media_noc_base)) {
-		DRM_ERROR("failed to remap media noc base\n");
-		return PTR_ERR(ctx->media_noc_base);
-	}
-
-	ctx->irq = platform_get_irq(pdev, 0);
-	if (ctx->irq < 0) {
-		DRM_ERROR("failed to parse the irq\n");
-		return -ENODEV;
-	}
-
-	ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
-	if (!ctx->ade_core_clk) {
-		DRM_ERROR("failed to parse the ADE_CORE\n");
-		return -ENODEV;
-	}
-	ctx->media_noc_clk = devm_clk_get(&pdev->dev,
-					"aclk_codec_jpeg_src");
-	if (!ctx->media_noc_clk) {
-		DRM_ERROR("failed to parse the CODEC_JPEG\n");
-	    return -ENODEV;
-	}
-	ctx->ade_pix_clk = devm_clk_get(&pdev->dev, "clk_ade_pix");
-	if (!ctx->ade_pix_clk) {
-		DRM_ERROR("failed to parse the ADE_PIX_SRC\n");
-	    return -ENODEV;
-	}
-
-	ret = of_property_read_u32(np, "ade_core_clk_rate",
-				   &ctx->ade_core_rate);
-	if (ret) {
-		DRM_ERROR("failed to parse the ade_core_clk_rate\n");
-	    return -ENODEV;
-	}
-	ret = of_property_read_u32(np, "media_noc_clk_rate",
-				   &ctx->media_noc_rate);
-	if (ret) {
-		DRM_ERROR("failed to parse the media_noc_clk_rate\n");
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static int ade_probe(struct platform_device *pdev)
-{
-	struct ade_data *ade;
-	int ret;
-
-	DRM_DEBUG_DRIVER("enter.\n");
-
-	ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
-	if (!ade) {
-		DRM_ERROR("failed to alloc ade_data\n");
-		return -ENOMEM;
-	}
-
-	ret = ade_dts_parse(pdev, &ade->ctx);
-	if (ret) {
-		DRM_ERROR("failed to parse dts!!\n");
-		return ret;
-	}
-
-	platform_set_drvdata(pdev, ade);
-
-	return component_add(&pdev->dev, &ade_ops);
-}
-
-static int ade_remove(struct platform_device *pdev)
-{
-	component_del(&pdev->dev, &ade_ops);
-
-	return 0;
-}
-
-static const struct of_device_id ade_of_match[] = {
-	{ .compatible = "hisilicon,hi6220-ade" },
-	{ }
-};
-MODULE_DEVICE_TABLE(of, ade_of_match);
-
-static struct platform_driver ade_driver = {
-	.probe = ade_probe,
-	.remove = ade_remove,
-	.driver = {
-		   .name = "hisi-ade",
-		   .owner = THIS_MODULE,
-		   .of_match_table = ade_of_match,
-	},
-};
-
-module_platform_driver(ade_driver);
-
-MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
-MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
-MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("Hisilicon DRM ADE(crtc/plane) Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
deleted file mode 100644
index 73f0938..0000000
--- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * 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.
- *
- */
-
-#ifndef __HISI_DRM_ADE_H__
-#define __HISI_DRM_ADE_H__
-
-int ade_enable_vblank(struct drm_device *dev, unsigned int pipe);
-void ade_disable_vblank(struct drm_device *dev, unsigned int pipe);
-
-#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
deleted file mode 100644
index 76eb711..0000000
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Hisilicon SoCs drm master driver
- *
- * Copyright (c) 2014-2015 Hisilicon Limited.
- * Author:
- *	Xinliang Liu <xinliang.liu@linaro.org>
- *	Xinliang Liu <z.liuxinliang@hisilicon.com>
- *	Xinwei Kong <kong.kongxinwei@hisilicon.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.
- *
- */
-
-#include <linux/of_platform.h>
-#include <linux/component.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
-
-#include "hisi_drm_ade.h"
-#include "hisi_drm_drv.h"
-
-#define DRIVER_NAME	"hisi-drm"
-
-static int hisi_drm_unload(struct drm_device *dev)
-{
-	struct hisi_drm_private *priv = dev->dev_private;
-
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-	if (priv->fbdev) {
-		drm_fbdev_cma_fini(priv->fbdev);
-		priv->fbdev = NULL;
-	}
-#endif
-	drm_kms_helper_poll_fini(dev);
-	drm_vblank_cleanup(dev);
-	drm_mode_config_cleanup(dev);
-	devm_kfree(dev->dev, priv);
-	dev->dev_private = NULL;
-
-	return 0;
-}
-
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-static void hisi_fbdev_output_poll_changed(struct drm_device *dev)
-{
-	struct hisi_drm_private *priv = dev->dev_private;
-
-	if (priv->fbdev) {
-		drm_fbdev_cma_hotplug_event(priv->fbdev);
-	} else {
-		priv->fbdev = drm_fbdev_cma_init(dev, 32,
-				dev->mode_config.num_crtc,
-				dev->mode_config.num_connector);
-		if (IS_ERR(priv->fbdev))
-			priv->fbdev = NULL;
-	}
-}
-#endif
-
-static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
-	.fb_create = drm_fb_cma_create,
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-	.output_poll_changed = hisi_fbdev_output_poll_changed,
-#endif
-	.atomic_check = drm_atomic_helper_check,
-	.atomic_commit = drm_atomic_helper_commit,
-};
-
-static void hisi_drm_mode_config_init(struct drm_device *dev)
-{
-	dev->mode_config.min_width = 0;
-	dev->mode_config.min_height = 0;
-
-	dev->mode_config.max_width = 2048;
-	dev->mode_config.max_height = 2048;
-
-	dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
-}
-
-static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
-{
-	struct hisi_drm_private *priv;
-	int ret;
-
-	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	dev->dev_private = priv;
-	dev_set_drvdata(dev->dev, dev);
-
-	/* dev->mode_config initialization */
-	drm_mode_config_init(dev);
-	hisi_drm_mode_config_init(dev);
-
-	/* bind and init sub drivers */
-	ret = component_bind_all(dev->dev, dev);
-	if (ret) {
-		DRM_ERROR("failed to bind all component.\n");
-		goto err_mode_config_cleanup;
-	}
-
-	/* vblank init */
-	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
-	if (ret) {
-		DRM_ERROR("failed to initialize vblank.\n");
-		goto err_unbind_all;
-	}
-	/* with irq_enabled = true, we can use the vblank feature. */
-	dev->irq_enabled = true;
-
-	/* reset all the states of crtc/plane/encoder/connector */
-	drm_mode_config_reset(dev);
-
-	/* init kms poll for handling hpd */
-	drm_kms_helper_poll_init(dev);
-
-	/* force detection after connectors init */
-	(void)drm_helper_hpd_irq_event(dev);
-
-	return 0;
-
-err_unbind_all:
-	component_unbind_all(dev->dev, dev);
-err_mode_config_cleanup:
-	drm_mode_config_cleanup(dev);
-	devm_kfree(dev->dev, priv);
-	dev->dev_private = NULL;
-
-	return ret;
-}
-
-static const struct file_operations hisi_drm_fops = {
-	.owner		= THIS_MODULE,
-	.open		= drm_open,
-	.release	= drm_release,
-	.unlocked_ioctl	= drm_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl	= drm_compat_ioctl,
-#endif
-	.poll		= drm_poll,
-	.read		= drm_read,
-	.llseek		= no_llseek,
-	.mmap		= drm_gem_cma_mmap,
-};
-
-static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
-					     struct drm_gem_object *obj,
-					     int flags)
-{
-	/* we want to be able to write in mmapped buffer */
-	flags |= O_RDWR;
-	return drm_gem_prime_export(dev, obj, flags);
-}
-
-static int hisi_gem_cma_dumb_create(struct drm_file *file,
-				    struct drm_device *dev,
-				    struct drm_mode_create_dumb *args)
-{
-	int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
-
-	/* mali gpu need pitch 8 bytes alignment for 32bpp */
-	args->pitch = roundup(min_pitch, 8);
-
-	return drm_gem_cma_dumb_create_internal(file, dev, args);
-}
-
-static struct drm_driver hisi_drm_driver = {
-	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
-				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
-	.load			= hisi_drm_load,
-	.unload                 = hisi_drm_unload,
-	.fops			= &hisi_drm_fops,
-	.set_busid		= drm_platform_set_busid,
-
-	.gem_free_object	= drm_gem_cma_free_object,
-	.gem_vm_ops		= &drm_gem_cma_vm_ops,
-	.dumb_create		= hisi_gem_cma_dumb_create,
-	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
-	.dumb_destroy		= drm_gem_dumb_destroy,
-
-	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
-	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
-	.gem_prime_export	= hisi_gem_prime_export,
-	.gem_prime_import	= drm_gem_prime_import,
-	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
-	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
-	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
-	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
-	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
-
-	.get_vblank_counter	= drm_vblank_count,
-	.enable_vblank		= ade_enable_vblank,
-	.disable_vblank		= ade_disable_vblank,
-
-	.name			= "hisi",
-	.desc			= "Hisilicon SoCs' DRM Driver",
-	.date			= "20150718",
-	.major			= 1,
-	.minor			= 0,
-};
-
-static int compare_of(struct device *dev, void *data)
-{
-	return dev->of_node == data;
-}
-
-static int hisi_drm_bind(struct device *dev)
-{
-	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
-	return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
-}
-
-static void hisi_drm_unbind(struct device *dev)
-{
-	drm_put_dev(dev_get_drvdata(dev));
-}
-
-static const struct component_master_ops hisi_drm_ops = {
-	.bind = hisi_drm_bind,
-	.unbind = hisi_drm_unbind,
-};
-
-static int hisi_drm_platform_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct device_node *node = dev->of_node;
-	struct device_node *child_np;
-	struct component_match *match = NULL;
-
-	of_platform_populate(node, NULL, NULL, dev);
-
-	child_np = of_get_next_available_child(node, NULL);
-	while (child_np) {
-		component_match_add(dev, &match, compare_of, child_np);
-		of_node_put(child_np);
-		child_np = of_get_next_available_child(node, child_np);
-	}
-
-	return component_master_add_with_match(dev, &hisi_drm_ops, match);
-
-	return 0;
-}
-
-static int hisi_drm_platform_remove(struct platform_device *pdev)
-{
-	component_master_del(&pdev->dev, &hisi_drm_ops);
-	of_platform_depopulate(&pdev->dev);
-	return 0;
-}
-
-static const struct of_device_id hisi_drm_dt_ids[] = {
-	{ .compatible = "hisilicon,hi6220-dss", },
-	{ /* end node */ },
-};
-MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
-
-static struct platform_driver hisi_drm_platform_driver = {
-	.probe = hisi_drm_platform_probe,
-	.remove = hisi_drm_platform_remove,
-	.driver = {
-		.owner = THIS_MODULE,
-		.name = DRIVER_NAME,
-		.of_match_table = hisi_drm_dt_ids,
-	},
-};
-
-module_platform_driver(hisi_drm_platform_driver);
-
-MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
-MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
-MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("hisilicon SoCs' DRM master driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
deleted file mode 100644
index 984121f..0000000
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * 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.
- *
- */
-
-#ifndef __HISI_DRM_DRV_H__
-#define __HISI_DRM_DRV_H__
-
-struct hisi_drm_private {
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-	struct drm_fbdev_cma *fbdev;
-#endif
-};
-
-#endif /* __HISI_DRM_DRV_H__ */
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
deleted file mode 100644
index 83c5445..0000000
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- * Hisilicon hi6220 SoC dsi driver
- *
- * Copyright (c) 2014-2015 Hisilicon Limited.
- * Author:
- *	Xinliang Liu <xinliang.liu@linaro.org>
- *	Xinliang Liu <z.liuxinliang@hisilicon.com>
- *	Xinwei Kong <kong.kongxinwei@hisilicon.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.
- *
- */
-
-#include <linux/clk.h>
-#include <linux/component.h>
-#include <linux/of_graph.h>
-
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_mipi_dsi.h>
-#include <drm/drm_encoder_slave.h>
-#include <drm/drm_atomic_helper.h>
-
-#include "hisi_dsi_reg.h"
-
-#define MAX_TX_ESC_CLK		   (10)
-#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
-#define DEFAULT_MIPI_CLK_RATE   19200000
-#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
-#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
-	      phy->lane_byte_clk_kHz)))
-
-#define encoder_to_dsi(encoder) \
-	container_of(encoder, struct hisi_dsi, encoder)
-#define host_to_dsi(host) \
-	container_of(host, struct hisi_dsi, host)
-
-struct mipi_phy_register {
-	u32 clk_t_lpx;
-	u32 clk_t_hs_prepare;
-	u32 clk_t_hs_zero;
-	u32 clk_t_hs_trial;
-	u32 clk_t_wakeup;
-	u32 data_t_lpx;
-	u32 data_t_hs_prepare;
-	u32 data_t_hs_zero;
-	u32 data_t_hs_trial;
-	u32 data_t_ta_go;
-	u32 data_t_ta_get;
-	u32 data_t_wakeup;
-	u32 hstx_ckg_sel;
-	u32 pll_fbd_div5f;
-	u32 pll_fbd_div1f;
-	u32 pll_fbd_2p;
-	u32 pll_enbwt;
-	u32 pll_fbd_p;
-	u32 pll_fbd_s;
-	u32 pll_pre_div1p;
-	u32 pll_pre_p;
-	u32 pll_vco_750M;
-	u32 pll_lpf_rs;
-	u32 pll_lpf_cs;
-	u32 clklp2hs_time;
-	u32 clkhs2lp_time;
-	u32 lp2hs_time;
-	u32 hs2lp_time;
-	u32 clk_to_data_delay;
-	u32 data_to_clk_delay;
-	u32 lane_byte_clk_kHz;
-	u32 clk_division;
-};
-
-struct dsi_hw_ctx {
-	void __iomem *base;
-	struct clk *dsi_cfg_clk;
-};
-
-struct hisi_dsi {
-	struct drm_encoder encoder;
-	struct drm_bridge *bridge;
-	struct mipi_dsi_host host;
-	struct drm_display_mode cur_mode;
-	struct dsi_hw_ctx *ctx;
-	struct mipi_phy_register phy;
-
-	u32 lanes;
-	enum mipi_dsi_pixel_format format;
-	unsigned long mode_flags;
-	bool enable;
-};
-
-struct dsi_data {
-	struct hisi_dsi dsi;
-	struct dsi_hw_ctx ctx;
-};
-
-struct dsi_phy_seq_info {
-	u32 min_range_kHz;
-	u32 max_range_kHz;
-	u32 pll_vco_750M;
-	u32 hstx_ckg_sel;
-};
-
-static const struct dsi_phy_seq_info dphy_seq_info[] = {
-	{   46000,    62000,   1,    7 },
-	{   62000,    93000,   0,    7 },
-	{   93000,   125000,   1,    6 },
-	{  125000,   187000,   0,    6 },
-	{  187000,   250000,   1,    5 },
-	{  250000,   375000,   0,    5 },
-	{  375000,   500000,   1,    4 },
-	{  500000,   750000,   0,    4 },
-	{  750000,  1000000,   1,    0 },
-	{ 1000000,  1500000,   0,    0 }
-};
-
-static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
-					     struct mipi_phy_register *phy)
-{
-	u32 ui = 0;
-	u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
-	u32 i = 0;
-	u32 q_pll = 1;
-	u32 m_pll = 0;
-	u32 n_pll = 0;
-	u32 r_pll = 1;
-	u32 m_n = 0;
-	u32 m_n_int = 0;
-	u64 f_kHz;
-	u64 temp;
-	u64 tmp_kHz = phy_freq_kHz;
-
-	do {
-		f_kHz = tmp_kHz;
-
-		/* Find the PLL clock range from the table */
-		for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
-			if (f_kHz > dphy_seq_info[i].min_range_kHz &&
-			    f_kHz <= dphy_seq_info[i].max_range_kHz)
-				break;
-
-		if (i == ARRAY_SIZE(dphy_seq_info)) {
-			DRM_ERROR("%lldkHz out of range\n", f_kHz);
-			return;
-		}
-
-		phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
-		phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
-
-		if (phy->hstx_ckg_sel <= 7 &&
-		    phy->hstx_ckg_sel >= 4)
-			q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
-
-		temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
-		m_n_int = temp / (u64)1000000000;
-		m_n = (temp % (u64)1000000000) / (u64)100000000;
-
-		if (m_n_int % 2 == 0) {
-			if (m_n * 6 >= 50) {
-				n_pll = 2;
-				m_pll = (m_n_int + 1) * n_pll;
-			} else if (m_n * 6 >= 30) {
-				n_pll = 3;
-				m_pll = m_n_int * n_pll + 2;
-			} else {
-				n_pll = 1;
-				m_pll = m_n_int * n_pll;
-			}
-		} else {
-			if (m_n * 6 >= 50) {
-				n_pll = 1;
-				m_pll = (m_n_int + 1) * n_pll;
-			} else if (m_n * 6 >= 30) {
-				n_pll = 1;
-				m_pll = (m_n_int + 1) * n_pll;
-			} else if (m_n * 6 >= 10) {
-				n_pll = 3;
-				m_pll = m_n_int * n_pll + 1;
-			} else {
-				n_pll = 2;
-				m_pll = m_n_int * n_pll;
-			}
-		}
-
-		if (n_pll == 1) {
-			phy->pll_fbd_p = 0;
-			phy->pll_pre_div1p = 1;
-		} else {
-			phy->pll_fbd_p = n_pll;
-			phy->pll_pre_div1p = 0;
-		}
-
-		if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
-			r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
-
-		if (m_pll == 2) {
-			phy->pll_pre_p = 0;
-			phy->pll_fbd_s = 0;
-			phy->pll_fbd_div1f = 0;
-			phy->pll_fbd_div5f = 1;
-		} else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
-			phy->pll_pre_p = m_pll / (2 * r_pll);
-			phy->pll_fbd_s = 0;
-			phy->pll_fbd_div1f = 1;
-			phy->pll_fbd_div5f = 0;
-		} else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
-			if (((m_pll / (2 * r_pll)) % 2) == 0) {
-				phy->pll_pre_p =
-					(m_pll / (2 * r_pll)) / 2 - 1;
-				phy->pll_fbd_s =
-					(m_pll / (2 * r_pll)) % 2 + 2;
-			} else {
-				phy->pll_pre_p =
-					(m_pll / (2 * r_pll)) / 2;
-				phy->pll_fbd_s =
-					(m_pll / (2 * r_pll)) % 2;
-			}
-			phy->pll_fbd_div1f = 0;
-			phy->pll_fbd_div5f = 0;
-		} else {
-			phy->pll_pre_p = 0;
-			phy->pll_fbd_s = 0;
-			phy->pll_fbd_div1f = 0;
-			phy->pll_fbd_div5f = 1;
-		}
-
-		f_kHz = (u64)1000000000 * (u64)m_pll /
-			((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
-
-		if (f_kHz >= phy_freq_kHz)
-			break;
-
-		tmp_kHz += 10;
-
-	} while (1);
-
-	ui = 1000000 / f_kHz;
-
-	phy->clk_t_lpx = ROUND(50, 8 * ui);
-	phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
-
-	phy->clk_t_hs_zero = ROUND(262, 8 * ui);
-	phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
-	phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
-	if (phy->clk_t_wakeup > 0xff)
-		phy->clk_t_wakeup = 0xff;
-	phy->data_t_wakeup = phy->clk_t_wakeup;
-	phy->data_t_lpx = phy->clk_t_lpx;
-	phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
-	phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
-	phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
-	phy->data_t_ta_go = 3;
-	phy->data_t_ta_get = 4;
-
-	phy->pll_enbwt = 1;
-	phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
-	phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
-	phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
-	phy->hs2lp_time = phy->clkhs2lp_time;
-	phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
-	phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
-				phy->clkhs2lp_time;
-
-	phy->lane_byte_clk_kHz = f_kHz / 8;
-	phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
-	if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
-		phy->clk_division++;
-}
-
-static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
-{
-	u32 val;
-
-	/* TODO: only support RGB888 now, to support more */
-	switch (format) {
-	case MIPI_DSI_FMT_RGB888:
-		val = DSI_24BITS_1;
-		break;
-	default:
-		val = DSI_24BITS_1;
-		break;
-	}
-
-	return val;
-}
-
-static void dsi_mipi_phy_clks(void __iomem *base,
-			      struct mipi_phy_register *phy,
-			      u32 lanes)
-{
-	u32 delay_count;
-	bool is_ready;
-	u32 val;
-	u32 i;
-
-	/* set lanes value */
-	val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
-	writel(val, base + PHY_IF_CFG);
-
-	/* set phy clk division */
-	val = readl(base + CLKMGR_CFG) | phy->clk_division;
-	writel(val, base + CLKMGR_CFG);
-
-	/* clean up phy set param */
-	writel(0, base + PHY_RSTZ);
-	writel(0, base + PHY_TST_CTRL0);
-	writel(1, base + PHY_TST_CTRL0);
-	writel(0, base + PHY_TST_CTRL0);
-
-	/* clock lane Timing control - TLPX */
-	dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
-
-	/* clock lane Timing control - THS-PREPARE */
-	dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
-
-	/* clock lane Timing control - THS-ZERO */
-	dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
-
-	/* clock lane Timing control - THS-TRAIL */
-	dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
-
-	/* clock lane Timing control - TWAKEUP */
-	dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
-
-	/* data lane */
-	for (i = 0; i < lanes; i++) {
-		/* Timing control - TLPX*/
-		dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
-
-		/* Timing control - THS-PREPARE */
-		dsi_phy_tst_set(base, 0x10021 + (i << 4),
-				phy->data_t_hs_prepare);
-
-		/* Timing control - THS-ZERO */
-		dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
-
-		/* Timing control - THS-TRAIL */
-		dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
-
-		/* Timing control - TTA-GO */
-		dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
-
-		/* Timing control - TTA-GET */
-		dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
-
-		/*  Timing control - TWAKEUP */
-		dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
-	}
-
-	/* physical configuration I  */
-	dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
-
-	/* physical configuration pll II  */
-	val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
-				(phy->pll_fbd_2p << 1) + phy->pll_enbwt;
-	dsi_phy_tst_set(base, 0x10063, val);
-
-	/* physical configuration pll II  */
-	dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
-
-	/* physical configuration pll III  */
-	dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
-
-	/*physical configuration pll IV*/
-	val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
-	dsi_phy_tst_set(base, 0x10066, val);
-
-	/*physical configuration pll V*/
-	val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
-					phy->pll_lpf_cs + BIT(5);
-	dsi_phy_tst_set(base, 0x10067, val);
-
-	writel(BIT(2), base + PHY_RSTZ);
-	udelay(1);
-	writel(BIT(2) | BIT(0), base + PHY_RSTZ);
-	udelay(1);
-	writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
-	usleep_range(1000, 1500);
-
-	/* wait for phy's clock ready */
-	delay_count = 0;
-	is_ready = false;
-	while (1) {
-		val = readl(base +  PHY_STATUS);
-		if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
-			is_ready = (delay_count < 100) ? true : false;
-			delay_count = 0;
-			break;
-		}
-
-		udelay(1);
-		++delay_count;
-	}
-
-	if (!is_ready)
-		DRM_INFO("phylock and phystopstateclklane is not ready.\n");
-}
-
-static void dsi_set_mode_timing(void __iomem *base,
-				struct mipi_phy_register *phy,
-				struct drm_display_mode *mode,
-				enum mipi_dsi_pixel_format format)
-{
-	u32 hfp, hbp, hsw, vfp, vbp, vsw;
-	u32 hline_time;
-	u32 hsa_time;
-	u32 hbp_time;
-	u32 pixel_clk_kHz;
-	int htot, vtot;
-	u32 val;
-
-	/* DSI color coding setting */
-	val = dsi_get_dpi_color_coding(format);
-	writel(val, base + DPI_COLOR_CODING);
-
-	/* DSI format and pol setting */
-	val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
-	val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
-	writel(val, base +  DPI_CFG_POL);
-
-	/*
-	 * The DSI IP accepts vertical timing using lines as normal,
-	 * but horizontal timing is a mixture of pixel-clocks for the
-	 * active region and byte-lane clocks for the blanking-related
-	 * timings.  hfp is specified as the total hline_time in byte-
-	 * lane clocks minus hsa, hbp and active.
-	 */
-	pixel_clk_kHz = mode->clock;
-	htot = mode->htotal;
-	vtot = mode->vtotal;
-	hfp = mode->hsync_start - mode->hdisplay;
-	hbp = mode->htotal - mode->hsync_end;
-	hsw = mode->hsync_end - mode->hsync_start;
-	vfp = mode->vsync_start - mode->vdisplay;
-	vbp = mode->vtotal - mode->vsync_end;
-	vsw = mode->vsync_end - mode->vsync_start;
-	if (vsw > 15) {
-		DRM_INFO("vsw exceeded 15\n");
-		vtot -= vsw - 15;
-		vsw = 15;
-	}
-
-	hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
-	hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
-	hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
-		      pixel_clk_kHz;
-
-	if ((R(hline_time) / 1000) > htot) {
-		DRM_INFO("--: hline_time=%d\n", hline_time);
-		hline_time--;
-	}
-
-	if ((R(hline_time) / 1000) < htot) {
-		DRM_INFO("++: hline_time=%d\n", hline_time);
-		hline_time++;
-	}
-
-	/* all specified in byte-lane clocks */
-	writel(hsa_time, base + VID_HSA_TIME);
-	writel(hbp_time, base + VID_HBP_TIME);
-	writel(hline_time, base + VID_HLINE_TIME);
-
-	writel(vsw, base + VID_VSA_LINES);
-	writel(vbp, base + VID_VBP_LINES);
-	writel(vfp, base + VID_VFP_LINES);
-	writel(mode->vdisplay, base + VID_VACTIVE_LINES);
-	writel(mode->hdisplay, base + VID_PKT_SIZE);
-}
-
-static void dsi_set_video_mode_type(void __iomem *base,
-				    struct mipi_phy_register *phy,
-				    unsigned long flags)
-{
-	u32 val;
-	u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
-		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
-	u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
-		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
-	u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
-
-	/*
-	 * choose video type
-	 */
-	if ((flags & mode_mask) == non_burst_sync_pulse)
-		val = DSI_NON_BURST_SYNC_PULSES;
-	else if ((flags & mode_mask) == non_burst_sync_event)
-		val = DSI_NON_BURST_SYNC_EVENTS;
-	else
-		val = DSI_BURST_SYNC_PULSES_1;
-
-	writel(val, base + VID_MODE_CFG);
-	/* TODO: to support LCD panel need to set LP command transfer */
-}
-
-static void dsi_mipi_init(struct hisi_dsi *dsi)
-{
-	struct dsi_hw_ctx *ctx = dsi->ctx;
-	struct mipi_phy_register *phy = &dsi->phy;
-	struct drm_display_mode *mode = &dsi->cur_mode;
-	void __iomem *base = ctx->base;
-	u32 dphy_freq_kHz;
-
-	/* count phy params */
-	dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
-	set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
-
-	/* reset Core */
-	writel(0, base + PWR_UP);
-
-	/* set phy clocks */
-	dsi_mipi_phy_clks(base, phy, dsi->lanes);
-
-	/* set dsi mode */
-	dsi_set_mode_timing(base, phy, mode, dsi->format);
-
-	/* set video mode type and low power */
-	dsi_set_video_mode_type(base, phy, dsi->mode_flags);
-
-	/* DSI and D-PHY Initialization */
-	writel(DSI_VIDEO_MODE, base + MODE_CFG);
-	writel(BIT(0), base + LPCLK_CTRL);
-	writel(BIT(0), base + PWR_UP);
-
-	DRM_INFO("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
-			dsi->lanes, mode->clock, phy->lane_byte_clk_kHz);
-}
-
-static void dsi_encoder_disable(struct drm_encoder *encoder)
-{
-	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
-	struct dsi_hw_ctx *ctx = dsi->ctx;
-	void __iomem *base = ctx->base;
-
-	DRM_DEBUG_DRIVER("enter\n");
-	if (!dsi->enable)
-		return;
-
-	writel(0, base + PWR_UP);
-	writel(0, base + LPCLK_CTRL);
-	writel(0, base + PHY_RSTZ);
-	clk_disable_unprepare(ctx->dsi_cfg_clk);
-
-	dsi->enable = false;
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void dsi_encoder_enable(struct drm_encoder *encoder)
-{
-	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
-	struct dsi_hw_ctx *ctx = dsi->ctx;
-	int ret;
-
-	DRM_DEBUG_DRIVER("enter.\n");
-	if (dsi->enable)
-		return;
-
-	/* mipi dphy clock enable */
-	ret = clk_prepare_enable(ctx->dsi_cfg_clk);
-	if (ret) {
-		DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
-		return;
-	}
-
-	dsi_mipi_init(dsi);
-
-	dsi->enable = true;
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static void dsi_encoder_mode_set(struct drm_encoder *encoder,
-				 struct drm_display_mode *mode,
-				 struct drm_display_mode *adj_mode)
-{
-	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
-
-	DRM_DEBUG_DRIVER("enter.\n");
-	drm_mode_copy(&dsi->cur_mode, adj_mode);
-	DRM_DEBUG_DRIVER("exit success.\n");
-}
-
-static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
-				    struct drm_crtc_state *crtc_state,
-				    struct drm_connector_state *conn_state)
-{
-	struct drm_display_mode *mode = &crtc_state->mode;
-
-	DRM_DEBUG_DRIVER("enter.\n");
-	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
-		DRM_ERROR("not support INTERLACE mode\n");
-		return MODE_NO_INTERLACE;
-	}
-
-	/* pixel clock support range is (1190494208/64, 1190494208)Hz */
-	if (mode->clock < 18602 || mode->clock > 1190494) {
-		DRM_ERROR("mode clock not support\n");
-		return MODE_CLOCK_RANGE;
-	}
-
-	DRM_DEBUG_DRIVER("exit success.\n");
-	return 0;
-}
-
-static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
-	.atomic_check	= dsi_encoder_atomic_check,
-	.mode_set	= dsi_encoder_mode_set,
-	.enable		= dsi_encoder_enable,
-	.disable	= dsi_encoder_disable
-};
-
-static const struct drm_encoder_funcs hisi_encoder_funcs = {
-	.destroy = drm_encoder_cleanup,
-};
-
-static int hisi_drm_encoder_init(struct drm_device *dev,
-				 struct drm_encoder *encoder)
-{
-	int ret;
-
-	encoder->possible_crtcs = 1;
-	ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
-			       DRM_MODE_ENCODER_TMDS);
-	if (ret) {
-		DRM_ERROR("failed to init dsi encoder\n");
-		return ret;
-	}
-
-	drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
-
-	return 0;
-}
-
-static int dsi_host_attach(struct mipi_dsi_host *host,
-			   struct mipi_dsi_device *mdsi)
-{
-	struct hisi_dsi *dsi = host_to_dsi(host);
-
-	if (mdsi->lanes < 1 || mdsi->lanes > 4) {
-		DRM_ERROR("dsi device params invalid\n");
-		return -EINVAL;
-	}
-
-	dsi->lanes = mdsi->lanes;
-	dsi->format = mdsi->format;
-	dsi->mode_flags = mdsi->mode_flags;
-
-	return 0;
-}
-
-static int dsi_host_detach(struct mipi_dsi_host *host,
-			   struct mipi_dsi_device *mdsi)
-{
-	/* do nothing */
-	return 0;
-}
-
-static struct mipi_dsi_host_ops dsi_host_ops = {
-	.attach = dsi_host_attach,
-	.detach = dsi_host_detach,
-};
-
-static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
-{
-	struct mipi_dsi_host *host = &dsi->host;
-	int ret;
-
-	host->dev = dev;
-	host->ops = &dsi_host_ops;
-	ret = mipi_dsi_host_register(host);
-	if (ret) {
-		DRM_ERROR("failed to register dsi host\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static int dsi_bridge_init(struct drm_device *dev, struct hisi_dsi *dsi)
-{
-	struct drm_encoder *encoder = &dsi->encoder;
-	struct drm_bridge *bridge = dsi->bridge;
-	int ret;
-
-	/* associate the bridge to dsi encoder */
-	encoder->bridge = bridge;
-	bridge->encoder = encoder;
-
-	ret = drm_bridge_attach(dev, bridge);
-	if (ret) {
-		DRM_ERROR("failed to attach exteranl bridge\n");
-		return ret;
-	}
-
-	return 0;
-}
-
-static int dsi_bind(struct device *dev, struct device *master, void *data)
-{
-	struct dsi_data *ddata = dev_get_drvdata(dev);
-	struct hisi_dsi *dsi = &ddata->dsi;
-	struct drm_device *drm_dev = data;
-	int ret;
-
-	ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
-	if (ret)
-		return ret;
-
-	ret = dsi_host_init(dev, dsi);
-	if (ret)
-		return ret;
-
-	ret = dsi_bridge_init(drm_dev, dsi);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-static void dsi_unbind(struct device *dev, struct device *master, void *data)
-{
-	/* do nothing */
-}
-
-static const struct component_ops dsi_ops = {
-	.bind	= dsi_bind,
-	.unbind	= dsi_unbind,
-};
-
-static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
-{
-	struct dsi_hw_ctx *ctx = dsi->ctx;
-	struct device_node *np = pdev->dev.of_node;
-	struct device_node *endpoint, *bridge_node;
-	struct drm_bridge *bridge;
-	struct resource *res;
-
-	/*
-	 * Get the endpoint node. In our case, dsi has one output port
-	 * to which the external HDMI bridge is connected.
-	 */
-	endpoint = of_graph_get_next_endpoint(np, NULL);
-	if (!endpoint) {
-		DRM_ERROR("no valid endpoint node\n");
-		return -ENODEV;
-	}
-	of_node_put(endpoint);
-
-	bridge_node = of_graph_get_remote_port_parent(endpoint);
-	if (!bridge_node) {
-		DRM_ERROR("no valid bridge node\n");
-		return -ENODEV;
-	}
-	of_node_put(bridge_node);
-
-	bridge = of_drm_find_bridge(bridge_node);
-	if (!bridge) {
-		DRM_INFO("wait for external HDMI bridge driver.\n");
-		return -EPROBE_DEFER;
-	}
-	dsi->bridge = bridge;
-
-	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
-	if (IS_ERR(ctx->dsi_cfg_clk)) {
-		DRM_ERROR("failed to get dsi plck clock\n");
-		return PTR_ERR(ctx->dsi_cfg_clk);
-	}
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	ctx->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(ctx->base)) {
-		DRM_ERROR("failed to remap dsi io region\n");
-		return PTR_ERR(ctx->base);
-	}
-
-	return 0;
-}
-
-static int dsi_probe(struct platform_device *pdev)
-{
-	struct dsi_data *data;
-	struct hisi_dsi *dsi;
-	struct dsi_hw_ctx *ctx;
-	int ret;
-
-	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
-	if (!data) {
-		DRM_ERROR("failed to allocate dsi data.\n");
-		return -ENOMEM;
-	}
-	dsi = &data->dsi;
-	ctx = &data->ctx;
-	dsi->ctx = ctx;
-
-	ret = dsi_parse_dt(pdev, dsi);
-	if (ret)
-		return ret;
-
-	platform_set_drvdata(pdev, data);
-
-	return component_add(&pdev->dev, &dsi_ops);
-}
-
-static int dsi_remove(struct platform_device *pdev)
-{
-	component_del(&pdev->dev, &dsi_ops);
-
-	return 0;
-}
-
-static const struct of_device_id dsi_of_match[] = {
-	{.compatible = "hisilicon,hi6220-dsi"},
-	{ }
-};
-MODULE_DEVICE_TABLE(of, dsi_of_match);
-
-static struct platform_driver dsi_driver = {
-	.probe = dsi_probe,
-	.remove = dsi_remove,
-	.driver = {
-		.name = "hisi-dsi",
-		.owner = THIS_MODULE,
-		.of_match_table = dsi_of_match,
-	},
-};
-
-module_platform_driver(dsi_driver);
-
-MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
-MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
-MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
-MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
deleted file mode 100644
index db8f9df..0000000
--- a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2014-2015 Hisilicon Limited.
- *
- * 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.
- *
- */
-
-#ifndef __HISI_DSI_REG_H__
-#define __HISI_DSI_REG_H__
-
-/*
- * regs
- */
-#define  PWR_UP                  (0x4)   /* Core power-up */
-#define  PHY_IF_CFG              (0xA4)  /* D-PHY interface configuration */
-#define  CLKMGR_CFG              (0x8)   /* the internal clock dividers */
-#define  PHY_RSTZ                (0xA0)  /* D-PHY reset control */
-#define  PHY_TST_CTRL0           (0xB4)  /* D-PHY test interface control 0 */
-#define  PHY_TST_CTRL1           (0xB8)  /* D-PHY test interface control 1 */
-#define  DPI_VCID                (0xC)   /* DPI virtual channel id */
-#define  DPI_COLOR_CODING        (0x10)  /* DPI color coding */
-#define  DPI_CFG_POL             (0x14)  /* DPI polarity configuration */
-#define  VID_HSA_TIME            (0x48)  /* Horizontal Sync Active time */
-#define  VID_HBP_TIME            (0x4C)  /* Horizontal Back Porch time */
-#define  VID_HLINE_TIME          (0x50)  /* Line time */
-#define  VID_VSA_LINES           (0x54)  /* Vertical Sync Active period */
-#define  VID_VBP_LINES           (0x58)  /* Vertical Back Porch period */
-#define  VID_VFP_LINES           (0x5C)  /* Vertical Front Porch period */
-#define  VID_VACTIVE_LINES       (0x60)  /* Vertical resolution */
-#define  VID_PKT_SIZE            (0x3C)  /* Video packet size */
-#define  VID_MODE_CFG            (0x38)  /* Video mode configuration */
-#define  DPI_LP_CMD_TIM          (0x18)  /* Low-power command timing config */
-#define  PHY_TMR_CFG             (0x9C)  /* Data lanes timing configuration */
-#define  BTA_TO_CNT              (0x8C)  /* Response timeout definition */
-#define  PHY_TMR_LPCLK_CFG       (0x98)  /* clock lane timing configuration */
-#define  CLK_DATA_TMR_CFG        (0xCC)
-#define  LPCLK_CTRL              (0x94)  /* Low-power in clock lane */
-#define  PCKHDL_CFG              (0x2C)  /* Packet handler configuration */
-#define  EDPI_CMD_SIZE           (0x64)  /* Size for eDPI packets */
-#define  MODE_CFG                (0x34)  /* Video or Command mode selection */
-#define  PHY_STATUS              (0xB0)  /* D-PHY PPI status interface */
-
-#define	PHY_STOP_WAIT_TIME      (0x30)
-
-/*
- * regs relevant enum
- */
-enum dpi_color_coding {
-	DSI_24BITS_1 = 5,
-};
-
-enum dsi_video_mode_type {
-	DSI_NON_BURST_SYNC_PULSES = 0,
-	DSI_NON_BURST_SYNC_EVENTS,
-	DSI_BURST_SYNC_PULSES_1,
-	DSI_BURST_SYNC_PULSES_2
-};
-
-enum dsi_work_mode {
-	DSI_VIDEO_MODE = 0,
-	DSI_COMMAND_MODE
-};
-
-/*
- * regs Write/Read functions
- */
-static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
-{
-	writel(reg, base + PHY_TST_CTRL1);
-	/* reg addr written at first */
-	wmb();
-	writel(0x02, base + PHY_TST_CTRL0);
-	/* cmd1 sent for write */
-	wmb();
-	writel(0x00, base + PHY_TST_CTRL0);
-	/* cmd2 sent for write */
-	wmb();
-	writel(val, base + PHY_TST_CTRL1);
-	/* Then write data */
-	wmb();
-	writel(0x02, base + PHY_TST_CTRL0);
-	/* cmd2 sent for write */
-	wmb();
-	writel(0x00, base + PHY_TST_CTRL0);
-}
-
-#endif /* __HISI_DRM_DSI_H__ */
diff --git a/drivers/gpu/drm/hisilicon/kirin/Kconfig b/drivers/gpu/drm/hisilicon/kirin/Kconfig
new file mode 100644
index 0000000..5dcbc8d
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/Kconfig
@@ -0,0 +1,19 @@
+config DRM_HISI_KIRIN
+	tristate "DRM Support for Hisilicon Kirin series SoCs Platform"
+	depends on DRM && OF && ARM64
+	select DRM_KMS_HELPER
+	select DRM_GEM_CMA_HELPER
+	select DRM_KMS_CMA_HELPER
+	help
+	  Choose this option if you have a hisilicon Kirin chipsets(hi6220).
+	  If M is selected the module will be called kirin-drm.
+
+config HISI_KIRIN_DW_DSI
+	tristate "HiSilicon Kirin specific extensions for Synopsys DW MIPI DSI"
+	depends on DRM_HISI_KIRIN
+	select DRM_MIPI_DSI
+	select DRM_PANEL
+	help
+	 This selects support for HiSilicon Kirin SoC specific extensions for
+	 the Synopsys DesignWare DSI driver. If you want to enable MIPI DSI on
+	 hi6220 based SoC, you should selet this option.
diff --git a/drivers/gpu/drm/hisilicon/kirin/Makefile b/drivers/gpu/drm/hisilicon/kirin/Makefile
new file mode 100644
index 0000000..cdf6158
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/Makefile
@@ -0,0 +1,6 @@
+kirin-drm-y := kirin_drm_drv.o \
+	       kirin_drm_ade.o
+
+obj-$(CONFIG_DRM_HISI_KIRIN) += kirin-drm.o
+
+obj-$(CONFIG_HISI_KIRIN_DW_DSI) += dw_drm_dsi.o
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
new file mode 100644
index 0000000..fe94ccb
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -0,0 +1,832 @@
+/*
+ * Hisilicon hi6220 SoC dsi driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.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.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "dw_dsi_reg.h"
+
+#define MAX_TX_ESC_CLK		   (10)
+#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
+#define DEFAULT_MIPI_CLK_RATE   19200000
+#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
+#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
+	      phy->lane_byte_clk_kHz)))
+
+#define encoder_to_dsi(encoder) \
+	container_of(encoder, struct hisi_dsi, encoder)
+#define host_to_dsi(host) \
+	container_of(host, struct hisi_dsi, host)
+
+struct mipi_phy_register {
+	u32 clk_t_lpx;
+	u32 clk_t_hs_prepare;
+	u32 clk_t_hs_zero;
+	u32 clk_t_hs_trial;
+	u32 clk_t_wakeup;
+	u32 data_t_lpx;
+	u32 data_t_hs_prepare;
+	u32 data_t_hs_zero;
+	u32 data_t_hs_trial;
+	u32 data_t_ta_go;
+	u32 data_t_ta_get;
+	u32 data_t_wakeup;
+	u32 hstx_ckg_sel;
+	u32 pll_fbd_div5f;
+	u32 pll_fbd_div1f;
+	u32 pll_fbd_2p;
+	u32 pll_enbwt;
+	u32 pll_fbd_p;
+	u32 pll_fbd_s;
+	u32 pll_pre_div1p;
+	u32 pll_pre_p;
+	u32 pll_vco_750M;
+	u32 pll_lpf_rs;
+	u32 pll_lpf_cs;
+	u32 clklp2hs_time;
+	u32 clkhs2lp_time;
+	u32 lp2hs_time;
+	u32 hs2lp_time;
+	u32 clk_to_data_delay;
+	u32 data_to_clk_delay;
+	u32 lane_byte_clk_kHz;
+	u32 clk_division;
+};
+
+struct dsi_hw_ctx {
+	void __iomem *base;
+	struct clk *dsi_cfg_clk;
+};
+
+struct hisi_dsi {
+	struct drm_encoder encoder;
+	struct drm_bridge *bridge;
+	struct mipi_dsi_host host;
+	struct drm_display_mode cur_mode;
+	struct dsi_hw_ctx *ctx;
+	struct mipi_phy_register phy;
+
+	u32 lanes;
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
+	bool enable;
+};
+
+struct dsi_data {
+	struct hisi_dsi dsi;
+	struct dsi_hw_ctx ctx;
+};
+
+struct dsi_phy_seq_info {
+	u32 min_range_kHz;
+	u32 max_range_kHz;
+	u32 pll_vco_750M;
+	u32 hstx_ckg_sel;
+};
+
+static const struct dsi_phy_seq_info dphy_seq_info[] = {
+	{   46000,    62000,   1,    7 },
+	{   62000,    93000,   0,    7 },
+	{   93000,   125000,   1,    6 },
+	{  125000,   187000,   0,    6 },
+	{  187000,   250000,   1,    5 },
+	{  250000,   375000,   0,    5 },
+	{  375000,   500000,   1,    4 },
+	{  500000,   750000,   0,    4 },
+	{  750000,  1000000,   1,    0 },
+	{ 1000000,  1500000,   0,    0 }
+};
+
+static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
+					     struct mipi_phy_register *phy)
+{
+	u32 ui = 0;
+	u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
+	u32 i = 0;
+	u32 q_pll = 1;
+	u32 m_pll = 0;
+	u32 n_pll = 0;
+	u32 r_pll = 1;
+	u32 m_n = 0;
+	u32 m_n_int = 0;
+	u64 f_kHz;
+	u64 temp;
+	u64 tmp_kHz = phy_freq_kHz;
+
+	do {
+		f_kHz = tmp_kHz;
+
+		/* Find the PLL clock range from the table */
+		for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
+			if (f_kHz > dphy_seq_info[i].min_range_kHz &&
+			    f_kHz <= dphy_seq_info[i].max_range_kHz)
+				break;
+
+		if (i == ARRAY_SIZE(dphy_seq_info)) {
+			DRM_ERROR("%lldkHz out of range\n", f_kHz);
+			return;
+		}
+
+		phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
+		phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
+
+		if (phy->hstx_ckg_sel <= 7 &&
+		    phy->hstx_ckg_sel >= 4)
+			q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
+
+		temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
+		m_n_int = temp / (u64)1000000000;
+		m_n = (temp % (u64)1000000000) / (u64)100000000;
+
+		if (m_n_int % 2 == 0) {
+			if (m_n * 6 >= 50) {
+				n_pll = 2;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 30) {
+				n_pll = 3;
+				m_pll = m_n_int * n_pll + 2;
+			} else {
+				n_pll = 1;
+				m_pll = m_n_int * n_pll;
+			}
+		} else {
+			if (m_n * 6 >= 50) {
+				n_pll = 1;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 30) {
+				n_pll = 1;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 10) {
+				n_pll = 3;
+				m_pll = m_n_int * n_pll + 1;
+			} else {
+				n_pll = 2;
+				m_pll = m_n_int * n_pll;
+			}
+		}
+
+		if (n_pll == 1) {
+			phy->pll_fbd_p = 0;
+			phy->pll_pre_div1p = 1;
+		} else {
+			phy->pll_fbd_p = n_pll;
+			phy->pll_pre_div1p = 0;
+		}
+
+		if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
+			r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
+
+		if (m_pll == 2) {
+			phy->pll_pre_p = 0;
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 1;
+		} else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
+			phy->pll_pre_p = m_pll / (2 * r_pll);
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 1;
+			phy->pll_fbd_div5f = 0;
+		} else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
+			if (((m_pll / (2 * r_pll)) % 2) == 0) {
+				phy->pll_pre_p =
+					(m_pll / (2 * r_pll)) / 2 - 1;
+				phy->pll_fbd_s =
+					(m_pll / (2 * r_pll)) % 2 + 2;
+			} else {
+				phy->pll_pre_p =
+					(m_pll / (2 * r_pll)) / 2;
+				phy->pll_fbd_s =
+					(m_pll / (2 * r_pll)) % 2;
+			}
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 0;
+		} else {
+			phy->pll_pre_p = 0;
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 1;
+		}
+
+		f_kHz = (u64)1000000000 * (u64)m_pll /
+			((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
+
+		if (f_kHz >= phy_freq_kHz)
+			break;
+
+		tmp_kHz += 10;
+
+	} while (1);
+
+	ui = 1000000 / f_kHz;
+
+	phy->clk_t_lpx = ROUND(50, 8 * ui);
+	phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
+
+	phy->clk_t_hs_zero = ROUND(262, 8 * ui);
+	phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
+	phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
+	if (phy->clk_t_wakeup > 0xff)
+		phy->clk_t_wakeup = 0xff;
+	phy->data_t_wakeup = phy->clk_t_wakeup;
+	phy->data_t_lpx = phy->clk_t_lpx;
+	phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
+	phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
+	phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
+	phy->data_t_ta_go = 3;
+	phy->data_t_ta_get = 4;
+
+	phy->pll_enbwt = 1;
+	phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
+	phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
+	phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
+	phy->hs2lp_time = phy->clkhs2lp_time;
+	phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
+	phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
+				phy->clkhs2lp_time;
+
+	phy->lane_byte_clk_kHz = f_kHz / 8;
+	phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
+	if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
+		phy->clk_division++;
+}
+
+static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
+{
+	u32 val;
+
+	/* TODO: only support RGB888 now, to support more */
+	switch (format) {
+	case MIPI_DSI_FMT_RGB888:
+		val = DSI_24BITS_1;
+		break;
+	default:
+		val = DSI_24BITS_1;
+		break;
+	}
+
+	return val;
+}
+
+static void dsi_mipi_phy_clks(void __iomem *base,
+			      struct mipi_phy_register *phy,
+			      u32 lanes)
+{
+	u32 delay_count;
+	bool is_ready;
+	u32 val;
+	u32 i;
+
+	/* set lanes value */
+	val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
+	writel(val, base + PHY_IF_CFG);
+
+	/* set phy clk division */
+	val = readl(base + CLKMGR_CFG) | phy->clk_division;
+	writel(val, base + CLKMGR_CFG);
+
+	/* clean up phy set param */
+	writel(0, base + PHY_RSTZ);
+	writel(0, base + PHY_TST_CTRL0);
+	writel(1, base + PHY_TST_CTRL0);
+	writel(0, base + PHY_TST_CTRL0);
+
+	/* clock lane Timing control - TLPX */
+	dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
+
+	/* clock lane Timing control - THS-PREPARE */
+	dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
+
+	/* clock lane Timing control - THS-ZERO */
+	dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
+
+	/* clock lane Timing control - THS-TRAIL */
+	dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
+
+	/* clock lane Timing control - TWAKEUP */
+	dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
+
+	/* data lane */
+	for (i = 0; i < lanes; i++) {
+		/* Timing control - TLPX*/
+		dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
+
+		/* Timing control - THS-PREPARE */
+		dsi_phy_tst_set(base, 0x10021 + (i << 4),
+				phy->data_t_hs_prepare);
+
+		/* Timing control - THS-ZERO */
+		dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
+
+		/* Timing control - THS-TRAIL */
+		dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
+
+		/* Timing control - TTA-GO */
+		dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
+
+		/* Timing control - TTA-GET */
+		dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
+
+		/*  Timing control - TWAKEUP */
+		dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
+	}
+
+	/* physical configuration I  */
+	dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
+
+	/* physical configuration pll II  */
+	val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
+				(phy->pll_fbd_2p << 1) + phy->pll_enbwt;
+	dsi_phy_tst_set(base, 0x10063, val);
+
+	/* physical configuration pll II  */
+	dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
+
+	/* physical configuration pll III  */
+	dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
+
+	/*physical configuration pll IV*/
+	val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
+	dsi_phy_tst_set(base, 0x10066, val);
+
+	/*physical configuration pll V*/
+	val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
+					phy->pll_lpf_cs + BIT(5);
+	dsi_phy_tst_set(base, 0x10067, val);
+
+	writel(BIT(2), base + PHY_RSTZ);
+	udelay(1);
+	writel(BIT(2) | BIT(0), base + PHY_RSTZ);
+	udelay(1);
+	writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
+	usleep_range(1000, 1500);
+
+	/* wait for phy's clock ready */
+	delay_count = 0;
+	is_ready = false;
+	while (1) {
+		val = readl(base +  PHY_STATUS);
+		if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
+			is_ready = (delay_count < 100) ? true : false;
+			delay_count = 0;
+			break;
+		}
+
+		udelay(1);
+		++delay_count;
+	}
+
+	if (!is_ready)
+		DRM_INFO("phylock and phystopstateclklane is not ready.\n");
+}
+
+static void dsi_set_mode_timing(void __iomem *base,
+				struct mipi_phy_register *phy,
+				struct drm_display_mode *mode,
+				enum mipi_dsi_pixel_format format)
+{
+	u32 hfp, hbp, hsw, vfp, vbp, vsw;
+	u32 hline_time;
+	u32 hsa_time;
+	u32 hbp_time;
+	u32 pixel_clk_kHz;
+	int htot, vtot;
+	u32 val;
+
+	/* DSI color coding setting */
+	val = dsi_get_dpi_color_coding(format);
+	writel(val, base + DPI_COLOR_CODING);
+
+	/* DSI format and pol setting */
+	val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
+	val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
+	writel(val, base +  DPI_CFG_POL);
+
+	/*
+	 * The DSI IP accepts vertical timing using lines as normal,
+	 * but horizontal timing is a mixture of pixel-clocks for the
+	 * active region and byte-lane clocks for the blanking-related
+	 * timings.  hfp is specified as the total hline_time in byte-
+	 * lane clocks minus hsa, hbp and active.
+	 */
+	pixel_clk_kHz = mode->clock;
+	htot = mode->htotal;
+	vtot = mode->vtotal;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hbp = mode->htotal - mode->hsync_end;
+	hsw = mode->hsync_end - mode->hsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+	vsw = mode->vsync_end - mode->vsync_start;
+	if (vsw > 15) {
+		DRM_INFO("vsw exceeded 15\n");
+		vtot -= vsw - 15;
+		vsw = 15;
+	}
+
+	hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
+	hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
+	hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
+		      pixel_clk_kHz;
+
+	if ((R(hline_time) / 1000) > htot) {
+		DRM_INFO("--: hline_time=%d\n", hline_time);
+		hline_time--;
+	}
+
+	if ((R(hline_time) / 1000) < htot) {
+		DRM_INFO("++: hline_time=%d\n", hline_time);
+		hline_time++;
+	}
+
+	/* all specified in byte-lane clocks */
+	writel(hsa_time, base + VID_HSA_TIME);
+	writel(hbp_time, base + VID_HBP_TIME);
+	writel(hline_time, base + VID_HLINE_TIME);
+
+	writel(vsw, base + VID_VSA_LINES);
+	writel(vbp, base + VID_VBP_LINES);
+	writel(vfp, base + VID_VFP_LINES);
+	writel(mode->vdisplay, base + VID_VACTIVE_LINES);
+	writel(mode->hdisplay, base + VID_PKT_SIZE);
+}
+
+static void dsi_set_video_mode_type(void __iomem *base,
+				    struct mipi_phy_register *phy,
+				    unsigned long flags)
+{
+	u32 val;
+	u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
+		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
+
+	/*
+	 * choose video type
+	 */
+	if ((flags & mode_mask) == non_burst_sync_pulse)
+		val = DSI_NON_BURST_SYNC_PULSES;
+	else if ((flags & mode_mask) == non_burst_sync_event)
+		val = DSI_NON_BURST_SYNC_EVENTS;
+	else
+		val = DSI_BURST_SYNC_PULSES_1;
+
+	writel(val, base + VID_MODE_CFG);
+	/* TODO: to support LCD panel need to set LP command transfer */
+}
+
+static void dsi_mipi_init(struct hisi_dsi *dsi)
+{
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct mipi_phy_register *phy = &dsi->phy;
+	struct drm_display_mode *mode = &dsi->cur_mode;
+	void __iomem *base = ctx->base;
+	u32 dphy_freq_kHz;
+
+	/* count phy params */
+	dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
+	set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
+
+	/* reset Core */
+	writel(0, base + PWR_UP);
+
+	/* set phy clocks */
+	dsi_mipi_phy_clks(base, phy, dsi->lanes);
+
+	/* set dsi mode */
+	dsi_set_mode_timing(base, phy, mode, dsi->format);
+
+	/* set video mode type and low power */
+	dsi_set_video_mode_type(base, phy, dsi->mode_flags);
+
+	/* DSI and D-PHY Initialization */
+	writel(DSI_VIDEO_MODE, base + MODE_CFG);
+	writel(BIT(0), base + LPCLK_CTRL);
+	writel(BIT(0), base + PWR_UP);
+
+	DRM_INFO("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
+			dsi->lanes, mode->clock, phy->lane_byte_clk_kHz);
+}
+
+static void dsi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	void __iomem *base = ctx->base;
+
+	DRM_DEBUG_DRIVER("enter\n");
+	if (!dsi->enable)
+		return;
+
+	writel(0, base + PWR_UP);
+	writel(0, base + LPCLK_CTRL);
+	writel(0, base + PHY_RSTZ);
+	clk_disable_unprepare(ctx->dsi_cfg_clk);
+
+	dsi->enable = false;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void dsi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (dsi->enable)
+		return;
+
+	/* mipi dphy clock enable */
+	ret = clk_prepare_enable(ctx->dsi_cfg_clk);
+	if (ret) {
+		DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
+		return;
+	}
+
+	dsi_mipi_init(dsi);
+
+	dsi->enable = true;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void dsi_encoder_mode_set(struct drm_encoder *encoder,
+				 struct drm_display_mode *mode,
+				 struct drm_display_mode *adj_mode)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	drm_mode_copy(&dsi->cur_mode, adj_mode);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
+				    struct drm_crtc_state *crtc_state,
+				    struct drm_connector_state *conn_state)
+{
+	struct drm_display_mode *mode = &crtc_state->mode;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		DRM_ERROR("not support INTERLACE mode\n");
+		return MODE_NO_INTERLACE;
+	}
+
+	/* pixel clock support range is (1190494208/64, 1190494208)Hz */
+	if (mode->clock < 18602 || mode->clock > 1190494) {
+		DRM_ERROR("mode clock not support\n");
+		return MODE_CLOCK_RANGE;
+	}
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
+	.atomic_check	= dsi_encoder_atomic_check,
+	.mode_set	= dsi_encoder_mode_set,
+	.enable		= dsi_encoder_enable,
+	.disable	= dsi_encoder_disable
+};
+
+static const struct drm_encoder_funcs hisi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int hisi_drm_encoder_init(struct drm_device *dev,
+				 struct drm_encoder *encoder)
+{
+	int ret;
+
+	encoder->possible_crtcs = 1;
+	ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS);
+	if (ret) {
+		DRM_ERROR("failed to init dsi encoder\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
+
+	return 0;
+}
+
+static int dsi_host_attach(struct mipi_dsi_host *host,
+			   struct mipi_dsi_device *mdsi)
+{
+	struct hisi_dsi *dsi = host_to_dsi(host);
+
+	if (mdsi->lanes < 1 || mdsi->lanes > 4) {
+		DRM_ERROR("dsi device params invalid\n");
+		return -EINVAL;
+	}
+
+	dsi->lanes = mdsi->lanes;
+	dsi->format = mdsi->format;
+	dsi->mode_flags = mdsi->mode_flags;
+
+	return 0;
+}
+
+static int dsi_host_detach(struct mipi_dsi_host *host,
+			   struct mipi_dsi_device *mdsi)
+{
+	/* do nothing */
+	return 0;
+}
+
+static struct mipi_dsi_host_ops dsi_host_ops = {
+	.attach = dsi_host_attach,
+	.detach = dsi_host_detach,
+};
+
+static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
+{
+	struct mipi_dsi_host *host = &dsi->host;
+	int ret;
+
+	host->dev = dev;
+	host->ops = &dsi_host_ops;
+	ret = mipi_dsi_host_register(host);
+	if (ret) {
+		DRM_ERROR("failed to register dsi host\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dsi_bridge_init(struct drm_device *dev, struct hisi_dsi *dsi)
+{
+	struct drm_encoder *encoder = &dsi->encoder;
+	struct drm_bridge *bridge = dsi->bridge;
+	int ret;
+
+	/* associate the bridge to dsi encoder */
+	encoder->bridge = bridge;
+	bridge->encoder = encoder;
+
+	ret = drm_bridge_attach(dev, bridge);
+	if (ret) {
+		DRM_ERROR("failed to attach exteranl bridge\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+	struct dsi_data *ddata = dev_get_drvdata(dev);
+	struct hisi_dsi *dsi = &ddata->dsi;
+	struct drm_device *drm_dev = data;
+	int ret;
+
+	ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
+	if (ret)
+		return ret;
+
+	ret = dsi_host_init(dev, dsi);
+	if (ret)
+		return ret;
+
+	ret = dsi_bridge_init(drm_dev, dsi);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void dsi_unbind(struct device *dev, struct device *master, void *data)
+{
+	/* do nothing */
+}
+
+static const struct component_ops dsi_ops = {
+	.bind	= dsi_bind,
+	.unbind	= dsi_unbind,
+};
+
+static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
+{
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *endpoint, *bridge_node;
+	struct drm_bridge *bridge;
+	struct resource *res;
+
+	/*
+	 * Get the endpoint node. In our case, dsi has one output port
+	 * to which the external HDMI bridge is connected.
+	 */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		DRM_ERROR("no valid endpoint node\n");
+		return -ENODEV;
+	}
+	of_node_put(endpoint);
+
+	bridge_node = of_graph_get_remote_port_parent(endpoint);
+	if (!bridge_node) {
+		DRM_ERROR("no valid bridge node\n");
+		return -ENODEV;
+	}
+	of_node_put(bridge_node);
+
+	bridge = of_drm_find_bridge(bridge_node);
+	if (!bridge) {
+		DRM_INFO("wait for external HDMI bridge driver.\n");
+		return -EPROBE_DEFER;
+	}
+	dsi->bridge = bridge;
+
+	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
+	if (IS_ERR(ctx->dsi_cfg_clk)) {
+		DRM_ERROR("failed to get dsi plck clock\n");
+		return PTR_ERR(ctx->dsi_cfg_clk);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ctx->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->base)) {
+		DRM_ERROR("failed to remap dsi io region\n");
+		return PTR_ERR(ctx->base);
+	}
+
+	return 0;
+}
+
+static int dsi_probe(struct platform_device *pdev)
+{
+	struct dsi_data *data;
+	struct hisi_dsi *dsi;
+	struct dsi_hw_ctx *ctx;
+	int ret;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		DRM_ERROR("failed to allocate dsi data.\n");
+		return -ENOMEM;
+	}
+	dsi = &data->dsi;
+	ctx = &data->ctx;
+	dsi->ctx = ctx;
+
+	ret = dsi_parse_dt(pdev, dsi);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, data);
+
+	return component_add(&pdev->dev, &dsi_ops);
+}
+
+static int dsi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &dsi_ops);
+
+	return 0;
+}
+
+static const struct of_device_id dsi_of_match[] = {
+	{.compatible = "hisilicon,hi6220-dsi"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dsi_of_match);
+
+static struct platform_driver dsi_driver = {
+	.probe = dsi_probe,
+	.remove = dsi_remove,
+	.driver = {
+		.name = "hisi-dsi",
+		.owner = THIS_MODULE,
+		.of_match_table = dsi_of_match,
+	},
+};
+
+module_platform_driver(dsi_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
new file mode 100644
index 0000000..db8f9df
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HISI_DSI_REG_H__
+#define __HISI_DSI_REG_H__
+
+/*
+ * regs
+ */
+#define  PWR_UP                  (0x4)   /* Core power-up */
+#define  PHY_IF_CFG              (0xA4)  /* D-PHY interface configuration */
+#define  CLKMGR_CFG              (0x8)   /* the internal clock dividers */
+#define  PHY_RSTZ                (0xA0)  /* D-PHY reset control */
+#define  PHY_TST_CTRL0           (0xB4)  /* D-PHY test interface control 0 */
+#define  PHY_TST_CTRL1           (0xB8)  /* D-PHY test interface control 1 */
+#define  DPI_VCID                (0xC)   /* DPI virtual channel id */
+#define  DPI_COLOR_CODING        (0x10)  /* DPI color coding */
+#define  DPI_CFG_POL             (0x14)  /* DPI polarity configuration */
+#define  VID_HSA_TIME            (0x48)  /* Horizontal Sync Active time */
+#define  VID_HBP_TIME            (0x4C)  /* Horizontal Back Porch time */
+#define  VID_HLINE_TIME          (0x50)  /* Line time */
+#define  VID_VSA_LINES           (0x54)  /* Vertical Sync Active period */
+#define  VID_VBP_LINES           (0x58)  /* Vertical Back Porch period */
+#define  VID_VFP_LINES           (0x5C)  /* Vertical Front Porch period */
+#define  VID_VACTIVE_LINES       (0x60)  /* Vertical resolution */
+#define  VID_PKT_SIZE            (0x3C)  /* Video packet size */
+#define  VID_MODE_CFG            (0x38)  /* Video mode configuration */
+#define  DPI_LP_CMD_TIM          (0x18)  /* Low-power command timing config */
+#define  PHY_TMR_CFG             (0x9C)  /* Data lanes timing configuration */
+#define  BTA_TO_CNT              (0x8C)  /* Response timeout definition */
+#define  PHY_TMR_LPCLK_CFG       (0x98)  /* clock lane timing configuration */
+#define  CLK_DATA_TMR_CFG        (0xCC)
+#define  LPCLK_CTRL              (0x94)  /* Low-power in clock lane */
+#define  PCKHDL_CFG              (0x2C)  /* Packet handler configuration */
+#define  EDPI_CMD_SIZE           (0x64)  /* Size for eDPI packets */
+#define  MODE_CFG                (0x34)  /* Video or Command mode selection */
+#define  PHY_STATUS              (0xB0)  /* D-PHY PPI status interface */
+
+#define	PHY_STOP_WAIT_TIME      (0x30)
+
+/*
+ * regs relevant enum
+ */
+enum dpi_color_coding {
+	DSI_24BITS_1 = 5,
+};
+
+enum dsi_video_mode_type {
+	DSI_NON_BURST_SYNC_PULSES = 0,
+	DSI_NON_BURST_SYNC_EVENTS,
+	DSI_BURST_SYNC_PULSES_1,
+	DSI_BURST_SYNC_PULSES_2
+};
+
+enum dsi_work_mode {
+	DSI_VIDEO_MODE = 0,
+	DSI_COMMAND_MODE
+};
+
+/*
+ * regs Write/Read functions
+ */
+static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
+{
+	writel(reg, base + PHY_TST_CTRL1);
+	/* reg addr written at first */
+	wmb();
+	writel(0x02, base + PHY_TST_CTRL0);
+	/* cmd1 sent for write */
+	wmb();
+	writel(0x00, base + PHY_TST_CTRL0);
+	/* cmd2 sent for write */
+	wmb();
+	writel(val, base + PHY_TST_CTRL1);
+	/* Then write data */
+	wmb();
+	writel(0x02, base + PHY_TST_CTRL0);
+	/* cmd2 sent for write */
+	wmb();
+	writel(0x00, base + PHY_TST_CTRL0);
+}
+
+#endif /* __HISI_DRM_DSI_H__ */
diff --git a/drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h
new file mode 100644
index 0000000..73f0938
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HISI_DRM_ADE_H__
+#define __HISI_DRM_ADE_H__
+
+int ade_enable_vblank(struct drm_device *dev, unsigned int pipe);
+void ade_disable_vblank(struct drm_device *dev, unsigned int pipe);
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
new file mode 100644
index 0000000..1055cce
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HISI_ADE_REG_H__
+#define __HISI_ADE_REG_H__
+
+/*
+ * ADE Registers Offset
+ */
+#define ADE_CTRL			(0x4)
+#define ADE_CTRL1			(0x8C)
+#define ADE_ROT_SRC_CFG			(0x10)
+#define ADE_DISP_SRC_CFG		(0x18)
+#define ADE_WDMA2_SRC_CFG		(0x1C)
+#define ADE_SEC_OVLY_SRC_CFG		(0x20)
+#define ADE_WDMA3_SRC_CFG		(0x24)
+#define ADE_OVLY1_TRANS_CFG		(0x2C)
+#define ADE_EN				(0x100)
+#define INTR_MASK_CPU_0			(0xC10)
+#define INTR_MASK_CPU_1			(0xC14)
+#define ADE_FRM_DISGARD_CTRL		(0xA4)
+/* reset and reload regs */
+#define ADE_SOFT_RST_SEL0		(0x78)
+#define ADE_SOFT_RST_SEL1		(0x7C)
+#define ADE_RELOAD_DIS0			(0xAC)
+#define ADE_RELOAD_DIS1			(0xB0)
+#define ADE_CH_RDMA_BIT_OFST		(0)
+#define ADE_CLIP_BIT_OFST		(15)
+#define ADE_SCL_BIT_OFST		(21)
+#define ADE_CTRAN_BIT_OFST		(24)
+#define ADE_OVLY_BIT_OFST		(37) /* 32+5 */
+/* channel regs */
+#define RD_CH_PE(x)			(0x1000 + (x) * 0x80)
+#define RD_CH_CTRL(x)			(0x1004 + (x) * 0x80)
+#define RD_CH_ADDR(x)			(0x1008 + (x) * 0x80)
+#define RD_CH_SIZE(x)			(0x100C + (x) * 0x80)
+#define RD_CH_STRIDE(x)			(0x1010 + (x) * 0x80)
+#define RD_CH_SPACE(x)			(0x1014 + (x) * 0x80)
+#define RD_CH_PARTIAL_SIZE(x)		(0x1018 + (x) * 0x80)
+#define RD_CH_PARTIAL_SPACE(x)		(0x101C + (x) * 0x80)
+#define RD_CH_EN(x)			(0x1020 + (x) * 0x80)
+#define RD_CH_STATUS(x)			(0x1024 + (x) * 0x80)
+#define RD_CH_DISP_CTRL			(0x1404)
+#define RD_CH_DISP_ADDR			(0x1408)
+#define RD_CH_DISP_SIZE			(0x140C)
+#define RD_CH_DISP_STRIDE		(0x1410)
+#define RD_CH_DISP_SPACE		(0x1414)
+#define RD_CH_DISP_EN			(0x142C)
+/* clip regs */
+#define ADE_CLIP_DISABLE(x)		(0x6800 + (x) * 0x100)
+#define ADE_CLIP_SIZE0(x)		(0x6804 + (x) * 0x100)
+#define ADE_CLIP_SIZE1(x)		(0x6808 + (x) * 0x100)
+#define ADE_CLIP_SIZE2(x)		(0x680C + (x) * 0x100)
+#define ADE_CLIP_CFG_OK(x)		(0x6810 + (x) * 0x100)
+/* scale regs */
+#define ADE_SCL1_MUX_CFG		(0xC)
+#define ADE_SCL2_SRC_CFG		(0x14)
+#define ADE_SCL3_MUX_CFG		(0x8)
+#define ADE_SCL_CTRL(x)			(0x3000 + (x) * 0x800)
+#define ADE_SCL_HSP(x)			(0x3004 + (x) * 0x800)
+#define ADE_SCL_UV_HSP(x)		(0x3008 + (x) * 0x800)
+#define ADE_SCL_VSP(x)			(0x300C + (x) * 0x800)
+#define ADE_SCL_UV_VSP(x)		(0x3010 + (x) * 0x800)
+#define ADE_SCL_ORES(x)			(0x3014 + (x) * 0x800)
+#define ADE_SCL_IRES(x)			(0x3018 + (x) * 0x800)
+#define ADE_SCL_START(x)		(0x301C + (x) * 0x800)
+#define ADE_SCL_ERR(x)			(0x3020 + (x) * 0x800)
+#define ADE_SCL_PIX_OFST(x)		(0x3024 + (x) * 0x800)
+#define ADE_SCL_UV_PIX_OFST(x)		(0x3028 + (x) * 0x800)
+#define ADE_SCL_COEF_CLR(x)		(0x3030 + (x) * 0x800)
+#define ADE_SCL_HCOEF(x, m, n)		(0x3100 + (x) * 0x800 + \
+					12 * (m) + 4 * (n))
+#define ADE_SCL_VCOEF(x, i, j)		(0x340C + (x) * 0x800 + \
+					12 * (i) + 4 * (j))
+/* ctran regs */
+#define ADE_CTRAN5_TRANS_CFG		(0x40)
+#define ADE_CTRAN_DIS(x)		(0x5004 + (x) * 0x100)
+#define ADE_CTRAN_MODE_CHOOSE(x)	(0x5008 + (x) * 0x100)
+#define ADE_CTRAN_STAT(x)		(0x500C + (x) * 0x100)
+#define ADE_CTRAN_CHDC0(x)		(0x5010 + (x) * 0x100)
+#define ADE_CTRAN_CHDC1(x)		(0x5014 + (x) * 0x100)
+#define ADE_CTRAN_CHDC2(x)		(0x5018 + (x) * 0x100)
+#define ADE_CTRAN_CHDC3(x)		(0x501C + (x) * 0x100)
+#define ADE_CTRAN_CHDC4(x)		(0x5020 + (x) * 0x100)
+#define ADE_CTRAN_CHDC5(x)		(0x5024 + (x) * 0x100)
+#define ADE_CTRAN_CSC0(x)		(0x5028 + (x) * 0x100)
+#define ADE_CTRAN_CSC1(x)		(0x502C + (x) * 0x100)
+#define ADE_CTRAN_CSC2(x)		(0x5030 + (x) * 0x100)
+#define ADE_CTRAN_CSC3(x)		(0x5034 + (x) * 0x100)
+#define ADE_CTRAN_CSC4(x)		(0x5038 + (x) * 0x100)
+#define ADE_CTRAN_IMAGE_SIZE(x)		(0x503C + (x) * 0x100)
+#define ADE_CTRAN_CFG_OK(x)		(0x5040 + (x) * 0x100)
+/* overlay regs */
+#define ADE_OVLY_ALPHA_ST		(0x2000)
+#define ADE_OVLY_CH_XY0(x)		(0x2004 + (x) * 4)
+#define ADE_OVLY_CH_XY1(x)		(0x2024 + (x) * 4)
+#define ADE_OVLY_CH_CTL(x)		(0x204C + (x) * 4)
+#define ADE_OVLY_OUTPUT_SIZE(x)		(0x2070 + (x) * 8)
+#define ADE_OVLY_BASE_COLOR(x)		(0x2074 + (x) * 8)
+#define ADE_OVLYX_CTL(x)		(0x209C + (x) * 4)
+#define ADE_OVLY_CTL			(0x98)
+#define ADE_OVLY_CH_ALP_MODE_OFST	(0)
+#define ADE_OVLY_CH_ALP_SEL_OFST	(2)
+#define ADE_OVLY_CH_UNDER_ALP_SEL_OFST	(4)
+#define ADE_OVLY_CH_EN_OFST		(6)
+#define ADE_OVLY_CH_ALP_GBL_OFST	(15)
+#define ADE_OVLY_CH_SEL_OFST		(28)
+
+/*
+ * media regs
+ */
+#define SC_MEDIA_RSTDIS			(0x530)
+#define SC_MEDIA_RSTEN			(0x52C)
+#define NOC_ADE0_QOSGENERATOR_MODE       0x010C
+#define NOC_ADE0_QOSGENERATOR_EXTCONTROL 0x0118
+#define NOC_ADE1_QOSGENERATOR_MODE       0x020C
+#define NOC_ADE1_QOSGENERATOR_EXTCONTROL 0x0218
+
+/*
+ * regs relevant enum
+ */
+enum {
+	LDI_TEST = 0,
+	LDI_WORK
+};
+
+enum {
+	LDI_ISR_FRAME_END_INT = 0x2,
+	LDI_ISR_UNDER_FLOW_INT = 0x4
+};
+
+enum {
+	ADE_ISR1_RES_SWITCH_CMPL = 0x80000000
+};
+
+enum {
+	LDI_DISP_MODE_NOT_3D_FBF = 0,
+	LDI_DISP_MODE_3D_FBF
+};
+
+enum {
+	ADE_RGB = 0,
+	ADE_BGR
+};
+
+enum {
+	ADE_DISABLE = 0,
+	ADE_ENABLE
+};
+
+enum {
+	ADE_OUT_RGB_565 = 0,
+	ADE_OUT_RGB_666,
+	ADE_OUT_RGB_888
+};
+
+/*
+ * ADE read as big-endian, so revert the
+ * rgb order described in the SoC datasheet
+ */
+enum ADE_FORMAT {
+	ADE_RGB_565 = 0,
+	ADE_BGR_565,
+	ADE_XRGB_8888,
+	ADE_XBGR_8888,
+	ADE_ARGB_8888,
+	ADE_ABGR_8888,
+	ADE_RGBA_8888,
+	ADE_BGRA_8888,
+	ADE_RGB_888,
+	ADE_BGR_888 = 9,
+	ADE_FORMAT_NOT_SUPPORT = 800
+};
+
+/* ldi src cfg */
+enum {
+	TOP_DISP_SRC_NONE = 0,
+	TOP_DISP_SRC_OVLY2,
+	TOP_DISP_SRC_DISP,
+	TOP_DISP_SRC_ROT,
+	TOP_DISP_SRC_SCL2
+};
+
+enum {
+	ADE_ISR_DMA_ERROR = 0x2000000
+};
+
+enum ade_channel {
+	ADE_CH1 = 0,	/* channel 1 for primary plane */
+	ADE_CH_NUM
+};
+
+enum ade_scale {
+	ADE_SCL1 = 0,
+	ADE_SCL2,
+	ADE_SCL3,
+	ADE_SCL_NUM
+};
+
+enum ade_ctran {
+	ADE_CTRAN1 = 0,
+	ADE_CTRAN2,
+	ADE_CTRAN3,
+	ADE_CTRAN4,
+	ADE_CTRAN5,
+	ADE_CTRAN6,
+	ADE_CTRAN_NUM
+};
+
+enum ade_overlay {
+	ADE_OVLY1 = 0,
+	ADE_OVLY2,
+	ADE_OVLY3,
+	ADE_OVLY_NUM
+};
+
+enum {
+	ADE_ALP_GLOBAL = 0,
+	ADE_ALP_PIXEL,
+	ADE_ALP_PIXEL_AND_GLB
+};
+
+enum {
+	ADE_ALP_MUL_COEFF_0 = 0,	/* alpha */
+	ADE_ALP_MUL_COEFF_1,		/* 1-alpha */
+	ADE_ALP_MUL_COEFF_2,		/* 0 */
+	ADE_ALP_MUL_COEFF_3		/* 1 */
+};
+
+/*
+ * ADE Register Union Struct
+ */
+union U_ADE_CTRL1 {
+struct {
+	unsigned int	auto_clk_gate_en	:1;
+	unsigned int	rot_buf_shr_out		:1;
+	unsigned int	reserved_44		:30;
+	} bits;
+	unsigned int	u32;
+};
+
+union U_ADE_SOFT_RST_SEL0 {
+struct {
+	unsigned int    ch1_rdma_srst_sel     :1;
+	unsigned int    ch2_rdma_srst_sel     :1;
+	unsigned int    ch3_rdma_srst_sel     :1;
+	unsigned int    ch4_rdma_srst_sel     :1;
+	unsigned int    ch5_rdma_srst_sel     :1;
+	unsigned int    ch6_rdma_srst_sel     :1;
+	unsigned int    disp_rdma_srst_sel    :1;
+	unsigned int    cmdq1_rdma_srst_sel   :1;
+	unsigned int    cmdq2_rdma_srst_sel   :1;
+	unsigned int    reserved_29           :1;
+	unsigned int    ch1_wdma_srst_sel     :1;
+	unsigned int    ch2_wdma_srst_sel     :1;
+	unsigned int    ch3_wdma_srst_sel     :1;
+	unsigned int    reserved_28           :1;
+	unsigned int    cmdq_wdma_srst_sel    :1;
+	unsigned int    clip1_srst_sel        :1;
+	unsigned int    clip2_srst_sel        :1;
+	unsigned int    clip3_srst_sel        :1;
+	unsigned int    clip4_srst_sel        :1;
+	unsigned int    clip5_srst_sel        :1;
+	unsigned int    clip6_srst_sel        :1;
+	unsigned int    scl1_srst_sel         :1;
+	unsigned int    scl2_srst_sel         :1;
+	unsigned int    scl3_srst_sel         :1;
+	unsigned int    ctran1_srst_sel       :1;
+	unsigned int    ctran2_srst_sel       :1;
+	unsigned int    ctran3_srst_sel       :1;
+	unsigned int    ctran4_srst_sel       :1;
+	unsigned int    ctran5_srst_sel       :1;
+	unsigned int    ctran6_srst_sel       :1;
+	unsigned int    rot_srst_sel          :1;
+	unsigned int    reserved_27           :1;
+	} bits;
+	unsigned int	u32;
+};
+
+union U_ADE_CTRL {
+struct {
+	unsigned int    frm_end_start         :2;
+	unsigned int    dfs_buf_cfg           :1;
+	unsigned int    rot_buf_cfg           :3;
+	unsigned int    rd_ch5_nv             :1;
+	unsigned int    rd_ch6_nv             :1;
+	unsigned int    dfs_buf_unflow_lev1   :13;
+	unsigned int    dfs_buf_unflow_lev2   :11;
+	} bits;
+	unsigned int	u32;
+};
+
+/*
+ * ADE Register Write/Read functions
+ */
+static inline void set_TOP_CTL_clk_gate_en(u8 *base, u32 val)
+{
+	union U_ADE_CTRL1   ade_ctrl1;
+	u8 *reg_addr = base + ADE_CTRL1;
+
+	ade_ctrl1.u32 = readl(reg_addr);
+	ade_ctrl1.bits.auto_clk_gate_en = val;
+	writel(ade_ctrl1.u32, reg_addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_disp_rdma(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.disp_rdma_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_ctran5(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.ctran5_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_ctran6(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.ctran6_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_CTL_frm_end_start(u8 *base, u32 val)
+{
+	union U_ADE_CTRL  ade_ctrl;
+	u8 *reg_addr = base + ADE_CTRL;
+
+	ade_ctrl.u32 = readl(reg_addr);
+	ade_ctrl.bits.frm_end_start = val;
+	writel(ade_ctrl.u32, reg_addr);
+}
+
+/*
+ * LDI Registers Offset
+ */
+#define LDI_HRZ_CTRL0		(0x7400)
+#define LDI_HRZ_CTRL1		(0x7404)
+#define LDI_VRT_CTRL0		(0x7408)
+#define LDI_VRT_CTRL1		(0x740C)
+#define LDI_PLR_CTRL		(0x7410)
+#define LDI_DSP_SIZE		(0x7414)
+#define LDI_INT_EN		(0x741C)
+#define LDI_CTRL		(0x7420)
+#define LDI_ORG_INT		(0x7424)
+#define LDI_MSK_INT		(0x7428)
+#define LDI_INT_CLR		(0x742C)
+#define LDI_WORK_MODE		(0x7430)
+#define LDI_DE_SPACE_LOW	(0x7438)
+#define LDI_MCU_INTS		(0x7450)
+#define LDI_MCU_INTE		(0x7454)
+#define LDI_MCU_INTC		(0x7458)
+#define LDI_HDMI_DSI_GT		(0x7434)
+
+/*
+ * LDI Timing Polarity defines
+ */
+#define HISI_LDI_FLAG_NVSYNC	BIT(0)
+#define HISI_LDI_FLAG_NHSYNC	BIT(1)
+#define HISI_LDI_FLAG_NPIXCLK	BIT(2)
+#define HISI_LDI_FLAG_NDE	BIT(3)
+
+/*
+ * LDI Register Union Struct
+ */
+union U_LDI_CTRL {
+struct {
+	unsigned int    ldi_en                :1;
+	unsigned int    disp_mode_buf         :1;
+	unsigned int    date_gate_en          :1;
+	unsigned int    bpp                   :2;
+	unsigned int    wait_vsync_en         :1;
+	unsigned int    corlorbar_width       :7;
+	unsigned int    bgr                   :1;
+	unsigned int    color_mode            :1;
+	unsigned int    shutdown              :1;
+	unsigned int    vactive_line          :12;
+	unsigned int    ldi_en_self_clr       :1;
+	unsigned int    reserved_573          :3;
+	} bits;
+	unsigned int    u32;
+};
+
+union U_LDI_WORK_MODE {
+struct {
+	unsigned int    work_mode             :1;
+	unsigned int    wback_en              :1;
+	unsigned int    colorbar_en           :1;
+	unsigned int    reserved_577          :29;
+	} bits;
+	unsigned int    u32;
+};
+
+/*
+ * LDI Register Write/Read Helper functions
+ */
+static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs)
+{
+	u32 mask = (1 << bw) - 1;
+	u32 tmp = readl(addr);
+
+	tmp &= ~(mask << bs);
+	writel(tmp | ((val & mask) << bs), addr);
+}
+
+static inline void set_LDI_CTRL_ldi_en(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.ldi_en = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_disp_mode(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.disp_mode_buf = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_bpp(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.bpp = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_corlorbar_width(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.corlorbar_width = (val > 0) ? val - 1 : 0;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_bgr(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.bgr = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_WORK_MODE_work_mode(u8 *base, u32 val)
+{
+	union U_LDI_WORK_MODE ldi_work_mode;
+	u8 *addr = base + LDI_WORK_MODE;
+
+	ldi_work_mode.u32 = readl(addr);
+	ldi_work_mode.bits.work_mode = val;
+	writel(ldi_work_mode.u32, addr);
+}
+
+static inline void set_LDI_WORK_MODE_colorbar_en(u8 *base, u32 val)
+{
+	union U_LDI_WORK_MODE ldi_work_mode;
+	u8 *addr = base + LDI_WORK_MODE;
+
+	ldi_work_mode.u32 = readl(addr);
+	ldi_work_mode.bits.colorbar_en = val;
+	writel(ldi_work_mode.u32, addr);
+}
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
new file mode 100644
index 0000000..fbf68eb
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -0,0 +1,1100 @@
+/*
+ * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.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.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <video/display_timing.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+
+#include "kirin_drm_drv.h"
+#include "kirin_ade_reg.h"
+
+#define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
+#define PRIMARY_CH	(ADE_CH1)
+
+#define to_ade_crtc(crtc) \
+	container_of(crtc, struct ade_crtc, base)
+
+#define to_ade_plane(plane) \
+	container_of(plane, struct ade_plane, base)
+
+struct ade_hw_ctx {
+	void __iomem  *base;
+	void __iomem  *media_base;
+	void __iomem  *media_noc_base;
+
+	int irq;
+	u32 ade_core_rate;
+	u32 media_noc_rate;
+
+	struct clk *ade_core_clk;
+	struct clk *media_noc_clk;
+	struct clk *ade_pix_clk;
+	bool power_on;
+};
+
+struct ade_crtc {
+	struct drm_crtc base;
+	struct ade_hw_ctx *ctx;
+	bool enable;
+	u64 use_mask;
+};
+
+struct ade_plane {
+	struct drm_plane base;
+	void *ctx;
+	u8 ch; /* channel */
+};
+
+struct ade_data {
+	struct ade_crtc acrtc;
+	struct ade_plane aplane[ADE_CH_NUM];
+	struct ade_hw_ctx ctx;
+};
+
+/* ade-format info: */
+struct ade_format {
+	u32 pixel_format;
+	enum ADE_FORMAT ade_format;
+};
+
+static const struct ade_format ade_formats[] = {
+	/* 16bpp RGB: */
+	{ DRM_FORMAT_RGB565, ADE_RGB_565 },
+	{ DRM_FORMAT_BGR565, ADE_BGR_565 },
+	/* 24bpp RGB: */
+	{ DRM_FORMAT_RGB888, ADE_RGB_888 },
+	{ DRM_FORMAT_BGR888, ADE_BGR_888 },
+	/* 32bpp [A]RGB: */
+	{ DRM_FORMAT_XRGB8888, ADE_XRGB_8888 },
+	{ DRM_FORMAT_XBGR8888, ADE_XBGR_8888 },
+	{ DRM_FORMAT_RGBA8888, ADE_RGBA_8888 },
+	{ DRM_FORMAT_BGRA8888, ADE_BGRA_8888 },
+	{ DRM_FORMAT_ARGB8888, ADE_ARGB_8888 },
+	{ DRM_FORMAT_ABGR8888, ADE_ABGR_8888 },
+};
+
+static const u32 channel_formats1[] = {
+	/* channel 1,2,3,4 */
+	DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888
+};
+
+u32 ade_get_channel_formats(u8 ch, const u32 **formats)
+{
+	switch (ch) {
+	case ADE_CH1:
+		*formats = channel_formats1;
+		return ARRAY_SIZE(channel_formats1);
+	default:
+		DRM_ERROR("no this channel %d\n", ch);
+		*formats = NULL;
+		return 0;
+	}
+}
+
+/* convert from fourcc format to ade format */
+static u32 ade_get_format(u32 pixel_format)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ade_formats); i++)
+		if (ade_formats[i].pixel_format == pixel_format)
+			return ade_formats[i].ade_format;
+
+	/* not found */
+	DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", pixel_format);
+	return ADE_FORMAT_NOT_SUPPORT;
+}
+
+static void ade_init(struct ade_hw_ctx *ctx)
+{
+	void __iomem *base = ctx->base;
+
+	/* enable clk gate */
+	set_TOP_CTL_clk_gate_en(base, 1);
+	/* clear overlay */
+	writel(0, base + ADE_OVLY1_TRANS_CFG);
+	writel(0, base + ADE_OVLY_CTL);
+	writel(0, base + ADE_OVLYX_CTL(ADE_OVLY2));
+	/* clear reset and reload regs */
+	writel(0, base + ADE_SOFT_RST_SEL0);
+	writel(0, base + ADE_SOFT_RST_SEL1);
+	writel(0xFFFFFFFF, base + ADE_RELOAD_DIS0);
+	writel(0xFFFFFFFF, base + ADE_RELOAD_DIS1);
+	/* for video set to 1, means that ade registers
+	 * became effective at frame end
+	 */
+	set_TOP_CTL_frm_end_start(base, 1);
+}
+
+static void ade_ldi_set_mode(struct ade_crtc *acrtc,
+			     struct drm_display_mode *mode,
+			     struct drm_display_mode *adj_mode)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 out_w = mode->hdisplay;
+	u32 out_h = mode->vdisplay;
+	u32 hfp, hbp, hsw, vfp, vbp, vsw;
+	u32 plr_flags;
+	int ret;
+
+	plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
+			? HISI_LDI_FLAG_NVSYNC : 0;
+	plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
+			? HISI_LDI_FLAG_NHSYNC : 0;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hbp = mode->htotal - mode->hsync_end;
+	hsw = mode->hsync_end - mode->hsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+	vsw = mode->vsync_end - mode->vsync_start;
+	if (vsw > 15) {
+		DRM_INFO("vsw exceeded 15\n");
+		vsw = 15;
+	}
+
+	writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
+	/* p3-73 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(hsw - 1, base + LDI_HRZ_CTRL1);
+	writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
+	/* p3-74 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(vsw - 1, base + LDI_VRT_CTRL1);
+
+	/* p3-75 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
+	       base + LDI_DSP_SIZE);
+	writel(plr_flags, base + LDI_PLR_CTRL);
+
+	ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
+	/* Success should be guaranteed in aotomic_check
+	 * failer shouldn't happen here
+	 */
+	if (ret)
+		DRM_ERROR("set ade_pixel_clk_rate fail\n");
+	adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
+
+	/* ctran6 setting */
+	writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
+	writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
+	acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
+	DRM_INFO("set mode: %dx%d\n", out_w, out_h);
+
+	/*
+	 * other parameters setting
+	 */
+	writel(BIT(0), base + LDI_WORK_MODE);
+	writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
+	       base + LDI_CTRL);
+	set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
+}
+
+static int ade_power_up(struct ade_hw_ctx *ctx)
+{
+	void __iomem *media_base = ctx->media_base;
+	int ret;
+
+	ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
+	if (ret) {
+		DRM_ERROR("clk_set_rate ade_core_rate error\n");
+		return ret;
+	}
+	ret = clk_set_rate(ctx->media_noc_clk, ctx->media_noc_rate);
+	if (ret) {
+		DRM_ERROR("media_noc_clk media_noc_rate error\n");
+		return ret;
+	}
+	ret = clk_prepare_enable(ctx->media_noc_clk);
+	if (ret) {
+		DRM_ERROR("fail to clk_prepare_enable media_noc_clk\n");
+		return ret;
+	}
+
+	writel(0x20, media_base + SC_MEDIA_RSTDIS);
+
+	ret = clk_prepare_enable(ctx->ade_core_clk);
+	if (ret) {
+		DRM_ERROR("fail to clk_prepare_enable ade_core_clk\n");
+		return ret;
+	}
+
+	ade_init(ctx);
+	ctx->power_on = true;
+	return 0;
+}
+
+static void ade_power_down(struct ade_hw_ctx *ctx)
+{
+	void __iomem *base = ctx->base;
+	void __iomem *media_base = ctx->media_base;
+
+	set_LDI_CTRL_ldi_en(base, ADE_DISABLE);
+	/* dsi pixel off */
+	set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
+
+	clk_disable_unprepare(ctx->ade_core_clk);
+	writel(0x20, media_base + SC_MEDIA_RSTEN);
+	clk_disable_unprepare(ctx->media_noc_clk);
+	ctx->power_on = false;
+}
+
+static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
+						 unsigned int index)
+{
+	unsigned int index_tmp = 0;
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		if (index_tmp == index)
+			return crtc;
+
+		index_tmp++;
+	}
+
+	WARN_ON(true);
+	return NULL;
+}
+
+int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 intr_en;
+
+	DRM_INFO("enable_vblank enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+
+	intr_en = readl(base + LDI_INT_EN);
+	intr_en |= LDI_ISR_FRAME_END_INT;
+	writel(intr_en, base + LDI_INT_EN);
+
+	return 0;
+}
+
+void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
+{
+	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, pipe);
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 intr_en;
+
+	DRM_INFO("disable_vblank enter.\n");
+	if (!ctx->power_on) {
+		DRM_ERROR("power is down! vblank disable fail\n");
+		return;
+	}
+	intr_en = readl(base + LDI_INT_EN);
+	intr_en &= ~LDI_ISR_FRAME_END_INT;
+	writel(intr_en, base + LDI_INT_EN);
+}
+
+static irqreturn_t ade_irq_handler(int irq, void *data)
+{
+	struct ade_crtc *acrtc = data;
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	struct drm_crtc *crtc = &acrtc->base;
+	struct drm_device *dev = crtc->dev;
+	void __iomem *base = ctx->base;
+	u32 status;
+
+	status = readl(base + LDI_MSK_INT);
+	/* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
+
+	/* vblank irq */
+	if (status & LDI_ISR_FRAME_END_INT) {
+		writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
+		drm_handle_vblank(dev, drm_crtc_index(crtc));
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * set modules' reset mode: by software or hardware
+ * set modules' reload enable/disable
+ */
+static void ade_set_reset_and_reload(struct ade_crtc *acrtc)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 mask0 = (u32)acrtc->use_mask;
+	u32 mask1 = (u32)(acrtc->use_mask >> 32);
+
+	DRM_DEBUG_DRIVER("mask=0x%llX, mask0=0x%X, mask1=0x%X\n",
+			 acrtc->use_mask, mask0, mask1);
+
+	writel(mask0, base + ADE_SOFT_RST_SEL0);
+	writel(mask1, base + ADE_SOFT_RST_SEL1);
+	writel(~mask0, base + ADE_RELOAD_DIS0);
+	writel(~mask1, base + ADE_RELOAD_DIS1);
+}
+
+void ade_set_medianoc_qos(struct ade_crtc *acrtc)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->media_noc_base;
+	void __iomem *reg;
+	u32 val;
+
+	reg = base + NOC_ADE0_QOSGENERATOR_MODE;
+	val = (readl(reg) & 0xfffffffc) | 0x2;
+	writel(val, reg);
+
+	reg = base + NOC_ADE0_QOSGENERATOR_EXTCONTROL;
+	val = readl(reg) | 0x1;
+	writel(val, reg);
+
+	reg = base + NOC_ADE1_QOSGENERATOR_MODE;
+	val = (readl(reg) & 0xfffffffc) | 0x2;
+	writel(val, reg);
+
+	reg = base + NOC_ADE1_QOSGENERATOR_EXTCONTROL;
+	val = readl(reg) | 0x1;
+	writel(val, reg);
+}
+
+/*
+ * commit to ldi to display
+ */
+static void ade_display_commit(struct ade_crtc *acrtc)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	/* TODO: set rotator after overlay */
+
+	/* TODO: set scale after overlay */
+
+	/* display source setting */
+	writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+
+	/* set reset mode:soft or hw, and reload modules */
+	ade_set_reset_and_reload(acrtc);
+
+	DRM_INFO("ADE GO\n");
+	/* enable ade */
+	wmb();
+	writel(ADE_ENABLE, base + ADE_EN);
+	/* enable ldi */
+	wmb();
+	set_LDI_CTRL_ldi_en(base, ADE_ENABLE);
+	/* dsi pixel on */
+	set_reg(base + LDI_HDMI_DSI_GT, 0x0, 1, 0);
+}
+
+static void ade_crtc_enable(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (acrtc->enable)
+		return;
+
+	if (!ctx->power_on) {
+		ret = ade_power_up(ctx);
+		if (ret) {
+			DRM_ERROR("failed to initialize ade clk\n");
+			return;
+		}
+	}
+
+	ade_set_medianoc_qos(acrtc);
+	ade_display_commit(acrtc);
+	acrtc->enable = true;
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_disable(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+
+	if (!acrtc->enable)
+		return;
+
+	ade_power_down(ctx);
+	acrtc->use_mask = 0;
+	acrtc->enable = false;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+int ade_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+	/* do nothing */
+	return 0;
+}
+
+static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	struct drm_display_mode *mode = &crtc->state->mode;
+	struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+	ade_ldi_set_mode(acrtc, mode, adj_mode);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_state)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_state)
+
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	/* commit to  display: LDI input setting */
+	if (acrtc->enable) {
+		/* set reset and reload */
+		ade_set_reset_and_reload(acrtc);
+		/* flush ade regitsters */
+		wmb();
+		writel(ADE_ENABLE, base + ADE_EN);
+	}
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
+	.enable		= ade_crtc_enable,
+	.disable	= ade_crtc_disable,
+	.atomic_check	= ade_crtc_atomic_check,
+	.mode_set_nofb	= ade_crtc_mode_set_nofb,
+	.atomic_begin	= ade_crtc_atomic_begin,
+	.atomic_flush	= ade_crtc_atomic_flush,
+};
+
+static const struct drm_crtc_funcs ade_crtc_funcs = {
+	.destroy	= drm_crtc_cleanup,
+	.set_config	= drm_atomic_helper_set_config,
+	.page_flip	= drm_atomic_helper_page_flip,
+	.reset		= drm_atomic_helper_crtc_reset,
+	.set_property = drm_atomic_helper_crtc_set_property,
+	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
+};
+
+static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+			 struct drm_plane *plane)
+{
+	int ret;
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &ade_crtc_funcs);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
+	drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
+
+	return 0;
+}
+
+static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
+			 u32 ch, u32 y, u32 in_h, u32 fmt)
+{
+	u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
+	struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 stride = fb->pitches[0];
+	u32 addr = (u32)obj->paddr + y * stride;
+
+	DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x, \
+			 addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
+			 ch + 1, y, in_h, stride, (u32)obj->paddr,
+			 addr, fb->width, fb->height,
+			 fmt, drm_get_format_name(fb->pixel_format));
+
+	/* get reg offset */
+	reg_ctrl = RD_CH_CTRL(ch);
+	reg_addr = RD_CH_ADDR(ch);
+	reg_size = RD_CH_SIZE(ch);
+	reg_stride = RD_CH_STRIDE(ch);
+	reg_space = RD_CH_SPACE(ch);
+	reg_en = RD_CH_EN(ch);
+
+	/*
+	 * TODO: set rotation
+	 */
+	writel((fmt << 16) & 0x1f0000, base + reg_ctrl);
+	writel(addr, base + reg_addr);
+	writel((in_h << 16) | stride, base + reg_size);
+	writel(stride, base + reg_stride);
+	writel(in_h * stride, base + reg_space);
+	writel(1, base + reg_en);
+
+	acrtc->use_mask |= BIT(ADE_CH_RDMA_BIT_OFST + ch);
+}
+
+static void ade_rdma_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 reg_en;
+
+	/* get reg offset */
+	reg_en = RD_CH_EN(ch);
+
+	writel(0, base + reg_en);
+	acrtc->use_mask &= ~BIT(ADE_CH_RDMA_BIT_OFST + ch);
+}
+
+static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
+			 u32 in_w, u32 in_h)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 disable_val;
+	u32 clip_left;
+	u32 clip_right;
+
+	/*
+	 * clip width, no need to clip height
+	 */
+	if (fb_w == in_w) { /* bypass */
+		disable_val = 1;
+		clip_left = 0;
+		clip_right = 0;
+	} else {
+		disable_val = 0;
+		clip_left = x;
+		clip_right = fb_w - (x + in_w) - 1;
+	}
+
+	DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n",
+			 ch + 1, clip_left, clip_right);
+
+	writel(disable_val, base + ADE_CLIP_DISABLE(ch));
+	writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
+	writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
+
+	acrtc->use_mask |= BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static void ade_clip_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	writel(1, base + ADE_CLIP_DISABLE(ch));
+	acrtc->use_mask &= ~BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static bool has_Alpha_channel(int format)
+{
+	switch (format) {
+	case ADE_ARGB_8888:
+	case ADE_ABGR_8888:
+	case ADE_RGBA_8888:
+	case ADE_BGRA_8888:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
+				    u8 *alp_sel, u8 *under_alp_sel)
+{
+	bool has_alpha = has_Alpha_channel(fmt);
+
+	/*
+	 * get alp_mode
+	 */
+	if (has_alpha && glb_alpha < 255)
+		*alp_mode = ADE_ALP_PIXEL_AND_GLB;
+	else if (has_alpha)
+		*alp_mode = ADE_ALP_PIXEL;
+	else
+		*alp_mode = ADE_ALP_GLOBAL;
+
+	/*
+	 * get alp sel
+	 */
+	*alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */
+	*under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
+}
+
+static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
+			    u32 in_w, u32 in_h, u32 fmt)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u8 ovly_ch = 0;
+	u8 x = ADE_OVLY2;
+	u8 glb_alpha = 255;
+	u32 x1 = x0 + in_w - 1;
+	u32 y1 = y0 + in_h - 1;
+	u32 val;
+	u8 alp_sel;
+	u8 under_alp_sel;
+	u8 alp_mode;
+
+	ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
+				&under_alp_sel);
+
+	/* overlay routing setting */
+	writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
+	writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
+	val = (ch + 1) << ADE_OVLY_CH_SEL_OFST | BIT(ADE_OVLY_CH_EN_OFST) |
+		alp_sel << ADE_OVLY_CH_ALP_SEL_OFST |
+		under_alp_sel << ADE_OVLY_CH_UNDER_ALP_SEL_OFST |
+		glb_alpha << ADE_OVLY_CH_ALP_GBL_OFST |
+		alp_mode << ADE_OVLY_CH_ALP_MODE_OFST;
+	DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+	val = (x + 1) << (ovly_ch * 4) | readl(base + ADE_OVLY_CTL);
+	DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
+	writel(val, base + ADE_OVLY_CTL);
+
+	/* when primary is enable, indicate that it's ready to output. */
+	if (ch == PRIMARY_CH) {
+		val = (in_w - 1) << 16 | (in_h - 1);
+		writel(val, base + ADE_OVLY_OUTPUT_SIZE(x));
+		writel(1, base + ADE_OVLYX_CTL(x));
+		acrtc->use_mask |= BIT(ADE_OVLY_BIT_OFST + x);
+	}
+}
+
+static void ade_overlay_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u8 ovly_ch = 0;
+	u32 val;
+
+	val = ~BIT(6) & readl(base + ADE_OVLY_CH_CTL(ovly_ch));
+	DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+	val = ~(0x3 << (ovly_ch * 4)) & readl(base + ADE_OVLY_CTL);
+
+	DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
+	writel(val, base + ADE_OVLY_CTL);
+}
+
+/*
+ * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
+ */
+static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
+			       struct drm_framebuffer *fb, int crtc_x,
+			       int crtc_y, unsigned int crtc_w,
+			       unsigned int crtc_h, u32 src_x,
+			       u32 src_y, u32 src_w, u32 src_h)
+{
+	u8 ch = aplane->ch;
+	u32 fmt = ade_get_format(fb->pixel_format);
+	u32 in_w;
+	u32 in_h;
+
+	DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d",
+			 ch + 1, src_x, src_y, src_w, src_h,
+			 crtc_x, crtc_y, crtc_w, crtc_h);
+
+	/* 1) DMA setting */
+	in_w = src_w;
+	in_h = src_h;
+	ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt);
+
+	/* 2) clip setting */
+	ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
+
+	/* 3) TODO: scale setting for overlay planes */
+
+	/* 4) TODO: ctran/csc setting for overlay planes */
+
+	/* 5) overlay/compositor routing setting */
+	ade_overlay_set(acrtc, ch, crtc_x, crtc_y, in_w, in_h, fmt);
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_disable_channel(struct ade_plane *aplane,
+				struct ade_crtc *acrtc)
+{
+	u32 ch = aplane->ch;
+
+	DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
+
+	/*
+	 * when primary is disable, power is down
+	 * so no need to disable this channel.
+	 */
+	if (ch == PRIMARY_CH)
+		return;
+
+	/* disable read DMA */
+	ade_rdma_disable(acrtc, ch);
+
+	/* disable clip */
+	ade_clip_disable(acrtc, ch);
+
+	/* disable overlay routing */
+	ade_overlay_disable(acrtc, ch);
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int ade_plane_prepare_fb(struct drm_plane *plane,
+				const struct drm_plane_state *new_state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+	return 0;
+}
+
+static void ade_plane_cleanup_fb(struct drm_plane *plane,
+				 const struct drm_plane_state *old_state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int ade_plane_atomic_check(struct drm_plane *plane,
+				  struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_crtc *crtc = state->crtc;
+	struct drm_crtc_state *crtc_state;
+	u32 src_x = state->src_x >> 16;
+	u32 src_y = state->src_y >> 16;
+	u32 src_w = state->src_w >> 16;
+	u32 src_h = state->src_h >> 16;
+	int crtc_x = state->crtc_x;
+	int crtc_y = state->crtc_y;
+	u32 crtc_w = state->crtc_w;
+	u32 crtc_h = state->crtc_h;
+
+	if (!crtc || !fb)
+		return 0;
+
+	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		DRM_ERROR("Scale not support!!!\n");
+		return -EINVAL;
+	}
+
+	if (src_x + src_w > fb->width ||
+	    src_y + src_h > fb->height)
+		return -EINVAL;
+
+	if (crtc_x < 0 || crtc_y < 0)
+		return -EINVAL;
+
+	if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
+	    crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void ade_plane_atomic_update(struct drm_plane *plane,
+				    struct drm_plane_state *old_state)
+{
+	struct drm_plane_state	*state	= plane->state;
+	struct ade_plane *aplane = to_ade_plane(plane);
+	struct ade_crtc *acrtc;
+
+	if (!state->crtc)
+		return;
+
+	acrtc = to_ade_crtc(state->crtc);
+	ade_update_channel(aplane, acrtc, state->fb,
+			   state->crtc_x, state->crtc_y,
+			   state->crtc_w, state->crtc_h,
+			   state->src_x >> 16, state->src_y >> 16,
+			   state->src_w >> 16, state->src_h >> 16);
+}
+
+static void ade_plane_atomic_disable(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct ade_plane *aplane = to_ade_plane(plane);
+	struct ade_crtc *acrtc;
+
+	if (!old_state->crtc)
+		return;
+	acrtc = to_ade_crtc(old_state->crtc);
+	ade_disable_channel(aplane, acrtc);
+}
+
+static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
+	.prepare_fb = ade_plane_prepare_fb,
+	.cleanup_fb = ade_plane_cleanup_fb,
+	.atomic_check = ade_plane_atomic_check,
+	.atomic_update = ade_plane_atomic_update,
+	.atomic_disable = ade_plane_atomic_disable,
+};
+
+static struct drm_plane_funcs ade_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.set_property = drm_atomic_helper_plane_set_property,
+	.destroy = drm_plane_cleanup,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
+			  enum drm_plane_type type)
+{
+	const u32 *fmts;
+	u32 fmts_cnt;
+	int ret = 0;
+
+	/* get  properties */
+	fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts);
+	if (ret)
+		return ret;
+
+	ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
+				       fmts, fmts_cnt, type);
+	if (ret) {
+		DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
+		return ret;
+	}
+
+	drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs);
+
+	return 0;
+}
+
+static int ade_bind(struct device *dev, struct device *master, void *data)
+{
+	struct ade_data *ade = dev_get_drvdata(dev);
+	struct ade_hw_ctx *ctx = &ade->ctx;
+	struct ade_crtc *acrtc = &ade->acrtc;
+	struct drm_device *drm_dev = (struct drm_device *)data;
+	struct ade_plane *aplane;
+	enum drm_plane_type type;
+	int ret;
+	int i;
+
+	/*
+	 * plane init
+	 * TODO: Now only support primary plane, overlay planes
+	 * need to do.
+	 */
+	for (i = 0; i < ADE_CH_NUM; i++) {
+		aplane = &ade->aplane[i];
+		aplane->ch = i;
+		aplane->ctx = ctx;
+		type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
+			DRM_PLANE_TYPE_OVERLAY;
+
+		ret = ade_plane_init(drm_dev, aplane, type);
+		if (ret)
+			return ret;
+	}
+
+	/* crtc init */
+	acrtc->ctx = ctx;
+	ret = ade_crtc_init(drm_dev, &acrtc->base,
+			    &ade->aplane[PRIMARY_CH].base);
+	if (ret)
+		return ret;
+
+	/* vblank irq init */
+	ret = request_irq(ctx->irq, ade_irq_handler, DRIVER_IRQ_SHARED,
+			  drm_dev->driver->name, acrtc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void ade_unbind(struct device *dev, struct device *master, void *data)
+{
+	/* do nothing */
+}
+
+static const struct component_ops ade_ops = {
+	.bind	= ade_bind,
+	.unbind	= ade_unbind,
+};
+
+static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx)
+{
+	struct resource *res;
+	struct device *dev;
+	struct device_node *np;
+	int ret;
+
+	dev = &pdev->dev;
+	np  = dev->of_node;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ade_base");
+	ctx->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->base)) {
+		DRM_ERROR("failed to remap ade io base\n");
+		return  PTR_ERR(ctx->base);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_base");
+	ctx->media_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->media_base)) {
+		DRM_ERROR("failed to remap media io base\n");
+		return PTR_ERR(ctx->media_base);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_noc_base");
+	ctx->media_noc_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->media_noc_base)) {
+		DRM_ERROR("failed to remap media noc base\n");
+		return PTR_ERR(ctx->media_noc_base);
+	}
+
+	ctx->irq = platform_get_irq(pdev, 0);
+	if (ctx->irq < 0) {
+		DRM_ERROR("failed to parse the irq\n");
+		return -ENODEV;
+	}
+
+	ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
+	if (!ctx->ade_core_clk) {
+		DRM_ERROR("failed to parse the ADE_CORE\n");
+		return -ENODEV;
+	}
+	ctx->media_noc_clk = devm_clk_get(&pdev->dev,
+					"aclk_codec_jpeg_src");
+	if (!ctx->media_noc_clk) {
+		DRM_ERROR("failed to parse the CODEC_JPEG\n");
+	    return -ENODEV;
+	}
+	ctx->ade_pix_clk = devm_clk_get(&pdev->dev, "clk_ade_pix");
+	if (!ctx->ade_pix_clk) {
+		DRM_ERROR("failed to parse the ADE_PIX_SRC\n");
+	    return -ENODEV;
+	}
+
+	ret = of_property_read_u32(np, "ade_core_clk_rate",
+				   &ctx->ade_core_rate);
+	if (ret) {
+		DRM_ERROR("failed to parse the ade_core_clk_rate\n");
+	    return -ENODEV;
+	}
+	ret = of_property_read_u32(np, "media_noc_clk_rate",
+				   &ctx->media_noc_rate);
+	if (ret) {
+		DRM_ERROR("failed to parse the media_noc_clk_rate\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int ade_probe(struct platform_device *pdev)
+{
+	struct ade_data *ade;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+
+	ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
+	if (!ade) {
+		DRM_ERROR("failed to alloc ade_data\n");
+		return -ENOMEM;
+	}
+
+	ret = ade_dts_parse(pdev, &ade->ctx);
+	if (ret) {
+		DRM_ERROR("failed to parse dts!!\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, ade);
+
+	return component_add(&pdev->dev, &ade_ops);
+}
+
+static int ade_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &ade_ops);
+
+	return 0;
+}
+
+static const struct of_device_id ade_of_match[] = {
+	{ .compatible = "hisilicon,hi6220-ade" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ade_of_match);
+
+static struct platform_driver ade_driver = {
+	.probe = ade_probe,
+	.remove = ade_remove,
+	.driver = {
+		   .name = "hisi-ade",
+		   .owner = THIS_MODULE,
+		   .of_match_table = ade_of_match,
+	},
+};
+
+module_platform_driver(ade_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("Hisilicon DRM ADE(crtc/plane) Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
new file mode 100644
index 0000000..dd23a66
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -0,0 +1,280 @@
+/*
+ * Hisilicon SoCs drm master driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.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.
+ *
+ */
+
+#include <linux/of_platform.h>
+#include <linux/component.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "hisi_drm_ade.h"
+#include "kirin_drm_drv.h"
+
+#define DRIVER_NAME	"hisi-drm"
+
+static int hisi_drm_unload(struct drm_device *dev)
+{
+	struct hisi_drm_private *priv = dev->dev_private;
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	if (priv->fbdev) {
+		drm_fbdev_cma_fini(priv->fbdev);
+		priv->fbdev = NULL;
+	}
+#endif
+	drm_kms_helper_poll_fini(dev);
+	drm_vblank_cleanup(dev);
+	drm_mode_config_cleanup(dev);
+	devm_kfree(dev->dev, priv);
+	dev->dev_private = NULL;
+
+	return 0;
+}
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+static void hisi_fbdev_output_poll_changed(struct drm_device *dev)
+{
+	struct hisi_drm_private *priv = dev->dev_private;
+
+	if (priv->fbdev) {
+		drm_fbdev_cma_hotplug_event(priv->fbdev);
+	} else {
+		priv->fbdev = drm_fbdev_cma_init(dev, 32,
+				dev->mode_config.num_crtc,
+				dev->mode_config.num_connector);
+		if (IS_ERR(priv->fbdev))
+			priv->fbdev = NULL;
+	}
+}
+#endif
+
+static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
+	.fb_create = drm_fb_cma_create,
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	.output_poll_changed = hisi_fbdev_output_poll_changed,
+#endif
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static void hisi_drm_mode_config_init(struct drm_device *dev)
+{
+	dev->mode_config.min_width = 0;
+	dev->mode_config.min_height = 0;
+
+	dev->mode_config.max_width = 2048;
+	dev->mode_config.max_height = 2048;
+
+	dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
+}
+
+static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
+{
+	struct hisi_drm_private *priv;
+	int ret;
+
+	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev->dev_private = priv;
+	dev_set_drvdata(dev->dev, dev);
+
+	/* dev->mode_config initialization */
+	drm_mode_config_init(dev);
+	hisi_drm_mode_config_init(dev);
+
+	/* bind and init sub drivers */
+	ret = component_bind_all(dev->dev, dev);
+	if (ret) {
+		DRM_ERROR("failed to bind all component.\n");
+		goto err_mode_config_cleanup;
+	}
+
+	/* vblank init */
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret) {
+		DRM_ERROR("failed to initialize vblank.\n");
+		goto err_unbind_all;
+	}
+	/* with irq_enabled = true, we can use the vblank feature. */
+	dev->irq_enabled = true;
+
+	/* reset all the states of crtc/plane/encoder/connector */
+	drm_mode_config_reset(dev);
+
+	/* init kms poll for handling hpd */
+	drm_kms_helper_poll_init(dev);
+
+	/* force detection after connectors init */
+	(void)drm_helper_hpd_irq_event(dev);
+
+	return 0;
+
+err_unbind_all:
+	component_unbind_all(dev->dev, dev);
+err_mode_config_cleanup:
+	drm_mode_config_cleanup(dev);
+	devm_kfree(dev->dev, priv);
+	dev->dev_private = NULL;
+
+	return ret;
+}
+
+static const struct file_operations hisi_drm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= drm_compat_ioctl,
+#endif
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+	.mmap		= drm_gem_cma_mmap,
+};
+
+static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
+					     struct drm_gem_object *obj,
+					     int flags)
+{
+	/* we want to be able to write in mmapped buffer */
+	flags |= O_RDWR;
+	return drm_gem_prime_export(dev, obj, flags);
+}
+
+static int hisi_gem_cma_dumb_create(struct drm_file *file,
+				    struct drm_device *dev,
+				    struct drm_mode_create_dumb *args)
+{
+	int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+	/* mali gpu need pitch 8 bytes alignment for 32bpp */
+	args->pitch = roundup(min_pitch, 8);
+
+	return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
+static struct drm_driver hisi_drm_driver = {
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
+				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
+	.load			= hisi_drm_load,
+	.unload                 = hisi_drm_unload,
+	.fops			= &hisi_drm_fops,
+	.set_busid		= drm_platform_set_busid,
+
+	.gem_free_object	= drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+	.dumb_create		= hisi_gem_cma_dumb_create,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_export	= hisi_gem_prime_export,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
+
+	.get_vblank_counter	= drm_vblank_count,
+	.enable_vblank		= ade_enable_vblank,
+	.disable_vblank		= ade_disable_vblank,
+
+	.name			= "hisi",
+	.desc			= "Hisilicon SoCs' DRM Driver",
+	.date			= "20150718",
+	.major			= 1,
+	.minor			= 0,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int hisi_drm_bind(struct device *dev)
+{
+	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
+}
+
+static void hisi_drm_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops hisi_drm_ops = {
+	.bind = hisi_drm_bind,
+	.unbind = hisi_drm_unbind,
+};
+
+static int hisi_drm_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct device_node *child_np;
+	struct component_match *match = NULL;
+
+	of_platform_populate(node, NULL, NULL, dev);
+
+	child_np = of_get_next_available_child(node, NULL);
+	while (child_np) {
+		component_match_add(dev, &match, compare_of, child_np);
+		of_node_put(child_np);
+		child_np = of_get_next_available_child(node, child_np);
+	}
+
+	return component_master_add_with_match(dev, &hisi_drm_ops, match);
+
+	return 0;
+}
+
+static int hisi_drm_platform_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &hisi_drm_ops);
+	of_platform_depopulate(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id hisi_drm_dt_ids[] = {
+	{ .compatible = "hisilicon,hi6220-dss", },
+	{ /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
+
+static struct platform_driver hisi_drm_platform_driver = {
+	.probe = hisi_drm_platform_probe,
+	.remove = hisi_drm_platform_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRIVER_NAME,
+		.of_match_table = hisi_drm_dt_ids,
+	},
+};
+
+module_platform_driver(hisi_drm_platform_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("hisilicon SoCs' DRM master driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
new file mode 100644
index 0000000..984121f
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __HISI_DRM_DRV_H__
+#define __HISI_DRM_DRV_H__
+
+struct hisi_drm_private {
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	struct drm_fbdev_cma *fbdev;
+#endif
+};
+
+#endif /* __HISI_DRM_DRV_H__ */
