diff mbox

[4/6] drm: kirin: Sync with kirin drm driver

Message ID 1466737689-2303-5-git-send-email-john.stultz@linaro.org
State New
Headers show

Commit Message

John Stultz June 24, 2016, 3:08 a.m. UTC
This patch syncs the now moved hisi driver with the upstream
kirin driver backport from Guodong's rebase tree.

This provides binding documentation as well as device-tree
changes, which allow for features like HDMI hotplug support
as well as DSI panel support.

Credit for the hisilicon/kirin driver we're syncing with goes to
Xinliang Liu <xinliang.liu@linaro.org> who authored most of the
code.

Signed-off-by: John Stultz <john.stultz@linaro.org>

---
 .../bindings/display/hisilicon/dw-dsi.txt          |  72 ++
 .../bindings/display/hisilicon/hisi-ade.txt        |  68 +-
 .../bindings/display/hisilicon/hisi-drm.txt        |  66 --
 .../bindings/display/hisilicon/hisi-dsi.txt        |  53 --
 MAINTAINERS                                        |  10 +
 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts     |  58 +-
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi          |  87 +-
 drivers/gpu/drm/Makefile                           |   2 +-
 drivers/gpu/drm/hisilicon/Kconfig                  |  10 -
 drivers/gpu/drm/hisilicon/kirin/Kconfig            |   1 +
 drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c       | 929 +++++++++++++++------
 drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h       | 158 ++--
 drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h     |  16 -
 drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h    | 512 +++---------
 drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c    | 803 +++++++++---------
 drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c    | 255 ++++--
 drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h    |  23 +-
 include/drm/drm_mipi_dsi.h                         |  27 +
 18 files changed, 1743 insertions(+), 1407 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt
 delete mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
 delete mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
 delete mode 100644 drivers/gpu/drm/hisilicon/kirin/hisi_drm_ade.h

-- 
1.9.1
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt b/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt
new file mode 100644
index 0000000..d270bfe
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/dw-dsi.txt
@@ -0,0 +1,72 @@ 
+Device-Tree bindings for DesignWare DSI Host Controller v1.20a driver
+
+A DSI Host Controller resides in the middle of display controller and external
+HDMI converter or panel.
+
+Required properties:
+- compatible: value should be "hisilicon,hi6220-dsi".
+- reg: physical base address and length of dsi controller's registers.
+- clocks: contains APB clock phandle + clock-specifier pair.
+- clock-names: should be "pclk".
+- ports: contains DSI controller input and output sub port.
+  The input port connects to ADE output port with the reg value "0".
+  The output port with the reg value "1", it could connect to panel or
+  any other bridge endpoints.
+  See Documentation/devicetree/bindings/graph.txt for more device graph info.
+
+A example of HiKey board hi6220 SoC and board specific DT entry:
+Example:
+
+SoC specific:
+	dsi: dsi@f4107800 {
+		compatible = "hisilicon,hi6220-dsi";
+		reg = <0x0 0xf4107800 0x0 0x100>;
+		clocks = <&media_ctrl  HI6220_DSI_PCLK>;
+		clock-names = "pclk";
+		status = "disabled";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			/* 0 for input port */
+			port@0 {
+				reg = <0>;
+				dsi_in: endpoint {
+					remote-endpoint = <&ade_out>;
+				};
+			};
+		};
+	};
+
+
+Board specific:
+	&dsi {
+		status = "ok";
+
+		ports {
+			/* 1 for output port */
+			port@1 {
+				reg = <1>;
+
+				dsi_out0: endpoint@0 {
+					remote-endpoint = <&adv7533_in>;
+				};
+			};
+		};
+	};
+
+	&i2c2 {
+		...
+
+		adv7533: adv7533@39 {
+			...
+
+			port {
+				adv7533_in: endpoint {
+					remote-endpoint = <&dsi_out0>;
+				};
+			};
+		};
+	};
+
diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
index 2777a2c..38dc9d6 100644
--- a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
+++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
@@ -5,15 +5,31 @@  data from memory, do composition, do post image processing, generate RGB
 timing stream and transfer to DSI.
 
 Required properties:
-- compatible: value should be one of the following
-	"hisilicon,hi6220-ade".
-- reg: physical base address and length of the controller's registers.
-- reg-names: name of physical base.
-- interrupt: the interrupt number.
-- clocks: the clocks needed.
-- clock-names: the name of the clocks.
-- ade_core_clk_rate: ADE core clock rate.
-- media_noc_clk_rate: media noc module clock rate.
+- compatible: value should be "hisilicon,hi6220-ade".
+- reg: physical base address and length of the ADE controller's registers.
+- hisilicon,noc-syscon: ADE NOC QoS syscon.
+- resets: The ADE reset controller node.
+- interrupt: the ldi vblank interrupt number used.
+- clocks: a list of phandle + clock-specifier pairs, one for each entry
+  in clock-names.
+- clock-names: should contain:
+  "clk_ade_core" for the ADE core clock.
+  "clk_codec_jpeg" for the media NOC QoS clock, which use the same clock with
+  jpeg codec.
+  "clk_ade_pix" for the ADE pixel clok.
+- assigned-clocks: Should contain "clk_ade_core" and "clk_codec_jpeg" clocks'
+  phandle + clock-specifier pairs.
+- assigned-clock-rates: clock rates, one for each entry in assigned-clocks.
+  The rate of "clk_ade_core" could be "360000000" or "180000000";
+  The rate of "clk_codec_jpeg" could be or less than "1440000000".
+  These rate values could be configured according to performance and power
+  consumption.
+- port: the output port. This contains one endpoint subnode, with its
+  remote-endpoint set to the phandle of the connected DSI input endpoint.
+  See Documentation/devicetree/bindings/graph.txt for more device graph info.
+
+Optional properties:
+- dma-coherent: Present if dma operations are coherent.
 
 
 A example of HiKey board hi6220 SoC specific DT entry:
@@ -21,22 +37,28 @@  Example:
 
 	ade: ade@f4100000 {
 		compatible = "hisilicon,hi6220-ade";
-		reg = <0x0 0xf4100000 0x0 0x7800>,
-		      <0x0 0xf4410000 0x0 0x1000>;
-		reg-names = "ade_base",
-			    "media_base";
-		interrupts = <0 115 4>;
+		reg = <0x0 0xf4100000 0x0 0x7800>;
+		reg-names = "ade_base";
+		hisilicon,noc-syscon = <&medianoc_ade>;
+		resets = <&media_ctrl MEDIA_ADE>;
+		interrupts = <0 115 4>; /* ldi interrupt */
 
 		clocks = <&media_ctrl HI6220_ADE_CORE>,
 			 <&media_ctrl HI6220_CODEC_JPEG>,
-			 <&media_ctrl HI6220_ADE_PIX_SRC>,
-			 <&media_ctrl HI6220_PLL_SYS>,
-			 <&media_ctrl HI6220_PLL_SYS_MEDIA>;
+			 <&media_ctrl HI6220_ADE_PIX_SRC>;
+		/*clock name*/
 		clock-names  = "clk_ade_core",
-			       "aclk_codec_jpeg_src",
-			       "clk_ade_pix",
-			       "clk_syspll_src",
-			       "clk_medpll_src";
-		ade_core_clk_rate = <360000000>;
-		media_noc_clk_rate = <288000000>;
+			       "clk_codec_jpeg",
+			       "clk_ade_pix";
+
+		assigned-clocks = <&media_ctrl HI6220_ADE_CORE>,
+			<&media_ctrl HI6220_CODEC_JPEG>;
+		assigned-clock-rates = <360000000>, <288000000>;
+		dma-coherent;
+
+		port {
+			ade_out: endpoint {
+				remote-endpoint = <&dsi_in>;
+			};
+		};
 	};
diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
deleted file mode 100644
index fd93026..0000000
--- a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
+++ /dev/null
@@ -1,66 +0,0 @@ 
-Hisilicon DRM master device
-
-The Hisilicon DRM master device is a virtual device needed to list all
-the other display relevant nodes that comprise the display subsystem.
-
-
-Required properties:
-- compatible: Should be "hisilicon,<chip>-dss"
-- #address-cells: should be set to 2.
-- #size-cells: should be set to 2.
-- range: to allow probing of subdevices.
-
-Optional properties:
-- dma-coherent: Present if dma operations are coherent.
-
-Required sub nodes:
-All the device nodes of display subsystem of SoC should be the sub nodes.
-Such as display controller node, DSI node and so on.
-
-A example of HiKey board hi6220 SoC specific DT entry:
-Example:
-
-	display-subsystem {
-		compatible = "hisilicon,hi6220-dss";
-		#address-cells = <2>;
-		#size-cells = <2>;
-		ranges;
-		dma-coherent;
-
-		ade: ade@f4100000 {
-			compatible = "hisilicon,hi6220-ade";
-			reg = <0x0 0xf4100000 0x0 0x7800>,
-			      <0x0 0xf4410000 0x0 0x1000>;
-			reg-names = "ade_base",
-				    "media_base";
-			interrupts = <0 115 4>; /* ldi interrupt */
-
-			clocks = <&media_ctrl HI6220_ADE_CORE>,
-				 <&media_ctrl HI6220_CODEC_JPEG>,
-				 <&media_ctrl HI6220_ADE_PIX_SRC>,
-				 <&media_ctrl HI6220_PLL_SYS>,
-				 <&media_ctrl HI6220_PLL_SYS_MEDIA>;
-			/*clock name*/
-			clock-names  = "clk_ade_core",
-				       "aclk_codec_jpeg_src",
-				       "clk_ade_pix",
-				       "clk_syspll_src",
-				       "clk_medpll_src";
-			ade_core_clk_rate = <360000000>;
-			media_noc_clk_rate = <288000000>;
-		};
-
-		dsi: dsi@0xf4107800 {
-			compatible = "hisilicon,hi6220-dsi";
-			reg = <0x0 0xf4107800 0x0 0x100>;
-			clocks = <&media_ctrl  HI6220_DSI_PCLK>;
-			clock-names = "pclk_dsi";
-
-			port {
-				dsi_out: endpoint {
-					remote-endpoint = <&adv_in>;
-				};
-			};
-
-		};
-	};
diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
deleted file mode 100644
index 30abaa85..0000000
--- a/Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
+++ /dev/null
@@ -1,53 +0,0 @@ 
-Device-Tree bindings for hisilicon DSI controller driver
-
-A DSI controller resides in the middle of display controller and external
-HDMI converter.
-
-Required properties:
-- compatible: value should be one of the following
-	"hisilicon,hi6220-dsi".
-- reg: physical base address and length of the controller's registers.
-- clocks: the clocks needed.
-- clock-names: the name of the clocks.
-- port: DSI controller output port. This contains one endpoint subnode, with its
-  remote-endpoint set to the phandle of the connected external HDMI endpoint.
-  See Documentation/devicetree/bindings/graph.txt for device graph info.
-
-A example of HiKey board hi6220 SoC and board specific DT entry:
-Example:
-
-SoC specific:
-	dsi: dsi@0xf4107800 {
-		compatible = "hisilicon,hi6220-dsi";
-		reg = <0x0 0xf4107800 0x0 0x100>;
-		clocks = <&media_ctrl  HI6220_DSI_PCLK>;
-		clock-names = "pclk_dsi";
-
-		port {
-			dsi_out: endpoint {
-				remote-endpoint = <&adv_in>;
-			};
-		};
-
-	};
-
-Board specific:
-	i2c2: i2c@f7102000 {
-		status = "ok";
-
-		adv7533: adv7533@39 {
-			compatible = "adi,adv7533";
-			reg = <0x39>;
-			interrupt-parent = <&gpio1>;
-			interrupts = <1 2>;
-			pd-gpio = <&gpio0 4 0>;
-			adi,dsi-lanes = <4>;
-
-			port {
-				adv_in: endpoint {
-					remote-endpoint = <&dsi_out>;
-				};
-			};
-		};
-	};
-
diff --git a/MAINTAINERS b/MAINTAINERS
index ab65bbe..6e8cfea 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3705,6 +3705,16 @@  S:	Maintained
 F:	drivers/gpu/drm/gma500
 F:	include/drm/gma500*
 
+DRM DRIVERS FOR HISILICON
+M:	Xinliang Liu <z.liuxinliang@hisilicon.com>
+R:	Xinwei Kong <kong.kongxinwei@hisilicon.com>
+R:	Chen Feng <puck.chen@hisilicon.com>
+L:	dri-devel@lists.freedesktop.org
+T:	git git://github.com/xin3liang/linux.git
+S:	Maintained
+F:	drivers/gpu/drm/hisilicon/
+F:	Documentation/devicetree/bindings/display/hisilicon/
+
 DRM DRIVERS FOR NVIDIA TEGRA
 M:	Thierry Reding <thierry.reding@gmail.com>
 M:	Terje Bergström <tbergstrom@nvidia.com>
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
index 5d5e240..c33e713 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -107,15 +107,15 @@ 
 				interrupts = <1 2>;
 				pd-gpio = <&gpio0 4 0>;
 				adi,dsi-lanes = <4>;
+				adi,disable-timing-generator;
 
 				port {
-					adv_in: endpoint {
-						remote-endpoint = <&dsi_out>;
+					adv7533_in: endpoint {
+						remote-endpoint = <&dsi_out0>;
 					};
 				};
 			};
 		};
-
 		uart1: uart@f7111000 {
 			status = "ok";
 		};
@@ -336,3 +336,55 @@ 
 		};
 	};
 };
+
+&ade {
+	status = "ok";
+};
+
+&dsi {
+	#address-cells = <1>;
+	#size-cells = <0>;
+	mux-gpio = <&gpio0 1 0>;
+	status = "ok";
+
+	ports {
+		/* 1 for output port */
+		port@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			dsi_out0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&adv7533_in>;
+			};
+
+			dsi_out1: endpoint@1 {
+				reg = <1>;
+				remote-endpoint = <&panel0_in>;
+			};
+		};
+	};
+
+	/* For panel reg's value should >= 1 */
+	panel@1 {
+		compatible = "innolux,n070icn-pb1";
+		reg = <1>;
+		power-on-delay= <50>;
+		reset-delay = <100>;
+		init-delay = <100>;
+		panel-width-mm = <58>;
+		panel-height-mm = <103>;
+		pwr-en-gpio = <&gpio2 1 0>;
+		bl-en-gpio = <&gpio2 3 0>;
+		pwm-gpio = <&gpio12 7 0>;
+
+		port {
+			panel0_in: endpoint {
+				remote-endpoint = <&dsi_out1>;
+			};
+		};
+	};
+};
+
+
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
index 80aa50b..09e2c71 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -255,6 +255,7 @@ 
 			compatible = "hisilicon,hi6220-mediactrl", "syscon";
 			reg = <0x0 0xf4410000 0x0 0x1000>;
 			#clock-cells = <1>;
+			#reset-cells = <1>;
 		};
 
 		pm_ctrl: pm_ctrl@f7032000 {
@@ -271,6 +272,11 @@ 
 			mboxes = <&mailbox 1 0 11>;
 		};
 
+		medianoc_ade: medianoc_ade@f4520000 {
+			compatible = "syscon";
+			reg = <0x0 0xf4520000 0x0 0x4000>;
+		};
+
 		uart0: uart@f8015000 {	/* console */
 			compatible = "arm,pl011", "arm,primecell";
 			reg = <0x0 0xf8015000 0x0 0x1000>;
@@ -705,7 +711,7 @@ 
 			pinctrl-0 = <&spi0_pmx_func &spi0_cfg_func>;
 			num-cs = <1>;
 			cs-gpios = <&gpio6 2 0>;
-			status = "ok";
+			status = "disabled";
 		};
 
 		i2c0: i2c@f7100000 {
@@ -925,46 +931,51 @@ 
 			};
 		};
 
-		display-subsystem {
-			compatible = "hisilicon,hi6220-dss";
-			#address-cells = <2>;
-			#size-cells = <2>;
-			ranges;
-
-			ade: ade@f4100000 {
-				compatible = "hisilicon,hi6220-ade";
-				reg = <0x0 0xf4100000 0x0 0x7800>,
-				      <0x0 0xf4410000 0x0 0x1000>,
-				      <0x0 0xf4520000 0x0 0x1000>;
-				reg-names = "ade_base",
-					    "media_base",
-					    "media_noc_base";
-				interrupts = <0 115 4>; /* ldi interrupt */
-
-				clocks = <&media_ctrl HI6220_ADE_CORE>,
-					 <&media_ctrl HI6220_CODEC_JPEG>,
-					 <&media_ctrl HI6220_ADE_PIX_SRC>,
-					 <&media_ctrl HI6220_PLL_SYS>,
-					 <&media_ctrl HI6220_PLL_SYS_MEDIA>;
-				/*clock name*/
-				clock-names  = "clk_ade_core",
-					       "aclk_codec_jpeg_src",
-					       "clk_ade_pix",
-					       "clk_syspll_src",
-					       "clk_medpll_src";
-				ade_core_clk_rate = <360000000>;
-				media_noc_clk_rate = <288000000>;
+		ade: ade@f4100000 {
+			compatible = "hisilicon,hi6220-ade";
+			reg = <0x0 0xf4100000 0x0 0x7800>;
+			reg-names = "ade_base";
+			hisilicon,noc-syscon = <&medianoc_ade>;
+			resets = <&media_ctrl MEDIA_ADE>;
+			interrupts = <0 115 4>; /* ldi interrupt */
+
+			clocks = <&media_ctrl HI6220_ADE_CORE>,
+				 <&media_ctrl HI6220_CODEC_JPEG>,
+				 <&media_ctrl HI6220_ADE_PIX_SRC>;
+			/*clock name*/
+			clock-names  = "clk_ade_core",
+				       "clk_codec_jpeg",
+				       "clk_ade_pix";
+
+			assigned-clocks = <&media_ctrl HI6220_ADE_CORE>,
+				<&media_ctrl HI6220_CODEC_JPEG>;
+			assigned-clock-rates = <360000000>, <288000000>;
+			dma-coherent;
+			status = "disabled";
+
+			port {
+				ade_out: endpoint {
+					remote-endpoint = <&dsi_in>;
+				};
 			};
+		};
+
+		dsi: dsi@f4107800 {
+			compatible = "hisilicon,hi6220-dsi";
+			reg = <0x0 0xf4107800 0x0 0x100>;
+			clocks = <&media_ctrl  HI6220_DSI_PCLK>;
+			clock-names = "pclk";
+			status = "disabled";
 
-			dsi: dsi@0xf4107800 {
-				compatible = "hisilicon,hi6220-dsi";
-				reg = <0x0 0xf4107800 0x0 0x100>;
-				clocks = <&media_ctrl  HI6220_DSI_PCLK>;
-				clock-names = "pclk_dsi";
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
 
-				port {
-					dsi_out: endpoint {
-						remote-endpoint = <&adv_in>;
+				/* 0 for input port */
+				port@0 {
+					reg = <0>;
+					dsi_in: endpoint {
+						remote-endpoint = <&ade_out>;
 					};
 				};
 			};
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e7efcb7..95ba482 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -75,4 +75,4 @@  obj-y			+= i2c/
 obj-y			+= panel/
 obj-y			+= bridge/
 obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
-obj-$(CONFIG_DRM_HISI) += hisilicon/
+obj-y			+= hisilicon/
diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
index 7503981..558c61b 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -1,13 +1,3 @@ 
-config DRM_HISI
-	tristate "DRM Support for Hisilicon SoCs Platform"
-	depends on DRM
-	select DRM_KMS_HELPER
-	select DRM_GEM_CMA_HELPER
-	select DRM_KMS_CMA_HELPER
-	select DRM_MIPI_DSI
-	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
diff --git a/drivers/gpu/drm/hisilicon/kirin/Kconfig b/drivers/gpu/drm/hisilicon/kirin/Kconfig
index 5dcbc8d..57f6017 100644
--- a/drivers/gpu/drm/hisilicon/kirin/Kconfig
+++ b/drivers/gpu/drm/hisilicon/kirin/Kconfig
@@ -4,6 +4,7 @@  config DRM_HISI_KIRIN
 	select DRM_KMS_HELPER
 	select DRM_GEM_CMA_HELPER
 	select DRM_KMS_CMA_HELPER
+	select HISI_KIRIN_DW_DSI
 	help
 	  Choose this option if you have a hisilicon Kirin chipsets(hi6220).
 	  If M is selected the module will be called kirin-drm.
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
index fe94ccb..aebb8fc 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -1,10 +1,12 @@ 
 /*
- * Hisilicon hi6220 SoC dsi driver
+ * DesignWare MIPI DSI Host Controller v1.02 driver
+ *
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
  *
- * Copyright (c) 2014-2015 Hisilicon Limited.
  * Author:
- *	Xinliang Liu <xinliang.liu@linaro.org>
  *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinliang Liu <xinliang.liu@linaro.org>
  *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -16,27 +18,39 @@ 
 #include <linux/clk.h>
 #include <linux/component.h>
 #include <linux/of_graph.h>
+#include <linux/iopoll.h>
+#include <video/mipi_display.h>
+#include <linux/gpio/consumer.h>
 
+#include <drm/drm_of.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 <drm/drm_panel.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 MAX_TX_ESC_CLK		10
+#define ROUND(x, y)		((x) / (y) + \
+				((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
+#define PHY_REF_CLK_RATE	19200000
+#define PHY_REF_CLK_PERIOD_PS	(1000000000 / (PHY_REF_CLK_RATE / 1000))
 
 #define encoder_to_dsi(encoder) \
-	container_of(encoder, struct hisi_dsi, encoder)
+	container_of(encoder, struct dw_dsi, encoder)
 #define host_to_dsi(host) \
-	container_of(host, struct hisi_dsi, host)
+	container_of(host, struct dw_dsi, host)
+#define connector_to_dsi(connector) \
+	container_of(connector, struct dw_dsi, connector)
+
+enum dsi_output_client {
+	OUT_HDMI = 0,
+	OUT_PANEL,
+	OUT_MAX
+};
 
-struct mipi_phy_register {
+struct mipi_phy_params {
 	u32 clk_t_lpx;
 	u32 clk_t_hs_prepare;
 	u32 clk_t_hs_zero;
@@ -73,41 +87,53 @@  struct mipi_phy_register {
 
 struct dsi_hw_ctx {
 	void __iomem *base;
-	struct clk *dsi_cfg_clk;
+	struct clk *pclk;
+};
+
+struct dw_dsi_client {
+	u32 lanes;
+	u32 phy_clock; /* in kHz */
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
 };
 
-struct hisi_dsi {
+struct dw_dsi {
 	struct drm_encoder encoder;
 	struct drm_bridge *bridge;
+	struct drm_panel *panel;
 	struct mipi_dsi_host host;
+	struct drm_connector connector; /* connector for panel */
 	struct drm_display_mode cur_mode;
 	struct dsi_hw_ctx *ctx;
-	struct mipi_phy_register phy;
+	struct mipi_phy_params phy;
 
 	u32 lanes;
 	enum mipi_dsi_pixel_format format;
 	unsigned long mode_flags;
+	struct gpio_desc *gpio_mux;
+	struct dw_dsi_client client[OUT_MAX];
+	enum dsi_output_client cur_client;
 	bool enable;
 };
 
 struct dsi_data {
-	struct hisi_dsi dsi;
+	struct dw_dsi dsi;
 	struct dsi_hw_ctx ctx;
 };
 
-struct dsi_phy_seq_info {
+struct dsi_phy_range {
 	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 },
+static const struct dsi_phy_range dphy_range_info[] = {
+	{   46875,    62500,   1,    7 },
+	{   62500,    93750,   0,    7 },
+	{   93750,   125000,   1,    6 },
+	{  125000,   187500,   0,    6 },
+	{  187500,   250000,   1,    5 },
 	{  250000,   375000,   0,    5 },
 	{  375000,   500000,   1,    4 },
 	{  500000,   750000,   0,    4 },
@@ -115,11 +141,55 @@  static const struct dsi_phy_seq_info dphy_seq_info[] = {
 	{ 1000000,  1500000,   0,    0 }
 };
 
-static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
-					     struct mipi_phy_register *phy)
+void dsi_set_output_client(struct drm_device *dev)
+{
+	enum dsi_output_client client;
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	struct dw_dsi *dsi;
+
+
+	mutex_lock(&dev->mode_config.mutex);
+
+	/* find dsi encoder */
+	drm_for_each_encoder(encoder, dev)
+		if (encoder->encoder_type == DRM_MODE_ENCODER_DSI)
+			break;
+	dsi = encoder_to_dsi(encoder);
+
+	/* find HDMI connector */
+	drm_for_each_connector(connector, dev)
+		if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)
+			break;
+
+	/*
+	 * set the proper dsi output client
+	 */
+	client = connector->status == connector_status_connected ?
+		OUT_HDMI : OUT_PANEL;
+	if (client != dsi->cur_client) {
+		/* associate bridge and dsi encoder */
+		if (client == OUT_HDMI)
+			encoder->bridge = dsi->bridge;
+		else
+			encoder->bridge = NULL;
+
+		gpiod_set_value_cansleep(dsi->gpio_mux, client);
+		dsi->cur_client = client;
+		/* let the userspace know panel connector status has changed */
+		drm_sysfs_hotplug_event(dev);
+		DRM_INFO("client change to %s\n", client == OUT_HDMI ?
+				 "HDMI" : "panel");
+	}
+
+	mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(dsi_set_output_client);
+
+static u32 dsi_calc_phy_rate(u32 req_kHz, struct mipi_phy_params *phy)
 {
-	u32 ui = 0;
-	u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
+	u32 ref_clk_ps = PHY_REF_CLK_PERIOD_PS;
+	u32 tmp_kHz = req_kHz;
 	u32 i = 0;
 	u32 q_pll = 1;
 	u32 m_pll = 0;
@@ -127,32 +197,33 @@  static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
 	u32 r_pll = 1;
 	u32 m_n = 0;
 	u32 m_n_int = 0;
-	u64 f_kHz;
+	u32 f_kHz = 0;
 	u64 temp;
-	u64 tmp_kHz = phy_freq_kHz;
 
+	/*
+	 * Find a rate >= req_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)
+		for (i = 0; i < ARRAY_SIZE(dphy_range_info); i++)
+			if (f_kHz >= dphy_range_info[i].min_range_kHz &&
+			    f_kHz <= dphy_range_info[i].max_range_kHz)
 				break;
 
-		if (i == ARRAY_SIZE(dphy_seq_info)) {
-			DRM_ERROR("%lldkHz out of range\n", f_kHz);
-			return;
+		if (i == ARRAY_SIZE(dphy_range_info)) {
+			DRM_ERROR("%dkHz out of range\n", f_kHz);
+			return 0;
 		}
 
-		phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
-		phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
+		phy->pll_vco_750M = dphy_range_info[i].pll_vco_750M;
+		phy->hstx_ckg_sel = dphy_range_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;
+		temp = f_kHz * (u64)q_pll * (u64)ref_clk_ps;
 		m_n_int = temp / (u64)1000000000;
 		m_n = (temp % (u64)1000000000) / (u64)100000000;
 
@@ -226,23 +297,39 @@  static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
 		}
 
 		f_kHz = (u64)1000000000 * (u64)m_pll /
-			((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
+			((u64)ref_clk_ps * (u64)n_pll * (u64)q_pll);
 
-		if (f_kHz >= phy_freq_kHz)
+		if (f_kHz >= req_kHz)
 			break;
 
 		tmp_kHz += 10;
 
-	} while (1);
+	} while (true);
 
-	ui = 1000000 / f_kHz;
+	return f_kHz;
+}
+
+static void dsi_get_phy_params(u32 phy_req_kHz,
+			       struct mipi_phy_params *phy)
+{
+	u32 ref_clk_ps = PHY_REF_CLK_PERIOD_PS;
+	u32 phy_rate_kHz;
+	u32 ui;
+
+	memset(phy, 0, sizeof(*phy));
+
+	phy_rate_kHz = dsi_calc_phy_rate(phy_req_kHz, phy);
+	if (!phy_rate_kHz)
+		return;
+
+	ui = 1000000 / phy_rate_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);
+	phy->clk_t_wakeup = ROUND(1000000, (ref_clk_ps / 1000) - 1);
 	if (phy->clk_t_wakeup > 0xff)
 		phy->clk_t_wakeup = 0xff;
 	phy->data_t_wakeup = phy->clk_t_wakeup;
@@ -262,17 +349,18 @@  static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
 	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++;
+	phy->lane_byte_clk_kHz = phy_rate_kHz / 8;
+	phy->clk_division =
+		DIV_ROUND_UP(phy->lane_byte_clk_kHz, MAX_TX_ESC_CLK);
 }
 
 static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
 {
 	u32 val;
 
-	/* TODO: only support RGB888 now, to support more */
+	/*
+	 * TODO: only support RGB888 now, to support more
+	 */
 	switch (format) {
 	case MIPI_DSI_FMT_RGB888:
 		val = DSI_24BITS_1;
@@ -285,120 +373,146 @@  static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
 	return val;
 }
 
-static void dsi_mipi_phy_clks(void __iomem *base,
-			      struct mipi_phy_register *phy,
+/*
+ * dsi phy reg write function
+ */
+static void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
+{
+	u32 reg_write = 0x10000 + reg;
+
+	/*
+	 * latch reg first
+	 */
+	writel(reg_write, base + PHY_TST_CTRL1);
+	writel(0x02, base + PHY_TST_CTRL0);
+	writel(0x00, base + PHY_TST_CTRL0);
+
+	/*
+	 * then latch value
+	 */
+	writel(val, base + PHY_TST_CTRL1);
+	writel(0x02, base + PHY_TST_CTRL0);
+	writel(0x00, base + PHY_TST_CTRL0);
+}
+
+static void dsi_set_phy_timer(void __iomem *base,
+			      struct mipi_phy_params *phy,
 			      u32 lanes)
 {
-	u32 delay_count;
-	bool is_ready;
 	u32 val;
-	u32 i;
 
-	/* set lanes value */
+	/*
+	 * Set lane value and phy stop wait time.
+	 */
 	val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
 	writel(val, base + PHY_IF_CFG);
 
-	/* set phy clk division */
+	/*
+	 * Set phy clk division.
+	 */
 	val = readl(base + CLKMGR_CFG) | phy->clk_division;
 	writel(val, base + CLKMGR_CFG);
 
-	/* clean up phy set param */
+	/*
+	 * Set lp and hs switching params.
+	 */
+	dw_update_bits(base + PHY_TMR_CFG, 24, MASK(8), phy->hs2lp_time);
+	dw_update_bits(base + PHY_TMR_CFG, 16, MASK(8), phy->lp2hs_time);
+	dw_update_bits(base + PHY_TMR_LPCLK_CFG, 16, MASK(10),
+		       phy->clkhs2lp_time);
+	dw_update_bits(base + PHY_TMR_LPCLK_CFG, 0, MASK(10),
+		       phy->clklp2hs_time);
+	dw_update_bits(base + CLK_DATA_TMR_CFG, 8, MASK(8),
+		       phy->data_to_clk_delay);
+	dw_update_bits(base + CLK_DATA_TMR_CFG, 0, MASK(8),
+		       phy->clk_to_data_delay);
+}
+
+static void dsi_set_mipi_phy(void __iomem *base,
+			     struct mipi_phy_params *phy,
+			     u32 lanes)
+{
+	u32 delay_count;
+	u32 val;
+	u32 i;
+
+	/* phy timer setting */
+	dsi_set_phy_timer(base, phy, lanes);
+
+	/*
+	 * Reset to clean up phy tst params.
+	 */
 	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);
+	/*
+	 * Clock lane timing control setting: TLPX, THS-PREPARE,
+	 * THS-ZERO, THS-TRAIL, TWAKEUP.
+	 */
+	dsi_phy_tst_set(base, CLK_TLPX, phy->clk_t_lpx);
+	dsi_phy_tst_set(base, CLK_THS_PREPARE, phy->clk_t_hs_prepare);
+	dsi_phy_tst_set(base, CLK_THS_ZERO, phy->clk_t_hs_zero);
+	dsi_phy_tst_set(base, CLK_THS_TRAIL, phy->clk_t_hs_trial);
+	dsi_phy_tst_set(base, CLK_TWAKEUP, phy->clk_t_wakeup);
 
-	/* data lane */
+	/*
+	 * Data lane timing control setting: TLPX, THS-PREPARE,
+	 * THS-ZERO, THS-TRAIL, TTA-GO, TTA-GET, TWAKEUP.
+	 */
 	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),
+		dsi_phy_tst_set(base, DATA_TLPX(i), phy->data_t_lpx);
+		dsi_phy_tst_set(base, DATA_THS_PREPARE(i),
 				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);
+		dsi_phy_tst_set(base, DATA_THS_ZERO(i), phy->data_t_hs_zero);
+		dsi_phy_tst_set(base, DATA_THS_TRAIL(i), phy->data_t_hs_trial);
+		dsi_phy_tst_set(base, DATA_TTA_GO(i), phy->data_t_ta_go);
+		dsi_phy_tst_set(base, DATA_TTA_GET(i), phy->data_t_ta_get);
+		dsi_phy_tst_set(base, DATA_TWAKEUP(i), phy->data_t_wakeup);
 	}
 
-	/* physical configuration I  */
-	dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
-
-	/* physical configuration pll II  */
+	/*
+	 * physical configuration: I, pll I, pll II, pll III,
+	 * pll IV, pll V.
+	 */
+	dsi_phy_tst_set(base, PHY_CFG_I, phy->hstx_ckg_sel);
 	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*/
+	dsi_phy_tst_set(base, PHY_CFG_PLL_I, val);
+	dsi_phy_tst_set(base, PHY_CFG_PLL_II, phy->pll_fbd_p);
+	dsi_phy_tst_set(base, PHY_CFG_PLL_III, phy->pll_fbd_s);
 	val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
-	dsi_phy_tst_set(base, 0x10066, val);
+	dsi_phy_tst_set(base, PHY_CFG_PLL_IV, val);
+	val = (5 << 5) + (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
+		phy->pll_lpf_cs;
+	dsi_phy_tst_set(base, PHY_CFG_PLL_V, 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);
+	writel(PHY_ENABLECLK, base + PHY_RSTZ);
 	udelay(1);
-	writel(BIT(2) | BIT(0), base + PHY_RSTZ);
+	writel(PHY_ENABLECLK | PHY_UNSHUTDOWNZ, base + PHY_RSTZ);
 	udelay(1);
-	writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
+	writel(PHY_ENABLECLK | PHY_UNRSTZ | PHY_UNSHUTDOWNZ, base + PHY_RSTZ);
 	usleep_range(1000, 1500);
 
-	/* wait for phy's clock ready */
-	delay_count = 0;
-	is_ready = false;
-	while (1) {
+	/*
+	 * wait for phy's clock ready
+	 */
+	delay_count = 100;
+	while (delay_count--) {
 		val = readl(base +  PHY_STATUS);
-		if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
-			is_ready = (delay_count < 100) ? true : false;
-			delay_count = 0;
+		if ((BIT(0) | BIT(2)) & val)
 			break;
-		}
 
 		udelay(1);
-		++delay_count;
 	}
 
-	if (!is_ready)
+	if (!delay_count)
 		DRM_INFO("phylock and phystopstateclklane is not ready.\n");
 }
 
 static void dsi_set_mode_timing(void __iomem *base,
-				struct mipi_phy_register *phy,
+				u32 lane_byte_clk_kHz,
 				struct drm_display_mode *mode,
 				enum mipi_dsi_pixel_format format)
 {
@@ -409,12 +523,11 @@  static void dsi_set_mode_timing(void __iomem *base,
 	u32 pixel_clk_kHz;
 	int htot, vtot;
 	u32 val;
+	u64 tmp;
 
-	/* 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);
@@ -436,25 +549,14 @@  static void dsi_set_mode_timing(void __iomem *base,
 	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;
+		DRM_DEBUG_DRIVER("vsw exceeded 15\n");
 		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++;
-	}
+	hsa_time = (hsw * lane_byte_clk_kHz) / pixel_clk_kHz;
+	hbp_time = (hbp * lane_byte_clk_kHz) / pixel_clk_kHz;
+	tmp = (u64)htot * (u64)lane_byte_clk_kHz;
+	hline_time = DIV_ROUND_UP(tmp, pixel_clk_kHz);
 
 	/* all specified in byte-lane clocks */
 	writel(hsa_time, base + VID_HSA_TIME);
@@ -466,11 +568,16 @@  static void dsi_set_mode_timing(void __iomem *base,
 	writel(vfp, base + VID_VFP_LINES);
 	writel(mode->vdisplay, base + VID_VACTIVE_LINES);
 	writel(mode->hdisplay, base + VID_PKT_SIZE);
+
+	DRM_DEBUG_DRIVER("htot=%d, hfp=%d, hbp=%d, hsw=%d\n",
+			 htot, hfp, hbp, hsw);
+	DRM_DEBUG_DRIVER("vtol=%d, vfp=%d, vbp=%d, vsw=%d\n",
+			 vtot, vfp, vbp, vsw);
+	DRM_DEBUG_DRIVER("hsa_time=%d, hbp_time=%d, hline_time=%d\n",
+			 hsa_time, hbp_time, hline_time);
 }
 
-static void dsi_set_video_mode_type(void __iomem *base,
-				    struct mipi_phy_register *phy,
-				    unsigned long flags)
+static void dsi_set_video_mode(void __iomem *base, unsigned long flags)
 {
 	u32 val;
 	u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
@@ -480,152 +587,185 @@  static void dsi_set_video_mode_type(void __iomem *base,
 	u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
 
 	/*
-	 * choose video type
+	 * choose video mode 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;
+		val = DSI_BURST_SYNC_PULSES_1 | (0x3f << 8);
 
 	writel(val, base + VID_MODE_CFG);
-	/* TODO: to support LCD panel need to set LP command transfer */
+	writel(PHY_TXREQUESTCLKHS, base + LPCLK_CTRL);
 }
 
-static void dsi_mipi_init(struct hisi_dsi *dsi)
+static void dsi_set_command_mode(void __iomem *base)
+{
+	writel(CMD_MODE_ALL_LP, base + CMD_MODE_CFG);
+	writel(DSI_COMMAND_MODE, base + MODE_CFG);
+}
+
+static void dw_dsi_set_mode(struct dw_dsi *dsi, enum dsi_work_mode mode)
+{
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	void __iomem *base = ctx->base;
+
+	writel(RESET, base + PWR_UP);
+	writel(mode, base + MODE_CFG);
+	writel(POWERUP, base + PWR_UP);
+}
+static void dsi_mipi_init(struct dw_dsi *dsi)
 {
 	struct dsi_hw_ctx *ctx = dsi->ctx;
-	struct mipi_phy_register *phy = &dsi->phy;
+	struct mipi_phy_params *phy = &dsi->phy;
 	struct drm_display_mode *mode = &dsi->cur_mode;
 	void __iomem *base = ctx->base;
-	u32 dphy_freq_kHz;
+	u32 id = dsi->cur_client;
+	u32 dphy_req_kHz;
+	int bpp;
 
-	/* count phy params */
-	dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
-	set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
+	/*
+	 * count phy params
+	 */
+	bpp = mipi_dsi_pixel_format_to_bpp(dsi->client[id].format);
+	if (bpp < 0)
+		return;
+	if (dsi->client[id].phy_clock)
+		dphy_req_kHz = dsi->client[id].phy_clock;
+	else
+		dphy_req_kHz = mode->clock * bpp / dsi->client[id].lanes;
+	dsi_get_phy_params(dphy_req_kHz, phy);
 
 	/* reset Core */
-	writel(0, base + PWR_UP);
+	writel(RESET, base + PWR_UP);
 
-	/* set phy clocks */
-	dsi_mipi_phy_clks(base, phy, dsi->lanes);
+	/* set dsi phy params */
+	dsi_set_mipi_phy(base, phy, dsi->client[id].lanes);
 
-	/* set dsi mode */
-	dsi_set_mode_timing(base, phy, mode, dsi->format);
+	/* set dsi mode timing */
+	dsi_set_mode_timing(base, phy->lane_byte_clk_kHz, mode,
+			    dsi->client[id].format);
 
-	/* set video mode type and low power */
-	dsi_set_video_mode_type(base, phy, dsi->mode_flags);
+	/* set dsi video mode */
+	dsi_set_video_mode(base, dsi->client[id].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);
+	/* set command mode */
+	dsi_set_command_mode(base);
 
-	DRM_INFO("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
-			dsi->lanes, mode->clock, phy->lane_byte_clk_kHz);
+	/* dsi wake up */
+	writel(POWERUP, base + PWR_UP);
+
+	DRM_DEBUG_DRIVER("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n",
+			 dsi->client[id].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 dw_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;
 
+	dw_dsi_set_mode(dsi, DSI_COMMAND_MODE);
+	/* turn off panel's backlight */
+	if (dsi->panel && drm_panel_disable(dsi->panel))
+		DRM_ERROR("failed to disaable panel\n");
+
+	/* turn off panel */
+	if (dsi->panel && drm_panel_unprepare(dsi->panel))
+		DRM_ERROR("failed to unprepare panel\n");
+
 	writel(0, base + PWR_UP);
 	writel(0, base + LPCLK_CTRL);
 	writel(0, base + PHY_RSTZ);
-	clk_disable_unprepare(ctx->dsi_cfg_clk);
+	clk_disable_unprepare(ctx->pclk);
 
 	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 dw_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);
+	ret = clk_prepare_enable(ctx->pclk);
 	if (ret) {
-		DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
+		DRM_ERROR("fail to enable pclk: %d\n", ret);
 		return;
 	}
 
 	dsi_mipi_init(dsi);
 
+	/* turn on panel */
+	if (dsi->panel && drm_panel_prepare(dsi->panel))
+		DRM_ERROR("failed to prepare panel\n");
+
+	dw_dsi_set_mode(dsi, DSI_VIDEO_MODE);
+
+	/* turn on panel's back light */
+	if (dsi->panel && drm_panel_enable(dsi->panel))
+		DRM_ERROR("failed to enable panel\n");
+
 	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);
+	struct dw_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");
+	/* do nothing */
 	return 0;
 }
 
-static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
+static const struct drm_encoder_helper_funcs dw_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 = {
+static const struct drm_encoder_funcs dw_encoder_funcs = {
 	.destroy = drm_encoder_cleanup,
 };
 
-static int hisi_drm_encoder_init(struct drm_device *dev,
-				 struct drm_encoder *encoder)
+static int dw_drm_encoder_init(struct device *dev,
+			       struct drm_device *drm_dev,
+			       struct drm_encoder *encoder)
 {
 	int ret;
+	u32 crtc_mask = drm_of_find_possible_crtcs(drm_dev, dev->of_node);
+
+	if (!crtc_mask) {
+		DRM_ERROR("failed to find crtc mask\n");
+		return -EINVAL;
+	}
 
-	encoder->possible_crtcs = 1;
-	ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
-			       DRM_MODE_ENCODER_TMDS);
+	encoder->possible_crtcs = crtc_mask;
+	ret = drm_encoder_init(drm_dev, encoder, &dw_encoder_funcs,
+			       DRM_MODE_ENCODER_DSI);
 	if (ret) {
 		DRM_ERROR("failed to init dsi encoder\n");
 		return ret;
 	}
 
-	drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
+	drm_encoder_helper_add(encoder, &dw_encoder_helper_funcs);
 
 	return 0;
 }
@@ -633,16 +773,20 @@  static int hisi_drm_encoder_init(struct drm_device *dev,
 static int dsi_host_attach(struct mipi_dsi_host *host,
 			   struct mipi_dsi_device *mdsi)
 {
-	struct hisi_dsi *dsi = host_to_dsi(host);
+	struct dw_dsi *dsi = host_to_dsi(host);
+	u32 id = mdsi->channel >= 1 ? OUT_PANEL : OUT_HDMI;
 
 	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;
+	dsi->client[id].lanes = mdsi->lanes;
+	dsi->client[id].format = mdsi->format;
+	dsi->client[id].mode_flags = mdsi->mode_flags;
+	dsi->client[id].phy_clock = mdsi->phy_clock;
+
+	DRM_INFO("host attach, client name=[%s], id=%d\n", mdsi->name, id);
 
 	return 0;
 }
@@ -654,12 +798,117 @@  static int dsi_host_detach(struct mipi_dsi_host *host,
 	return 0;
 }
 
-static struct mipi_dsi_host_ops dsi_host_ops = {
+static int dsi_gen_pkt_hdr_write(void __iomem *base, u32 val)
+{
+	u32 status;
+	int ret;
+
+	ret = readx_poll_timeout(readl, base + CMD_PKT_STATUS, status,
+				 !(status & GEN_CMD_FULL), 1000,
+				 CMD_PKT_STATUS_TIMEOUT_US);
+	if (ret < 0) {
+		DRM_ERROR("failed to get available command FIFO\n");
+		return ret;
+	}
+
+	writel(val, base + GEN_HDR);
+
+	ret = readx_poll_timeout(readl, base + CMD_PKT_STATUS, status,
+				 status & (GEN_CMD_EMPTY | GEN_PLD_W_EMPTY),
+				 1000, CMD_PKT_STATUS_TIMEOUT_US);
+	if (ret < 0) {
+		DRM_ERROR("failed to write command FIFO\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int dsi_dcs_short_write(void __iomem *base,
+			       const struct mipi_dsi_msg *msg)
+{
+	const u16 *tx_buf = msg->tx_buf;
+	u32 val = GEN_HDATA(*tx_buf) | GEN_HTYPE(msg->type);
+
+	if (msg->tx_len > 2) {
+		DRM_ERROR("too long tx buf length %zu for short write\n",
+			  msg->tx_len);
+		return -EINVAL;
+	}
+
+	return dsi_gen_pkt_hdr_write(base, val);
+}
+
+static int dsi_dcs_long_write(void __iomem *base,
+			      const struct mipi_dsi_msg *msg)
+{
+	const u32 *tx_buf = msg->tx_buf;
+	int len = msg->tx_len, pld_data_bytes = sizeof(*tx_buf), ret;
+	u32 val = GEN_HDATA(msg->tx_len) | GEN_HTYPE(msg->type);
+	u32 remainder = 0;
+	u32 status;
+
+	if (msg->tx_len < 3) {
+		DRM_ERROR("wrong tx buf length %zu for long write\n",
+			  msg->tx_len);
+		return -EINVAL;
+	}
+
+	while (DIV_ROUND_UP(len, pld_data_bytes)) {
+		if (len < pld_data_bytes) {
+			memcpy(&remainder, tx_buf, len);
+			writel(remainder, base + GEN_PLD_DATA);
+			len = 0;
+		} else {
+			writel(*tx_buf, base + GEN_PLD_DATA);
+			tx_buf++;
+			len -= pld_data_bytes;
+		}
+
+		ret = readx_poll_timeout(readl, base + CMD_PKT_STATUS,
+					 status, !(status & GEN_PLD_W_FULL), 1000,
+					 CMD_PKT_STATUS_TIMEOUT_US);
+		if (ret < 0) {
+			DRM_ERROR("failed to get available write payload FIFO\n");
+			return ret;
+		}
+	}
+
+	return dsi_gen_pkt_hdr_write(base, val);
+}
+
+static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
+				    const struct mipi_dsi_msg *msg)
+{
+	struct dw_dsi *dsi = host_to_dsi(host);
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	void __iomem *base = ctx->base;
+	int ret;
+
+	switch (msg->type) {
+	case MIPI_DSI_DCS_SHORT_WRITE:
+	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+	case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+		ret = dsi_dcs_short_write(base, msg);
+		break;
+	case MIPI_DSI_DCS_LONG_WRITE:
+		ret = dsi_dcs_long_write(base, msg);
+		break;
+	default:
+		DRM_ERROR("unsupported message type\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static const struct mipi_dsi_host_ops dsi_host_ops = {
 	.attach = dsi_host_attach,
 	.detach = dsi_host_detach,
+	.transfer = dsi_host_transfer,
 };
 
-static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
+static int dsi_host_init(struct device *dev, struct dw_dsi *dsi)
 {
 	struct mipi_dsi_host *host = &dsi->host;
 	int ret;
@@ -675,44 +924,132 @@  static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
 	return 0;
 }
 
-static int dsi_bridge_init(struct drm_device *dev, struct hisi_dsi *dsi)
+static int dsi_bridge_init(struct drm_device *dev, struct dw_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");
+		DRM_ERROR("failed to attach external bridge\n");
 		return ret;
 	}
 
 	return 0;
 }
 
-static int dsi_bind(struct device *dev, struct device *master, void *data)
+static int dsi_connector_get_modes(struct drm_connector *connector)
 {
-	struct dsi_data *ddata = dev_get_drvdata(dev);
-	struct hisi_dsi *dsi = &ddata->dsi;
-	struct drm_device *drm_dev = data;
+	struct dw_dsi *dsi = connector_to_dsi(connector);
+
+	return drm_panel_get_modes(dsi->panel);
+}
+
+static enum drm_mode_status
+dsi_connector_mode_valid(struct drm_connector *connector,
+			 struct drm_display_mode *mode)
+{
+	enum drm_mode_status mode_status = MODE_OK;
+
+	return mode_status;
+}
+
+static struct drm_encoder *
+dsi_connector_best_encoder(struct drm_connector *connector)
+{
+	struct dw_dsi *dsi = connector_to_dsi(connector);
+
+	return &dsi->encoder;
+}
+
+static struct drm_connector_helper_funcs dsi_connector_helper_funcs = {
+	.get_modes = dsi_connector_get_modes,
+	.mode_valid = dsi_connector_mode_valid,
+	.best_encoder = dsi_connector_best_encoder,
+};
+
+static enum drm_connector_status
+dsi_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct dw_dsi *dsi = connector_to_dsi(connector);
+	enum drm_connector_status status;
+
+	status = dsi->cur_client == OUT_PANEL ?	connector_status_connected :
+		connector_status_disconnected;
+
+	return status;
+}
+
+static void dsi_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs dsi_atomic_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = dsi_connector_detect,
+	.destroy = dsi_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int dsi_connector_init(struct drm_device *dev, struct dw_dsi *dsi)
+{
+	struct drm_encoder *encoder = &dsi->encoder;
+	struct drm_connector *connector = &dsi->connector;
 	int ret;
 
-	ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+	drm_connector_helper_add(connector,
+				 &dsi_connector_helper_funcs);
+
+	ret = drm_connector_init(dev, &dsi->connector,
+				 &dsi_atomic_connector_funcs,
+				 DRM_MODE_CONNECTOR_DSI);
 	if (ret)
 		return ret;
 
-	ret = dsi_host_init(dev, dsi);
+	ret = drm_mode_connector_attach_encoder(connector, encoder);
 	if (ret)
 		return ret;
 
-	ret = dsi_bridge_init(drm_dev, dsi);
+	ret = drm_panel_attach(dsi->panel, connector);
 	if (ret)
 		return ret;
 
+	DRM_INFO("connector init\n");
+	return 0;
+}
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+	struct dsi_data *ddata = dev_get_drvdata(dev);
+	struct dw_dsi *dsi = &ddata->dsi;
+	struct drm_device *drm_dev = data;
+	int ret;
+
+	ret = dw_drm_encoder_init(dev, drm_dev, &dsi->encoder);
+	if (ret)
+		return ret;
+
+	if (dsi->bridge) {
+		ret = dsi_bridge_init(drm_dev, dsi);
+		if (ret)
+			return ret;
+	}
+
+	if (dsi->panel) {
+		ret = dsi_connector_init(drm_dev, dsi);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
@@ -726,24 +1063,11 @@  static const struct component_ops dsi_ops = {
 	.unbind	= dsi_unbind,
 };
 
-static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
+static int dsi_parse_bridge_endpoint(struct dw_dsi *dsi,
+				     struct device_node *endpoint)
 {
-	struct dsi_hw_ctx *ctx = dsi->ctx;
-	struct device_node *np = pdev->dev.of_node;
-	struct device_node *endpoint, *bridge_node;
+	struct device_node *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) {
@@ -759,10 +1083,92 @@  static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
 	}
 	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);
+	return 0;
+}
+
+static int dsi_parse_panel_endpoint(struct dw_dsi *dsi,
+				    struct device_node *endpoint)
+{
+	struct device_node *panel_node;
+	struct drm_panel *panel;
+
+	panel_node = of_graph_get_remote_port_parent(endpoint);
+	if (!panel_node) {
+		DRM_ERROR("no valid panel node\n");
+		return -ENODEV;
+	}
+	of_node_put(panel_node);
+
+	panel = of_drm_find_panel(panel_node);
+	if (!panel) {
+		DRM_DEBUG_DRIVER("skip this panel endpoint.\n");
+		return 0;
+	}
+	dsi->panel = panel;
+
+	return 0;
+}
+
+static int dsi_parse_endpoint(struct dw_dsi *dsi,
+			      struct device_node *np,
+			      enum dsi_output_client client)
+{
+	struct device_node *ep_node;
+	struct of_endpoint ep;
+	int ret = 0;
+
+	if (client == OUT_MAX)
+		return -EINVAL;
+
+	for_each_endpoint_of_node(np, ep_node) {
+		ret = of_graph_parse_endpoint(ep_node, &ep);
+		if (ret) {
+			of_node_put(ep_node);
+			return ret;
+		}
+
+		/* skip dsi input port, port == 0 is input port */
+		if (ep.port == 0)
+			continue;
+
+		/* parse bridge endpoint */
+		if (client == OUT_HDMI) {
+			if (ep.id == 0) {
+				ret = dsi_parse_bridge_endpoint(dsi, ep_node);
+				if (dsi->bridge)
+					break;
+			}
+		} else { /* parse panel endpoint */
+			if (ep.id > 0) {
+				ret = dsi_parse_panel_endpoint(dsi, ep_node);
+				if (dsi->panel)
+					break;
+			}
+		}
+
+		if (ret) {
+			of_node_put(ep_node);
+			return ret;
+		}
+	}
+
+	if (!dsi->bridge && !dsi->panel) {
+		DRM_ERROR("at least one bridge or panel node is required\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int dsi_parse_dt(struct platform_device *pdev, struct dw_dsi *dsi)
+{
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct resource *res;
+
+	ctx->pclk = devm_clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(ctx->pclk)) {
+		DRM_ERROR("failed to get pclk clock\n");
+		return PTR_ERR(ctx->pclk);
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -772,17 +1178,25 @@  static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
 		return PTR_ERR(ctx->base);
 	}
 
+	dsi->gpio_mux = devm_gpiod_get(&pdev->dev, "mux", GPIOD_OUT_HIGH);
+	if (IS_ERR(dsi->gpio_mux))
+		return PTR_ERR(dsi->gpio_mux);
+	/* set dsi default output to panel */
+	dsi->cur_client = OUT_PANEL;
+
 	return 0;
 }
 
 static int dsi_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
+	struct device *dev = &pdev->dev;
 	struct dsi_data *data;
-	struct hisi_dsi *dsi;
+	struct dw_dsi *dsi;
 	struct dsi_hw_ctx *ctx;
 	int ret;
 
-	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 	if (!data) {
 		DRM_ERROR("failed to allocate dsi data.\n");
 		return -ENOMEM;
@@ -791,13 +1205,35 @@  static int dsi_probe(struct platform_device *pdev)
 	ctx = &data->ctx;
 	dsi->ctx = ctx;
 
-	ret = dsi_parse_dt(pdev, dsi);
+	/* parse HDMI bridge endpoint */
+	ret = dsi_parse_endpoint(dsi, np, OUT_HDMI);
+	if (ret)
+		return ret;
+
+	ret = dsi_host_init(dev, dsi);
 	if (ret)
 		return ret;
 
+	/* parse panel endpoint */
+	ret = dsi_parse_endpoint(dsi, np, OUT_PANEL);
+	if (ret)
+		goto err_host_unregister;
+
+	ret = dsi_parse_dt(pdev, dsi);
+	if (ret)
+		goto err_host_unregister;
+
 	platform_set_drvdata(pdev, data);
 
-	return component_add(&pdev->dev, &dsi_ops);
+	ret = component_add(dev, &dsi_ops);
+	if (ret)
+		goto err_host_unregister;
+
+	return 0;
+
+err_host_unregister:
+	mipi_dsi_host_unregister(&dsi->host);
+	return ret;
 }
 
 static int dsi_remove(struct platform_device *pdev)
@@ -817,8 +1253,7 @@  static struct platform_driver dsi_driver = {
 	.probe = dsi_probe,
 	.remove = dsi_remove,
 	.driver = {
-		.name = "hisi-dsi",
-		.owner = THIS_MODULE,
+		.name = "dw-dsi",
 		.of_match_table = dsi_of_match,
 	},
 };
@@ -828,5 +1263,5 @@  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_DESCRIPTION("DesignWare MIPI DSI Host Controller v1.02 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
index db8f9df..17f9c05 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_dsi_reg.h
@@ -1,5 +1,6 @@ 
 /*
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 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
@@ -7,42 +8,106 @@ 
  *
  */
 
-#ifndef __HISI_DSI_REG_H__
-#define __HISI_DSI_REG_H__
+#ifndef __DW_DSI_REG_H__
+#define __DW_DSI_REG_H__
+
+#define MASK(x)				(BIT(x) - 1)
 
 /*
  * 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 PWR_UP                  0x04  /* Core power-up */
+#define RESET                   0
+#define POWERUP                 BIT(0)
+#define PHY_IF_CFG              0xA4  /* D-PHY interface configuration */
+#define CLKMGR_CFG              0x08  /* the internal clock dividers */
+#define PHY_RSTZ                0xA0  /* D-PHY reset control */
+#define PHY_ENABLECLK           BIT(2)
+#define PHY_UNRSTZ              BIT(1)
+#define PHY_UNSHUTDOWNZ         BIT(0)
+#define PHY_TST_CTRL0           0xB4  /* D-PHY test interface control 0 */
+#define PHY_TST_CTRL1           0xB8  /* D-PHY test interface control 1 */
+#define CLK_TLPX                0x10
+#define CLK_THS_PREPARE         0x11
+#define CLK_THS_ZERO            0x12
+#define CLK_THS_TRAIL           0x13
+#define CLK_TWAKEUP             0x14
+#define DATA_TLPX(x)            (0x20 + ((x) << 4))
+#define DATA_THS_PREPARE(x)     (0x21 + ((x) << 4))
+#define DATA_THS_ZERO(x)        (0x22 + ((x) << 4))
+#define DATA_THS_TRAIL(x)       (0x23 + ((x) << 4))
+#define DATA_TTA_GO(x)          (0x24 + ((x) << 4))
+#define DATA_TTA_GET(x)         (0x25 + ((x) << 4))
+#define DATA_TWAKEUP(x)         (0x26 + ((x) << 4))
+#define PHY_CFG_I               0x60
+#define PHY_CFG_PLL_I           0x63
+#define PHY_CFG_PLL_II          0x64
+#define PHY_CFG_PLL_III         0x65
+#define PHY_CFG_PLL_IV          0x66
+#define PHY_CFG_PLL_V           0x67
+#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 GEN_HDR			0x6c
+#define GEN_HDATA(data)		(((data) & 0xffff) << 8)
+#define GEN_HDATA_MASK		(0xffff << 8)
+#define GEN_HTYPE(type)		(((type) & 0xff) << 0)
+#define GEN_HTYPE_MASK		0xff
+#define GEN_PLD_DATA		0x70
+#define CMD_PKT_STATUS		0x74
+#define GEN_CMD_EMPTY		BIT(0)
+#define GEN_CMD_FULL		BIT(1)
+#define GEN_PLD_W_EMPTY		BIT(2)
+#define GEN_PLD_W_FULL		BIT(3)
+#define GEN_PLD_R_EMPTY		BIT(4)
+#define GEN_PLD_R_FULL		BIT(5)
+#define GEN_RD_CMD_BUSY		BIT(6)
+#define CMD_MODE_CFG		0x68
+#define MAX_RD_PKT_SIZE_LP	BIT(24)
+#define DCS_LW_TX_LP		BIT(19)
+#define DCS_SR_0P_TX_LP		BIT(18)
+#define DCS_SW_1P_TX_LP		BIT(17)
+#define DCS_SW_0P_TX_LP		BIT(16)
+#define GEN_LW_TX_LP		BIT(14)
+#define GEN_SR_2P_TX_LP		BIT(13)
+#define GEN_SR_1P_TX_LP		BIT(12)
+#define GEN_SR_0P_TX_LP		BIT(11)
+#define GEN_SW_2P_TX_LP		BIT(10)
+#define GEN_SW_1P_TX_LP		BIT(9)
+#define GEN_SW_0P_TX_LP		BIT(8)
+#define EN_ACK_RQST		BIT(1)
+#define EN_TEAR_FX		BIT(0)
+#define CMD_MODE_ALL_LP		(MAX_RD_PKT_SIZE_LP | \
+				 DCS_LW_TX_LP | \
+				 DCS_SR_0P_TX_LP | \
+				 DCS_SW_1P_TX_LP | \
+				 DCS_SW_0P_TX_LP | \
+				 GEN_LW_TX_LP | \
+				 GEN_SR_2P_TX_LP | \
+				 GEN_SR_1P_TX_LP | \
+				 GEN_SR_0P_TX_LP | \
+				 GEN_SW_2P_TX_LP | \
+				 GEN_SW_1P_TX_LP | \
+				 GEN_SW_0P_TX_LP)
+#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 PHY_TXREQUESTCLKHS      BIT(0)
+#define MODE_CFG                0x34  /* Video or Command mode selection */
+#define PHY_STATUS              0xB0  /* D-PHY PPI status interface */
 
-#define	PHY_STOP_WAIT_TIME      (0x30)
+#define	PHY_STOP_WAIT_TIME      0x30
+#define CMD_PKT_STATUS_TIMEOUT_US	20000
 
 /*
  * regs relevant enum
@@ -64,26 +129,17 @@  enum dsi_work_mode {
 };
 
 /*
- * regs Write/Read functions
+ * Register Write/Read Helper functions
  */
-static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
+static inline void dw_update_bits(void __iomem *addr, u32 bit_start,
+				  u32 mask, 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);
+	u32 tmp, orig;
+
+	orig = readl(addr);
+	tmp = orig & ~(mask << bit_start);
+	tmp |= (val & mask) << bit_start;
+	writel(tmp, addr);
 }
 
-#endif /* __HISI_DRM_DSI_H__ */
+#endif /* __DW_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
deleted file mode 100644
index 73f0938..0000000
--- a/drivers/gpu/drm/hisilicon/kirin/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/kirin/kirin_ade_reg.h b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
index 1055cce..4cf281b7 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_ade_reg.h
@@ -1,5 +1,6 @@ 
 /*
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 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
@@ -7,164 +8,119 @@ 
  *
  */
 
-#ifndef __HISI_ADE_REG_H__
-#define __HISI_ADE_REG_H__
+#ifndef __KIRIN_ADE_REG_H__
+#define __KIRIN_ADE_REG_H__
 
 /*
- * ADE Registers Offset
+ * ADE Registers
  */
-#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)
+#define MASK(x)				(BIT(x) - 1)
+
+#define ADE_CTRL			0x0004
+#define FRM_END_START_OFST		0
+#define FRM_END_START_MASK		MASK(2)
+#define AUTO_CLK_GATE_EN_OFST		0
+#define AUTO_CLK_GATE_EN		BIT(0)
+#define ADE_DISP_SRC_CFG		0x0018
+#define ADE_CTRL1			0x008C
+#define ADE_EN				0x0100
+#define ADE_DISABLE			0
+#define ADE_ENABLE			1
 /* 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 */
+#define ADE_SOFT_RST_SEL(x)		(0x0078 + (x) * 0x4)
+#define ADE_RELOAD_DIS(x)		(0x00AC + (x) * 0x4)
+#define RDMA_OFST			0
+#define CLIP_OFST			15
+#define SCL_OFST			21
+#define CTRAN_OFST			24
+#define OVLY_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_OVLY1_TRANS_CFG		0x002C
+#define ADE_OVLY_CTL			0x0098
 #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 OUTPUT_XSIZE_OFST		16
 #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)
+#define CH_OVLY_SEL_OFST(x)		((x) * 4)
+#define CH_OVLY_SEL_MASK		MASK(2)
+#define CH_OVLY_SEL_VAL(x)		((x) + 1)
+#define CH_ALP_MODE_OFST		0
+#define CH_ALP_SEL_OFST			2
+#define CH_UNDER_ALP_SEL_OFST		4
+#define CH_EN_OFST			6
+#define CH_ALP_GBL_OFST			15
+#define CH_SEL_OFST			28
+/* ctran regs */
+#define ADE_CTRAN_DIS(x)		(0x5004 + (x) * 0x100)
+#define CTRAN_BYPASS_ON			1
+#define CTRAN_BYPASS_OFF		0
+#define ADE_CTRAN_IMAGE_SIZE(x)		(0x503C + (x) * 0x100)
+/* 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)
 
 /*
- * media regs
+ * LDI Registers
  */
-#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
+#define LDI_HRZ_CTRL0			0x7400
+#define HBP_OFST			20
+#define LDI_HRZ_CTRL1			0x7404
+#define LDI_VRT_CTRL0			0x7408
+#define VBP_OFST			20
+#define LDI_VRT_CTRL1			0x740C
+#define LDI_PLR_CTRL			0x7410
+#define FLAG_NVSYNC			BIT(0)
+#define FLAG_NHSYNC			BIT(1)
+#define FLAG_NPIXCLK			BIT(2)
+#define FLAG_NDE			BIT(3)
+#define LDI_DSP_SIZE			0x7414
+#define VSIZE_OFST			20
+#define LDI_INT_EN			0x741C
+#define FRAME_END_INT_EN_OFST		1
+#define LDI_CTRL			0x7420
+#define BPP_OFST			3
+#define DATA_GATE_EN			BIT(2)
+#define LDI_EN				BIT(0)
+#define LDI_MSK_INT			0x7428
+#define LDI_INT_CLR			0x742C
+#define LDI_WORK_MODE			0x7430
+#define LDI_HDMI_DSI_GT			0x7434
 
 /*
- * regs relevant enum
+ * ADE media bus service regs
  */
-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
-};
+#define ADE0_QOSGENERATOR_MODE		0x010C
+#define QOSGENERATOR_MODE_MASK		MASK(2)
+#define ADE0_QOSGENERATOR_EXTCONTROL	0x0118
+#define SOCKET_QOS_EN			BIT(0)
+#define ADE1_QOSGENERATOR_MODE		0x020C
+#define ADE1_QOSGENERATOR_EXTCONTROL	0x0218
 
 /*
- * ADE read as big-endian, so revert the
- * rgb order described in the SoC datasheet
+ * ADE regs relevant enums
  */
-enum ADE_FORMAT {
+enum frame_end_start {
+	/* regs take effect in every vsync */
+	REG_EFFECTIVE_IN_VSYNC = 0,
+	/* regs take effect in fist ade en and every frame end */
+	REG_EFFECTIVE_IN_ADEEN_FRMEND,
+	/* regs take effect in ade en immediately */
+	REG_EFFECTIVE_IN_ADEEN,
+	/* regs take effect in first vsync and every frame end */
+	REG_EFFECTIVE_IN_VSYNC_FRMEND
+};
+
+enum ade_fb_format {
 	ADE_RGB_565 = 0,
 	ADE_BGR_565,
 	ADE_XRGB_8888,
@@ -175,20 +131,7 @@  enum ADE_FORMAT {
 	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
+	ADE_FORMAT_UNSUPPORT = 800
 };
 
 enum ade_channel {
@@ -220,13 +163,13 @@  enum ade_overlay {
 	ADE_OVLY_NUM
 };
 
-enum {
+enum ade_alpha_mode {
 	ADE_ALP_GLOBAL = 0,
 	ADE_ALP_PIXEL,
 	ADE_ALP_PIXEL_AND_GLB
 };
 
-enum {
+enum ade_alpha_blending_mode {
 	ADE_ALP_MUL_COEFF_0 = 0,	/* alpha */
 	ADE_ALP_MUL_COEFF_1,		/* 1-alpha */
 	ADE_ALP_MUL_COEFF_2,		/* 0 */
@@ -234,261 +177,54 @@  enum {
 };
 
 /*
- * ADE Register Union Struct
+ * LDI regs relevant enums
  */
-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;
+enum dsi_pclk_en {
+	DSI_PCLK_ON = 0,
+	DSI_PCLK_OFF
 };
 
-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;
+enum ldi_output_format {
+	LDI_OUT_RGB_565 = 0,
+	LDI_OUT_RGB_666,
+	LDI_OUT_RGB_888
 };
 
-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;
+enum ldi_work_mode {
+	TEST_MODE = 0,
+	NORMAL_MODE
 };
 
-/*
- * 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)
+enum ldi_input_source {
+	DISP_SRC_NONE = 0,
+	DISP_SRC_OVLY2,
+	DISP_SRC_DISP,
+	DISP_SRC_ROT,
+	DISP_SRC_SCL2
+};
 
 /*
- * LDI Register Union Struct
+ * ADE media bus service relevant enums
  */
-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;
+enum qos_generator_mode {
+	FIXED_MODE = 0,
+	LIMITER_MODE,
+	BYPASS_MODE,
+	REGULATOR_MODE
 };
 
 /*
- * LDI Register Write/Read Helper functions
+ * 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)
+static inline void ade_update_bits(void __iomem *addr, u32 bit_start,
+				   u32 mask, u32 val)
 {
-	union U_LDI_WORK_MODE ldi_work_mode;
-	u8 *addr = base + LDI_WORK_MODE;
+	u32 tmp, orig;
 
-	ldi_work_mode.u32 = readl(addr);
-	ldi_work_mode.bits.colorbar_en = val;
-	writel(ldi_work_mode.u32, addr);
+	orig = readl(addr);
+	tmp = orig & ~(mask << bit_start);
+	tmp |= (val & mask) << bit_start;
+	writel(tmp, addr);
 }
 
 #endif
diff --git a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
index fbf68eb..971e48b 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_ade.c
@@ -1,10 +1,12 @@ 
 /*
  * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
  *
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
+ *
  * Author:
- *	Xinliang Liu <xinliang.liu@linaro.org>
  *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinliang Liu <xinliang.liu@linaro.org>
  *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -15,8 +17,10 @@ 
 
 #include <linux/bitops.h>
 #include <linux/clk.h>
-#include <linux/component.h>
 #include <video/display_timing.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc.h>
@@ -30,8 +34,9 @@ 
 #include "kirin_drm_drv.h"
 #include "kirin_ade_reg.h"
 
-#define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
-#define PRIMARY_CH	(ADE_CH1)
+#define PRIMARY_CH	ADE_CH1 /* primary plane */
+#define OUT_OVLY	ADE_OVLY2 /* output overlay compositor */
+#define ADE_DEBUG	1
 
 #define to_ade_crtc(crtc) \
 	container_of(crtc, struct ade_crtc, base)
@@ -41,24 +46,20 @@ 
 
 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 regmap *noc_regmap;
 	struct clk *ade_core_clk;
 	struct clk *media_noc_clk;
 	struct clk *ade_pix_clk;
+	struct reset_control *reset;
 	bool power_on;
+	int irq;
 };
 
 struct ade_crtc {
 	struct drm_crtc base;
 	struct ade_hw_ctx *ctx;
 	bool enable;
-	u64 use_mask;
+	u32 out_format;
 };
 
 struct ade_plane {
@@ -76,7 +77,7 @@  struct ade_data {
 /* ade-format info: */
 struct ade_format {
 	u32 pixel_format;
-	enum ADE_FORMAT ade_format;
+	enum ade_fb_format ade_format;
 };
 
 static const struct ade_format ade_formats[] = {
@@ -126,8 +127,31 @@  static u32 ade_get_format(u32 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;
+	DRM_ERROR("Not found pixel format!!fourcc_format= %d\n",
+		  pixel_format);
+	return ADE_FORMAT_UNSUPPORT;
+}
+
+static void ade_update_reload_bit(void __iomem *base, u32 bit_num, u32 val)
+{
+	u32 bit_ofst, reg_num;
+
+	bit_ofst = bit_num % 32;
+	reg_num = bit_num / 32;
+
+	ade_update_bits(base + ADE_RELOAD_DIS(reg_num), bit_ofst,
+			MASK(1), !!val);
+}
+
+static u32 ade_read_reload_bit(void __iomem *base, u32 bit_num)
+{
+	u32 tmp, bit_ofst, reg_num;
+
+	bit_ofst = bit_num % 32;
+	reg_num = bit_num / 32;
+
+	tmp = readl(base + ADE_RELOAD_DIS(reg_num));
+	return !!(BIT(bit_ofst) & tmp);
 }
 
 static void ade_init(struct ade_hw_ctx *ctx)
@@ -135,20 +159,40 @@  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);
+	ade_update_bits(base + ADE_CTRL1, AUTO_CLK_GATE_EN_OFST,
+			AUTO_CLK_GATE_EN, ADE_ENABLE);
 	/* clear overlay */
 	writel(0, base + ADE_OVLY1_TRANS_CFG);
 	writel(0, base + ADE_OVLY_CTL);
-	writel(0, base + ADE_OVLYX_CTL(ADE_OVLY2));
+	writel(0, base + ADE_OVLYX_CTL(OUT_OVLY));
 	/* 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
+	writel(MASK(32), base + ADE_SOFT_RST_SEL(0));
+	writel(MASK(32), base + ADE_SOFT_RST_SEL(1));
+	writel(MASK(32), base + ADE_RELOAD_DIS(0));
+	writel(MASK(32), base + ADE_RELOAD_DIS(1));
+	/*
+	 * for video mode, all the ade registers should
+	 * become effective at frame end.
+	 */
+	ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST,
+			FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND);
+}
+
+static void ade_set_pix_clk(struct ade_hw_ctx *ctx,
+			    struct drm_display_mode *mode,
+			    struct drm_display_mode *adj_mode)
+{
+	u32 clk_Hz = mode->clock * 1000;
+	int ret;
+
+	/*
+	 * Success should be guaranteed in mode_valid call back,
+	 * so failure shouldn't happen here
 	 */
-	set_TOP_CTL_frm_end_start(base, 1);
+	ret = clk_set_rate(ctx->ade_pix_clk, clk_Hz);
+	if (ret)
+		DRM_ERROR("failed to set pixel clk %dHz (%d)\n", clk_Hz, ret);
+	adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
 }
 
 static void ade_ldi_set_mode(struct ade_crtc *acrtc,
@@ -157,16 +201,13 @@  static void ade_ldi_set_mode(struct ade_crtc *acrtc,
 {
 	struct ade_hw_ctx *ctx = acrtc->ctx;
 	void __iomem *base = ctx->base;
-	u32 out_w = mode->hdisplay;
-	u32 out_h = mode->vdisplay;
+	u32 width = mode->hdisplay;
+	u32 height = 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;
+	plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? FLAG_NVSYNC : 0;
+	plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC) ? FLAG_NHSYNC : 0;
 	hfp = mode->hsync_start - mode->hdisplay;
 	hbp = mode->htotal - mode->hsync_end;
 	hsw = mode->hsync_end - mode->hsync_start;
@@ -174,77 +215,55 @@  static void ade_ldi_set_mode(struct ade_crtc *acrtc,
 	vbp = mode->vtotal - mode->vsync_end;
 	vsw = mode->vsync_end - mode->vsync_start;
 	if (vsw > 15) {
-		DRM_INFO("vsw exceeded 15\n");
+		DRM_DEBUG_DRIVER("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((hbp << HBP_OFST) | hfp, base + LDI_HRZ_CTRL0);
+	 /* the configured value is actual value - 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((vbp << VBP_OFST) | vfp, base + LDI_VRT_CTRL0);
+	 /* the configured value is actual value - 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),
+	 /* the configured value is actual value - 1 */
+	writel(((height - 1) << VSIZE_OFST) | (width - 1),
 	       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;
+	/* set overlay compositor output size */
+	writel(((width - 1) << OUTPUT_XSIZE_OFST) | (height - 1),
+	       base + ADE_OVLY_OUTPUT_SIZE(OUT_OVLY));
 
 	/* 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);
+	writel(CTRAN_BYPASS_ON, base + ADE_CTRAN_DIS(ADE_CTRAN6));
+	 /* the configured value is actual value - 1 */
+	writel(width * height - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
+	ade_update_reload_bit(base, CTRAN_OFST + ADE_CTRAN6, 0);
 
-	/*
-	 * 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);
+	ade_set_pix_clk(ctx, mode, adj_mode);
+
+	DRM_DEBUG_DRIVER("set mode: %dx%d\n", width, height);
 }
 
 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);
+	ret = clk_prepare_enable(ctx->media_noc_clk);
 	if (ret) {
-		DRM_ERROR("media_noc_clk media_noc_rate error\n");
+		DRM_ERROR("failed to enable media_noc_clk (%d)\n", ret);
 		return ret;
 	}
-	ret = clk_prepare_enable(ctx->media_noc_clk);
+
+	ret = reset_control_deassert(ctx->reset);
 	if (ret) {
-		DRM_ERROR("fail to clk_prepare_enable media_noc_clk\n");
+		DRM_ERROR("failed to deassert reset\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");
+		DRM_ERROR("failed to enable ade_core_clk (%d)\n", ret);
 		return ret;
 	}
 
@@ -256,70 +275,63 @@  static int ade_power_up(struct ade_hw_ctx *ctx)
 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);
+	writel(ADE_DISABLE, base + LDI_CTRL);
 	/* dsi pixel off */
-	set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
+	writel(DSI_PCLK_OFF, base + LDI_HDMI_DSI_GT);
 
 	clk_disable_unprepare(ctx->ade_core_clk);
-	writel(0x20, media_base + SC_MEDIA_RSTEN);
+	reset_control_assert(ctx->reset);
 	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)
+static void ade_set_medianoc_qos(struct ade_crtc *acrtc)
 {
-	unsigned int index_tmp = 0;
-	struct drm_crtc *crtc;
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	struct regmap *map = ctx->noc_regmap;
 
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (index_tmp == index)
-			return crtc;
+	regmap_update_bits(map, ADE0_QOSGENERATOR_MODE,
+			   QOSGENERATOR_MODE_MASK, BYPASS_MODE);
+	regmap_update_bits(map, ADE0_QOSGENERATOR_EXTCONTROL,
+			   SOCKET_QOS_EN, SOCKET_QOS_EN);
 
-		index_tmp++;
-	}
-
-	WARN_ON(true);
-	return NULL;
+	regmap_update_bits(map, ADE1_QOSGENERATOR_MODE,
+			   QOSGENERATOR_MODE_MASK, BYPASS_MODE);
+	regmap_update_bits(map, ADE1_QOSGENERATOR_EXTCONTROL,
+			   SOCKET_QOS_EN, SOCKET_QOS_EN);
 }
 
-int ade_enable_vblank(struct drm_device *dev, unsigned int pipe)
+static 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 kirin_drm_private *priv = dev->dev_private;
+	struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
 	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);
+	ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST,
+			MASK(1), 1);
 
 	return 0;
 }
 
-void ade_disable_vblank(struct drm_device *dev, unsigned int pipe)
+static 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 kirin_drm_private *priv = dev->dev_private;
+	struct ade_crtc *acrtc = to_ade_crtc(priv->crtc[pipe]);
 	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);
+
+	ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST,
+			MASK(1), 0);
 }
 
 static irqreturn_t ade_irq_handler(int irq, void *data)
@@ -327,94 +339,135 @@  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); */
+	DRM_DEBUG_VBL("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));
+	if (status & BIT(FRAME_END_INT_EN_OFST)) {
+		ade_update_bits(base + LDI_INT_CLR, FRAME_END_INT_EN_OFST,
+				MASK(1), 1);
+		drm_crtc_handle_vblank(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)
+static void ade_display_enable(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);
+	u32 out_fmt = acrtc->out_format;
 
-	DRM_DEBUG_DRIVER("mask=0x%llX, mask0=0x%X, mask1=0x%X\n",
-			 acrtc->use_mask, mask0, mask1);
+	/* enable output overlay compositor */
+	writel(ADE_ENABLE, base + ADE_OVLYX_CTL(OUT_OVLY));
+	ade_update_reload_bit(base, OVLY_OFST + OUT_OVLY, 0);
 
-	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);
+	/* display source setting */
+	writel(DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+
+	/* enable ade */
+	writel(ADE_ENABLE, base + ADE_EN);
+	/* enable ldi */
+	writel(NORMAL_MODE, base + LDI_WORK_MODE);
+	writel((out_fmt << BPP_OFST) | DATA_GATE_EN | LDI_EN,
+	       base + LDI_CTRL);
+	/* dsi pixel on */
+	writel(DSI_PCLK_ON, base + LDI_HDMI_DSI_GT);
 }
 
-void ade_set_medianoc_qos(struct ade_crtc *acrtc)
+#if ADE_DEBUG
+static void ade_rdma_dump_regs(void __iomem *base, u32 ch)
 {
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->media_noc_base;
-	void __iomem *reg;
+	u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
 	u32 val;
 
-	reg = base + NOC_ADE0_QOSGENERATOR_MODE;
-	val = (readl(reg) & 0xfffffffc) | 0x2;
-	writel(val, reg);
+	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);
 
-	reg = base + NOC_ADE0_QOSGENERATOR_EXTCONTROL;
-	val = readl(reg) | 0x1;
-	writel(val, reg);
+	val = ade_read_reload_bit(base, RDMA_OFST + ch);
+	DRM_DEBUG_DRIVER("[rdma%d]: reload(%d)\n", ch + 1, val);
+	val = readl(base + reg_ctrl);
+	DRM_DEBUG_DRIVER("[rdma%d]: reg_ctrl(0x%08x)\n", ch + 1, val);
+	val = readl(base + reg_addr);
+	DRM_DEBUG_DRIVER("[rdma%d]: reg_addr(0x%08x)\n", ch + 1, val);
+	val = readl(base + reg_size);
+	DRM_DEBUG_DRIVER("[rdma%d]: reg_size(0x%08x)\n", ch + 1, val);
+	val = readl(base + reg_stride);
+	DRM_DEBUG_DRIVER("[rdma%d]: reg_stride(0x%08x)\n", ch + 1, val);
+	val = readl(base + reg_space);
+	DRM_DEBUG_DRIVER("[rdma%d]: reg_space(0x%08x)\n", ch + 1, val);
+	val = readl(base + reg_en);
+	DRM_DEBUG_DRIVER("[rdma%d]: reg_en(0x%08x)\n", ch + 1, val);
+}
 
-	reg = base + NOC_ADE1_QOSGENERATOR_MODE;
-	val = (readl(reg) & 0xfffffffc) | 0x2;
-	writel(val, reg);
+static void ade_clip_dump_regs(void __iomem *base, u32 ch)
+{
+	u32 val;
 
-	reg = base + NOC_ADE1_QOSGENERATOR_EXTCONTROL;
-	val = readl(reg) | 0x1;
-	writel(val, reg);
+	val = ade_read_reload_bit(base, CLIP_OFST + ch);
+	DRM_DEBUG_DRIVER("[clip%d]: reload(%d)\n", ch + 1, val);
+	val = readl(base + ADE_CLIP_DISABLE(ch));
+	DRM_DEBUG_DRIVER("[clip%d]: reg_clip_disable(0x%08x)\n", ch + 1, val);
+	val = readl(base + ADE_CLIP_SIZE0(ch));
+	DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size0(0x%08x)\n", ch + 1, val);
+	val = readl(base + ADE_CLIP_SIZE1(ch));
+	DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size1(0x%08x)\n", ch + 1, val);
 }
 
-/*
- * commit to ldi to display
- */
-static void ade_display_commit(struct ade_crtc *acrtc)
+static void ade_compositor_routing_dump_regs(void __iomem *base, u32 ch)
 {
-	struct ade_hw_ctx *ctx = acrtc->ctx;
-	void __iomem *base = ctx->base;
+	u8 ovly_ch = 0; /* TODO: Only primary plane now */
+	u32 val;
 
-	/* TODO: set rotator after overlay */
+	val = readl(base + ADE_OVLY_CH_XY0(ovly_ch));
+	DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy0(0x%08x)\n", ovly_ch, val);
+	val = readl(base + ADE_OVLY_CH_XY1(ovly_ch));
+	DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy1(0x%08x)\n", ovly_ch, val);
+	val = readl(base + ADE_OVLY_CH_CTL(ovly_ch));
+	DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_ctl(0x%08x)\n", ovly_ch, val);
+}
 
-	/* TODO: set scale after overlay */
+static void ade_dump_overlay_compositor_regs(void __iomem *base, u32 comp)
+{
+	u32 val;
 
-	/* display source setting */
-	writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+	val = ade_read_reload_bit(base, OVLY_OFST + comp);
+	DRM_DEBUG_DRIVER("[overlay%d]: reload(%d)\n", comp + 1, val);
+	writel(ADE_ENABLE, base + ADE_OVLYX_CTL(comp));
+	DRM_DEBUG_DRIVER("[overlay%d]: reg_ctl(0x%08x)\n", comp + 1, val);
+	val = readl(base + ADE_OVLY_CTL);
+	DRM_DEBUG_DRIVER("ovly_ctl(0x%08x)\n", val);
+}
 
-	/* set reset mode:soft or hw, and reload modules */
-	ade_set_reset_and_reload(acrtc);
+static void ade_dump_regs(void __iomem *base)
+{
+	u32 i;
 
-	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);
+	/* dump channel regs */
+	for (i = 0; i < ADE_CH_NUM; i++) {
+		/* dump rdma regs */
+		ade_rdma_dump_regs(base, i);
+
+		/* dump clip regs */
+		ade_clip_dump_regs(base, i);
+
+		/* dump compositor routing regs */
+		ade_compositor_routing_dump_regs(base, i);
+	}
+
+	/* dump overlay compositor regs */
+	ade_dump_overlay_compositor_regs(base, OUT_OVLY);
 }
+#else
+static void ade_dump_regs(void __iomem *base) { }
+#endif
 
 static void ade_crtc_enable(struct drm_crtc *crtc)
 {
@@ -422,23 +475,19 @@  static void ade_crtc_enable(struct drm_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");
+		if (ret)
 			return;
-		}
 	}
 
 	ade_set_medianoc_qos(acrtc);
-	ade_display_commit(acrtc);
+	ade_display_enable(acrtc);
+	ade_dump_regs(ctx->base);
 	acrtc->enable = true;
-
-	DRM_DEBUG_DRIVER("exit success.\n");
 }
 
 static void ade_crtc_disable(struct drm_crtc *crtc)
@@ -446,21 +495,16 @@  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)
+static 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;
 }
@@ -472,11 +516,9 @@  static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
 	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,
@@ -485,10 +527,8 @@  static void ade_crtc_atomic_begin(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 (!ctx->power_on)
 		(void)ade_power_up(ctx);
-	DRM_DEBUG_DRIVER("exit success.\n");
 }
 
 static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
@@ -499,16 +539,12 @@  static void ade_crtc_atomic_flush(struct drm_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 */
+	/* only crtc is enabled regs take effect */
 	if (acrtc->enable) {
-		/* set reset and reload */
-		ade_set_reset_and_reload(acrtc);
-		/* flush ade regitsters */
-		wmb();
+		ade_dump_regs(base);
+		/* flush ade registers */
 		writel(ADE_ENABLE, base + ADE_EN);
 	}
-	DRM_DEBUG_DRIVER("exit success.\n");
 }
 
 static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
@@ -533,35 +569,48 @@  static const struct drm_crtc_funcs ade_crtc_funcs = {
 static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 			 struct drm_plane *plane)
 {
+	struct kirin_drm_private *priv = dev->dev_private;
+	struct device_node *port;
 	int ret;
 
-	ret = drm_crtc_init_with_planes(dev, crtc, plane,
-					NULL, &ade_crtc_funcs);
+	/* set crtc port so that
+	 * drm_of_find_possible_crtcs call works
+	 */
+	port = of_get_child_by_name(dev->dev->of_node, "port");
+	if (!port) {
+		DRM_ERROR("no port node found in %s\n",
+			  dev->dev->of_node->full_name);
+		return -EINVAL;
+	}
+	of_node_put(port);
+	crtc->port = port;
+
+	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);
+	priv->crtc[drm_crtc_index(crtc)] = crtc;
 
 	return 0;
 }
 
-static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
+static void ade_rdma_set(void __iomem *base, 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 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
 	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));
+	DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n",
+			 ch + 1, y, in_h, stride, (u32)obj->paddr);
+	DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
+			 addr, fb->width, fb->height, fmt,
+			 drm_get_format_name(fb->pixel_format));
 
 	/* get reg offset */
 	reg_ctrl = RD_CH_CTRL(ch);
@@ -579,29 +628,23 @@  static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
 	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);
+	writel(ADE_ENABLE, base + reg_en);
+	ade_update_reload_bit(base, RDMA_OFST + ch, 0);
 }
 
-static void ade_rdma_disable(struct ade_crtc *acrtc, u32 ch)
+static void ade_rdma_disable(void __iomem *base, 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);
+	ade_update_reload_bit(base, RDMA_OFST + ch, 1);
 }
 
-static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
+static void ade_clip_set(void __iomem *base, 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;
@@ -625,17 +668,13 @@  static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
 	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);
+	ade_update_reload_bit(base, CLIP_OFST + ch, 0);
 }
 
-static void ade_clip_disable(struct ade_crtc *acrtc, u32 ch)
+static void ade_clip_disable(void __iomem *base, 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);
+	ade_update_reload_bit(base, CLIP_OFST + ch, 1);
 }
 
 static bool has_Alpha_channel(int format)
@@ -673,13 +712,11 @@  static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
 	*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)
+static void ade_compositor_routing_set(void __iomem *base, 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 ovly_ch = 0; /* TODO: This is the zpos, only one plane now */
 	u8 glb_alpha = 255;
 	u32 x1 = x0 + in_w - 1;
 	u32 y1 = y0 + in_h - 1;
@@ -691,56 +728,46 @@  static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
 	ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
 				&under_alp_sel);
 
-	/* overlay routing setting */
+	/* 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);
+	val = (ch + 1) << CH_SEL_OFST | BIT(CH_EN_OFST) |
+		alp_sel << CH_ALP_SEL_OFST |
+		under_alp_sel << CH_UNDER_ALP_SEL_OFST |
+		glb_alpha << CH_ALP_GBL_OFST |
+		alp_mode << CH_ALP_MODE_OFST;
 	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);
-	}
+	/* connect this plane/channel to overlay2 compositor */
+	ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch),
+			CH_OVLY_SEL_MASK, CH_OVLY_SEL_VAL(OUT_OVLY));
 }
 
-static void ade_overlay_disable(struct ade_crtc *acrtc, u32 ch)
+static void ade_compositor_routing_disable(void __iomem *base, 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);
+	u8 ovly_ch = 0; /* TODO: Only primary plane now */
+
+	/* disable this plane/channel */
+	ade_update_bits(base + ADE_OVLY_CH_CTL(ovly_ch), CH_EN_OFST,
+			MASK(1), 0);
+	/* dis-connect this plane/channel of overlay2 compositor */
+	ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch),
+			CH_OVLY_SEL_MASK, 0);
 }
 
 /*
- * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
+ * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->compositor
  */
-static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
+static void ade_update_channel(struct ade_plane *aplane,
 			       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;
+	struct ade_hw_ctx *ctx = aplane->ctx;
+	void __iomem *base = ctx->base;
 	u32 fmt = ade_get_format(fb->pixel_format);
+	u32 ch = aplane->ch;
 	u32 in_w;
 	u32 in_h;
 
@@ -751,60 +778,48 @@  static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
 	/* 1) DMA setting */
 	in_w = src_w;
 	in_h = src_h;
-	ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt);
+	ade_rdma_set(base, fb, ch, src_y, in_h, fmt);
 
 	/* 2) clip setting */
-	ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
+	ade_clip_set(base, 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");
+	/* 5) compositor routing setting */
+	ade_compositor_routing_set(base, ch, crtc_x, crtc_y, in_w, in_h, fmt);
 }
 
-static void ade_disable_channel(struct ade_plane *aplane,
-				struct ade_crtc *acrtc)
+static void ade_disable_channel(struct ade_plane *aplane)
 {
+	struct ade_hw_ctx *ctx = aplane->ctx;
+	void __iomem *base = ctx->base;
 	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);
+	ade_rdma_disable(base, ch);
 
 	/* disable clip */
-	ade_clip_disable(acrtc, ch);
+	ade_clip_disable(base, ch);
 
-	/* disable overlay routing */
-	ade_overlay_disable(acrtc, ch);
-
-	DRM_DEBUG_DRIVER("exit success.\n");
+	/* disable compositor routing */
+	ade_compositor_routing_disable(base, ch);
 }
 
 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");
+	/* do nothing */
 	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");
+	/* do nothing */
 }
 
 static int ade_plane_atomic_check(struct drm_plane *plane,
@@ -821,10 +836,15 @@  static int ade_plane_atomic_check(struct drm_plane *plane,
 	int crtc_y = state->crtc_y;
 	u32 crtc_w = state->crtc_w;
 	u32 crtc_h = state->crtc_h;
+	u32 fmt;
 
 	if (!crtc || !fb)
 		return 0;
 
+	fmt = ade_get_format(fb->pixel_format);
+	if (fmt == ADE_FORMAT_UNSUPPORT)
+		return -EINVAL;
+
 	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
 	if (IS_ERR(crtc_state))
 		return PTR_ERR(crtc_state);
@@ -853,14 +873,8 @@  static void ade_plane_atomic_update(struct drm_plane *plane,
 {
 	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,
+	ade_update_channel(aplane, 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);
@@ -870,12 +884,8 @@  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);
+	ade_disable_channel(aplane);
 }
 
 static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
@@ -920,181 +930,128 @@  static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
 	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;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
 
-	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);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ctx->base = devm_ioremap_resource(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);
-	}
+	ctx->reset = devm_reset_control_get(dev, NULL);
+	if (IS_ERR(ctx->reset))
+		return PTR_ERR(ctx->reset);
 
-	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->noc_regmap =
+		syscon_regmap_lookup_by_phandle(np, "hisilicon,noc-syscon");
+	if (IS_ERR(ctx->noc_regmap)) {
+		DRM_ERROR("failed to get noc regmap\n");
+		return PTR_ERR(ctx->noc_regmap);
 	}
 
 	ctx->irq = platform_get_irq(pdev, 0);
 	if (ctx->irq < 0) {
-		DRM_ERROR("failed to parse the irq\n");
+		DRM_ERROR("failed to get irq\n");
 		return -ENODEV;
 	}
 
-	ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
+	ctx->ade_core_clk = devm_clk_get(dev, "clk_ade_core");
 	if (!ctx->ade_core_clk) {
-		DRM_ERROR("failed to parse the ADE_CORE\n");
+		DRM_ERROR("failed to parse clk ADE_CORE\n");
 		return -ENODEV;
 	}
-	ctx->media_noc_clk = devm_clk_get(&pdev->dev,
-					"aclk_codec_jpeg_src");
+
+	ctx->media_noc_clk = devm_clk_get(dev, "clk_codec_jpeg");
 	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");
+		DRM_ERROR("failed to parse clk CODEC_JPEG\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");
+	ctx->ade_pix_clk = devm_clk_get(dev, "clk_ade_pix");
+	if (!ctx->ade_pix_clk) {
+		DRM_ERROR("failed to parse clk ADE_PIX\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)
+static int ade_drm_init(struct drm_device *dev)
 {
+	struct platform_device *pdev = dev->platformdev;
 	struct ade_data *ade;
+	struct ade_hw_ctx *ctx;
+	struct ade_crtc *acrtc;
+	struct ade_plane *aplane;
+	enum drm_plane_type type;
 	int ret;
+	int i;
 
-	DRM_DEBUG_DRIVER("enter.\n");
-
-	ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
+	ade = devm_kzalloc(dev->dev, sizeof(*ade), GFP_KERNEL);
 	if (!ade) {
 		DRM_ERROR("failed to alloc ade_data\n");
 		return -ENOMEM;
 	}
+	platform_set_drvdata(pdev, ade);
 
-	ret = ade_dts_parse(pdev, &ade->ctx);
-	if (ret) {
-		DRM_ERROR("failed to parse dts!!\n");
+	ctx = &ade->ctx;
+	acrtc = &ade->acrtc;
+	acrtc->ctx = ctx;
+	acrtc->out_format = LDI_OUT_RGB_888;
+
+	ret = ade_dts_parse(pdev, ctx);
+	if (ret)
 		return ret;
+
+	/*
+	 * 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(dev, aplane, type);
+		if (ret)
+			return ret;
 	}
 
-	platform_set_drvdata(pdev, ade);
+	/* crtc init */
+	ret = ade_crtc_init(dev, &acrtc->base, &ade->aplane[PRIMARY_CH].base);
+	if (ret)
+		return ret;
+
+	/* vblank irq init */
+	ret = devm_request_irq(dev->dev, ctx->irq, ade_irq_handler,
+			       IRQF_SHARED, dev->driver->name, acrtc);
+	if (ret)
+		return ret;
+	dev->driver->get_vblank_counter = drm_vblank_no_hw_counter;
+	dev->driver->enable_vblank = ade_enable_vblank;
+	dev->driver->disable_vblank = ade_disable_vblank;
 
-	return component_add(&pdev->dev, &ade_ops);
+	return 0;
 }
 
-static int ade_remove(struct platform_device *pdev)
+static void ade_drm_cleanup(struct drm_device *dev)
 {
-	component_del(&pdev->dev, &ade_ops);
+	struct platform_device *pdev = dev->platformdev;
+	struct ade_data *ade = platform_get_drvdata(pdev);
+	struct drm_crtc *crtc = &ade->acrtc.base;
 
-	return 0;
+	drm_crtc_cleanup(crtc);
 }
 
-static const struct of_device_id ade_of_match[] = {
-	{ .compatible = "hisilicon,hi6220-ade" },
-	{ }
+const struct kirin_dc_ops ade_dc_ops = {
+	.init = ade_drm_init,
+	.cleanup = ade_drm_cleanup
 };
-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
index dd23a66..d8cc12a 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.c
@@ -1,10 +1,12 @@ 
 /*
- * Hisilicon SoCs drm master driver
+ * Hisilicon Kirin SoCs drm master driver
+ *
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 Hisilicon Limited.
  *
- * Copyright (c) 2014-2015 Hisilicon Limited.
  * Author:
- *	Xinliang Liu <xinliang.liu@linaro.org>
  *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinliang Liu <xinliang.liu@linaro.org>
  *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -15,6 +17,7 @@ 
 
 #include <linux/of_platform.h>
 #include <linux/component.h>
+#include <linux/of_graph.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_gem_cma_helper.h>
@@ -22,14 +25,13 @@ 
 #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 struct kirin_dc_ops *dc_ops;
 
-static int hisi_drm_unload(struct drm_device *dev)
+static int kirin_drm_kms_cleanup(struct drm_device *dev)
 {
-	struct hisi_drm_private *priv = dev->dev_private;
+	struct kirin_drm_private *priv = dev->dev_private;
 
 #ifdef CONFIG_DRM_FBDEV_EMULATION
 	if (priv->fbdev) {
@@ -39,6 +41,7 @@  static int hisi_drm_unload(struct drm_device *dev)
 #endif
 	drm_kms_helper_poll_fini(dev);
 	drm_vblank_cleanup(dev);
+	dc_ops->cleanup(dev);
 	drm_mode_config_cleanup(dev);
 	devm_kfree(dev->dev, priv);
 	dev->dev_private = NULL;
@@ -46,11 +49,15 @@  static int hisi_drm_unload(struct drm_device *dev)
 	return 0;
 }
 
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-static void hisi_fbdev_output_poll_changed(struct drm_device *dev)
+static void kirin_fbdev_output_poll_changed(struct drm_device *dev)
 {
-	struct hisi_drm_private *priv = dev->dev_private;
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	struct kirin_drm_private *priv = dev->dev_private;
+#endif
 
+	dsi_set_output_client(dev);
+
+#ifdef CONFIG_DRM_FBDEV_EMULATION
 	if (priv->fbdev) {
 		drm_fbdev_cma_hotplug_event(priv->fbdev);
 	} else {
@@ -60,19 +67,17 @@  static void hisi_fbdev_output_poll_changed(struct drm_device *dev)
 		if (IS_ERR(priv->fbdev))
 			priv->fbdev = NULL;
 	}
-}
 #endif
+}
 
-static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
+static const struct drm_mode_config_funcs kirin_drm_mode_config_funcs = {
 	.fb_create = drm_fb_cma_create,
-#ifdef CONFIG_DRM_FBDEV_EMULATION
-	.output_poll_changed = hisi_fbdev_output_poll_changed,
-#endif
+	.output_poll_changed = kirin_fbdev_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
 };
 
-static void hisi_drm_mode_config_init(struct drm_device *dev)
+static void kirin_drm_mode_config_init(struct drm_device *dev)
 {
 	dev->mode_config.min_width = 0;
 	dev->mode_config.min_height = 0;
@@ -80,12 +85,12 @@  static void hisi_drm_mode_config_init(struct drm_device *dev)
 	dev->mode_config.max_width = 2048;
 	dev->mode_config.max_height = 2048;
 
-	dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
+	dev->mode_config.funcs = &kirin_drm_mode_config_funcs;
 }
 
-static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
+static int kirin_drm_kms_init(struct drm_device *dev)
 {
-	struct hisi_drm_private *priv;
+	struct kirin_drm_private *priv;
 	int ret;
 
 	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
@@ -97,13 +102,18 @@  static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 
 	/* dev->mode_config initialization */
 	drm_mode_config_init(dev);
-	hisi_drm_mode_config_init(dev);
+	kirin_drm_mode_config_init(dev);
+
+	/* display controller init */
+	ret = dc_ops->init(dev);
+	if (ret)
+		goto err_mode_config_cleanup;
 
 	/* 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;
+		goto err_dc_cleanup;
 	}
 
 	/* vblank init */
@@ -128,6 +138,8 @@  static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 
 err_unbind_all:
 	component_unbind_all(dev->dev, dev);
+err_dc_cleanup:
+	dc_ops->cleanup(dev);
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(dev);
 	devm_kfree(dev->dev, priv);
@@ -136,7 +148,7 @@  err_mode_config_cleanup:
 	return ret;
 }
 
-static const struct file_operations hisi_drm_fops = {
+static const struct file_operations kirin_drm_fops = {
 	.owner		= THIS_MODULE,
 	.open		= drm_open,
 	.release	= drm_release,
@@ -150,44 +162,28 @@  static const struct file_operations hisi_drm_fops = {
 	.mmap		= drm_gem_cma_mmap,
 };
 
-static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
-					     struct drm_gem_object *obj,
-					     int flags)
+static int kirin_gem_cma_dumb_create(struct drm_file *file,
+				     struct drm_device *dev,
+				     struct drm_mode_create_dumb *args)
 {
-	/* 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 = {
+static struct drm_driver kirin_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,
+	.fops			= &kirin_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_create		= kirin_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_export	= drm_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,
@@ -195,12 +191,8 @@  static struct drm_driver hisi_drm_driver = {
 	.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",
+	.name			= "kirin",
+	.desc			= "Hisilicon Kirin SoCs' DRM Driver",
 	.date			= "20150718",
 	.major			= 1,
 	.minor			= 0,
@@ -211,70 +203,167 @@  static int compare_of(struct device *dev, void *data)
 	return dev->of_node == data;
 }
 
-static int hisi_drm_bind(struct device *dev)
+static int kirin_drm_connectors_register(struct drm_device *dev)
 {
-	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
-	return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
+	struct drm_connector *connector;
+	struct drm_connector *failed_connector;
+	int ret;
+
+	mutex_lock(&dev->mode_config.mutex);
+	drm_for_each_connector(connector, dev) {
+		ret = drm_connector_register(connector);
+		if (ret) {
+			failed_connector = connector;
+			goto err;
+		}
+	}
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return 0;
+
+err:
+	drm_for_each_connector(connector, dev) {
+		if (failed_connector == connector)
+			break;
+		drm_connector_unregister(connector);
+	}
+	mutex_unlock(&dev->mode_config.mutex);
+
+	return ret;
 }
 
-static void hisi_drm_unbind(struct device *dev)
+static int kirin_drm_bind(struct device *dev)
+{
+	struct drm_driver *driver = &kirin_drm_driver;
+	struct drm_device *drm_dev;
+	int ret;
+
+	drm_dev = drm_dev_alloc(driver, dev);
+	if (!drm_dev)
+		return -ENOMEM;
+
+	drm_dev->platformdev = to_platform_device(dev);
+
+	ret = kirin_drm_kms_init(drm_dev);
+	if (ret)
+		goto err_drm_dev_unref;
+
+	ret = drm_dev_register(drm_dev, 0);
+	if (ret)
+		goto err_kms_cleanup;
+
+	/* connectors should be registered after drm device register */
+	ret = kirin_drm_connectors_register(drm_dev);
+	if (ret)
+		goto err_drm_dev_unregister;
+
+	DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n",
+		 driver->name, driver->major, driver->minor, driver->patchlevel,
+		 driver->date, drm_dev->primary->index);
+
+	return 0;
+
+err_drm_dev_unregister:
+	drm_dev_unregister(drm_dev);
+err_kms_cleanup:
+	kirin_drm_kms_cleanup(drm_dev);
+err_drm_dev_unref:
+	drm_dev_unref(drm_dev);
+
+	return ret;
+}
+
+static void kirin_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 const struct component_master_ops kirin_drm_ops = {
+	.bind = kirin_drm_bind,
+	.unbind = kirin_drm_unbind,
 };
 
-static int hisi_drm_platform_probe(struct platform_device *pdev)
+static struct device_node *kirin_get_remote_node(struct device_node *np)
+{
+	struct device_node *endpoint, *remote;
+
+	/* get the first endpoint, in our case only one remote node
+	 * is connected to display controller.
+	 */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		DRM_ERROR("no valid endpoint node\n");
+		return ERR_PTR(-ENODEV);
+	}
+	of_node_put(endpoint);
+
+	remote = of_graph_get_remote_port_parent(endpoint);
+	if (!remote) {
+		DRM_ERROR("no valid remote node\n");
+		return ERR_PTR(-ENODEV);
+	}
+	of_node_put(remote);
+
+	if (!of_device_is_available(remote)) {
+		DRM_ERROR("not available for remote node\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	return remote;
+}
+
+static int kirin_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 device_node *np = dev->of_node;
 	struct component_match *match = NULL;
+	struct device_node *remote;
 
-	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);
+	dc_ops = (struct kirin_dc_ops *)of_device_get_match_data(dev);
+	if (!dc_ops) {
+		DRM_ERROR("failed to get dt id data\n");
+		return -EINVAL;
 	}
 
-	return component_master_add_with_match(dev, &hisi_drm_ops, match);
+	remote = kirin_get_remote_node(np);
+	if (IS_ERR(remote))
+		return PTR_ERR(remote);
+
+	component_match_add(dev, &match, compare_of, remote);
+
+	return component_master_add_with_match(dev, &kirin_drm_ops, match);
 
 	return 0;
 }
 
-static int hisi_drm_platform_remove(struct platform_device *pdev)
+static int kirin_drm_platform_remove(struct platform_device *pdev)
 {
-	component_master_del(&pdev->dev, &hisi_drm_ops);
-	of_platform_depopulate(&pdev->dev);
+	component_master_del(&pdev->dev, &kirin_drm_ops);
+	dc_ops = NULL;
 	return 0;
 }
 
-static const struct of_device_id hisi_drm_dt_ids[] = {
-	{ .compatible = "hisilicon,hi6220-dss", },
+static const struct of_device_id kirin_drm_dt_ids[] = {
+	{ .compatible = "hisilicon,hi6220-ade",
+	  .data = &ade_dc_ops,
+	},
 	{ /* end node */ },
 };
-MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
+MODULE_DEVICE_TABLE(of, kirin_drm_dt_ids);
 
-static struct platform_driver hisi_drm_platform_driver = {
-	.probe = hisi_drm_platform_probe,
-	.remove = hisi_drm_platform_remove,
+static struct platform_driver kirin_drm_platform_driver = {
+	.probe = kirin_drm_platform_probe,
+	.remove = kirin_drm_platform_remove,
 	.driver = {
-		.owner = THIS_MODULE,
-		.name = DRIVER_NAME,
-		.of_match_table = hisi_drm_dt_ids,
+		.name = "kirin-drm",
+		.of_match_table = kirin_drm_dt_ids,
 	},
 };
 
-module_platform_driver(hisi_drm_platform_driver);
+module_platform_driver(kirin_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_DESCRIPTION("hisilicon Kirin 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
index 984121f..d9cfd3f 100644
--- a/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/kirin/kirin_drm_drv.h
@@ -1,5 +1,6 @@ 
 /*
- * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Copyright (c) 2016 Linaro Limited.
+ * Copyright (c) 2014-2016 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
@@ -7,13 +8,25 @@ 
  *
  */
 
-#ifndef __HISI_DRM_DRV_H__
-#define __HISI_DRM_DRV_H__
+#ifndef __KIRIN_DRM_DRV_H__
+#define __KIRIN_DRM_DRV_H__
 
-struct hisi_drm_private {
+#define MAX_CRTC	2
+
+/* display controller init/cleanup ops */
+struct kirin_dc_ops {
+	int (*init)(struct drm_device *dev);
+	void (*cleanup)(struct drm_device *dev);
+};
+
+struct kirin_drm_private {
+	struct drm_crtc *crtc[MAX_CRTC];
 #ifdef CONFIG_DRM_FBDEV_EMULATION
 	struct drm_fbdev_cma *fbdev;
 #endif
 };
 
-#endif /* __HISI_DRM_DRV_H__ */
+extern const struct kirin_dc_ops ade_dc_ops;
+extern void dsi_set_output_client(struct drm_device *dev);
+
+#endif /* __KIRIN_DRM_DRV_H__ */
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index fc1df05..7f7b7c1 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -144,6 +144,31 @@  enum mipi_dsi_pixel_format {
 #define DSI_DEV_NAME_SIZE		20
 
 /**
+ * mipi_dsi_pixel_format_to_bpp - obtain the number of bits per pixel for any
+ *                                given pixel format defined by the MIPI DSI
+ *                                specification
+ * @fmt: MIPI DSI pixel format
+ *
+ * Returns: The number of bits per pixel of the given pixel format.
+ */
+static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
+{
+	switch (fmt) {
+	case MIPI_DSI_FMT_RGB888:
+	case MIPI_DSI_FMT_RGB666:
+		return 24;
+
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		return 18;
+
+	case MIPI_DSI_FMT_RGB565:
+		return 16;
+	}
+
+	return -EINVAL;
+}
+
+/**
  * struct mipi_dsi_device - DSI peripheral device
  * @host: DSI host for this peripheral
  * @dev: driver model device node for this peripheral
@@ -152,6 +177,7 @@  enum mipi_dsi_pixel_format {
  * @format: pixel format for video mode
  * @lanes: number of active data lanes
  * @mode_flags: DSI operation mode related flags
+ * @phy_clock: phy clock assigned to this peripheral in kHz
  */
 struct mipi_dsi_device {
 	struct mipi_dsi_host *host;
@@ -163,6 +189,7 @@  struct mipi_dsi_device {
 	unsigned int lanes;
 	enum mipi_dsi_pixel_format format;
 	unsigned long mode_flags;
+	u32 phy_clock; /* in kHz */
 };
 
 static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)