All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/10] Add New DRM Driver for HiSilicon hi6220 SoC
@ 2015-11-28 10:38 ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: andy.green, xuyiping, linux-doc, w.f, zourongrong, linuxarm,
	xuwei5, bintian.wang, haojian.zhuang, benjamin.gaignard,
	puck.chen, lijianhua, liguozhu, linux-arm-kernel

  This patch set adds a new drm driver for HiSilicon hi6220 SoC.
Current testing and support board is Hikey board which is one of Linaro
96boards. It is an arm64 open source board. For more information about
this board, please access https://www.96boards.org.

Hardware Detail
---------------
  The display subsystem of Hi6220 SoC is shown as bellow:
 +-----+       +----------+     +-----+     +---------+
 |     |       |          |     |     |     |         |             	
 | FB  |------>|   ADE    |---->| DSI |---->| External|
 |     |       |          |     |     |     |  HDMI   |
 +-----+       +----------+     +-----+     +---------+

- ADE(Advanced Display Engine) is the display controller. It contains 7
channels, 3 overlay compositors and a LDI.
  - A channel looks like: DMA-->clip-->scale-->ctrans(or called csc).
  - Overlay compositor is response to compose planes which come from 7
  channels and pass composed image to LDI.
  - LDI is response to generate timings and RGB data stream.
- DSI converts the RGB data stream from ADE to DSI packets.
- External HDMI module is connected with DSI bus. Now Hikey use a ADI's
  ADV7533 external HDMI chip.

Change History
-------------
Changes in v2:
- Remove abtraction layer of plane/crtc/encoder/connector.
- Refactor atomic implementation according to Daniel Vetter's guides:
http://blog.ffwll.ch/2014/11/atomic-modeset-support-for-kms-drivers.html
http://blog.ffwll.ch/2015/09/xdc-2015-atomic-modesetting-for-drivers.html
http://blog.ffwll.ch/2015/08/atomic-modesetting-design-overview.html
- Use bridge instead of slave encoder to connect external HDMI.
- Move dt binding docs to bindings/display/hisilicon directory. 


Xinliang Liu (10):
  arm64: dts: hisilicon: Add display subsystem DT nodes for hi6220.
  drm/hisilicon: Add device tree binding for hi6220 display subsystem
  drm/hisilicon: Add hisilicon DRM master driver
  drm/hisilicon: Add crtc funcs for ADE
  drm/hisilicon: Add plane funcs for ADE
  drm/hisilicon: Add vblank feature
  drm/hisilicon: Add cma fbdev and hotplug
  drm/hisilicon: Add dsi encoder driver
  drm/hisilicon: Add dsi host driver
  drm/hisilicon: Add support for external bridge

 .../bindings/display/hisilicon/hisi-ade.txt        |   42 +
 .../bindings/display/hisilicon/hisi-drm.txt        |   66 ++
 .../bindings/display/hisilicon/hisi-dsi.txt        |   53 +
 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts     |   21 +
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi          |   44 +
 drivers/gpu/drm/Kconfig                            |    2 +
 drivers/gpu/drm/Makefile                           |    1 +
 drivers/gpu/drm/hisilicon/Kconfig                  |   10 +
 drivers/gpu/drm/hisilicon/Makefile                 |    5 +
 drivers/gpu/drm/hisilicon/hisi_ade_reg.h           |  490 +++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_ade.c           | 1068 ++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_ade.h           |   16 +
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c           |  280 +++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.h           |   19 +
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c           |  829 +++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h           |   89 ++
 16 files changed, 3035 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
 create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_ade_reg.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h

-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 00/10] Add New DRM Driver for HiSilicon hi6220 SoC
@ 2015-11-28 10:38 ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

  This patch set adds a new drm driver for HiSilicon hi6220 SoC.
Current testing and support board is Hikey board which is one of Linaro
96boards. It is an arm64 open source board. For more information about
this board, please access https://www.96boards.org.

Hardware Detail
---------------
  The display subsystem of Hi6220 SoC is shown as bellow:
 +-----+       +----------+     +-----+     +---------+
 |     |       |          |     |     |     |         |             	
 | FB  |------>|   ADE    |---->| DSI |---->| External|
 |     |       |          |     |     |     |  HDMI   |
 +-----+       +----------+     +-----+     +---------+

- ADE(Advanced Display Engine) is the display controller. It contains 7
channels, 3 overlay compositors and a LDI.
  - A channel looks like: DMA-->clip-->scale-->ctrans(or called csc).
  - Overlay compositor is response to compose planes which come from 7
  channels and pass composed image to LDI.
  - LDI is response to generate timings and RGB data stream.
- DSI converts the RGB data stream from ADE to DSI packets.
- External HDMI module is connected with DSI bus. Now Hikey use a ADI's
  ADV7533 external HDMI chip.

Change History
-------------
Changes in v2:
- Remove abtraction layer of plane/crtc/encoder/connector.
- Refactor atomic implementation according to Daniel Vetter's guides:
http://blog.ffwll.ch/2014/11/atomic-modeset-support-for-kms-drivers.html
http://blog.ffwll.ch/2015/09/xdc-2015-atomic-modesetting-for-drivers.html
http://blog.ffwll.ch/2015/08/atomic-modesetting-design-overview.html
- Use bridge instead of slave encoder to connect external HDMI.
- Move dt binding docs to bindings/display/hisilicon directory. 


Xinliang Liu (10):
  arm64: dts: hisilicon: Add display subsystem DT nodes for hi6220.
  drm/hisilicon: Add device tree binding for hi6220 display subsystem
  drm/hisilicon: Add hisilicon DRM master driver
  drm/hisilicon: Add crtc funcs for ADE
  drm/hisilicon: Add plane funcs for ADE
  drm/hisilicon: Add vblank feature
  drm/hisilicon: Add cma fbdev and hotplug
  drm/hisilicon: Add dsi encoder driver
  drm/hisilicon: Add dsi host driver
  drm/hisilicon: Add support for external bridge

 .../bindings/display/hisilicon/hisi-ade.txt        |   42 +
 .../bindings/display/hisilicon/hisi-drm.txt        |   66 ++
 .../bindings/display/hisilicon/hisi-dsi.txt        |   53 +
 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts     |   21 +
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi          |   44 +
 drivers/gpu/drm/Kconfig                            |    2 +
 drivers/gpu/drm/Makefile                           |    1 +
 drivers/gpu/drm/hisilicon/Kconfig                  |   10 +
 drivers/gpu/drm/hisilicon/Makefile                 |    5 +
 drivers/gpu/drm/hisilicon/hisi_ade_reg.h           |  490 +++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_ade.c           | 1068 ++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_ade.h           |   16 +
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c           |  280 +++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.h           |   19 +
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c           |  829 +++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h           |   89 ++
 16 files changed, 3035 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
 create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_ade_reg.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h

-- 
1.9.1

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 01/10] arm64: dts: hisilicon: Add display subsystem DT nodes for hi6220
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:38   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal, Xinliang Liu

Add ade, dsi and adv7533 DT nodes for hikey board.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 21 ++++++++++++
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi      | 44 ++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
index 8d43a0f..81236b3 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -31,4 +31,25 @@
 		device_type = "memory";
 		reg = <0x0 0x0 0x0 0x40000000>;
 	};
+
+	soc {
+		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/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
index 82d2488..2d6cf03 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -208,5 +208,49 @@
 			clock-names = "uartclk", "apb_pclk";
 			status = "disabled";
 		};
+
+		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>;
+				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>;
+					};
+				};
+
+			};
+		};
 	};
 };
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 01/10] arm64: dts: hisilicon: Add display subsystem DT nodes for hi6220
@ 2015-11-28 10:38   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Add ade, dsi and adv7533 DT nodes for hikey board.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts | 21 ++++++++++++
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi      | 44 ++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
index 8d43a0f..81236b3 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -31,4 +31,25 @@
 		device_type = "memory";
 		reg = <0x0 0x0 0x0 0x40000000>;
 	};
+
+	soc {
+		i2c2: i2c at f7102000 {
+			status = "ok";
+
+			adv7533: adv7533 at 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/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
index 82d2488..2d6cf03 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -208,5 +208,49 @@
 			clock-names = "uartclk", "apb_pclk";
 			status = "disabled";
 		};
+
+		display-subsystem {
+			compatible = "hisilicon,hi6220-dss";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			ranges;
+
+			ade: ade at 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 at 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>;
+					};
+				};
+
+			};
+		};
 	};
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:38   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal, Xinliang Liu

Add the device tree binding documentation for hi6220 SoC display subsystem.
drm master device binding doc.
ADE display controller binding doc.
DSI controller binding doc.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 .../bindings/display/hisilicon/hisi-ade.txt        | 42 ++++++++++++++
 .../bindings/display/hisilicon/hisi-drm.txt        | 66 ++++++++++++++++++++++
 .../bindings/display/hisilicon/hisi-dsi.txt        | 53 +++++++++++++++++
 3 files changed, 161 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt

diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
new file mode 100644
index 0000000..2777a2c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
@@ -0,0 +1,42 @@
+Device-Tree bindings for hisilicon ADE display controller driver
+
+ADE (Advanced Display Engine) is the display controller which grab image
+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.
+
+
+A example of HiKey board hi6220 SoC specific DT entry:
+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>;
+
+		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-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>;
+	};
diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
new file mode 100644
index 0000000..fd93026
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
@@ -0,0 +1,66 @@
+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
new file mode 100644
index 0000000..30abaa85
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
@@ -0,0 +1,53 @@
+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>;
+				};
+			};
+		};
+	};
+
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem
@ 2015-11-28 10:38   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Add the device tree binding documentation for hi6220 SoC display subsystem.
drm master device binding doc.
ADE display controller binding doc.
DSI controller binding doc.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 .../bindings/display/hisilicon/hisi-ade.txt        | 42 ++++++++++++++
 .../bindings/display/hisilicon/hisi-drm.txt        | 66 ++++++++++++++++++++++
 .../bindings/display/hisilicon/hisi-dsi.txt        | 53 +++++++++++++++++
 3 files changed, 161 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
 create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt

diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
new file mode 100644
index 0000000..2777a2c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
@@ -0,0 +1,42 @@
+Device-Tree bindings for hisilicon ADE display controller driver
+
+ADE (Advanced Display Engine) is the display controller which grab image
+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.
+
+
+A example of HiKey board hi6220 SoC specific DT entry:
+Example:
+
+	ade: ade at f4100000 {
+		compatible = "hisilicon,hi6220-ade";
+		reg = <0x0 0xf4100000 0x0 0x7800>,
+		      <0x0 0xf4410000 0x0 0x1000>;
+		reg-names = "ade_base",
+			    "media_base";
+		interrupts = <0 115 4>;
+
+		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-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>;
+	};
diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
new file mode 100644
index 0000000..fd93026
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
@@ -0,0 +1,66 @@
+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 at 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 at 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
new file mode 100644
index 0000000..30abaa85
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
@@ -0,0 +1,53 @@
+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 at 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 at f7102000 {
+		status = "ok";
+
+		adv7533: adv7533 at 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>;
+				};
+			};
+		};
+	};
+
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:38   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal, Xinliang Liu

Add DRM master driver for hi6220 SoC which used in HiKey board.
Add dumb buffer feature.
Add prime dmabuf feature.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/Kconfig                  |   2 +
 drivers/gpu/drm/Makefile                 |   1 +
 drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
 drivers/gpu/drm/hisilicon/Makefile       |   3 +
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
 5 files changed, 229 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 8773fad..038aae8 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
 source "drivers/gpu/drm/imx/Kconfig"
 
 source "drivers/gpu/drm/vc4/Kconfig"
+
+source "drivers/gpu/drm/hisilicon/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1e9ff4c..e7efcb7 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -75,3 +75,4 @@ obj-y			+= i2c/
 obj-y			+= panel/
 obj-y			+= bridge/
 obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
+obj-$(CONFIG_DRM_HISI) += hisilicon/
diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
new file mode 100644
index 0000000..70aa8d1
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -0,0 +1,9 @@
+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
+	help
+	  Choose this option if you have a hisilicon chipsets(hi6220).
+	  If M is selected the module will be called hisi-drm.
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
new file mode 100644
index 0000000..7375456
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -0,0 +1,3 @@
+hisi-drm-y := hisi_drm_drv.o 
+
+obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
new file mode 100644
index 0000000..445e2ec
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -0,0 +1,214 @@
+/*
+ * Hisilicon SoCs drm master driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/of_platform.h>
+#include <linux/component.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_atomic_helper.h>
+
+#define DRIVER_NAME	"hisi-drm"
+
+static int hisi_drm_unload(struct drm_device *dev)
+{
+	drm_mode_config_cleanup(dev);
+	return 0;
+}
+
+static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
+	.fb_create = drm_fb_cma_create,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static void hisi_drm_mode_config_init(struct drm_device *dev)
+{
+	dev->mode_config.min_width = 0;
+	dev->mode_config.min_height = 0;
+
+	dev->mode_config.max_width = 2048;
+	dev->mode_config.max_height = 2048;
+
+	dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
+}
+
+static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
+{
+	int ret;
+
+	dev_set_drvdata(dev->dev, dev);
+
+	/* dev->mode_config initialization */
+	drm_mode_config_init(dev);
+	hisi_drm_mode_config_init(dev);
+
+	/* bind and init sub drivers */
+	ret = component_bind_all(dev->dev, dev);
+	if (ret) {
+		DRM_ERROR("failed to bind all component.\n");
+		goto err_mode_config_cleanup;
+	}
+
+	/* reset all the states of crtc/plane/encoder/connector */
+	drm_mode_config_reset(dev);
+
+	return 0;
+
+err_mode_config_cleanup:
+	drm_mode_config_cleanup(dev);
+
+	return ret;
+}
+
+static const struct file_operations hisi_drm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= drm_compat_ioctl,
+#endif
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+	.mmap		= drm_gem_cma_mmap,
+};
+
+static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
+					     struct drm_gem_object *obj,
+					     int flags)
+{
+	/* we want to be able to write in mmapped buffer */
+	flags |= O_RDWR;
+	return drm_gem_prime_export(dev, obj, flags);
+}
+
+static int hisi_gem_cma_dumb_create(struct drm_file *file,
+				    struct drm_device *dev,
+				    struct drm_mode_create_dumb *args)
+{
+	int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+	/* mali gpu need pitch 8 bytes alignment for 32bpp */
+	args->pitch = roundup(min_pitch, 8);
+
+	return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
+static struct drm_driver hisi_drm_driver = {
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
+				  DRIVER_ATOMIC,
+	.load			= hisi_drm_load,
+	.unload                 = hisi_drm_unload,
+	.fops			= &hisi_drm_fops,
+	.set_busid		= drm_platform_set_busid,
+
+	.gem_free_object	= drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+	.dumb_create		= hisi_gem_cma_dumb_create,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_export	= hisi_gem_prime_export,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
+
+	.name			= "hisi",
+	.desc			= "Hisilicon SoCs' DRM Driver",
+	.date			= "20150718",
+	.major			= 1,
+	.minor			= 0,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int hisi_drm_bind(struct device *dev)
+{
+	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
+}
+
+static void hisi_drm_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops hisi_drm_ops = {
+	.bind = hisi_drm_bind,
+	.unbind = hisi_drm_unbind,
+};
+
+static int hisi_drm_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct device_node *child_np;
+	struct component_match *match = NULL;
+
+	of_platform_populate(node, NULL, NULL, dev);
+
+	child_np = of_get_next_available_child(node, NULL);
+	while (child_np) {
+		component_match_add(dev, &match, compare_of, child_np);
+		of_node_put(child_np);
+		child_np = of_get_next_available_child(node, child_np);
+	}
+
+	return component_master_add_with_match(dev, &hisi_drm_ops, match);
+
+	return 0;
+}
+
+static int hisi_drm_platform_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &hisi_drm_ops);
+	of_platform_depopulate(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id hisi_drm_dt_ids[] = {
+	{ .compatible = "hisilicon,hi6220-dss", },
+	{ /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
+
+static struct platform_driver hisi_drm_platform_driver = {
+	.probe = hisi_drm_platform_probe,
+	.remove = hisi_drm_platform_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRIVER_NAME,
+		.of_match_table = hisi_drm_dt_ids,
+	},
+};
+
+module_platform_driver(hisi_drm_platform_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("hisilicon SoCs' DRM master driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-11-28 10:38   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Add DRM master driver for hi6220 SoC which used in HiKey board.
Add dumb buffer feature.
Add prime dmabuf feature.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/Kconfig                  |   2 +
 drivers/gpu/drm/Makefile                 |   1 +
 drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
 drivers/gpu/drm/hisilicon/Makefile       |   3 +
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
 5 files changed, 229 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
 create mode 100644 drivers/gpu/drm/hisilicon/Makefile
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 8773fad..038aae8 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
 source "drivers/gpu/drm/imx/Kconfig"
 
 source "drivers/gpu/drm/vc4/Kconfig"
+
+source "drivers/gpu/drm/hisilicon/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 1e9ff4c..e7efcb7 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -75,3 +75,4 @@ obj-y			+= i2c/
 obj-y			+= panel/
 obj-y			+= bridge/
 obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
+obj-$(CONFIG_DRM_HISI) += hisilicon/
diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
new file mode 100644
index 0000000..70aa8d1
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -0,0 +1,9 @@
+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
+	help
+	  Choose this option if you have a hisilicon chipsets(hi6220).
+	  If M is selected the module will be called hisi-drm.
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
new file mode 100644
index 0000000..7375456
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -0,0 +1,3 @@
+hisi-drm-y := hisi_drm_drv.o 
+
+obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
new file mode 100644
index 0000000..445e2ec
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -0,0 +1,214 @@
+/*
+ * Hisilicon SoCs drm master driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/of_platform.h>
+#include <linux/component.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_atomic_helper.h>
+
+#define DRIVER_NAME	"hisi-drm"
+
+static int hisi_drm_unload(struct drm_device *dev)
+{
+	drm_mode_config_cleanup(dev);
+	return 0;
+}
+
+static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
+	.fb_create = drm_fb_cma_create,
+	.atomic_check = drm_atomic_helper_check,
+	.atomic_commit = drm_atomic_helper_commit,
+};
+
+static void hisi_drm_mode_config_init(struct drm_device *dev)
+{
+	dev->mode_config.min_width = 0;
+	dev->mode_config.min_height = 0;
+
+	dev->mode_config.max_width = 2048;
+	dev->mode_config.max_height = 2048;
+
+	dev->mode_config.funcs = &hisi_drm_mode_config_funcs;
+}
+
+static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
+{
+	int ret;
+
+	dev_set_drvdata(dev->dev, dev);
+
+	/* dev->mode_config initialization */
+	drm_mode_config_init(dev);
+	hisi_drm_mode_config_init(dev);
+
+	/* bind and init sub drivers */
+	ret = component_bind_all(dev->dev, dev);
+	if (ret) {
+		DRM_ERROR("failed to bind all component.\n");
+		goto err_mode_config_cleanup;
+	}
+
+	/* reset all the states of crtc/plane/encoder/connector */
+	drm_mode_config_reset(dev);
+
+	return 0;
+
+err_mode_config_cleanup:
+	drm_mode_config_cleanup(dev);
+
+	return ret;
+}
+
+static const struct file_operations hisi_drm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= drm_compat_ioctl,
+#endif
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+	.mmap		= drm_gem_cma_mmap,
+};
+
+static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
+					     struct drm_gem_object *obj,
+					     int flags)
+{
+	/* we want to be able to write in mmapped buffer */
+	flags |= O_RDWR;
+	return drm_gem_prime_export(dev, obj, flags);
+}
+
+static int hisi_gem_cma_dumb_create(struct drm_file *file,
+				    struct drm_device *dev,
+				    struct drm_mode_create_dumb *args)
+{
+	int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+
+	/* mali gpu need pitch 8 bytes alignment for 32bpp */
+	args->pitch = roundup(min_pitch, 8);
+
+	return drm_gem_cma_dumb_create_internal(file, dev, args);
+}
+
+static struct drm_driver hisi_drm_driver = {
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
+				  DRIVER_ATOMIC,
+	.load			= hisi_drm_load,
+	.unload                 = hisi_drm_unload,
+	.fops			= &hisi_drm_fops,
+	.set_busid		= drm_platform_set_busid,
+
+	.gem_free_object	= drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+	.dumb_create		= hisi_gem_cma_dumb_create,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_export	= hisi_gem_prime_export,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
+
+	.name			= "hisi",
+	.desc			= "Hisilicon SoCs' DRM Driver",
+	.date			= "20150718",
+	.major			= 1,
+	.minor			= 0,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int hisi_drm_bind(struct device *dev)
+{
+	dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
+}
+
+static void hisi_drm_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops hisi_drm_ops = {
+	.bind = hisi_drm_bind,
+	.unbind = hisi_drm_unbind,
+};
+
+static int hisi_drm_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *node = dev->of_node;
+	struct device_node *child_np;
+	struct component_match *match = NULL;
+
+	of_platform_populate(node, NULL, NULL, dev);
+
+	child_np = of_get_next_available_child(node, NULL);
+	while (child_np) {
+		component_match_add(dev, &match, compare_of, child_np);
+		of_node_put(child_np);
+		child_np = of_get_next_available_child(node, child_np);
+	}
+
+	return component_master_add_with_match(dev, &hisi_drm_ops, match);
+
+	return 0;
+}
+
+static int hisi_drm_platform_remove(struct platform_device *pdev)
+{
+	component_master_del(&pdev->dev, &hisi_drm_ops);
+	of_platform_depopulate(&pdev->dev);
+	return 0;
+}
+
+static const struct of_device_id hisi_drm_dt_ids[] = {
+	{ .compatible = "hisilicon,hi6220-dss", },
+	{ /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, hisi_drm_dt_ids);
+
+static struct platform_driver hisi_drm_platform_driver = {
+	.probe = hisi_drm_platform_probe,
+	.remove = hisi_drm_platform_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRIVER_NAME,
+		.of_match_table = hisi_drm_dt_ids,
+	},
+};
+
+module_platform_driver(hisi_drm_platform_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("hisilicon SoCs' DRM master driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 04/10] drm/hisilicon: Add crtc funcs for ADE
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:38   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: andy.green, xuyiping, linux-doc, w.f, zourongrong, linuxarm,
	xuwei5, bintian.wang, haojian.zhuang, benjamin.gaignard,
	puck.chen, lijianhua, liguozhu, linux-arm-kernel

Add crtc funcs and helper funcs for ADE.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/Makefile       |   3 +-
 drivers/gpu/drm/hisilicon/hisi_ade_reg.h | 490 +++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 511 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c |  15 +
 drivers/gpu/drm/hisilicon/hisi_drm_drv.h |  16 +
 5 files changed, 1034 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_ade_reg.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.h

diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index 7375456..3433c8b 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -1,3 +1,4 @@
-hisi-drm-y := hisi_drm_drv.o 
+hisi-drm-y := hisi_drm_drv.o \
+	      hisi_drm_ade.o
 
 obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hisi_ade_reg.h b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
new file mode 100644
index 0000000..6a7bc46
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_ADE_REG_H__
+#define __HISI_ADE_REG_H__
+
+/*
+ * ADE Registers Offset
+ */
+#define ADE_CTRL			(0x4)
+#define ADE_CTRL1			(0x8C)
+#define ADE_ROT_SRC_CFG			(0x10)
+#define ADE_DISP_SRC_CFG		(0x18)
+#define ADE_WDMA2_SRC_CFG		(0x1C)
+#define ADE_SEC_OVLY_SRC_CFG		(0x20)
+#define ADE_WDMA3_SRC_CFG		(0x24)
+#define ADE_OVLY1_TRANS_CFG		(0x2C)
+#define ADE_EN				(0x100)
+#define INTR_MASK_CPU_0			(0xC10)
+#define INTR_MASK_CPU_1			(0xC14)
+#define ADE_FRM_DISGARD_CTRL		(0xA4)
+/* reset and reload regs */
+#define ADE_SOFT_RST_SEL0		(0x78)
+#define ADE_SOFT_RST_SEL1		(0x7C)
+#define ADE_RELOAD_DIS0			(0xAC)
+#define ADE_RELOAD_DIS1			(0xB0)
+#define ADE_CH_RDMA_BIT_OFST		(0)
+#define ADE_CLIP_BIT_OFST		(15)
+#define ADE_SCL_BIT_OFST		(21)
+#define ADE_CTRAN_BIT_OFST		(24)
+#define ADE_OVLY_BIT_OFST		(37) /* 32+5 */
+/* channel regs */
+#define RD_CH_PE(x)			(0x1000 + (x) * 0x80)
+#define RD_CH_CTRL(x)			(0x1004 + (x) * 0x80)
+#define RD_CH_ADDR(x)			(0x1008 + (x) * 0x80)
+#define RD_CH_SIZE(x)			(0x100C + (x) * 0x80)
+#define RD_CH_STRIDE(x)			(0x1010 + (x) * 0x80)
+#define RD_CH_SPACE(x)			(0x1014 + (x) * 0x80)
+#define RD_CH_PARTIAL_SIZE(x)		(0x1018 + (x) * 0x80)
+#define RD_CH_PARTIAL_SPACE(x)		(0x101C + (x) * 0x80)
+#define RD_CH_EN(x)			(0x1020 + (x) * 0x80)
+#define RD_CH_STATUS(x)			(0x1024 + (x) * 0x80)
+#define RD_CH_DISP_CTRL			(0x1404)
+#define RD_CH_DISP_ADDR			(0x1408)
+#define RD_CH_DISP_SIZE			(0x140C)
+#define RD_CH_DISP_STRIDE		(0x1410)
+#define RD_CH_DISP_SPACE		(0x1414)
+#define RD_CH_DISP_EN			(0x142C)
+/* clip regs */
+#define ADE_CLIP_DISABLE(x)		(0x6800 + (x) * 0x100)
+#define ADE_CLIP_SIZE0(x)		(0x6804 + (x) * 0x100)
+#define ADE_CLIP_SIZE1(x)		(0x6808 + (x) * 0x100)
+#define ADE_CLIP_SIZE2(x)		(0x680C + (x) * 0x100)
+#define ADE_CLIP_CFG_OK(x)		(0x6810 + (x) * 0x100)
+/* scale regs */
+#define ADE_SCL1_MUX_CFG		(0xC)
+#define ADE_SCL2_SRC_CFG		(0x14)
+#define ADE_SCL3_MUX_CFG		(0x8)
+#define ADE_SCL_CTRL(x)			(0x3000 + (x) * 0x800)
+#define ADE_SCL_HSP(x)			(0x3004 + (x) * 0x800)
+#define ADE_SCL_UV_HSP(x)		(0x3008 + (x) * 0x800)
+#define ADE_SCL_VSP(x)			(0x300C + (x) * 0x800)
+#define ADE_SCL_UV_VSP(x)		(0x3010 + (x) * 0x800)
+#define ADE_SCL_ORES(x)			(0x3014 + (x) * 0x800)
+#define ADE_SCL_IRES(x)			(0x3018 + (x) * 0x800)
+#define ADE_SCL_START(x)		(0x301C + (x) * 0x800)
+#define ADE_SCL_ERR(x)			(0x3020 + (x) * 0x800)
+#define ADE_SCL_PIX_OFST(x)		(0x3024 + (x) * 0x800)
+#define ADE_SCL_UV_PIX_OFST(x)		(0x3028 + (x) * 0x800)
+#define ADE_SCL_COEF_CLR(x)		(0x3030 + (x) * 0x800)
+#define ADE_SCL_HCOEF(x, m, n)		(0x3100 + (x) * 0x800 + \
+					12 * (m) + 4 * (n))
+#define ADE_SCL_VCOEF(x, i, j)		(0x340C + (x) * 0x800 + \
+					12 * (i) + 4 * (j))
+/* ctran regs */
+#define ADE_CTRAN5_TRANS_CFG		(0x40)
+#define ADE_CTRAN_DIS(x)		(0x5004 + (x) * 0x100)
+#define ADE_CTRAN_MODE_CHOOSE(x)	(0x5008 + (x) * 0x100)
+#define ADE_CTRAN_STAT(x)		(0x500C + (x) * 0x100)
+#define ADE_CTRAN_CHDC0(x)		(0x5010 + (x) * 0x100)
+#define ADE_CTRAN_CHDC1(x)		(0x5014 + (x) * 0x100)
+#define ADE_CTRAN_CHDC2(x)		(0x5018 + (x) * 0x100)
+#define ADE_CTRAN_CHDC3(x)		(0x501C + (x) * 0x100)
+#define ADE_CTRAN_CHDC4(x)		(0x5020 + (x) * 0x100)
+#define ADE_CTRAN_CHDC5(x)		(0x5024 + (x) * 0x100)
+#define ADE_CTRAN_CSC0(x)		(0x5028 + (x) * 0x100)
+#define ADE_CTRAN_CSC1(x)		(0x502C + (x) * 0x100)
+#define ADE_CTRAN_CSC2(x)		(0x5030 + (x) * 0x100)
+#define ADE_CTRAN_CSC3(x)		(0x5034 + (x) * 0x100)
+#define ADE_CTRAN_CSC4(x)		(0x5038 + (x) * 0x100)
+#define ADE_CTRAN_IMAGE_SIZE(x)		(0x503C + (x) * 0x100)
+#define ADE_CTRAN_CFG_OK(x)		(0x5040 + (x) * 0x100)
+/* overlay regs */
+#define ADE_OVLY_ALPHA_ST		(0x2000)
+#define ADE_OVLY_CH_XY0(x)		(0x2004 + (x) * 4)
+#define ADE_OVLY_CH_XY1(x)		(0x2024 + (x) * 4)
+#define ADE_OVLY_CH_CTL(x)		(0x204C + (x) * 4)
+#define ADE_OVLY_OUTPUT_SIZE(x)		(0x2070 + (x) * 8)
+#define ADE_OVLY_BASE_COLOR(x)		(0x2074 + (x) * 8)
+#define ADE_OVLYX_CTL(x)		(0x209C + (x) * 4)
+#define ADE_OVLY_CTL			(0x98)
+#define ADE_OVLY_CH_ALP_MODE_OFST	(0)
+#define ADE_OVLY_CH_ALP_SEL_OFST	(2)
+#define ADE_OVLY_CH_UNDER_ALP_SEL_OFST	(4)
+#define ADE_OVLY_CH_EN_OFST		(6)
+#define ADE_OVLY_CH_ALP_GBL_OFST	(15)
+#define ADE_OVLY_CH_SEL_OFST		(28)
+
+/*
+ * media regs
+ */
+#define SC_MEDIA_RSTDIS			(0x530)
+#define SC_MEDIA_RSTEN			(0x52C)
+
+/*
+ * regs relevant enum
+ */
+enum {
+	LDI_TEST = 0,
+	LDI_WORK
+};
+
+enum {
+	LDI_ISR_FRAME_END_INT = 0x2,
+	LDI_ISR_UNDER_FLOW_INT = 0x4
+};
+
+enum {
+	ADE_ISR1_RES_SWITCH_CMPL = 0x80000000
+};
+
+enum {
+	LDI_DISP_MODE_NOT_3D_FBF = 0,
+	LDI_DISP_MODE_3D_FBF
+};
+
+enum {
+	ADE_RGB = 0,
+	ADE_BGR
+};
+
+enum {
+	ADE_DISABLE = 0,
+	ADE_ENABLE
+};
+
+enum {
+	ADE_OUT_RGB_565 = 0,
+	ADE_OUT_RGB_666,
+	ADE_OUT_RGB_888
+};
+
+/*
+ * ADE read as big-endian, so revert the
+ * rgb order described in the SoC datasheet
+ */
+enum ADE_FORMAT {
+	ADE_RGB_565 = 0,
+	ADE_BGR_565,
+	ADE_XRGB_8888,
+	ADE_XBGR_8888,
+	ADE_ARGB_8888,
+	ADE_ABGR_8888,
+	ADE_RGBA_8888,
+	ADE_BGRA_8888,
+	ADE_RGB_888,
+	ADE_BGR_888 = 9,
+	ADE_FORMAT_NOT_SUPPORT = 800
+};
+
+/* ldi src cfg */
+enum {
+	TOP_DISP_SRC_NONE = 0,
+	TOP_DISP_SRC_OVLY2,
+	TOP_DISP_SRC_DISP,
+	TOP_DISP_SRC_ROT,
+	TOP_DISP_SRC_SCL2
+};
+
+enum {
+	ADE_ISR_DMA_ERROR = 0x2000000
+};
+
+enum ade_channel {
+	ADE_CH1 = 0,	/* channel 1 for primary plane */
+	ADE_CH_NUM
+};
+
+enum ade_scale {
+	ADE_SCL1 = 0,
+	ADE_SCL2,
+	ADE_SCL3,
+	ADE_SCL_NUM
+};
+
+enum ade_ctran {
+	ADE_CTRAN1 = 0,
+	ADE_CTRAN2,
+	ADE_CTRAN3,
+	ADE_CTRAN4,
+	ADE_CTRAN5,
+	ADE_CTRAN6,
+	ADE_CTRAN_NUM
+};
+
+enum ade_overlay {
+	ADE_OVLY1 = 0,
+	ADE_OVLY2,
+	ADE_OVLY3,
+	ADE_OVLY_NUM
+};
+
+enum {
+	ADE_ALP_GLOBAL = 0,
+	ADE_ALP_PIXEL,
+	ADE_ALP_PIXEL_AND_GLB
+};
+
+enum {
+	ADE_ALP_MUL_COEFF_0 = 0,	/* alpha */
+	ADE_ALP_MUL_COEFF_1,		/* 1-alpha */
+	ADE_ALP_MUL_COEFF_2,		/* 0 */
+	ADE_ALP_MUL_COEFF_3		/* 1 */
+};
+
+/*
+ * ADE Register Union Struct
+ */
+union U_ADE_CTRL1 {
+struct {
+	unsigned int	auto_clk_gate_en	:1;
+	unsigned int	rot_buf_shr_out		:1;
+	unsigned int	reserved_44		:30;
+	} bits;
+	unsigned int	u32;
+};
+
+union U_ADE_SOFT_RST_SEL0 {
+struct {
+	unsigned int    ch1_rdma_srst_sel     :1;
+	unsigned int    ch2_rdma_srst_sel     :1;
+	unsigned int    ch3_rdma_srst_sel     :1;
+	unsigned int    ch4_rdma_srst_sel     :1;
+	unsigned int    ch5_rdma_srst_sel     :1;
+	unsigned int    ch6_rdma_srst_sel     :1;
+	unsigned int    disp_rdma_srst_sel    :1;
+	unsigned int    cmdq1_rdma_srst_sel   :1;
+	unsigned int    cmdq2_rdma_srst_sel   :1;
+	unsigned int    reserved_29           :1;
+	unsigned int    ch1_wdma_srst_sel     :1;
+	unsigned int    ch2_wdma_srst_sel     :1;
+	unsigned int    ch3_wdma_srst_sel     :1;
+	unsigned int    reserved_28           :1;
+	unsigned int    cmdq_wdma_srst_sel    :1;
+	unsigned int    clip1_srst_sel        :1;
+	unsigned int    clip2_srst_sel        :1;
+	unsigned int    clip3_srst_sel        :1;
+	unsigned int    clip4_srst_sel        :1;
+	unsigned int    clip5_srst_sel        :1;
+	unsigned int    clip6_srst_sel        :1;
+	unsigned int    scl1_srst_sel         :1;
+	unsigned int    scl2_srst_sel         :1;
+	unsigned int    scl3_srst_sel         :1;
+	unsigned int    ctran1_srst_sel       :1;
+	unsigned int    ctran2_srst_sel       :1;
+	unsigned int    ctran3_srst_sel       :1;
+	unsigned int    ctran4_srst_sel       :1;
+	unsigned int    ctran5_srst_sel       :1;
+	unsigned int    ctran6_srst_sel       :1;
+	unsigned int    rot_srst_sel          :1;
+	unsigned int    reserved_27           :1;
+	} bits;
+	unsigned int	u32;
+};
+
+union U_ADE_CTRL {
+struct {
+	unsigned int    frm_end_start         :2;
+	unsigned int    dfs_buf_cfg           :1;
+	unsigned int    rot_buf_cfg           :3;
+	unsigned int    rd_ch5_nv             :1;
+	unsigned int    rd_ch6_nv             :1;
+	unsigned int    dfs_buf_unflow_lev1   :13;
+	unsigned int    dfs_buf_unflow_lev2   :11;
+	} bits;
+	unsigned int	u32;
+};
+
+/*
+ * ADE Register Write/Read functions
+ */
+static inline void set_TOP_CTL_clk_gate_en(u8 *base, u32 val)
+{
+	union U_ADE_CTRL1   ade_ctrl1;
+	u8 *reg_addr = base + ADE_CTRL1;
+
+	ade_ctrl1.u32 = readl(reg_addr);
+	ade_ctrl1.bits.auto_clk_gate_en = val;
+	writel(ade_ctrl1.u32, reg_addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_disp_rdma(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.disp_rdma_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_ctran5(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.ctran5_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_ctran6(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.ctran6_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_CTL_frm_end_start(u8 *base, u32 val)
+{
+	union U_ADE_CTRL  ade_ctrl;
+	u8 *reg_addr = base + ADE_CTRL;
+
+	ade_ctrl.u32 = readl(reg_addr);
+	ade_ctrl.bits.frm_end_start = val;
+	writel(ade_ctrl.u32, reg_addr);
+}
+
+/*
+ * LDI Registers Offset
+ */
+#define LDI_HRZ_CTRL0		(0x7400)
+#define LDI_HRZ_CTRL1		(0x7404)
+#define LDI_VRT_CTRL0		(0x7408)
+#define LDI_VRT_CTRL1		(0x740C)
+#define LDI_PLR_CTRL		(0x7410)
+#define LDI_DSP_SIZE		(0x7414)
+#define LDI_INT_EN		(0x741C)
+#define LDI_CTRL		(0x7420)
+#define LDI_ORG_INT		(0x7424)
+#define LDI_MSK_INT		(0x7428)
+#define LDI_INT_CLR		(0x742C)
+#define LDI_WORK_MODE		(0x7430)
+#define LDI_DE_SPACE_LOW	(0x7438)
+#define LDI_MCU_INTS		(0x7450)
+#define LDI_MCU_INTE		(0x7454)
+#define LDI_MCU_INTC		(0x7458)
+#define LDI_HDMI_DSI_GT		(0x7434)
+
+/*
+ * LDI Timing Polarity defines
+ */
+#define HISI_LDI_FLAG_NVSYNC	BIT(0)
+#define HISI_LDI_FLAG_NHSYNC	BIT(1)
+#define HISI_LDI_FLAG_NPIXCLK	BIT(2)
+#define HISI_LDI_FLAG_NDE	BIT(3)
+
+/*
+ * LDI Register Union Struct
+ */
+union U_LDI_CTRL {
+struct {
+	unsigned int    ldi_en                :1;
+	unsigned int    disp_mode_buf         :1;
+	unsigned int    date_gate_en          :1;
+	unsigned int    bpp                   :2;
+	unsigned int    wait_vsync_en         :1;
+	unsigned int    corlorbar_width       :7;
+	unsigned int    bgr                   :1;
+	unsigned int    color_mode            :1;
+	unsigned int    shutdown              :1;
+	unsigned int    vactive_line          :12;
+	unsigned int    ldi_en_self_clr       :1;
+	unsigned int    reserved_573          :3;
+	} bits;
+	unsigned int    u32;
+};
+
+union U_LDI_WORK_MODE {
+struct {
+	unsigned int    work_mode             :1;
+	unsigned int    wback_en              :1;
+	unsigned int    colorbar_en           :1;
+	unsigned int    reserved_577          :29;
+	} bits;
+	unsigned int    u32;
+};
+
+/*
+ * LDI Register Write/Read Helper functions
+ */
+static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs)
+{
+	u32 mask = (1 << bw) - 1;
+	u32 tmp = readl(addr);
+
+	tmp &= ~(mask << bs);
+	writel(tmp | ((val & mask) << bs), addr);
+}
+
+static inline void set_LDI_CTRL_ldi_en(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.ldi_en = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_disp_mode(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.disp_mode_buf = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_bpp(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.bpp = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_corlorbar_width(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.corlorbar_width = (val > 0) ? val - 1 : 0;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_bgr(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.bgr = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_WORK_MODE_work_mode(u8 *base, u32 val)
+{
+	union U_LDI_WORK_MODE ldi_work_mode;
+	u8 *addr = base + LDI_WORK_MODE;
+
+	ldi_work_mode.u32 = readl(addr);
+	ldi_work_mode.bits.work_mode = val;
+	writel(ldi_work_mode.u32, addr);
+}
+
+static inline void set_LDI_WORK_MODE_colorbar_en(u8 *base, u32 val)
+{
+	union U_LDI_WORK_MODE ldi_work_mode;
+	u8 *addr = base + LDI_WORK_MODE;
+
+	ldi_work_mode.u32 = readl(addr);
+	ldi_work_mode.bits.colorbar_en = val;
+	writel(ldi_work_mode.u32, addr);
+}
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
new file mode 100644
index 0000000..d157879
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
@@ -0,0 +1,511 @@
+/*
+ * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <video/display_timing.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "hisi_drm_drv.h"
+#include "hisi_ade_reg.h"
+
+#define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
+
+#define to_ade_crtc(crtc) \
+	container_of(crtc, struct ade_crtc, base)
+
+struct ade_hw_ctx {
+	void __iomem  *base;
+	void __iomem  *media_base;
+
+	int irq;
+	u32 ade_core_rate;
+	u32 media_noc_rate;
+
+	struct clk *ade_core_clk;
+	struct clk *media_noc_clk;
+	struct clk *ade_pix_clk;
+	bool power_on;
+};
+
+struct ade_crtc {
+	struct drm_crtc base;
+	struct ade_hw_ctx *ctx;
+	bool enable;
+	u64 use_mask;
+};
+
+struct ade_data {
+	struct ade_crtc acrtc;
+	struct ade_hw_ctx ctx;
+};
+
+static void ade_init(struct ade_hw_ctx *ctx)
+{
+	void __iomem *base = ctx->base;
+
+	/* enable clk gate */
+	set_TOP_CTL_clk_gate_en(base, 1);
+	/* clear overlay */
+	writel(0, base + ADE_OVLY1_TRANS_CFG);
+	writel(0, base + ADE_OVLY_CTL);
+	writel(0, base + ADE_OVLYX_CTL(ADE_OVLY2));
+	/* clear reset and reload regs */
+	writel(0, base + ADE_SOFT_RST_SEL0);
+	writel(0, base + ADE_SOFT_RST_SEL1);
+	writel(0xFFFFFFFF, base + ADE_RELOAD_DIS0);
+	writel(0xFFFFFFFF, base + ADE_RELOAD_DIS1);
+	/* for video set to 1, means that ade registers
+	 * became effective at frame end
+	 */
+	set_TOP_CTL_frm_end_start(base, 1);
+}
+
+static void ade_ldi_set_mode(struct ade_crtc *acrtc,
+			     struct drm_display_mode *mode,
+			     struct drm_display_mode *adj_mode)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 out_w = mode->hdisplay;
+	u32 out_h = mode->vdisplay;
+	u32 hfp, hbp, hsw, vfp, vbp, vsw;
+	u32 plr_flags;
+	int ret;
+
+	plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
+			? HISI_LDI_FLAG_NVSYNC : 0;
+	plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
+			? HISI_LDI_FLAG_NHSYNC : 0;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hbp = mode->htotal - mode->hsync_end;
+	hsw = mode->hsync_end - mode->hsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+	vsw = mode->vsync_end - mode->vsync_start;
+	if (vsw > 15) {
+		DRM_INFO("vsw exceeded 15\n");
+		vsw = 15;
+	}
+
+	writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
+	/* p3-73 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(hsw - 1, base + LDI_HRZ_CTRL1);
+	writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
+	/* p3-74 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(vsw - 1, base + LDI_VRT_CTRL1);
+
+	/* p3-75 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
+	       base + LDI_DSP_SIZE);
+	writel(plr_flags, base + LDI_PLR_CTRL);
+
+	ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
+	/* Success should be guaranteed in aotomic_check
+	 * failer shouldn't happen here
+	 */
+	if (ret)
+		DRM_ERROR("set ade_pixel_clk_rate fail\n");
+	adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
+
+	/* ctran6 setting */
+	writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
+	writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
+	acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
+	DRM_INFO("set mode: %dx%d\n", out_w, out_h);
+
+	/*
+	 * other parameters setting
+	 */
+	writel(BIT(0), base + LDI_WORK_MODE);
+	writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
+	       base + LDI_CTRL);
+	set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
+}
+
+static int ade_power_up(struct ade_hw_ctx *ctx)
+{
+	void __iomem *media_base = ctx->media_base;
+	int ret;
+
+	ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
+	if (ret) {
+		DRM_ERROR("clk_set_rate ade_core_rate error\n");
+		return ret;
+	}
+	ret = clk_set_rate(ctx->media_noc_clk, ctx->media_noc_rate);
+	if (ret) {
+		DRM_ERROR("media_noc_clk media_noc_rate error\n");
+		return ret;
+	}
+	ret = clk_prepare_enable(ctx->media_noc_clk);
+	if (ret) {
+		DRM_ERROR("fail to clk_prepare_enable media_noc_clk\n");
+		return ret;
+	}
+
+	writel(0x20, media_base + SC_MEDIA_RSTDIS);
+
+	ret = clk_prepare_enable(ctx->ade_core_clk);
+	if (ret) {
+		DRM_ERROR("fail to clk_prepare_enable ade_core_clk\n");
+		return ret;
+	}
+
+	ade_init(ctx);
+	ctx->power_on = true;
+	return 0;
+}
+
+static void ade_power_down(struct ade_hw_ctx *ctx)
+{
+	void __iomem *base = ctx->base;
+	void __iomem *media_base = ctx->media_base;
+
+	set_LDI_CTRL_ldi_en(base, ADE_DISABLE);
+	/* dsi pixel off */
+	set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
+
+	clk_disable_unprepare(ctx->ade_core_clk);
+	writel(0x20, media_base + SC_MEDIA_RSTEN);
+	clk_disable_unprepare(ctx->media_noc_clk);
+	ctx->power_on = false;
+}
+
+
+
+/*
+ * set modules' reset mode: by software or hardware
+ * set modules' reload enable/disable
+ */
+static void ade_set_reset_and_reload(struct ade_crtc *acrtc)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 mask0 = (u32)acrtc->use_mask;
+	u32 mask1 = (u32)(acrtc->use_mask >> 32);
+
+	DRM_DEBUG_DRIVER("mask=0x%llX, mask0=0x%X, mask1=0x%X\n",
+			 acrtc->use_mask, mask0, mask1);
+
+	writel(mask0, base + ADE_SOFT_RST_SEL0);
+	writel(mask1, base + ADE_SOFT_RST_SEL1);
+	writel(~mask0, base + ADE_RELOAD_DIS0);
+	writel(~mask1, base + ADE_RELOAD_DIS1);
+}
+
+/*
+ * commit to ldi to display
+ */
+static void ade_display_commit(struct ade_crtc *acrtc)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	/* TODO: set rotator after overlay */
+
+	/* TODO: set scale after overlay */
+
+	/* display source setting */
+	writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+
+	/* set reset mode:soft or hw, and reload modules */
+	ade_set_reset_and_reload(acrtc);
+
+	DRM_INFO("ADE GO\n");
+	/* enable ade */
+	wmb();
+	writel(ADE_ENABLE, base + ADE_EN);
+	/* enable ldi */
+	wmb();
+	set_LDI_CTRL_ldi_en(base, ADE_ENABLE);
+	/* dsi pixel on */
+	set_reg(base + LDI_HDMI_DSI_GT, 0x0, 1, 0);
+}
+
+static void ade_crtc_enable(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (acrtc->enable)
+		return;
+
+	if (!ctx->power_on) {
+		ret = ade_power_up(ctx);
+		if (ret) {
+			DRM_ERROR("failed to initialize ade clk\n");
+			return;
+		}
+	}
+
+	ade_display_commit(acrtc);
+	acrtc->enable = true;
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_disable(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+
+	if (!acrtc->enable)
+		return;
+
+	ade_power_down(ctx);
+	acrtc->use_mask = 0;
+	acrtc->enable = false;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+int ade_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+	/* do nothing */
+	return 0;
+}
+
+static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	struct drm_display_mode *mode = &crtc->state->mode;
+	struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+	ade_ldi_set_mode(acrtc, mode, adj_mode);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_state)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_state)
+
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	/* commit to  display: LDI input setting */
+	if (acrtc->enable) {
+		/* set reset and reload */
+		ade_set_reset_and_reload(acrtc);
+		/* flush ade regitsters */
+		wmb();
+		writel(ADE_ENABLE, base + ADE_EN);
+	}
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
+	.enable		= ade_crtc_enable,
+	.disable	= ade_crtc_disable,
+	.atomic_check	= ade_crtc_atomic_check,
+	.mode_set_nofb	= ade_crtc_mode_set_nofb,
+	.atomic_begin	= ade_crtc_atomic_begin,
+	.atomic_flush	= ade_crtc_atomic_flush,
+};
+
+static const struct drm_crtc_funcs ade_crtc_funcs = {
+	.destroy	= drm_crtc_cleanup,
+	.set_config	= drm_atomic_helper_set_config,
+	.page_flip	= drm_atomic_helper_page_flip,
+	.reset		= drm_atomic_helper_crtc_reset,
+	.set_property = drm_atomic_helper_crtc_set_property,
+	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
+};
+
+static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+			 struct drm_plane *plane)
+{
+	int ret;
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &ade_crtc_funcs);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
+	drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
+
+	return 0;
+}
+
+static int ade_bind(struct device *dev, struct device *master, void *data)
+{
+	return 0;
+}
+
+static void ade_unbind(struct device *dev, struct device *master, void *data)
+{
+	/* do nothing */
+}
+
+static const struct component_ops ade_ops = {
+	.bind	= ade_bind,
+	.unbind	= ade_unbind,
+};
+
+static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx)
+{
+	struct resource *res;
+	struct device *dev;
+	struct device_node *np;
+	int ret;
+
+	dev = &pdev->dev;
+	np  = dev->of_node;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ade_base");
+	ctx->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->base)) {
+		DRM_ERROR("failed to remap ade io base\n");
+		return  PTR_ERR(ctx->base);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_base");
+	ctx->media_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->media_base)) {
+		DRM_ERROR("failed to remap media io base\n");
+		return PTR_ERR(ctx->media_base);
+	}
+
+	ctx->irq = platform_get_irq(pdev, 0);
+	if (ctx->irq < 0) {
+		DRM_ERROR("failed to parse the irq\n");
+		return -ENODEV;
+	}
+
+	ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
+	if (!ctx->ade_core_clk) {
+		DRM_ERROR("failed to parse the ADE_CORE\n");
+		return -ENODEV;
+	}
+	ctx->media_noc_clk = devm_clk_get(&pdev->dev,
+					"aclk_codec_jpeg_src");
+	if (!ctx->media_noc_clk) {
+		DRM_ERROR("failed to parse the CODEC_JPEG\n");
+	    return -ENODEV;
+	}
+	ctx->ade_pix_clk = devm_clk_get(&pdev->dev, "clk_ade_pix");
+	if (!ctx->ade_pix_clk) {
+		DRM_ERROR("failed to parse the ADE_PIX_SRC\n");
+	    return -ENODEV;
+	}
+
+	ret = of_property_read_u32(np, "ade_core_clk_rate",
+				   &ctx->ade_core_rate);
+	if (ret) {
+		DRM_ERROR("failed to parse the ade_core_clk_rate\n");
+	    return -ENODEV;
+	}
+	ret = of_property_read_u32(np, "media_noc_clk_rate",
+				   &ctx->media_noc_rate);
+	if (ret) {
+		DRM_ERROR("failed to parse the media_noc_clk_rate\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int ade_probe(struct platform_device *pdev)
+{
+	struct ade_data *ade;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+
+	ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
+	if (!ade) {
+		DRM_ERROR("failed to alloc ade_data\n");
+		return -ENOMEM;
+	}
+
+	ret = ade_dts_parse(pdev, &ade->ctx);
+	if (ret) {
+		DRM_ERROR("failed to parse dts!!\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, ade);
+
+	return component_add(&pdev->dev, &ade_ops);
+}
+
+static int ade_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &ade_ops);
+
+	return 0;
+}
+
+static const struct of_device_id ade_of_match[] = {
+	{ .compatible = "hisilicon,hi6220-ade" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ade_of_match);
+
+static struct platform_driver ade_driver = {
+	.probe = ade_probe,
+	.remove = ade_remove,
+	.driver = {
+		   .name = "hisi-ade",
+		   .owner = THIS_MODULE,
+		   .of_match_table = ade_of_match,
+	},
+};
+
+module_platform_driver(ade_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("Hisilicon DRM ADE(crtc/plane) Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index 445e2ec..d0eca80 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -21,11 +21,18 @@
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_atomic_helper.h>
 
+#include "hisi_drm_drv.h"
+
 #define DRIVER_NAME	"hisi-drm"
 
 static int hisi_drm_unload(struct drm_device *dev)
 {
+	struct hisi_drm_private *priv = dev->dev_private;
+
 	drm_mode_config_cleanup(dev);
+	devm_kfree(dev->dev, priv);
+	dev->dev_private = NULL;
+
 	return 0;
 }
 
@@ -48,8 +55,14 @@ static void hisi_drm_mode_config_init(struct drm_device *dev)
 
 static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 {
+	struct hisi_drm_private *priv;
 	int ret;
 
+	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev->dev_private = priv;
 	dev_set_drvdata(dev->dev, dev);
 
 	/* dev->mode_config initialization */
@@ -70,6 +83,8 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(dev);
+	devm_kfree(dev->dev, priv);
+	dev->dev_private = NULL;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
new file mode 100644
index 0000000..a10229e
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_DRM_DRV_H__
+#define __HISI_DRM_DRV_H__
+
+struct hisi_drm_private {
+};
+
+#endif /* __HISI_DRM_DRV_H__ */
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 04/10] drm/hisilicon: Add crtc funcs for ADE
@ 2015-11-28 10:38   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:38 UTC (permalink / raw)
  To: linux-arm-kernel

Add crtc funcs and helper funcs for ADE.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/Makefile       |   3 +-
 drivers/gpu/drm/hisilicon/hisi_ade_reg.h | 490 +++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 511 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c |  15 +
 drivers/gpu/drm/hisilicon/hisi_drm_drv.h |  16 +
 5 files changed, 1034 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_ade_reg.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.h

diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index 7375456..3433c8b 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -1,3 +1,4 @@
-hisi-drm-y := hisi_drm_drv.o 
+hisi-drm-y := hisi_drm_drv.o \
+	      hisi_drm_ade.o
 
 obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hisi_ade_reg.h b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
new file mode 100644
index 0000000..6a7bc46
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_ADE_REG_H__
+#define __HISI_ADE_REG_H__
+
+/*
+ * ADE Registers Offset
+ */
+#define ADE_CTRL			(0x4)
+#define ADE_CTRL1			(0x8C)
+#define ADE_ROT_SRC_CFG			(0x10)
+#define ADE_DISP_SRC_CFG		(0x18)
+#define ADE_WDMA2_SRC_CFG		(0x1C)
+#define ADE_SEC_OVLY_SRC_CFG		(0x20)
+#define ADE_WDMA3_SRC_CFG		(0x24)
+#define ADE_OVLY1_TRANS_CFG		(0x2C)
+#define ADE_EN				(0x100)
+#define INTR_MASK_CPU_0			(0xC10)
+#define INTR_MASK_CPU_1			(0xC14)
+#define ADE_FRM_DISGARD_CTRL		(0xA4)
+/* reset and reload regs */
+#define ADE_SOFT_RST_SEL0		(0x78)
+#define ADE_SOFT_RST_SEL1		(0x7C)
+#define ADE_RELOAD_DIS0			(0xAC)
+#define ADE_RELOAD_DIS1			(0xB0)
+#define ADE_CH_RDMA_BIT_OFST		(0)
+#define ADE_CLIP_BIT_OFST		(15)
+#define ADE_SCL_BIT_OFST		(21)
+#define ADE_CTRAN_BIT_OFST		(24)
+#define ADE_OVLY_BIT_OFST		(37) /* 32+5 */
+/* channel regs */
+#define RD_CH_PE(x)			(0x1000 + (x) * 0x80)
+#define RD_CH_CTRL(x)			(0x1004 + (x) * 0x80)
+#define RD_CH_ADDR(x)			(0x1008 + (x) * 0x80)
+#define RD_CH_SIZE(x)			(0x100C + (x) * 0x80)
+#define RD_CH_STRIDE(x)			(0x1010 + (x) * 0x80)
+#define RD_CH_SPACE(x)			(0x1014 + (x) * 0x80)
+#define RD_CH_PARTIAL_SIZE(x)		(0x1018 + (x) * 0x80)
+#define RD_CH_PARTIAL_SPACE(x)		(0x101C + (x) * 0x80)
+#define RD_CH_EN(x)			(0x1020 + (x) * 0x80)
+#define RD_CH_STATUS(x)			(0x1024 + (x) * 0x80)
+#define RD_CH_DISP_CTRL			(0x1404)
+#define RD_CH_DISP_ADDR			(0x1408)
+#define RD_CH_DISP_SIZE			(0x140C)
+#define RD_CH_DISP_STRIDE		(0x1410)
+#define RD_CH_DISP_SPACE		(0x1414)
+#define RD_CH_DISP_EN			(0x142C)
+/* clip regs */
+#define ADE_CLIP_DISABLE(x)		(0x6800 + (x) * 0x100)
+#define ADE_CLIP_SIZE0(x)		(0x6804 + (x) * 0x100)
+#define ADE_CLIP_SIZE1(x)		(0x6808 + (x) * 0x100)
+#define ADE_CLIP_SIZE2(x)		(0x680C + (x) * 0x100)
+#define ADE_CLIP_CFG_OK(x)		(0x6810 + (x) * 0x100)
+/* scale regs */
+#define ADE_SCL1_MUX_CFG		(0xC)
+#define ADE_SCL2_SRC_CFG		(0x14)
+#define ADE_SCL3_MUX_CFG		(0x8)
+#define ADE_SCL_CTRL(x)			(0x3000 + (x) * 0x800)
+#define ADE_SCL_HSP(x)			(0x3004 + (x) * 0x800)
+#define ADE_SCL_UV_HSP(x)		(0x3008 + (x) * 0x800)
+#define ADE_SCL_VSP(x)			(0x300C + (x) * 0x800)
+#define ADE_SCL_UV_VSP(x)		(0x3010 + (x) * 0x800)
+#define ADE_SCL_ORES(x)			(0x3014 + (x) * 0x800)
+#define ADE_SCL_IRES(x)			(0x3018 + (x) * 0x800)
+#define ADE_SCL_START(x)		(0x301C + (x) * 0x800)
+#define ADE_SCL_ERR(x)			(0x3020 + (x) * 0x800)
+#define ADE_SCL_PIX_OFST(x)		(0x3024 + (x) * 0x800)
+#define ADE_SCL_UV_PIX_OFST(x)		(0x3028 + (x) * 0x800)
+#define ADE_SCL_COEF_CLR(x)		(0x3030 + (x) * 0x800)
+#define ADE_SCL_HCOEF(x, m, n)		(0x3100 + (x) * 0x800 + \
+					12 * (m) + 4 * (n))
+#define ADE_SCL_VCOEF(x, i, j)		(0x340C + (x) * 0x800 + \
+					12 * (i) + 4 * (j))
+/* ctran regs */
+#define ADE_CTRAN5_TRANS_CFG		(0x40)
+#define ADE_CTRAN_DIS(x)		(0x5004 + (x) * 0x100)
+#define ADE_CTRAN_MODE_CHOOSE(x)	(0x5008 + (x) * 0x100)
+#define ADE_CTRAN_STAT(x)		(0x500C + (x) * 0x100)
+#define ADE_CTRAN_CHDC0(x)		(0x5010 + (x) * 0x100)
+#define ADE_CTRAN_CHDC1(x)		(0x5014 + (x) * 0x100)
+#define ADE_CTRAN_CHDC2(x)		(0x5018 + (x) * 0x100)
+#define ADE_CTRAN_CHDC3(x)		(0x501C + (x) * 0x100)
+#define ADE_CTRAN_CHDC4(x)		(0x5020 + (x) * 0x100)
+#define ADE_CTRAN_CHDC5(x)		(0x5024 + (x) * 0x100)
+#define ADE_CTRAN_CSC0(x)		(0x5028 + (x) * 0x100)
+#define ADE_CTRAN_CSC1(x)		(0x502C + (x) * 0x100)
+#define ADE_CTRAN_CSC2(x)		(0x5030 + (x) * 0x100)
+#define ADE_CTRAN_CSC3(x)		(0x5034 + (x) * 0x100)
+#define ADE_CTRAN_CSC4(x)		(0x5038 + (x) * 0x100)
+#define ADE_CTRAN_IMAGE_SIZE(x)		(0x503C + (x) * 0x100)
+#define ADE_CTRAN_CFG_OK(x)		(0x5040 + (x) * 0x100)
+/* overlay regs */
+#define ADE_OVLY_ALPHA_ST		(0x2000)
+#define ADE_OVLY_CH_XY0(x)		(0x2004 + (x) * 4)
+#define ADE_OVLY_CH_XY1(x)		(0x2024 + (x) * 4)
+#define ADE_OVLY_CH_CTL(x)		(0x204C + (x) * 4)
+#define ADE_OVLY_OUTPUT_SIZE(x)		(0x2070 + (x) * 8)
+#define ADE_OVLY_BASE_COLOR(x)		(0x2074 + (x) * 8)
+#define ADE_OVLYX_CTL(x)		(0x209C + (x) * 4)
+#define ADE_OVLY_CTL			(0x98)
+#define ADE_OVLY_CH_ALP_MODE_OFST	(0)
+#define ADE_OVLY_CH_ALP_SEL_OFST	(2)
+#define ADE_OVLY_CH_UNDER_ALP_SEL_OFST	(4)
+#define ADE_OVLY_CH_EN_OFST		(6)
+#define ADE_OVLY_CH_ALP_GBL_OFST	(15)
+#define ADE_OVLY_CH_SEL_OFST		(28)
+
+/*
+ * media regs
+ */
+#define SC_MEDIA_RSTDIS			(0x530)
+#define SC_MEDIA_RSTEN			(0x52C)
+
+/*
+ * regs relevant enum
+ */
+enum {
+	LDI_TEST = 0,
+	LDI_WORK
+};
+
+enum {
+	LDI_ISR_FRAME_END_INT = 0x2,
+	LDI_ISR_UNDER_FLOW_INT = 0x4
+};
+
+enum {
+	ADE_ISR1_RES_SWITCH_CMPL = 0x80000000
+};
+
+enum {
+	LDI_DISP_MODE_NOT_3D_FBF = 0,
+	LDI_DISP_MODE_3D_FBF
+};
+
+enum {
+	ADE_RGB = 0,
+	ADE_BGR
+};
+
+enum {
+	ADE_DISABLE = 0,
+	ADE_ENABLE
+};
+
+enum {
+	ADE_OUT_RGB_565 = 0,
+	ADE_OUT_RGB_666,
+	ADE_OUT_RGB_888
+};
+
+/*
+ * ADE read as big-endian, so revert the
+ * rgb order described in the SoC datasheet
+ */
+enum ADE_FORMAT {
+	ADE_RGB_565 = 0,
+	ADE_BGR_565,
+	ADE_XRGB_8888,
+	ADE_XBGR_8888,
+	ADE_ARGB_8888,
+	ADE_ABGR_8888,
+	ADE_RGBA_8888,
+	ADE_BGRA_8888,
+	ADE_RGB_888,
+	ADE_BGR_888 = 9,
+	ADE_FORMAT_NOT_SUPPORT = 800
+};
+
+/* ldi src cfg */
+enum {
+	TOP_DISP_SRC_NONE = 0,
+	TOP_DISP_SRC_OVLY2,
+	TOP_DISP_SRC_DISP,
+	TOP_DISP_SRC_ROT,
+	TOP_DISP_SRC_SCL2
+};
+
+enum {
+	ADE_ISR_DMA_ERROR = 0x2000000
+};
+
+enum ade_channel {
+	ADE_CH1 = 0,	/* channel 1 for primary plane */
+	ADE_CH_NUM
+};
+
+enum ade_scale {
+	ADE_SCL1 = 0,
+	ADE_SCL2,
+	ADE_SCL3,
+	ADE_SCL_NUM
+};
+
+enum ade_ctran {
+	ADE_CTRAN1 = 0,
+	ADE_CTRAN2,
+	ADE_CTRAN3,
+	ADE_CTRAN4,
+	ADE_CTRAN5,
+	ADE_CTRAN6,
+	ADE_CTRAN_NUM
+};
+
+enum ade_overlay {
+	ADE_OVLY1 = 0,
+	ADE_OVLY2,
+	ADE_OVLY3,
+	ADE_OVLY_NUM
+};
+
+enum {
+	ADE_ALP_GLOBAL = 0,
+	ADE_ALP_PIXEL,
+	ADE_ALP_PIXEL_AND_GLB
+};
+
+enum {
+	ADE_ALP_MUL_COEFF_0 = 0,	/* alpha */
+	ADE_ALP_MUL_COEFF_1,		/* 1-alpha */
+	ADE_ALP_MUL_COEFF_2,		/* 0 */
+	ADE_ALP_MUL_COEFF_3		/* 1 */
+};
+
+/*
+ * ADE Register Union Struct
+ */
+union U_ADE_CTRL1 {
+struct {
+	unsigned int	auto_clk_gate_en	:1;
+	unsigned int	rot_buf_shr_out		:1;
+	unsigned int	reserved_44		:30;
+	} bits;
+	unsigned int	u32;
+};
+
+union U_ADE_SOFT_RST_SEL0 {
+struct {
+	unsigned int    ch1_rdma_srst_sel     :1;
+	unsigned int    ch2_rdma_srst_sel     :1;
+	unsigned int    ch3_rdma_srst_sel     :1;
+	unsigned int    ch4_rdma_srst_sel     :1;
+	unsigned int    ch5_rdma_srst_sel     :1;
+	unsigned int    ch6_rdma_srst_sel     :1;
+	unsigned int    disp_rdma_srst_sel    :1;
+	unsigned int    cmdq1_rdma_srst_sel   :1;
+	unsigned int    cmdq2_rdma_srst_sel   :1;
+	unsigned int    reserved_29           :1;
+	unsigned int    ch1_wdma_srst_sel     :1;
+	unsigned int    ch2_wdma_srst_sel     :1;
+	unsigned int    ch3_wdma_srst_sel     :1;
+	unsigned int    reserved_28           :1;
+	unsigned int    cmdq_wdma_srst_sel    :1;
+	unsigned int    clip1_srst_sel        :1;
+	unsigned int    clip2_srst_sel        :1;
+	unsigned int    clip3_srst_sel        :1;
+	unsigned int    clip4_srst_sel        :1;
+	unsigned int    clip5_srst_sel        :1;
+	unsigned int    clip6_srst_sel        :1;
+	unsigned int    scl1_srst_sel         :1;
+	unsigned int    scl2_srst_sel         :1;
+	unsigned int    scl3_srst_sel         :1;
+	unsigned int    ctran1_srst_sel       :1;
+	unsigned int    ctran2_srst_sel       :1;
+	unsigned int    ctran3_srst_sel       :1;
+	unsigned int    ctran4_srst_sel       :1;
+	unsigned int    ctran5_srst_sel       :1;
+	unsigned int    ctran6_srst_sel       :1;
+	unsigned int    rot_srst_sel          :1;
+	unsigned int    reserved_27           :1;
+	} bits;
+	unsigned int	u32;
+};
+
+union U_ADE_CTRL {
+struct {
+	unsigned int    frm_end_start         :2;
+	unsigned int    dfs_buf_cfg           :1;
+	unsigned int    rot_buf_cfg           :3;
+	unsigned int    rd_ch5_nv             :1;
+	unsigned int    rd_ch6_nv             :1;
+	unsigned int    dfs_buf_unflow_lev1   :13;
+	unsigned int    dfs_buf_unflow_lev2   :11;
+	} bits;
+	unsigned int	u32;
+};
+
+/*
+ * ADE Register Write/Read functions
+ */
+static inline void set_TOP_CTL_clk_gate_en(u8 *base, u32 val)
+{
+	union U_ADE_CTRL1   ade_ctrl1;
+	u8 *reg_addr = base + ADE_CTRL1;
+
+	ade_ctrl1.u32 = readl(reg_addr);
+	ade_ctrl1.bits.auto_clk_gate_en = val;
+	writel(ade_ctrl1.u32, reg_addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_disp_rdma(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.disp_rdma_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_ctran5(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.ctran5_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_SOFT_RST_SEL0_ctran6(u8 *base, u32 val)
+{
+	union U_ADE_SOFT_RST_SEL0 ade_soft_rst;
+	u8 *addr = base + ADE_SOFT_RST_SEL0;
+
+	ade_soft_rst.u32 = readl(addr);
+	ade_soft_rst.bits.ctran6_srst_sel = val;
+	writel(ade_soft_rst.u32, addr);
+}
+
+static inline void set_TOP_CTL_frm_end_start(u8 *base, u32 val)
+{
+	union U_ADE_CTRL  ade_ctrl;
+	u8 *reg_addr = base + ADE_CTRL;
+
+	ade_ctrl.u32 = readl(reg_addr);
+	ade_ctrl.bits.frm_end_start = val;
+	writel(ade_ctrl.u32, reg_addr);
+}
+
+/*
+ * LDI Registers Offset
+ */
+#define LDI_HRZ_CTRL0		(0x7400)
+#define LDI_HRZ_CTRL1		(0x7404)
+#define LDI_VRT_CTRL0		(0x7408)
+#define LDI_VRT_CTRL1		(0x740C)
+#define LDI_PLR_CTRL		(0x7410)
+#define LDI_DSP_SIZE		(0x7414)
+#define LDI_INT_EN		(0x741C)
+#define LDI_CTRL		(0x7420)
+#define LDI_ORG_INT		(0x7424)
+#define LDI_MSK_INT		(0x7428)
+#define LDI_INT_CLR		(0x742C)
+#define LDI_WORK_MODE		(0x7430)
+#define LDI_DE_SPACE_LOW	(0x7438)
+#define LDI_MCU_INTS		(0x7450)
+#define LDI_MCU_INTE		(0x7454)
+#define LDI_MCU_INTC		(0x7458)
+#define LDI_HDMI_DSI_GT		(0x7434)
+
+/*
+ * LDI Timing Polarity defines
+ */
+#define HISI_LDI_FLAG_NVSYNC	BIT(0)
+#define HISI_LDI_FLAG_NHSYNC	BIT(1)
+#define HISI_LDI_FLAG_NPIXCLK	BIT(2)
+#define HISI_LDI_FLAG_NDE	BIT(3)
+
+/*
+ * LDI Register Union Struct
+ */
+union U_LDI_CTRL {
+struct {
+	unsigned int    ldi_en                :1;
+	unsigned int    disp_mode_buf         :1;
+	unsigned int    date_gate_en          :1;
+	unsigned int    bpp                   :2;
+	unsigned int    wait_vsync_en         :1;
+	unsigned int    corlorbar_width       :7;
+	unsigned int    bgr                   :1;
+	unsigned int    color_mode            :1;
+	unsigned int    shutdown              :1;
+	unsigned int    vactive_line          :12;
+	unsigned int    ldi_en_self_clr       :1;
+	unsigned int    reserved_573          :3;
+	} bits;
+	unsigned int    u32;
+};
+
+union U_LDI_WORK_MODE {
+struct {
+	unsigned int    work_mode             :1;
+	unsigned int    wback_en              :1;
+	unsigned int    colorbar_en           :1;
+	unsigned int    reserved_577          :29;
+	} bits;
+	unsigned int    u32;
+};
+
+/*
+ * LDI Register Write/Read Helper functions
+ */
+static inline void set_reg(u8 *addr, u32 val, u32 bw, u32 bs)
+{
+	u32 mask = (1 << bw) - 1;
+	u32 tmp = readl(addr);
+
+	tmp &= ~(mask << bs);
+	writel(tmp | ((val & mask) << bs), addr);
+}
+
+static inline void set_LDI_CTRL_ldi_en(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.ldi_en = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_disp_mode(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.disp_mode_buf = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_bpp(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.bpp = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_corlorbar_width(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.corlorbar_width = (val > 0) ? val - 1 : 0;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_CTRL_bgr(u8 *base, u32 val)
+{
+	union U_LDI_CTRL ldi_ctrl;
+	u8 *addr = base + LDI_CTRL;
+
+	ldi_ctrl.u32 = readl(addr);
+	ldi_ctrl.bits.bgr = val;
+	writel(ldi_ctrl.u32, addr);
+}
+
+static inline void set_LDI_WORK_MODE_work_mode(u8 *base, u32 val)
+{
+	union U_LDI_WORK_MODE ldi_work_mode;
+	u8 *addr = base + LDI_WORK_MODE;
+
+	ldi_work_mode.u32 = readl(addr);
+	ldi_work_mode.bits.work_mode = val;
+	writel(ldi_work_mode.u32, addr);
+}
+
+static inline void set_LDI_WORK_MODE_colorbar_en(u8 *base, u32 val)
+{
+	union U_LDI_WORK_MODE ldi_work_mode;
+	u8 *addr = base + LDI_WORK_MODE;
+
+	ldi_work_mode.u32 = readl(addr);
+	ldi_work_mode.bits.colorbar_en = val;
+	writel(ldi_work_mode.u32, addr);
+}
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
new file mode 100644
index 0000000..d157879
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
@@ -0,0 +1,511 @@
+/*
+ * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <video/display_timing.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "hisi_drm_drv.h"
+#include "hisi_ade_reg.h"
+
+#define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
+
+#define to_ade_crtc(crtc) \
+	container_of(crtc, struct ade_crtc, base)
+
+struct ade_hw_ctx {
+	void __iomem  *base;
+	void __iomem  *media_base;
+
+	int irq;
+	u32 ade_core_rate;
+	u32 media_noc_rate;
+
+	struct clk *ade_core_clk;
+	struct clk *media_noc_clk;
+	struct clk *ade_pix_clk;
+	bool power_on;
+};
+
+struct ade_crtc {
+	struct drm_crtc base;
+	struct ade_hw_ctx *ctx;
+	bool enable;
+	u64 use_mask;
+};
+
+struct ade_data {
+	struct ade_crtc acrtc;
+	struct ade_hw_ctx ctx;
+};
+
+static void ade_init(struct ade_hw_ctx *ctx)
+{
+	void __iomem *base = ctx->base;
+
+	/* enable clk gate */
+	set_TOP_CTL_clk_gate_en(base, 1);
+	/* clear overlay */
+	writel(0, base + ADE_OVLY1_TRANS_CFG);
+	writel(0, base + ADE_OVLY_CTL);
+	writel(0, base + ADE_OVLYX_CTL(ADE_OVLY2));
+	/* clear reset and reload regs */
+	writel(0, base + ADE_SOFT_RST_SEL0);
+	writel(0, base + ADE_SOFT_RST_SEL1);
+	writel(0xFFFFFFFF, base + ADE_RELOAD_DIS0);
+	writel(0xFFFFFFFF, base + ADE_RELOAD_DIS1);
+	/* for video set to 1, means that ade registers
+	 * became effective at frame end
+	 */
+	set_TOP_CTL_frm_end_start(base, 1);
+}
+
+static void ade_ldi_set_mode(struct ade_crtc *acrtc,
+			     struct drm_display_mode *mode,
+			     struct drm_display_mode *adj_mode)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 out_w = mode->hdisplay;
+	u32 out_h = mode->vdisplay;
+	u32 hfp, hbp, hsw, vfp, vbp, vsw;
+	u32 plr_flags;
+	int ret;
+
+	plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
+			? HISI_LDI_FLAG_NVSYNC : 0;
+	plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
+			? HISI_LDI_FLAG_NHSYNC : 0;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hbp = mode->htotal - mode->hsync_end;
+	hsw = mode->hsync_end - mode->hsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+	vsw = mode->vsync_end - mode->vsync_start;
+	if (vsw > 15) {
+		DRM_INFO("vsw exceeded 15\n");
+		vsw = 15;
+	}
+
+	writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
+	/* p3-73 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(hsw - 1, base + LDI_HRZ_CTRL1);
+	writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
+	/* p3-74 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(vsw - 1, base + LDI_VRT_CTRL1);
+
+	/* p3-75 6220V100 pdf:
+	 *  "The configured value is the actual width - 1"
+	 */
+	writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
+	       base + LDI_DSP_SIZE);
+	writel(plr_flags, base + LDI_PLR_CTRL);
+
+	ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
+	/* Success should be guaranteed in aotomic_check
+	 * failer shouldn't happen here
+	 */
+	if (ret)
+		DRM_ERROR("set ade_pixel_clk_rate fail\n");
+	adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
+
+	/* ctran6 setting */
+	writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
+	writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
+	acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
+	DRM_INFO("set mode: %dx%d\n", out_w, out_h);
+
+	/*
+	 * other parameters setting
+	 */
+	writel(BIT(0), base + LDI_WORK_MODE);
+	writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
+	       base + LDI_CTRL);
+	set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
+}
+
+static int ade_power_up(struct ade_hw_ctx *ctx)
+{
+	void __iomem *media_base = ctx->media_base;
+	int ret;
+
+	ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
+	if (ret) {
+		DRM_ERROR("clk_set_rate ade_core_rate error\n");
+		return ret;
+	}
+	ret = clk_set_rate(ctx->media_noc_clk, ctx->media_noc_rate);
+	if (ret) {
+		DRM_ERROR("media_noc_clk media_noc_rate error\n");
+		return ret;
+	}
+	ret = clk_prepare_enable(ctx->media_noc_clk);
+	if (ret) {
+		DRM_ERROR("fail to clk_prepare_enable media_noc_clk\n");
+		return ret;
+	}
+
+	writel(0x20, media_base + SC_MEDIA_RSTDIS);
+
+	ret = clk_prepare_enable(ctx->ade_core_clk);
+	if (ret) {
+		DRM_ERROR("fail to clk_prepare_enable ade_core_clk\n");
+		return ret;
+	}
+
+	ade_init(ctx);
+	ctx->power_on = true;
+	return 0;
+}
+
+static void ade_power_down(struct ade_hw_ctx *ctx)
+{
+	void __iomem *base = ctx->base;
+	void __iomem *media_base = ctx->media_base;
+
+	set_LDI_CTRL_ldi_en(base, ADE_DISABLE);
+	/* dsi pixel off */
+	set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
+
+	clk_disable_unprepare(ctx->ade_core_clk);
+	writel(0x20, media_base + SC_MEDIA_RSTEN);
+	clk_disable_unprepare(ctx->media_noc_clk);
+	ctx->power_on = false;
+}
+
+
+
+/*
+ * set modules' reset mode: by software or hardware
+ * set modules' reload enable/disable
+ */
+static void ade_set_reset_and_reload(struct ade_crtc *acrtc)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 mask0 = (u32)acrtc->use_mask;
+	u32 mask1 = (u32)(acrtc->use_mask >> 32);
+
+	DRM_DEBUG_DRIVER("mask=0x%llX, mask0=0x%X, mask1=0x%X\n",
+			 acrtc->use_mask, mask0, mask1);
+
+	writel(mask0, base + ADE_SOFT_RST_SEL0);
+	writel(mask1, base + ADE_SOFT_RST_SEL1);
+	writel(~mask0, base + ADE_RELOAD_DIS0);
+	writel(~mask1, base + ADE_RELOAD_DIS1);
+}
+
+/*
+ * commit to ldi to display
+ */
+static void ade_display_commit(struct ade_crtc *acrtc)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	/* TODO: set rotator after overlay */
+
+	/* TODO: set scale after overlay */
+
+	/* display source setting */
+	writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+
+	/* set reset mode:soft or hw, and reload modules */
+	ade_set_reset_and_reload(acrtc);
+
+	DRM_INFO("ADE GO\n");
+	/* enable ade */
+	wmb();
+	writel(ADE_ENABLE, base + ADE_EN);
+	/* enable ldi */
+	wmb();
+	set_LDI_CTRL_ldi_en(base, ADE_ENABLE);
+	/* dsi pixel on */
+	set_reg(base + LDI_HDMI_DSI_GT, 0x0, 1, 0);
+}
+
+static void ade_crtc_enable(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (acrtc->enable)
+		return;
+
+	if (!ctx->power_on) {
+		ret = ade_power_up(ctx);
+		if (ret) {
+			DRM_ERROR("failed to initialize ade clk\n");
+			return;
+		}
+	}
+
+	ade_display_commit(acrtc);
+	acrtc->enable = true;
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_disable(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+
+	if (!acrtc->enable)
+		return;
+
+	ade_power_down(ctx);
+	acrtc->use_mask = 0;
+	acrtc->enable = false;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+int ade_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+	/* do nothing */
+	return 0;
+}
+
+static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	struct drm_display_mode *mode = &crtc->state->mode;
+	struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+	ade_ldi_set_mode(acrtc, mode, adj_mode);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_state)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
+				  struct drm_crtc_state *old_state)
+
+{
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	/* commit to  display: LDI input setting */
+	if (acrtc->enable) {
+		/* set reset and reload */
+		ade_set_reset_and_reload(acrtc);
+		/* flush ade regitsters */
+		wmb();
+		writel(ADE_ENABLE, base + ADE_EN);
+	}
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
+	.enable		= ade_crtc_enable,
+	.disable	= ade_crtc_disable,
+	.atomic_check	= ade_crtc_atomic_check,
+	.mode_set_nofb	= ade_crtc_mode_set_nofb,
+	.atomic_begin	= ade_crtc_atomic_begin,
+	.atomic_flush	= ade_crtc_atomic_flush,
+};
+
+static const struct drm_crtc_funcs ade_crtc_funcs = {
+	.destroy	= drm_crtc_cleanup,
+	.set_config	= drm_atomic_helper_set_config,
+	.page_flip	= drm_atomic_helper_page_flip,
+	.reset		= drm_atomic_helper_crtc_reset,
+	.set_property = drm_atomic_helper_crtc_set_property,
+	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
+};
+
+static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+			 struct drm_plane *plane)
+{
+	int ret;
+
+	ret = drm_crtc_init_with_planes(dev, crtc, plane,
+					NULL, &ade_crtc_funcs);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
+	drm_crtc_helper_add(crtc, &ade_crtc_helper_funcs);
+
+	return 0;
+}
+
+static int ade_bind(struct device *dev, struct device *master, void *data)
+{
+	return 0;
+}
+
+static void ade_unbind(struct device *dev, struct device *master, void *data)
+{
+	/* do nothing */
+}
+
+static const struct component_ops ade_ops = {
+	.bind	= ade_bind,
+	.unbind	= ade_unbind,
+};
+
+static int ade_dts_parse(struct platform_device *pdev, struct ade_hw_ctx *ctx)
+{
+	struct resource *res;
+	struct device *dev;
+	struct device_node *np;
+	int ret;
+
+	dev = &pdev->dev;
+	np  = dev->of_node;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ade_base");
+	ctx->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->base)) {
+		DRM_ERROR("failed to remap ade io base\n");
+		return  PTR_ERR(ctx->base);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "media_base");
+	ctx->media_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->media_base)) {
+		DRM_ERROR("failed to remap media io base\n");
+		return PTR_ERR(ctx->media_base);
+	}
+
+	ctx->irq = platform_get_irq(pdev, 0);
+	if (ctx->irq < 0) {
+		DRM_ERROR("failed to parse the irq\n");
+		return -ENODEV;
+	}
+
+	ctx->ade_core_clk = devm_clk_get(&pdev->dev, "clk_ade_core");
+	if (!ctx->ade_core_clk) {
+		DRM_ERROR("failed to parse the ADE_CORE\n");
+		return -ENODEV;
+	}
+	ctx->media_noc_clk = devm_clk_get(&pdev->dev,
+					"aclk_codec_jpeg_src");
+	if (!ctx->media_noc_clk) {
+		DRM_ERROR("failed to parse the CODEC_JPEG\n");
+	    return -ENODEV;
+	}
+	ctx->ade_pix_clk = devm_clk_get(&pdev->dev, "clk_ade_pix");
+	if (!ctx->ade_pix_clk) {
+		DRM_ERROR("failed to parse the ADE_PIX_SRC\n");
+	    return -ENODEV;
+	}
+
+	ret = of_property_read_u32(np, "ade_core_clk_rate",
+				   &ctx->ade_core_rate);
+	if (ret) {
+		DRM_ERROR("failed to parse the ade_core_clk_rate\n");
+	    return -ENODEV;
+	}
+	ret = of_property_read_u32(np, "media_noc_clk_rate",
+				   &ctx->media_noc_rate);
+	if (ret) {
+		DRM_ERROR("failed to parse the media_noc_clk_rate\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int ade_probe(struct platform_device *pdev)
+{
+	struct ade_data *ade;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+
+	ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
+	if (!ade) {
+		DRM_ERROR("failed to alloc ade_data\n");
+		return -ENOMEM;
+	}
+
+	ret = ade_dts_parse(pdev, &ade->ctx);
+	if (ret) {
+		DRM_ERROR("failed to parse dts!!\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, ade);
+
+	return component_add(&pdev->dev, &ade_ops);
+}
+
+static int ade_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &ade_ops);
+
+	return 0;
+}
+
+static const struct of_device_id ade_of_match[] = {
+	{ .compatible = "hisilicon,hi6220-ade" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ade_of_match);
+
+static struct platform_driver ade_driver = {
+	.probe = ade_probe,
+	.remove = ade_remove,
+	.driver = {
+		   .name = "hisi-ade",
+		   .owner = THIS_MODULE,
+		   .of_match_table = ade_of_match,
+	},
+};
+
+module_platform_driver(ade_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("Hisilicon DRM ADE(crtc/plane) Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index 445e2ec..d0eca80 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -21,11 +21,18 @@
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_atomic_helper.h>
 
+#include "hisi_drm_drv.h"
+
 #define DRIVER_NAME	"hisi-drm"
 
 static int hisi_drm_unload(struct drm_device *dev)
 {
+	struct hisi_drm_private *priv = dev->dev_private;
+
 	drm_mode_config_cleanup(dev);
+	devm_kfree(dev->dev, priv);
+	dev->dev_private = NULL;
+
 	return 0;
 }
 
@@ -48,8 +55,14 @@ static void hisi_drm_mode_config_init(struct drm_device *dev)
 
 static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 {
+	struct hisi_drm_private *priv;
 	int ret;
 
+	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev->dev_private = priv;
 	dev_set_drvdata(dev->dev, dev);
 
 	/* dev->mode_config initialization */
@@ -70,6 +83,8 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(dev);
+	devm_kfree(dev->dev, priv);
+	dev->dev_private = NULL;
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
new file mode 100644
index 0000000..a10229e
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_DRM_DRV_H__
+#define __HISI_DRM_DRV_H__
+
+struct hisi_drm_private {
+};
+
+#endif /* __HISI_DRM_DRV_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 05/10] drm/hisilicon: Add plane funcs for ADE
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:39   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal, Xinliang Liu

Add plane funcs and helper funcs for ADE.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 479 +++++++++++++++++++++++++++++++
 1 file changed, 479 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
index d157879..b0976c3 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
@@ -23,15 +23,22 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
 
 #include "hisi_drm_drv.h"
 #include "hisi_ade_reg.h"
 
 #define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
+#define PRIMARY_CH	(ADE_CH1)
 
 #define to_ade_crtc(crtc) \
 	container_of(crtc, struct ade_crtc, base)
 
+#define to_ade_plane(plane) \
+	container_of(plane, struct ade_plane, base)
+
 struct ade_hw_ctx {
 	void __iomem  *base;
 	void __iomem  *media_base;
@@ -53,11 +60,75 @@ struct ade_crtc {
 	u64 use_mask;
 };
 
+struct ade_plane {
+	struct drm_plane base;
+	void *ctx;
+	u8 ch; /* channel */
+};
+
 struct ade_data {
 	struct ade_crtc acrtc;
+	struct ade_plane aplane[ADE_CH_NUM];
 	struct ade_hw_ctx ctx;
 };
 
+/* ade-format info: */
+struct ade_format {
+	u32 pixel_format;
+	enum ADE_FORMAT ade_format;
+};
+
+static const struct ade_format ade_formats[] = {
+	/* 16bpp RGB: */
+	{ DRM_FORMAT_RGB565, ADE_RGB_565 },
+	{ DRM_FORMAT_BGR565, ADE_BGR_565 },
+	/* 24bpp RGB: */
+	{ DRM_FORMAT_RGB888, ADE_RGB_888 },
+	{ DRM_FORMAT_BGR888, ADE_BGR_888 },
+	/* 32bpp [A]RGB: */
+	{ DRM_FORMAT_XRGB8888, ADE_XRGB_8888 },
+	{ DRM_FORMAT_XBGR8888, ADE_XBGR_8888 },
+	{ DRM_FORMAT_RGBA8888, ADE_RGBA_8888 },
+	{ DRM_FORMAT_BGRA8888, ADE_BGRA_8888 },
+	{ DRM_FORMAT_ARGB8888, ADE_ARGB_8888 },
+	{ DRM_FORMAT_ABGR8888, ADE_ABGR_8888 },
+};
+
+static const u32 channel_formats1[] = {
+	/* channel 1,2,3,4 */
+	DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888
+};
+
+u32 ade_get_channel_formats(u8 ch, const u32 **formats)
+{
+	switch (ch) {
+	case ADE_CH1:
+		*formats = channel_formats1;
+		return ARRAY_SIZE(channel_formats1);
+	default:
+		DRM_ERROR("no this channel %d\n", ch);
+		*formats = NULL;
+		return 0;
+	}
+}
+
+/* convert from fourcc format to ade format */
+static u32 ade_get_format(u32 pixel_format)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ade_formats); i++)
+		if (ade_formats[i].pixel_format == pixel_format)
+			return ade_formats[i].ade_format;
+
+	/* not found */
+	DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", pixel_format);
+	return ADE_FORMAT_NOT_SUPPORT;
+}
+
 static void ade_init(struct ade_hw_ctx *ctx)
 {
 	void __iomem *base = ctx->base;
@@ -377,8 +448,416 @@ static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	return 0;
 }
 
+static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
+			 u32 ch, u32 y, u32 in_h, u32 fmt)
+{
+	u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
+	struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 stride = fb->pitches[0];
+	u32 addr = (u32)obj->paddr + y * stride;
+
+	DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x,",
+			 "addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
+			 ch + 1, y, in_h, stride, (u32)obj->paddr,
+			 addr, fb->width, fb->height,
+			 fmt, drm_get_format_name(fb->pixel_format));
+
+	/* get reg offset */
+	reg_ctrl = RD_CH_CTRL(ch);
+	reg_addr = RD_CH_ADDR(ch);
+	reg_size = RD_CH_SIZE(ch);
+	reg_stride = RD_CH_STRIDE(ch);
+	reg_space = RD_CH_SPACE(ch);
+	reg_en = RD_CH_EN(ch);
+
+	/*
+	 * TODO: set rotation
+	 */
+	writel((fmt << 16) & 0x1f0000, base + reg_ctrl);
+	writel(addr, base + reg_addr);
+	writel((in_h << 16) | stride, base + reg_size);
+	writel(stride, base + reg_stride);
+	writel(in_h * stride, base + reg_space);
+	writel(1, base + reg_en);
+
+	acrtc->use_mask |= BIT(ADE_CH_RDMA_BIT_OFST + ch);
+}
+
+static void ade_rdma_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 reg_en;
+
+	/* get reg offset */
+	reg_en = RD_CH_EN(ch);
+
+	writel(0, base + reg_en);
+	acrtc->use_mask &= ~BIT(ADE_CH_RDMA_BIT_OFST + ch);
+}
+
+static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
+			 u32 in_w, u32 in_h)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 disable_val;
+	u32 clip_left;
+	u32 clip_right;
+
+	/*
+	 * clip width, no need to clip height
+	 */
+	if (fb_w == in_w) { /* bypass */
+		disable_val = 1;
+		clip_left = 0;
+		clip_right = 0;
+	} else {
+		disable_val = 0;
+		clip_left = x;
+		clip_right = fb_w - (x + in_w) - 1;
+	}
+
+	DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n",
+			 ch + 1, clip_left, clip_right);
+
+	writel(disable_val, base + ADE_CLIP_DISABLE(ch));
+	writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
+	writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
+
+	acrtc->use_mask |= BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static void ade_clip_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	writel(1, base + ADE_CLIP_DISABLE(ch));
+	acrtc->use_mask &= ~BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static bool has_Alpha_channel(int format)
+{
+	switch (format) {
+	case ADE_ARGB_8888:
+	case ADE_ABGR_8888:
+	case ADE_RGBA_8888:
+	case ADE_BGRA_8888:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
+				    u8 *alp_sel, u8 *under_alp_sel)
+{
+	bool has_alpha = has_Alpha_channel(fmt);
+
+	/*
+	 * get alp_mode
+	 */
+	if (has_alpha && glb_alpha < 255)
+		*alp_mode = ADE_ALP_PIXEL_AND_GLB;
+	else if (has_alpha)
+		*alp_mode = ADE_ALP_PIXEL;
+	else
+		*alp_mode = ADE_ALP_GLOBAL;
+
+	/*
+	 * get alp sel
+	 */
+	*alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */
+	*under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
+}
+
+static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
+			    u32 in_w, u32 in_h, u32 fmt)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u8 ovly_ch = 0;
+	u8 x = ADE_OVLY2;
+	u8 glb_alpha = 255;
+	u32 x1 = x0 + in_w - 1;
+	u32 y1 = y0 + in_h - 1;
+	u32 val;
+	u8 alp_sel;
+	u8 under_alp_sel;
+	u8 alp_mode;
+
+	ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
+				&under_alp_sel);
+
+	/* overlay routing setting */
+	writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
+	writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
+	val = (ch + 1) << ADE_OVLY_CH_SEL_OFST | BIT(ADE_OVLY_CH_EN_OFST) |
+		alp_sel << ADE_OVLY_CH_ALP_SEL_OFST |
+		under_alp_sel << ADE_OVLY_CH_UNDER_ALP_SEL_OFST |
+		glb_alpha << ADE_OVLY_CH_ALP_GBL_OFST |
+		alp_mode << ADE_OVLY_CH_ALP_MODE_OFST;
+	DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+	val = (x + 1) << (ovly_ch * 4) | readl(base + ADE_OVLY_CTL);
+	DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
+	writel(val, base + ADE_OVLY_CTL);
+
+	/* when primary is enable, indicate that it's ready to output. */
+	if (ch == PRIMARY_CH) {
+		val = (in_w - 1) << 16 | (in_h - 1);
+		writel(val, base + ADE_OVLY_OUTPUT_SIZE(x));
+		writel(1, base + ADE_OVLYX_CTL(x));
+		acrtc->use_mask |= BIT(ADE_OVLY_BIT_OFST + x);
+	}
+}
+
+static void ade_overlay_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u8 ovly_ch = 0;
+	u32 val;
+
+	val = ~BIT(6) & readl(base + ADE_OVLY_CH_CTL(ovly_ch));
+	DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+	val = ~(0x3 << (ovly_ch * 4)) & readl(base + ADE_OVLY_CTL);
+
+	DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
+	writel(val, base + ADE_OVLY_CTL);
+}
+
+/*
+ * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
+ */
+static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
+			       struct drm_framebuffer *fb, int crtc_x,
+			       int crtc_y, unsigned int crtc_w,
+			       unsigned int crtc_h, u32 src_x,
+			       u32 src_y, u32 src_w, u32 src_h)
+{
+	u8 ch = aplane->ch;
+	u32 fmt = ade_get_format(fb->pixel_format);
+	u32 in_w;
+	u32 in_h;
+
+	DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d",
+			 ch + 1, src_x, src_y, src_w, src_h,
+			 crtc_x, crtc_y, crtc_w, crtc_h);
+
+	/* 1) DMA setting */
+	in_w = src_w;
+	in_h = src_h;
+	ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt);
+
+	/* 2) clip setting */
+	ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
+
+	/* 3) TODO: scale setting for overlay planes */
+
+	/* 4) TODO: ctran/csc setting for overlay planes */
+
+	/* 5) overlay/compositor routing setting */
+	ade_overlay_set(acrtc, ch, crtc_x, crtc_y, in_w, in_h, fmt);
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_disable_channel(struct ade_plane *aplane,
+				struct ade_crtc *acrtc)
+{
+	u32 ch = aplane->ch;
+
+	DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
+
+	/*
+	 * when primary is disable, power is down
+	 * so no need to disable this channel.
+	 */
+	if (ch == PRIMARY_CH)
+		return;
+
+	/* disable read DMA */
+	ade_rdma_disable(acrtc, ch);
+
+	/* disable clip */
+	ade_clip_disable(acrtc, ch);
+
+	/* disable overlay routing */
+	ade_overlay_disable(acrtc, ch);
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int ade_plane_prepare_fb(struct drm_plane *p,
+				struct drm_framebuffer *fb,
+				const struct drm_plane_state *new_state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+	return 0;
+}
+
+static void ade_plane_cleanup_fb(struct drm_plane *plane,
+				 struct drm_framebuffer *fb,
+				 const struct drm_plane_state *old_state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int ade_plane_atomic_check(struct drm_plane *plane,
+				  struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_crtc *crtc = state->crtc;
+	struct drm_crtc_state *crtc_state;
+	u32 src_x = state->src_x >> 16;
+	u32 src_y = state->src_y >> 16;
+	u32 src_w = state->src_w >> 16;
+	u32 src_h = state->src_h >> 16;
+	int crtc_x = state->crtc_x;
+	int crtc_y = state->crtc_y;
+	u32 crtc_w = state->crtc_w;
+	u32 crtc_h = state->crtc_h;
+
+	if (!crtc || !fb)
+		return 0;
+
+	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		DRM_ERROR("Scale not support!!!\n");
+		return -EINVAL;
+	}
+
+	if (src_x + src_w > fb->width ||
+	    src_y + src_h > fb->height)
+		return -EINVAL;
+
+	if (crtc_x < 0 || crtc_y < 0)
+		return -EINVAL;
+
+	if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
+	    crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void ade_plane_atomic_update(struct drm_plane *plane,
+				    struct drm_plane_state *old_state)
+{
+	struct drm_plane_state	*state	= plane->state;
+	struct ade_plane *aplane = to_ade_plane(plane);
+	struct ade_crtc *acrtc;
+
+	if (!state->crtc)
+		return;
+
+	acrtc = to_ade_crtc(state->crtc);
+	ade_update_channel(aplane, acrtc, state->fb,
+			   state->crtc_x, state->crtc_y,
+			   state->crtc_w, state->crtc_h,
+			   state->src_x >> 16, state->src_y >> 16,
+			   state->src_w >> 16, state->src_h >> 16);
+}
+
+static void ade_plane_atomic_disable(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct ade_plane *aplane = to_ade_plane(plane);
+	struct ade_crtc *acrtc;
+
+	if (!old_state->crtc)
+		return;
+	acrtc = to_ade_crtc(old_state->crtc);
+	ade_disable_channel(aplane, acrtc);
+}
+
+static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
+	.prepare_fb = ade_plane_prepare_fb,
+	.cleanup_fb = ade_plane_cleanup_fb,
+	.atomic_check = ade_plane_atomic_check,
+	.atomic_update = ade_plane_atomic_update,
+	.atomic_disable = ade_plane_atomic_disable,
+};
+
+static struct drm_plane_funcs ade_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.set_property = drm_atomic_helper_plane_set_property,
+	.destroy = drm_plane_cleanup,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
+			  enum drm_plane_type type)
+{
+	const u32 *fmts;
+	u32 fmts_cnt;
+	int ret = 0;
+
+	/* get  properties */
+	fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts);
+	if (ret)
+		return ret;
+
+	ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
+				       fmts, fmts_cnt, type);
+	if (ret) {
+		DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
+		return ret;
+	}
+
+	drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs);
+
+	return 0;
+}
+
 static int ade_bind(struct device *dev, struct device *master, void *data)
 {
+	struct ade_data *ade = dev_get_drvdata(dev);
+	struct ade_hw_ctx *ctx = &ade->ctx;
+	struct ade_crtc *acrtc = &ade->acrtc;
+	struct drm_device *drm_dev = (struct drm_device *)data;
+	struct ade_plane *aplane;
+	enum drm_plane_type type;
+	int ret;
+	int i;
+
+	/*
+	 * plane init
+	 * TODO: Now only support primary plane, overlay planes
+	 * need to do.
+	 */
+	for (i = 0; i < ADE_CH_NUM; i++) {
+		aplane = &ade->aplane[i];
+		aplane->ch = i;
+		aplane->ctx = ctx;
+		type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
+			DRM_PLANE_TYPE_OVERLAY;
+
+		ret = ade_plane_init(drm_dev, aplane, type);
+		if (ret)
+			return ret;
+	}
+
+	/* crtc init */
+	acrtc->ctx = ctx;
+	ret = ade_crtc_init(drm_dev, &acrtc->base,
+			    &ade->aplane[PRIMARY_CH].base);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 05/10] drm/hisilicon: Add plane funcs for ADE
@ 2015-11-28 10:39   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add plane funcs and helper funcs for ADE.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 479 +++++++++++++++++++++++++++++++
 1 file changed, 479 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
index d157879..b0976c3 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
@@ -23,15 +23,22 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_fb_cma_helper.h>
 
 #include "hisi_drm_drv.h"
 #include "hisi_ade_reg.h"
 
 #define FORCE_PIXEL_CLOCK_SAME_OR_HIGHER 0
+#define PRIMARY_CH	(ADE_CH1)
 
 #define to_ade_crtc(crtc) \
 	container_of(crtc, struct ade_crtc, base)
 
+#define to_ade_plane(plane) \
+	container_of(plane, struct ade_plane, base)
+
 struct ade_hw_ctx {
 	void __iomem  *base;
 	void __iomem  *media_base;
@@ -53,11 +60,75 @@ struct ade_crtc {
 	u64 use_mask;
 };
 
+struct ade_plane {
+	struct drm_plane base;
+	void *ctx;
+	u8 ch; /* channel */
+};
+
 struct ade_data {
 	struct ade_crtc acrtc;
+	struct ade_plane aplane[ADE_CH_NUM];
 	struct ade_hw_ctx ctx;
 };
 
+/* ade-format info: */
+struct ade_format {
+	u32 pixel_format;
+	enum ADE_FORMAT ade_format;
+};
+
+static const struct ade_format ade_formats[] = {
+	/* 16bpp RGB: */
+	{ DRM_FORMAT_RGB565, ADE_RGB_565 },
+	{ DRM_FORMAT_BGR565, ADE_BGR_565 },
+	/* 24bpp RGB: */
+	{ DRM_FORMAT_RGB888, ADE_RGB_888 },
+	{ DRM_FORMAT_BGR888, ADE_BGR_888 },
+	/* 32bpp [A]RGB: */
+	{ DRM_FORMAT_XRGB8888, ADE_XRGB_8888 },
+	{ DRM_FORMAT_XBGR8888, ADE_XBGR_8888 },
+	{ DRM_FORMAT_RGBA8888, ADE_RGBA_8888 },
+	{ DRM_FORMAT_BGRA8888, ADE_BGRA_8888 },
+	{ DRM_FORMAT_ARGB8888, ADE_ARGB_8888 },
+	{ DRM_FORMAT_ABGR8888, ADE_ABGR_8888 },
+};
+
+static const u32 channel_formats1[] = {
+	/* channel 1,2,3,4 */
+	DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
+	DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
+	DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_ABGR8888
+};
+
+u32 ade_get_channel_formats(u8 ch, const u32 **formats)
+{
+	switch (ch) {
+	case ADE_CH1:
+		*formats = channel_formats1;
+		return ARRAY_SIZE(channel_formats1);
+	default:
+		DRM_ERROR("no this channel %d\n", ch);
+		*formats = NULL;
+		return 0;
+	}
+}
+
+/* convert from fourcc format to ade format */
+static u32 ade_get_format(u32 pixel_format)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ade_formats); i++)
+		if (ade_formats[i].pixel_format == pixel_format)
+			return ade_formats[i].ade_format;
+
+	/* not found */
+	DRM_ERROR("Not found pixel format!!fourcc_format= %d\n", pixel_format);
+	return ADE_FORMAT_NOT_SUPPORT;
+}
+
 static void ade_init(struct ade_hw_ctx *ctx)
 {
 	void __iomem *base = ctx->base;
@@ -377,8 +448,416 @@ static int ade_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	return 0;
 }
 
+static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
+			 u32 ch, u32 y, u32 in_h, u32 fmt)
+{
+	u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
+	struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, 0);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 stride = fb->pitches[0];
+	u32 addr = (u32)obj->paddr + y * stride;
+
+	DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x,",
+			 "addr=0x%x, fb:%dx%d, pixel_format=%d(%s)\n",
+			 ch + 1, y, in_h, stride, (u32)obj->paddr,
+			 addr, fb->width, fb->height,
+			 fmt, drm_get_format_name(fb->pixel_format));
+
+	/* get reg offset */
+	reg_ctrl = RD_CH_CTRL(ch);
+	reg_addr = RD_CH_ADDR(ch);
+	reg_size = RD_CH_SIZE(ch);
+	reg_stride = RD_CH_STRIDE(ch);
+	reg_space = RD_CH_SPACE(ch);
+	reg_en = RD_CH_EN(ch);
+
+	/*
+	 * TODO: set rotation
+	 */
+	writel((fmt << 16) & 0x1f0000, base + reg_ctrl);
+	writel(addr, base + reg_addr);
+	writel((in_h << 16) | stride, base + reg_size);
+	writel(stride, base + reg_stride);
+	writel(in_h * stride, base + reg_space);
+	writel(1, base + reg_en);
+
+	acrtc->use_mask |= BIT(ADE_CH_RDMA_BIT_OFST + ch);
+}
+
+static void ade_rdma_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 reg_en;
+
+	/* get reg offset */
+	reg_en = RD_CH_EN(ch);
+
+	writel(0, base + reg_en);
+	acrtc->use_mask &= ~BIT(ADE_CH_RDMA_BIT_OFST + ch);
+}
+
+static void ade_clip_set(struct ade_crtc *acrtc, u32 ch, u32 fb_w, u32 x,
+			 u32 in_w, u32 in_h)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 disable_val;
+	u32 clip_left;
+	u32 clip_right;
+
+	/*
+	 * clip width, no need to clip height
+	 */
+	if (fb_w == in_w) { /* bypass */
+		disable_val = 1;
+		clip_left = 0;
+		clip_right = 0;
+	} else {
+		disable_val = 0;
+		clip_left = x;
+		clip_right = fb_w - (x + in_w) - 1;
+	}
+
+	DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n",
+			 ch + 1, clip_left, clip_right);
+
+	writel(disable_val, base + ADE_CLIP_DISABLE(ch));
+	writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
+	writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
+
+	acrtc->use_mask |= BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static void ade_clip_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	writel(1, base + ADE_CLIP_DISABLE(ch));
+	acrtc->use_mask &= ~BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static bool has_Alpha_channel(int format)
+{
+	switch (format) {
+	case ADE_ARGB_8888:
+	case ADE_ABGR_8888:
+	case ADE_RGBA_8888:
+	case ADE_BGRA_8888:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
+				    u8 *alp_sel, u8 *under_alp_sel)
+{
+	bool has_alpha = has_Alpha_channel(fmt);
+
+	/*
+	 * get alp_mode
+	 */
+	if (has_alpha && glb_alpha < 255)
+		*alp_mode = ADE_ALP_PIXEL_AND_GLB;
+	else if (has_alpha)
+		*alp_mode = ADE_ALP_PIXEL;
+	else
+		*alp_mode = ADE_ALP_GLOBAL;
+
+	/*
+	 * get alp sel
+	 */
+	*alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */
+	*under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
+}
+
+static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u32 x0, u32 y0,
+			    u32 in_w, u32 in_h, u32 fmt)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u8 ovly_ch = 0;
+	u8 x = ADE_OVLY2;
+	u8 glb_alpha = 255;
+	u32 x1 = x0 + in_w - 1;
+	u32 y1 = y0 + in_h - 1;
+	u32 val;
+	u8 alp_sel;
+	u8 under_alp_sel;
+	u8 alp_mode;
+
+	ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
+				&under_alp_sel);
+
+	/* overlay routing setting */
+	writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
+	writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
+	val = (ch + 1) << ADE_OVLY_CH_SEL_OFST | BIT(ADE_OVLY_CH_EN_OFST) |
+		alp_sel << ADE_OVLY_CH_ALP_SEL_OFST |
+		under_alp_sel << ADE_OVLY_CH_UNDER_ALP_SEL_OFST |
+		glb_alpha << ADE_OVLY_CH_ALP_GBL_OFST |
+		alp_mode << ADE_OVLY_CH_ALP_MODE_OFST;
+	DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+	val = (x + 1) << (ovly_ch * 4) | readl(base + ADE_OVLY_CTL);
+	DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
+	writel(val, base + ADE_OVLY_CTL);
+
+	/* when primary is enable, indicate that it's ready to output. */
+	if (ch == PRIMARY_CH) {
+		val = (in_w - 1) << 16 | (in_h - 1);
+		writel(val, base + ADE_OVLY_OUTPUT_SIZE(x));
+		writel(1, base + ADE_OVLYX_CTL(x));
+		acrtc->use_mask |= BIT(ADE_OVLY_BIT_OFST + x);
+	}
+}
+
+static void ade_overlay_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u8 ovly_ch = 0;
+	u32 val;
+
+	val = ~BIT(6) & readl(base + ADE_OVLY_CH_CTL(ovly_ch));
+	DRM_DEBUG_DRIVER("ch%d_ctl=0x%X\n", ovly_ch + 1, val);
+	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+	val = ~(0x3 << (ovly_ch * 4)) & readl(base + ADE_OVLY_CTL);
+
+	DRM_DEBUG_DRIVER("ovly_ctl=0x%X\n", val);
+	writel(val, base + ADE_OVLY_CTL);
+}
+
+/*
+ * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
+ */
+static void ade_update_channel(struct ade_plane *aplane, struct ade_crtc *acrtc,
+			       struct drm_framebuffer *fb, int crtc_x,
+			       int crtc_y, unsigned int crtc_w,
+			       unsigned int crtc_h, u32 src_x,
+			       u32 src_y, u32 src_w, u32 src_h)
+{
+	u8 ch = aplane->ch;
+	u32 fmt = ade_get_format(fb->pixel_format);
+	u32 in_w;
+	u32 in_h;
+
+	DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d",
+			 ch + 1, src_x, src_y, src_w, src_h,
+			 crtc_x, crtc_y, crtc_w, crtc_h);
+
+	/* 1) DMA setting */
+	in_w = src_w;
+	in_h = src_h;
+	ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt);
+
+	/* 2) clip setting */
+	ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
+
+	/* 3) TODO: scale setting for overlay planes */
+
+	/* 4) TODO: ctran/csc setting for overlay planes */
+
+	/* 5) overlay/compositor routing setting */
+	ade_overlay_set(acrtc, ch, crtc_x, crtc_y, in_w, in_h, fmt);
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void ade_disable_channel(struct ade_plane *aplane,
+				struct ade_crtc *acrtc)
+{
+	u32 ch = aplane->ch;
+
+	DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
+
+	/*
+	 * when primary is disable, power is down
+	 * so no need to disable this channel.
+	 */
+	if (ch == PRIMARY_CH)
+		return;
+
+	/* disable read DMA */
+	ade_rdma_disable(acrtc, ch);
+
+	/* disable clip */
+	ade_clip_disable(acrtc, ch);
+
+	/* disable overlay routing */
+	ade_overlay_disable(acrtc, ch);
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int ade_plane_prepare_fb(struct drm_plane *p,
+				struct drm_framebuffer *fb,
+				const struct drm_plane_state *new_state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+	return 0;
+}
+
+static void ade_plane_cleanup_fb(struct drm_plane *plane,
+				 struct drm_framebuffer *fb,
+				 const struct drm_plane_state *old_state)
+{
+	DRM_DEBUG_DRIVER("enter.\n");
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int ade_plane_atomic_check(struct drm_plane *plane,
+				  struct drm_plane_state *state)
+{
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_crtc *crtc = state->crtc;
+	struct drm_crtc_state *crtc_state;
+	u32 src_x = state->src_x >> 16;
+	u32 src_y = state->src_y >> 16;
+	u32 src_w = state->src_w >> 16;
+	u32 src_h = state->src_h >> 16;
+	int crtc_x = state->crtc_x;
+	int crtc_y = state->crtc_y;
+	u32 crtc_w = state->crtc_w;
+	u32 crtc_h = state->crtc_h;
+
+	if (!crtc || !fb)
+		return 0;
+
+	crtc_state = drm_atomic_get_crtc_state(state->state, crtc);
+	if (IS_ERR(crtc_state))
+		return PTR_ERR(crtc_state);
+
+	if (src_w != crtc_w || src_h != crtc_h) {
+		DRM_ERROR("Scale not support!!!\n");
+		return -EINVAL;
+	}
+
+	if (src_x + src_w > fb->width ||
+	    src_y + src_h > fb->height)
+		return -EINVAL;
+
+	if (crtc_x < 0 || crtc_y < 0)
+		return -EINVAL;
+
+	if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
+	    crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void ade_plane_atomic_update(struct drm_plane *plane,
+				    struct drm_plane_state *old_state)
+{
+	struct drm_plane_state	*state	= plane->state;
+	struct ade_plane *aplane = to_ade_plane(plane);
+	struct ade_crtc *acrtc;
+
+	if (!state->crtc)
+		return;
+
+	acrtc = to_ade_crtc(state->crtc);
+	ade_update_channel(aplane, acrtc, state->fb,
+			   state->crtc_x, state->crtc_y,
+			   state->crtc_w, state->crtc_h,
+			   state->src_x >> 16, state->src_y >> 16,
+			   state->src_w >> 16, state->src_h >> 16);
+}
+
+static void ade_plane_atomic_disable(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+	struct ade_plane *aplane = to_ade_plane(plane);
+	struct ade_crtc *acrtc;
+
+	if (!old_state->crtc)
+		return;
+	acrtc = to_ade_crtc(old_state->crtc);
+	ade_disable_channel(aplane, acrtc);
+}
+
+static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
+	.prepare_fb = ade_plane_prepare_fb,
+	.cleanup_fb = ade_plane_cleanup_fb,
+	.atomic_check = ade_plane_atomic_check,
+	.atomic_update = ade_plane_atomic_update,
+	.atomic_disable = ade_plane_atomic_disable,
+};
+
+static struct drm_plane_funcs ade_plane_funcs = {
+	.update_plane	= drm_atomic_helper_update_plane,
+	.disable_plane	= drm_atomic_helper_disable_plane,
+	.set_property = drm_atomic_helper_plane_set_property,
+	.destroy = drm_plane_cleanup,
+	.reset = drm_atomic_helper_plane_reset,
+	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+
+static int ade_plane_init(struct drm_device *dev, struct ade_plane *aplane,
+			  enum drm_plane_type type)
+{
+	const u32 *fmts;
+	u32 fmts_cnt;
+	int ret = 0;
+
+	/* get  properties */
+	fmts_cnt = ade_get_channel_formats(aplane->ch, &fmts);
+	if (ret)
+		return ret;
+
+	ret = drm_universal_plane_init(dev, &aplane->base, 1, &ade_plane_funcs,
+				       fmts, fmts_cnt, type);
+	if (ret) {
+		DRM_ERROR("fail to init plane, ch=%d\n", aplane->ch);
+		return ret;
+	}
+
+	drm_plane_helper_add(&aplane->base, &ade_plane_helper_funcs);
+
+	return 0;
+}
+
 static int ade_bind(struct device *dev, struct device *master, void *data)
 {
+	struct ade_data *ade = dev_get_drvdata(dev);
+	struct ade_hw_ctx *ctx = &ade->ctx;
+	struct ade_crtc *acrtc = &ade->acrtc;
+	struct drm_device *drm_dev = (struct drm_device *)data;
+	struct ade_plane *aplane;
+	enum drm_plane_type type;
+	int ret;
+	int i;
+
+	/*
+	 * plane init
+	 * TODO: Now only support primary plane, overlay planes
+	 * need to do.
+	 */
+	for (i = 0; i < ADE_CH_NUM; i++) {
+		aplane = &ade->aplane[i];
+		aplane->ch = i;
+		aplane->ctx = ctx;
+		type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
+			DRM_PLANE_TYPE_OVERLAY;
+
+		ret = ade_plane_init(drm_dev, aplane, type);
+		if (ret)
+			return ret;
+	}
+
+	/* crtc init */
+	acrtc->ctx = ctx;
+	ret = ade_crtc_init(drm_dev, &acrtc->base,
+			    &ade->aplane[PRIMARY_CH].base);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 06/10] drm/hisilicon: Add vblank feature
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:39   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal, Xinliang Liu

Add vblank handle for ADE.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
 3 files changed, 112 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
index b0976c3..acb11e7 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
@@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
 	ctx->power_on = false;
 }
 
+static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
+						 unsigned int index)
+{
+	unsigned int index_tmp = 0;
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		if (index_tmp == index)
+			return crtc;
+
+		index_tmp++;
+	}
+
+	WARN_ON(true);
+}
+
+int ade_enable_vblank(struct drm_device *dev, int crtc_index)
+{
+	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 intr_en;
+
+	DRM_INFO("enable_vblank enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+
+	intr_en = readl(base + LDI_INT_EN);
+	intr_en |= LDI_ISR_FRAME_END_INT;
+	writel(intr_en, base + LDI_INT_EN);
 
+	return 0;
+}
+
+void ade_disable_vblank(struct drm_device *dev, int crtc_index)
+{
+	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 intr_en;
+
+	DRM_INFO("disable_vblank enter.\n");
+	if (!ctx->power_on) {
+		DRM_ERROR("power is down! vblank disable fail\n");
+		return;
+	}
+	intr_en = readl(base + LDI_INT_EN);
+	intr_en &= ~LDI_ISR_FRAME_END_INT;
+	writel(intr_en, base + LDI_INT_EN);
+}
+
+static irqreturn_t ade_irq_handler(int irq, void *data)
+{
+	struct ade_crtc *acrtc = data;
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	struct drm_crtc *crtc = &acrtc->base;
+	struct drm_device *dev = crtc->dev;
+	void __iomem *base = ctx->base;
+	u32 status;
+
+	status = readl(base + LDI_MSK_INT);
+	/* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
+
+	/* vblank irq */
+	if (status & LDI_ISR_FRAME_END_INT) {
+		writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
+		drm_handle_vblank(dev, drm_crtc_index(crtc));
+	}
+
+	return IRQ_HANDLED;
+}
 
 /*
  * set modules' reset mode: by software or hardware
@@ -858,6 +930,12 @@ static int ade_bind(struct device *dev, struct device *master, void *data)
 	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;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
new file mode 100644
index 0000000..d1d7b5d
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_DRM_ADE_H__
+#define __HISI_DRM_ADE_H__
+
+int ade_enable_vblank(struct drm_device *dev, int crtc_index);
+void ade_disable_vblank(struct drm_device *dev, int crtc_index);
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index d0eca80..13f59aa 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -21,6 +21,7 @@
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_atomic_helper.h>
 
+#include "hisi_drm_ade.h"
 #include "hisi_drm_drv.h"
 
 #define DRIVER_NAME	"hisi-drm"
@@ -29,6 +30,7 @@ static int hisi_drm_unload(struct drm_device *dev)
 {
 	struct hisi_drm_private *priv = dev->dev_private;
 
+	drm_vblank_cleanup(dev);
 	drm_mode_config_cleanup(dev);
 	devm_kfree(dev->dev, priv);
 	dev->dev_private = NULL;
@@ -76,11 +78,22 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 		goto err_mode_config_cleanup;
 	}
 
+	/* vblank init */
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret) {
+		DRM_ERROR("failed to initialize vblank.\n");
+		goto err_unbind_all;
+	}
+	/* with irq_enabled = true, we can use the vblank feature. */
+	dev->irq_enabled = true;
+
 	/* reset all the states of crtc/plane/encoder/connector */
 	drm_mode_config_reset(dev);
 
 	return 0;
 
+err_unbind_all:
+	component_unbind_all(dev->dev, dev);
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(dev);
 	devm_kfree(dev->dev, priv);
@@ -126,7 +139,7 @@ static int hisi_gem_cma_dumb_create(struct drm_file *file,
 
 static struct drm_driver hisi_drm_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
-				  DRIVER_ATOMIC,
+				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
 	.load			= hisi_drm_load,
 	.unload                 = hisi_drm_unload,
 	.fops			= &hisi_drm_fops,
@@ -148,6 +161,10 @@ 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",
 	.date			= "20150718",
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 06/10] drm/hisilicon: Add vblank feature
@ 2015-11-28 10:39   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add vblank handle for ADE.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
 3 files changed, 112 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
index b0976c3..acb11e7 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
@@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
 	ctx->power_on = false;
 }
 
+static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
+						 unsigned int index)
+{
+	unsigned int index_tmp = 0;
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		if (index_tmp == index)
+			return crtc;
+
+		index_tmp++;
+	}
+
+	WARN_ON(true);
+}
+
+int ade_enable_vblank(struct drm_device *dev, int crtc_index)
+{
+	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 intr_en;
+
+	DRM_INFO("enable_vblank enter.\n");
+	if (!ctx->power_on)
+		(void)ade_power_up(ctx);
+
+	intr_en = readl(base + LDI_INT_EN);
+	intr_en |= LDI_ISR_FRAME_END_INT;
+	writel(intr_en, base + LDI_INT_EN);
 
+	return 0;
+}
+
+void ade_disable_vblank(struct drm_device *dev, int crtc_index)
+{
+	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
+	struct ade_crtc *acrtc = to_ade_crtc(crtc);
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 intr_en;
+
+	DRM_INFO("disable_vblank enter.\n");
+	if (!ctx->power_on) {
+		DRM_ERROR("power is down! vblank disable fail\n");
+		return;
+	}
+	intr_en = readl(base + LDI_INT_EN);
+	intr_en &= ~LDI_ISR_FRAME_END_INT;
+	writel(intr_en, base + LDI_INT_EN);
+}
+
+static irqreturn_t ade_irq_handler(int irq, void *data)
+{
+	struct ade_crtc *acrtc = data;
+	struct ade_hw_ctx *ctx = acrtc->ctx;
+	struct drm_crtc *crtc = &acrtc->base;
+	struct drm_device *dev = crtc->dev;
+	void __iomem *base = ctx->base;
+	u32 status;
+
+	status = readl(base + LDI_MSK_INT);
+	/* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
+
+	/* vblank irq */
+	if (status & LDI_ISR_FRAME_END_INT) {
+		writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
+		drm_handle_vblank(dev, drm_crtc_index(crtc));
+	}
+
+	return IRQ_HANDLED;
+}
 
 /*
  * set modules' reset mode: by software or hardware
@@ -858,6 +930,12 @@ static int ade_bind(struct device *dev, struct device *master, void *data)
 	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;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
new file mode 100644
index 0000000..d1d7b5d
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_DRM_ADE_H__
+#define __HISI_DRM_ADE_H__
+
+int ade_enable_vblank(struct drm_device *dev, int crtc_index);
+void ade_disable_vblank(struct drm_device *dev, int crtc_index);
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index d0eca80..13f59aa 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -21,6 +21,7 @@
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_atomic_helper.h>
 
+#include "hisi_drm_ade.h"
 #include "hisi_drm_drv.h"
 
 #define DRIVER_NAME	"hisi-drm"
@@ -29,6 +30,7 @@ static int hisi_drm_unload(struct drm_device *dev)
 {
 	struct hisi_drm_private *priv = dev->dev_private;
 
+	drm_vblank_cleanup(dev);
 	drm_mode_config_cleanup(dev);
 	devm_kfree(dev->dev, priv);
 	dev->dev_private = NULL;
@@ -76,11 +78,22 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 		goto err_mode_config_cleanup;
 	}
 
+	/* vblank init */
+	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+	if (ret) {
+		DRM_ERROR("failed to initialize vblank.\n");
+		goto err_unbind_all;
+	}
+	/* with irq_enabled = true, we can use the vblank feature. */
+	dev->irq_enabled = true;
+
 	/* reset all the states of crtc/plane/encoder/connector */
 	drm_mode_config_reset(dev);
 
 	return 0;
 
+err_unbind_all:
+	component_unbind_all(dev->dev, dev);
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(dev);
 	devm_kfree(dev->dev, priv);
@@ -126,7 +139,7 @@ static int hisi_gem_cma_dumb_create(struct drm_file *file,
 
 static struct drm_driver hisi_drm_driver = {
 	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
-				  DRIVER_ATOMIC,
+				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
 	.load			= hisi_drm_load,
 	.unload                 = hisi_drm_unload,
 	.fops			= &hisi_drm_fops,
@@ -148,6 +161,10 @@ 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",
 	.date			= "20150718",
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 07/10] drm/hisilicon: Add cma fbdev and hotplug
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:39   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal, Xinliang Liu

Add cma Fbdev, Fbdev is legency and optional, you can enable/disable it by
configuring DRM_FBDEV_EMULATION.
Add hotplug.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 34 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.h |  3 +++
 2 files changed, 37 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index 13f59aa..76eb711 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -20,6 +20,7 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
 
 #include "hisi_drm_ade.h"
 #include "hisi_drm_drv.h"
@@ -30,6 +31,13 @@ static int hisi_drm_unload(struct drm_device *dev)
 {
 	struct hisi_drm_private *priv = dev->dev_private;
 
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	if (priv->fbdev) {
+		drm_fbdev_cma_fini(priv->fbdev);
+		priv->fbdev = NULL;
+	}
+#endif
+	drm_kms_helper_poll_fini(dev);
 	drm_vblank_cleanup(dev);
 	drm_mode_config_cleanup(dev);
 	devm_kfree(dev->dev, priv);
@@ -38,8 +46,28 @@ 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)
+{
+	struct hisi_drm_private *priv = dev->dev_private;
+
+	if (priv->fbdev) {
+		drm_fbdev_cma_hotplug_event(priv->fbdev);
+	} else {
+		priv->fbdev = drm_fbdev_cma_init(dev, 32,
+				dev->mode_config.num_crtc,
+				dev->mode_config.num_connector);
+		if (IS_ERR(priv->fbdev))
+			priv->fbdev = NULL;
+	}
+}
+#endif
+
 static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
 	.fb_create = drm_fb_cma_create,
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	.output_poll_changed = hisi_fbdev_output_poll_changed,
+#endif
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
 };
@@ -90,6 +118,12 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 	/* reset all the states of crtc/plane/encoder/connector */
 	drm_mode_config_reset(dev);
 
+	/* init kms poll for handling hpd */
+	drm_kms_helper_poll_init(dev);
+
+	/* force detection after connectors init */
+	(void)drm_helper_hpd_irq_event(dev);
+
 	return 0;
 
 err_unbind_all:
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
index a10229e..984121f 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
@@ -11,6 +11,9 @@
 #define __HISI_DRM_DRV_H__
 
 struct hisi_drm_private {
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	struct drm_fbdev_cma *fbdev;
+#endif
 };
 
 #endif /* __HISI_DRM_DRV_H__ */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 07/10] drm/hisilicon: Add cma fbdev and hotplug
@ 2015-11-28 10:39   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add cma Fbdev, Fbdev is legency and optional, you can enable/disable it by
configuring DRM_FBDEV_EMULATION.
Add hotplug.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 34 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.h |  3 +++
 2 files changed, 37 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index 13f59aa..76eb711 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -20,6 +20,7 @@
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
 
 #include "hisi_drm_ade.h"
 #include "hisi_drm_drv.h"
@@ -30,6 +31,13 @@ static int hisi_drm_unload(struct drm_device *dev)
 {
 	struct hisi_drm_private *priv = dev->dev_private;
 
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	if (priv->fbdev) {
+		drm_fbdev_cma_fini(priv->fbdev);
+		priv->fbdev = NULL;
+	}
+#endif
+	drm_kms_helper_poll_fini(dev);
 	drm_vblank_cleanup(dev);
 	drm_mode_config_cleanup(dev);
 	devm_kfree(dev->dev, priv);
@@ -38,8 +46,28 @@ 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)
+{
+	struct hisi_drm_private *priv = dev->dev_private;
+
+	if (priv->fbdev) {
+		drm_fbdev_cma_hotplug_event(priv->fbdev);
+	} else {
+		priv->fbdev = drm_fbdev_cma_init(dev, 32,
+				dev->mode_config.num_crtc,
+				dev->mode_config.num_connector);
+		if (IS_ERR(priv->fbdev))
+			priv->fbdev = NULL;
+	}
+}
+#endif
+
 static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
 	.fb_create = drm_fb_cma_create,
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	.output_poll_changed = hisi_fbdev_output_poll_changed,
+#endif
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
 };
@@ -90,6 +118,12 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
 	/* reset all the states of crtc/plane/encoder/connector */
 	drm_mode_config_reset(dev);
 
+	/* init kms poll for handling hpd */
+	drm_kms_helper_poll_init(dev);
+
+	/* force detection after connectors init */
+	(void)drm_helper_hpd_irq_event(dev);
+
 	return 0;
 
 err_unbind_all:
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
index a10229e..984121f 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
@@ -11,6 +11,9 @@
 #define __HISI_DRM_DRV_H__
 
 struct hisi_drm_private {
+#ifdef CONFIG_DRM_FBDEV_EMULATION
+	struct drm_fbdev_cma *fbdev;
+#endif
 };
 
 #endif /* __HISI_DRM_DRV_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 08/10] drm/hisilicon: Add dsi encoder driver
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:39   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal, Xinliang Liu

Add dsi encoder driver for hi6220 SoC.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/Kconfig        |   1 +
 drivers/gpu/drm/hisilicon/Makefile       |   3 +-
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 728 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h |  89 ++++
 4 files changed, 820 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h

diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
index 70aa8d1..f1c33c2 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -4,6 +4,7 @@ config DRM_HISI
 	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.
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index 3433c8b..5083c1f 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -1,4 +1,5 @@
 hisi-drm-y := hisi_drm_drv.o \
-	      hisi_drm_ade.o
+	      hisi_drm_ade.o \
+	      hisi_drm_dsi.o
 
 obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
new file mode 100644
index 0000000..7a6cf66
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -0,0 +1,728 @@
+/*
+ * Hisilicon hi6220 SoC dsi driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "hisi_dsi_reg.h"
+
+#define MAX_TX_ESC_CLK		   (10)
+#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
+#define DEFAULT_MIPI_CLK_RATE   19200000
+#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
+#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
+	      phy->lane_byte_clk_kHz)))
+
+#define encoder_to_dsi(encoder) \
+	container_of(encoder, struct hisi_dsi, encoder)
+#define host_to_dsi(host) \
+	container_of(host, struct hisi_dsi, host)
+
+struct mipi_phy_register {
+	u32 clk_t_lpx;
+	u32 clk_t_hs_prepare;
+	u32 clk_t_hs_zero;
+	u32 clk_t_hs_trial;
+	u32 clk_t_wakeup;
+	u32 data_t_lpx;
+	u32 data_t_hs_prepare;
+	u32 data_t_hs_zero;
+	u32 data_t_hs_trial;
+	u32 data_t_ta_go;
+	u32 data_t_ta_get;
+	u32 data_t_wakeup;
+	u32 hstx_ckg_sel;
+	u32 pll_fbd_div5f;
+	u32 pll_fbd_div1f;
+	u32 pll_fbd_2p;
+	u32 pll_enbwt;
+	u32 pll_fbd_p;
+	u32 pll_fbd_s;
+	u32 pll_pre_div1p;
+	u32 pll_pre_p;
+	u32 pll_vco_750M;
+	u32 pll_lpf_rs;
+	u32 pll_lpf_cs;
+	u32 clklp2hs_time;
+	u32 clkhs2lp_time;
+	u32 lp2hs_time;
+	u32 hs2lp_time;
+	u32 clk_to_data_delay;
+	u32 data_to_clk_delay;
+	u32 lane_byte_clk_kHz;
+	u32 clk_division;
+};
+
+struct dsi_hw_ctx {
+	void __iomem *base;
+	struct clk *dsi_cfg_clk;
+};
+
+struct hisi_dsi {
+	struct drm_encoder encoder;
+	struct drm_display_mode cur_mode;
+	struct dsi_hw_ctx *ctx;
+	struct mipi_phy_register phy;
+
+	u32 lanes;
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
+	bool enable;
+};
+
+struct dsi_data {
+	struct hisi_dsi dsi;
+	struct dsi_hw_ctx ctx;
+};
+
+struct dsi_phy_seq_info {
+	u32 min_range_kHz;
+	u32 max_range_kHz;
+	u32 pll_vco_750M;
+	u32 hstx_ckg_sel;
+};
+
+static const struct dsi_phy_seq_info dphy_seq_info[] = {
+	{   46000,    62000,   1,    7 },
+	{   62000,    93000,   0,    7 },
+	{   93000,   125000,   1,    6 },
+	{  125000,   187000,   0,    6 },
+	{  187000,   250000,   1,    5 },
+	{  250000,   375000,   0,    5 },
+	{  375000,   500000,   1,    4 },
+	{  500000,   750000,   0,    4 },
+	{  750000,  1000000,   1,    0 },
+	{ 1000000,  1500000,   0,    0 }
+};
+
+static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
+					     struct mipi_phy_register *phy)
+{
+	u32 ui = 0;
+	u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
+	u32 i = 0;
+	u32 q_pll = 1;
+	u32 m_pll = 0;
+	u32 n_pll = 0;
+	u32 r_pll = 1;
+	u32 m_n = 0;
+	u32 m_n_int = 0;
+	u64 f_kHz;
+	u64 temp;
+	u64 tmp_kHz = phy_freq_kHz;
+
+	do {
+		f_kHz = tmp_kHz;
+
+		/* Find the PLL clock range from the table */
+		for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
+			if (f_kHz > dphy_seq_info[i].min_range_kHz &&
+			    f_kHz <= dphy_seq_info[i].max_range_kHz)
+				break;
+
+		if (i == ARRAY_SIZE(dphy_seq_info)) {
+			DRM_ERROR("%lldkHz out of range\n", f_kHz);
+			return;
+		}
+
+		phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
+		phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
+
+		if (phy->hstx_ckg_sel <= 7 &&
+		    phy->hstx_ckg_sel >= 4)
+			q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
+
+		temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
+		m_n_int = temp / (u64)1000000000;
+		m_n = (temp % (u64)1000000000) / (u64)100000000;
+
+		if (m_n_int % 2 == 0) {
+			if (m_n * 6 >= 50) {
+				n_pll = 2;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 30) {
+				n_pll = 3;
+				m_pll = m_n_int * n_pll + 2;
+			} else {
+				n_pll = 1;
+				m_pll = m_n_int * n_pll;
+			}
+		} else {
+			if (m_n * 6 >= 50) {
+				n_pll = 1;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 30) {
+				n_pll = 1;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 10) {
+				n_pll = 3;
+				m_pll = m_n_int * n_pll + 1;
+			} else {
+				n_pll = 2;
+				m_pll = m_n_int * n_pll;
+			}
+		}
+
+		if (n_pll == 1) {
+			phy->pll_fbd_p = 0;
+			phy->pll_pre_div1p = 1;
+		} else {
+			phy->pll_fbd_p = n_pll;
+			phy->pll_pre_div1p = 0;
+		}
+
+		if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
+			r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
+
+		if (m_pll == 2) {
+			phy->pll_pre_p = 0;
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 1;
+		} else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
+			phy->pll_pre_p = m_pll / (2 * r_pll);
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 1;
+			phy->pll_fbd_div5f = 0;
+		} else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
+			if (((m_pll / (2 * r_pll)) % 2) == 0) {
+				phy->pll_pre_p =
+					(m_pll / (2 * r_pll)) / 2 - 1;
+				phy->pll_fbd_s =
+					(m_pll / (2 * r_pll)) % 2 + 2;
+			} else {
+				phy->pll_pre_p =
+					(m_pll / (2 * r_pll)) / 2;
+				phy->pll_fbd_s =
+					(m_pll / (2 * r_pll)) % 2;
+			}
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 0;
+		} else {
+			phy->pll_pre_p = 0;
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 1;
+		}
+
+		f_kHz = (u64)1000000000 * (u64)m_pll /
+			((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
+
+		if (f_kHz >= phy_freq_kHz)
+			break;
+
+		tmp_kHz += 10;
+
+	} while (1);
+
+	ui = 1000000 / f_kHz;
+
+	phy->clk_t_lpx = ROUND(50, 8 * ui);
+	phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
+
+	phy->clk_t_hs_zero = ROUND(262, 8 * ui);
+	phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
+	phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
+	if (phy->clk_t_wakeup > 0xff)
+		phy->clk_t_wakeup = 0xff;
+	phy->data_t_wakeup = phy->clk_t_wakeup;
+	phy->data_t_lpx = phy->clk_t_lpx;
+	phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
+	phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
+	phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
+	phy->data_t_ta_go = 3;
+	phy->data_t_ta_get = 4;
+
+	phy->pll_enbwt = 1;
+	phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
+	phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
+	phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
+	phy->hs2lp_time = phy->clkhs2lp_time;
+	phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
+	phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
+				phy->clkhs2lp_time;
+
+	phy->lane_byte_clk_kHz = f_kHz / 8;
+	phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
+	if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
+		phy->clk_division++;
+}
+
+static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
+{
+	u32 val;
+
+	/* TODO: only support RGB888 now, to support more */
+	switch (format) {
+	case MIPI_DSI_FMT_RGB888:
+		val = DSI_24BITS_1;
+		break;
+	default:
+		val = DSI_24BITS_1;
+		break;
+	}
+
+	return val;
+}
+
+static void dsi_mipi_phy_clks(void __iomem *base,
+			      struct mipi_phy_register *phy,
+			      u32 lanes)
+{
+	u32 delay_count;
+	bool is_ready;
+	u32 val;
+	u32 i;
+
+	/* set lanes value */
+	val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
+	writel(val, base + PHY_IF_CFG);
+
+	/* set phy clk division */
+	val = readl(base + CLKMGR_CFG) | phy->clk_division;
+	writel(val, base + CLKMGR_CFG);
+
+	/* clean up phy set param */
+	writel(0, base + PHY_RSTZ);
+	writel(0, base + PHY_TST_CTRL0);
+	writel(1, base + PHY_TST_CTRL0);
+	writel(0, base + PHY_TST_CTRL0);
+
+	/* clock lane Timing control - TLPX */
+	dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
+
+	/* clock lane Timing control - THS-PREPARE */
+	dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
+
+	/* clock lane Timing control - THS-ZERO */
+	dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
+
+	/* clock lane Timing control - THS-TRAIL */
+	dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
+
+	/* clock lane Timing control - TWAKEUP */
+	dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
+
+	/* data lane */
+	for (i = 0; i < lanes; i++) {
+		/* Timing control - TLPX*/
+		dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
+
+		/* Timing control - THS-PREPARE */
+		dsi_phy_tst_set(base, 0x10021 + (i << 4),
+				phy->data_t_hs_prepare);
+
+		/* Timing control - THS-ZERO */
+		dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
+
+		/* Timing control - THS-TRAIL */
+		dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
+
+		/* Timing control - TTA-GO */
+		dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
+
+		/* Timing control - TTA-GET */
+		dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
+
+		/*  Timing control - TWAKEUP */
+		dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
+	}
+
+	/* physical configuration I  */
+	dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
+
+	/* physical configuration pll II  */
+	val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
+				(phy->pll_fbd_2p << 1) + phy->pll_enbwt;
+	dsi_phy_tst_set(base, 0x10063, val);
+
+	/* physical configuration pll II  */
+	dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
+
+	/* physical configuration pll III  */
+	dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
+
+	/*physical configuration pll IV*/
+	val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
+	dsi_phy_tst_set(base, 0x10066, val);
+
+	/*physical configuration pll V*/
+	val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
+					phy->pll_lpf_cs + BIT(5);
+	dsi_phy_tst_set(base, 0x10067, val);
+
+	writel(BIT(2), base + PHY_RSTZ);
+	udelay(1);
+	writel(BIT(2) | BIT(0), base + PHY_RSTZ);
+	udelay(1);
+	writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
+	usleep_range(1000, 1500);
+
+	/* wait for phy's clock ready */
+	delay_count = 0;
+	is_ready = false;
+	while (1) {
+		val = readl(base +  PHY_STATUS);
+		if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
+			is_ready = (delay_count < 100) ? true : false;
+			delay_count = 0;
+			break;
+		}
+
+		udelay(1);
+		++delay_count;
+	}
+
+	if (!is_ready)
+		DRM_INFO("phylock and phystopstateclklane is not ready.\n");
+}
+
+static void dsi_set_mode_timing(void __iomem *base,
+				struct mipi_phy_register *phy,
+				struct drm_display_mode *mode,
+				enum mipi_dsi_pixel_format format)
+{
+	u32 hfp, hbp, hsw, vfp, vbp, vsw;
+	u32 hline_time;
+	u32 hsa_time;
+	u32 hbp_time;
+	u32 pixel_clk_kHz;
+	int htot, vtot;
+	u32 val;
+
+	/* DSI color coding setting */
+	val = dsi_get_dpi_color_coding(format);
+	writel(val, base + DPI_COLOR_CODING);
+
+	/* DSI format and pol setting */
+	val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
+	val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
+	writel(val, base +  DPI_CFG_POL);
+
+	/*
+	 * The DSI IP accepts vertical timing using lines as normal,
+	 * but horizontal timing is a mixture of pixel-clocks for the
+	 * active region and byte-lane clocks for the blanking-related
+	 * timings.  hfp is specified as the total hline_time in byte-
+	 * lane clocks minus hsa, hbp and active.
+	 */
+	pixel_clk_kHz = mode->clock;
+	htot = mode->htotal;
+	vtot = mode->vtotal;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hbp = mode->htotal - mode->hsync_end;
+	hsw = mode->hsync_end - mode->hsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+	vsw = mode->vsync_end - mode->vsync_start;
+	if (vsw > 15) {
+		DRM_INFO("vsw exceeded 15\n");
+		vtot -= vsw - 15;
+		vsw = 15;
+	}
+
+	hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
+	hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
+	hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
+		      pixel_clk_kHz;
+
+	if ((R(hline_time) / 1000) > htot) {
+		DRM_INFO("--: hline_time=%d\n", hline_time);
+		hline_time--;
+	}
+
+	if ((R(hline_time) / 1000) < htot) {
+		DRM_INFO("++: hline_time=%d\n", hline_time);
+		hline_time++;
+	}
+
+	/* all specified in byte-lane clocks */
+	writel(hsa_time, base + VID_HSA_TIME);
+	writel(hbp_time, base + VID_HBP_TIME);
+	writel(hline_time, base + VID_HLINE_TIME);
+
+	writel(vsw, base + VID_VSA_LINES);
+	writel(vbp, base + VID_VBP_LINES);
+	writel(vfp, base + VID_VFP_LINES);
+	writel(mode->vdisplay, base + VID_VACTIVE_LINES);
+	writel(mode->hdisplay, base + VID_PKT_SIZE);
+}
+
+static void dsi_set_video_mode_type(void __iomem *base,
+				    struct mipi_phy_register *phy,
+				    unsigned long flags)
+{
+	u32 val;
+	u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
+		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
+
+	/*
+	 * choose video type
+	 */
+	if ((flags & mode_mask) == non_burst_sync_pulse)
+		val = DSI_NON_BURST_SYNC_PULSES;
+	else if ((flags & mode_mask) == non_burst_sync_event)
+		val = DSI_NON_BURST_SYNC_EVENTS;
+	else
+		val = DSI_BURST_SYNC_PULSES_1;
+
+	writel(val, base + VID_MODE_CFG);
+	/* TODO: to support LCD panel need to set LP command transfer */
+}
+
+static void dsi_mipi_init(struct hisi_dsi *dsi)
+{
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct mipi_phy_register *phy = &dsi->phy;
+	struct drm_display_mode *mode = &dsi->cur_mode;
+	void __iomem *base = ctx->base;
+	u32 dphy_freq_kHz;
+
+	/* count phy params */
+	dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
+	set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
+
+	/* reset Core */
+	writel(0, base + PWR_UP);
+
+	/* set phy clocks */
+	dsi_mipi_phy_clks(base, phy, dsi->lanes);
+
+	/* set dsi mode */
+	dsi_set_mode_timing(base, phy, mode, dsi->format);
+
+	/* set video mode type and low power */
+	dsi_set_video_mode_type(base, phy, dsi->mode_flags);
+
+	/* DSI and D-PHY Initialization */
+	writel(DSI_VIDEO_MODE, base + MODE_CFG);
+	writel(BIT(0), base + LPCLK_CTRL);
+	writel(BIT(0), base + PWR_UP);
+}
+
+static void dsi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	void __iomem *base = ctx->base;
+
+	DRM_DEBUG_DRIVER("enter\n");
+	if (!dsi->enable)
+		return;
+
+	writel(0, base + PWR_UP);
+	writel(0, base + LPCLK_CTRL);
+	writel(0, base + PHY_RSTZ);
+	clk_disable_unprepare(ctx->dsi_cfg_clk);
+
+	dsi->enable = false;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void dsi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (dsi->enable)
+		return;
+
+	/* mipi dphy clock enable */
+	ret = clk_prepare_enable(ctx->dsi_cfg_clk);
+	if (ret) {
+		DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
+		return;
+	}
+
+	dsi_mipi_init(dsi);
+
+	dsi->enable = true;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void dsi_encoder_mode_set(struct drm_encoder *encoder,
+				 struct drm_display_mode *mode,
+				 struct drm_display_mode *adj_mode)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	drm_mode_copy(&dsi->cur_mode, adj_mode);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
+				    struct drm_crtc_state *crtc_state,
+				    struct drm_connector_state *conn_state)
+{
+	struct drm_display_mode *mode = &crtc_state->mode;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		DRM_ERROR("not support INTERLACE mode\n");
+		return MODE_NO_INTERLACE;
+	}
+
+	/* pixel clock support range is (1190494208/64, 1190494208)Hz */
+	if (mode->clock < 18602 || mode->clock > 1190494) {
+		DRM_ERROR("mode clock not support\n");
+		return MODE_CLOCK_RANGE;
+	}
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
+	.atomic_check	= dsi_encoder_atomic_check,
+	.mode_set	= dsi_encoder_mode_set,
+	.enable		= dsi_encoder_enable,
+	.disable	= dsi_encoder_disable
+};
+
+static const struct drm_encoder_funcs hisi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int hisi_drm_encoder_init(struct drm_device *dev,
+				 struct drm_encoder *encoder)
+{
+	int ret;
+
+	encoder->possible_crtcs = 1;
+	ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS);
+	if (ret) {
+		DRM_ERROR("failed to init dsi encoder\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
+
+	return 0;
+}
+
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+	struct dsi_data *ddata = dev_get_drvdata(dev);
+	struct hisi_dsi *dsi = &ddata->dsi;
+	struct drm_device *drm_dev = data;
+	int ret;
+
+	ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void dsi_unbind(struct device *dev, struct device *master, void *data)
+{
+	/* do nothing */
+}
+
+static const struct component_ops dsi_ops = {
+	.bind	= dsi_bind,
+	.unbind	= dsi_unbind,
+};
+
+static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
+{
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct resource *res;
+
+
+	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
+	if (IS_ERR(ctx->dsi_cfg_clk)) {
+		DRM_ERROR("failed to get dsi plck clock\n");
+		return PTR_ERR(ctx->dsi_cfg_clk);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ctx->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->base)) {
+		DRM_ERROR("failed to remap dsi io region\n");
+		return PTR_ERR(ctx->base);
+	}
+
+	return 0;
+}
+
+static int dsi_probe(struct platform_device *pdev)
+{
+	struct dsi_data *data;
+	struct hisi_dsi *dsi;
+	struct dsi_hw_ctx *ctx;
+	int ret;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		DRM_ERROR("failed to allocate dsi data.\n");
+		return -ENOMEM;
+	}
+	dsi = &data->dsi;
+	ctx = &data->ctx;
+	dsi->ctx = ctx;
+
+	ret = dsi_parse_dt(pdev, dsi);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, data);
+
+	return component_add(&pdev->dev, &dsi_ops);
+}
+
+static int dsi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &dsi_ops);
+
+	return 0;
+}
+
+static const struct of_device_id dsi_of_match[] = {
+	{.compatible = "hisilicon,hi6220-dsi"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dsi_of_match);
+
+static struct platform_driver dsi_driver = {
+	.probe = dsi_probe,
+	.remove = dsi_remove,
+	.driver = {
+		.name = "hisi-dsi",
+		.owner = THIS_MODULE,
+		.of_match_table = dsi_of_match,
+	},
+};
+
+module_platform_driver(dsi_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
new file mode 100644
index 0000000..db8f9df
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_DSI_REG_H__
+#define __HISI_DSI_REG_H__
+
+/*
+ * regs
+ */
+#define  PWR_UP                  (0x4)   /* Core power-up */
+#define  PHY_IF_CFG              (0xA4)  /* D-PHY interface configuration */
+#define  CLKMGR_CFG              (0x8)   /* the internal clock dividers */
+#define  PHY_RSTZ                (0xA0)  /* D-PHY reset control */
+#define  PHY_TST_CTRL0           (0xB4)  /* D-PHY test interface control 0 */
+#define  PHY_TST_CTRL1           (0xB8)  /* D-PHY test interface control 1 */
+#define  DPI_VCID                (0xC)   /* DPI virtual channel id */
+#define  DPI_COLOR_CODING        (0x10)  /* DPI color coding */
+#define  DPI_CFG_POL             (0x14)  /* DPI polarity configuration */
+#define  VID_HSA_TIME            (0x48)  /* Horizontal Sync Active time */
+#define  VID_HBP_TIME            (0x4C)  /* Horizontal Back Porch time */
+#define  VID_HLINE_TIME          (0x50)  /* Line time */
+#define  VID_VSA_LINES           (0x54)  /* Vertical Sync Active period */
+#define  VID_VBP_LINES           (0x58)  /* Vertical Back Porch period */
+#define  VID_VFP_LINES           (0x5C)  /* Vertical Front Porch period */
+#define  VID_VACTIVE_LINES       (0x60)  /* Vertical resolution */
+#define  VID_PKT_SIZE            (0x3C)  /* Video packet size */
+#define  VID_MODE_CFG            (0x38)  /* Video mode configuration */
+#define  DPI_LP_CMD_TIM          (0x18)  /* Low-power command timing config */
+#define  PHY_TMR_CFG             (0x9C)  /* Data lanes timing configuration */
+#define  BTA_TO_CNT              (0x8C)  /* Response timeout definition */
+#define  PHY_TMR_LPCLK_CFG       (0x98)  /* clock lane timing configuration */
+#define  CLK_DATA_TMR_CFG        (0xCC)
+#define  LPCLK_CTRL              (0x94)  /* Low-power in clock lane */
+#define  PCKHDL_CFG              (0x2C)  /* Packet handler configuration */
+#define  EDPI_CMD_SIZE           (0x64)  /* Size for eDPI packets */
+#define  MODE_CFG                (0x34)  /* Video or Command mode selection */
+#define  PHY_STATUS              (0xB0)  /* D-PHY PPI status interface */
+
+#define	PHY_STOP_WAIT_TIME      (0x30)
+
+/*
+ * regs relevant enum
+ */
+enum dpi_color_coding {
+	DSI_24BITS_1 = 5,
+};
+
+enum dsi_video_mode_type {
+	DSI_NON_BURST_SYNC_PULSES = 0,
+	DSI_NON_BURST_SYNC_EVENTS,
+	DSI_BURST_SYNC_PULSES_1,
+	DSI_BURST_SYNC_PULSES_2
+};
+
+enum dsi_work_mode {
+	DSI_VIDEO_MODE = 0,
+	DSI_COMMAND_MODE
+};
+
+/*
+ * regs Write/Read functions
+ */
+static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
+{
+	writel(reg, base + PHY_TST_CTRL1);
+	/* reg addr written at first */
+	wmb();
+	writel(0x02, base + PHY_TST_CTRL0);
+	/* cmd1 sent for write */
+	wmb();
+	writel(0x00, base + PHY_TST_CTRL0);
+	/* cmd2 sent for write */
+	wmb();
+	writel(val, base + PHY_TST_CTRL1);
+	/* Then write data */
+	wmb();
+	writel(0x02, base + PHY_TST_CTRL0);
+	/* cmd2 sent for write */
+	wmb();
+	writel(0x00, base + PHY_TST_CTRL0);
+}
+
+#endif /* __HISI_DRM_DSI_H__ */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 08/10] drm/hisilicon: Add dsi encoder driver
@ 2015-11-28 10:39   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add dsi encoder driver for hi6220 SoC.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/Kconfig        |   1 +
 drivers/gpu/drm/hisilicon/Makefile       |   3 +-
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 728 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h |  89 ++++
 4 files changed, 820 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h

diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
index 70aa8d1..f1c33c2 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -4,6 +4,7 @@ config DRM_HISI
 	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.
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index 3433c8b..5083c1f 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -1,4 +1,5 @@
 hisi-drm-y := hisi_drm_drv.o \
-	      hisi_drm_ade.o
+	      hisi_drm_ade.o \
+	      hisi_drm_dsi.o
 
 obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
new file mode 100644
index 0000000..7a6cf66
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -0,0 +1,728 @@
+/*
+ * Hisilicon hi6220 SoC dsi driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *	Xinliang Liu <xinliang.liu@linaro.org>
+ *	Xinliang Liu <z.liuxinliang@hisilicon.com>
+ *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "hisi_dsi_reg.h"
+
+#define MAX_TX_ESC_CLK		   (10)
+#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
+#define DEFAULT_MIPI_CLK_RATE   19200000
+#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
+#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
+	      phy->lane_byte_clk_kHz)))
+
+#define encoder_to_dsi(encoder) \
+	container_of(encoder, struct hisi_dsi, encoder)
+#define host_to_dsi(host) \
+	container_of(host, struct hisi_dsi, host)
+
+struct mipi_phy_register {
+	u32 clk_t_lpx;
+	u32 clk_t_hs_prepare;
+	u32 clk_t_hs_zero;
+	u32 clk_t_hs_trial;
+	u32 clk_t_wakeup;
+	u32 data_t_lpx;
+	u32 data_t_hs_prepare;
+	u32 data_t_hs_zero;
+	u32 data_t_hs_trial;
+	u32 data_t_ta_go;
+	u32 data_t_ta_get;
+	u32 data_t_wakeup;
+	u32 hstx_ckg_sel;
+	u32 pll_fbd_div5f;
+	u32 pll_fbd_div1f;
+	u32 pll_fbd_2p;
+	u32 pll_enbwt;
+	u32 pll_fbd_p;
+	u32 pll_fbd_s;
+	u32 pll_pre_div1p;
+	u32 pll_pre_p;
+	u32 pll_vco_750M;
+	u32 pll_lpf_rs;
+	u32 pll_lpf_cs;
+	u32 clklp2hs_time;
+	u32 clkhs2lp_time;
+	u32 lp2hs_time;
+	u32 hs2lp_time;
+	u32 clk_to_data_delay;
+	u32 data_to_clk_delay;
+	u32 lane_byte_clk_kHz;
+	u32 clk_division;
+};
+
+struct dsi_hw_ctx {
+	void __iomem *base;
+	struct clk *dsi_cfg_clk;
+};
+
+struct hisi_dsi {
+	struct drm_encoder encoder;
+	struct drm_display_mode cur_mode;
+	struct dsi_hw_ctx *ctx;
+	struct mipi_phy_register phy;
+
+	u32 lanes;
+	enum mipi_dsi_pixel_format format;
+	unsigned long mode_flags;
+	bool enable;
+};
+
+struct dsi_data {
+	struct hisi_dsi dsi;
+	struct dsi_hw_ctx ctx;
+};
+
+struct dsi_phy_seq_info {
+	u32 min_range_kHz;
+	u32 max_range_kHz;
+	u32 pll_vco_750M;
+	u32 hstx_ckg_sel;
+};
+
+static const struct dsi_phy_seq_info dphy_seq_info[] = {
+	{   46000,    62000,   1,    7 },
+	{   62000,    93000,   0,    7 },
+	{   93000,   125000,   1,    6 },
+	{  125000,   187000,   0,    6 },
+	{  187000,   250000,   1,    5 },
+	{  250000,   375000,   0,    5 },
+	{  375000,   500000,   1,    4 },
+	{  500000,   750000,   0,    4 },
+	{  750000,  1000000,   1,    0 },
+	{ 1000000,  1500000,   0,    0 }
+};
+
+static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
+					     struct mipi_phy_register *phy)
+{
+	u32 ui = 0;
+	u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
+	u32 i = 0;
+	u32 q_pll = 1;
+	u32 m_pll = 0;
+	u32 n_pll = 0;
+	u32 r_pll = 1;
+	u32 m_n = 0;
+	u32 m_n_int = 0;
+	u64 f_kHz;
+	u64 temp;
+	u64 tmp_kHz = phy_freq_kHz;
+
+	do {
+		f_kHz = tmp_kHz;
+
+		/* Find the PLL clock range from the table */
+		for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
+			if (f_kHz > dphy_seq_info[i].min_range_kHz &&
+			    f_kHz <= dphy_seq_info[i].max_range_kHz)
+				break;
+
+		if (i == ARRAY_SIZE(dphy_seq_info)) {
+			DRM_ERROR("%lldkHz out of range\n", f_kHz);
+			return;
+		}
+
+		phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
+		phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
+
+		if (phy->hstx_ckg_sel <= 7 &&
+		    phy->hstx_ckg_sel >= 4)
+			q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
+
+		temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
+		m_n_int = temp / (u64)1000000000;
+		m_n = (temp % (u64)1000000000) / (u64)100000000;
+
+		if (m_n_int % 2 == 0) {
+			if (m_n * 6 >= 50) {
+				n_pll = 2;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 30) {
+				n_pll = 3;
+				m_pll = m_n_int * n_pll + 2;
+			} else {
+				n_pll = 1;
+				m_pll = m_n_int * n_pll;
+			}
+		} else {
+			if (m_n * 6 >= 50) {
+				n_pll = 1;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 30) {
+				n_pll = 1;
+				m_pll = (m_n_int + 1) * n_pll;
+			} else if (m_n * 6 >= 10) {
+				n_pll = 3;
+				m_pll = m_n_int * n_pll + 1;
+			} else {
+				n_pll = 2;
+				m_pll = m_n_int * n_pll;
+			}
+		}
+
+		if (n_pll == 1) {
+			phy->pll_fbd_p = 0;
+			phy->pll_pre_div1p = 1;
+		} else {
+			phy->pll_fbd_p = n_pll;
+			phy->pll_pre_div1p = 0;
+		}
+
+		if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
+			r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
+
+		if (m_pll == 2) {
+			phy->pll_pre_p = 0;
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 1;
+		} else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
+			phy->pll_pre_p = m_pll / (2 * r_pll);
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 1;
+			phy->pll_fbd_div5f = 0;
+		} else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
+			if (((m_pll / (2 * r_pll)) % 2) == 0) {
+				phy->pll_pre_p =
+					(m_pll / (2 * r_pll)) / 2 - 1;
+				phy->pll_fbd_s =
+					(m_pll / (2 * r_pll)) % 2 + 2;
+			} else {
+				phy->pll_pre_p =
+					(m_pll / (2 * r_pll)) / 2;
+				phy->pll_fbd_s =
+					(m_pll / (2 * r_pll)) % 2;
+			}
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 0;
+		} else {
+			phy->pll_pre_p = 0;
+			phy->pll_fbd_s = 0;
+			phy->pll_fbd_div1f = 0;
+			phy->pll_fbd_div5f = 1;
+		}
+
+		f_kHz = (u64)1000000000 * (u64)m_pll /
+			((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
+
+		if (f_kHz >= phy_freq_kHz)
+			break;
+
+		tmp_kHz += 10;
+
+	} while (1);
+
+	ui = 1000000 / f_kHz;
+
+	phy->clk_t_lpx = ROUND(50, 8 * ui);
+	phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
+
+	phy->clk_t_hs_zero = ROUND(262, 8 * ui);
+	phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
+	phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
+	if (phy->clk_t_wakeup > 0xff)
+		phy->clk_t_wakeup = 0xff;
+	phy->data_t_wakeup = phy->clk_t_wakeup;
+	phy->data_t_lpx = phy->clk_t_lpx;
+	phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
+	phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
+	phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
+	phy->data_t_ta_go = 3;
+	phy->data_t_ta_get = 4;
+
+	phy->pll_enbwt = 1;
+	phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
+	phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
+	phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
+	phy->hs2lp_time = phy->clkhs2lp_time;
+	phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
+	phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
+				phy->clkhs2lp_time;
+
+	phy->lane_byte_clk_kHz = f_kHz / 8;
+	phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
+	if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
+		phy->clk_division++;
+}
+
+static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
+{
+	u32 val;
+
+	/* TODO: only support RGB888 now, to support more */
+	switch (format) {
+	case MIPI_DSI_FMT_RGB888:
+		val = DSI_24BITS_1;
+		break;
+	default:
+		val = DSI_24BITS_1;
+		break;
+	}
+
+	return val;
+}
+
+static void dsi_mipi_phy_clks(void __iomem *base,
+			      struct mipi_phy_register *phy,
+			      u32 lanes)
+{
+	u32 delay_count;
+	bool is_ready;
+	u32 val;
+	u32 i;
+
+	/* set lanes value */
+	val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
+	writel(val, base + PHY_IF_CFG);
+
+	/* set phy clk division */
+	val = readl(base + CLKMGR_CFG) | phy->clk_division;
+	writel(val, base + CLKMGR_CFG);
+
+	/* clean up phy set param */
+	writel(0, base + PHY_RSTZ);
+	writel(0, base + PHY_TST_CTRL0);
+	writel(1, base + PHY_TST_CTRL0);
+	writel(0, base + PHY_TST_CTRL0);
+
+	/* clock lane Timing control - TLPX */
+	dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
+
+	/* clock lane Timing control - THS-PREPARE */
+	dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
+
+	/* clock lane Timing control - THS-ZERO */
+	dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
+
+	/* clock lane Timing control - THS-TRAIL */
+	dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
+
+	/* clock lane Timing control - TWAKEUP */
+	dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
+
+	/* data lane */
+	for (i = 0; i < lanes; i++) {
+		/* Timing control - TLPX*/
+		dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
+
+		/* Timing control - THS-PREPARE */
+		dsi_phy_tst_set(base, 0x10021 + (i << 4),
+				phy->data_t_hs_prepare);
+
+		/* Timing control - THS-ZERO */
+		dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
+
+		/* Timing control - THS-TRAIL */
+		dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
+
+		/* Timing control - TTA-GO */
+		dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
+
+		/* Timing control - TTA-GET */
+		dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
+
+		/*  Timing control - TWAKEUP */
+		dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
+	}
+
+	/* physical configuration I  */
+	dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
+
+	/* physical configuration pll II  */
+	val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
+				(phy->pll_fbd_2p << 1) + phy->pll_enbwt;
+	dsi_phy_tst_set(base, 0x10063, val);
+
+	/* physical configuration pll II  */
+	dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
+
+	/* physical configuration pll III  */
+	dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
+
+	/*physical configuration pll IV*/
+	val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
+	dsi_phy_tst_set(base, 0x10066, val);
+
+	/*physical configuration pll V*/
+	val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
+					phy->pll_lpf_cs + BIT(5);
+	dsi_phy_tst_set(base, 0x10067, val);
+
+	writel(BIT(2), base + PHY_RSTZ);
+	udelay(1);
+	writel(BIT(2) | BIT(0), base + PHY_RSTZ);
+	udelay(1);
+	writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
+	usleep_range(1000, 1500);
+
+	/* wait for phy's clock ready */
+	delay_count = 0;
+	is_ready = false;
+	while (1) {
+		val = readl(base +  PHY_STATUS);
+		if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
+			is_ready = (delay_count < 100) ? true : false;
+			delay_count = 0;
+			break;
+		}
+
+		udelay(1);
+		++delay_count;
+	}
+
+	if (!is_ready)
+		DRM_INFO("phylock and phystopstateclklane is not ready.\n");
+}
+
+static void dsi_set_mode_timing(void __iomem *base,
+				struct mipi_phy_register *phy,
+				struct drm_display_mode *mode,
+				enum mipi_dsi_pixel_format format)
+{
+	u32 hfp, hbp, hsw, vfp, vbp, vsw;
+	u32 hline_time;
+	u32 hsa_time;
+	u32 hbp_time;
+	u32 pixel_clk_kHz;
+	int htot, vtot;
+	u32 val;
+
+	/* DSI color coding setting */
+	val = dsi_get_dpi_color_coding(format);
+	writel(val, base + DPI_COLOR_CODING);
+
+	/* DSI format and pol setting */
+	val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
+	val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
+	writel(val, base +  DPI_CFG_POL);
+
+	/*
+	 * The DSI IP accepts vertical timing using lines as normal,
+	 * but horizontal timing is a mixture of pixel-clocks for the
+	 * active region and byte-lane clocks for the blanking-related
+	 * timings.  hfp is specified as the total hline_time in byte-
+	 * lane clocks minus hsa, hbp and active.
+	 */
+	pixel_clk_kHz = mode->clock;
+	htot = mode->htotal;
+	vtot = mode->vtotal;
+	hfp = mode->hsync_start - mode->hdisplay;
+	hbp = mode->htotal - mode->hsync_end;
+	hsw = mode->hsync_end - mode->hsync_start;
+	vfp = mode->vsync_start - mode->vdisplay;
+	vbp = mode->vtotal - mode->vsync_end;
+	vsw = mode->vsync_end - mode->vsync_start;
+	if (vsw > 15) {
+		DRM_INFO("vsw exceeded 15\n");
+		vtot -= vsw - 15;
+		vsw = 15;
+	}
+
+	hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
+	hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
+	hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
+		      pixel_clk_kHz;
+
+	if ((R(hline_time) / 1000) > htot) {
+		DRM_INFO("--: hline_time=%d\n", hline_time);
+		hline_time--;
+	}
+
+	if ((R(hline_time) / 1000) < htot) {
+		DRM_INFO("++: hline_time=%d\n", hline_time);
+		hline_time++;
+	}
+
+	/* all specified in byte-lane clocks */
+	writel(hsa_time, base + VID_HSA_TIME);
+	writel(hbp_time, base + VID_HBP_TIME);
+	writel(hline_time, base + VID_HLINE_TIME);
+
+	writel(vsw, base + VID_VSA_LINES);
+	writel(vbp, base + VID_VBP_LINES);
+	writel(vfp, base + VID_VFP_LINES);
+	writel(mode->vdisplay, base + VID_VACTIVE_LINES);
+	writel(mode->hdisplay, base + VID_PKT_SIZE);
+}
+
+static void dsi_set_video_mode_type(void __iomem *base,
+				    struct mipi_phy_register *phy,
+				    unsigned long flags)
+{
+	u32 val;
+	u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
+		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
+		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+	u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
+
+	/*
+	 * choose video type
+	 */
+	if ((flags & mode_mask) == non_burst_sync_pulse)
+		val = DSI_NON_BURST_SYNC_PULSES;
+	else if ((flags & mode_mask) == non_burst_sync_event)
+		val = DSI_NON_BURST_SYNC_EVENTS;
+	else
+		val = DSI_BURST_SYNC_PULSES_1;
+
+	writel(val, base + VID_MODE_CFG);
+	/* TODO: to support LCD panel need to set LP command transfer */
+}
+
+static void dsi_mipi_init(struct hisi_dsi *dsi)
+{
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct mipi_phy_register *phy = &dsi->phy;
+	struct drm_display_mode *mode = &dsi->cur_mode;
+	void __iomem *base = ctx->base;
+	u32 dphy_freq_kHz;
+
+	/* count phy params */
+	dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
+	set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
+
+	/* reset Core */
+	writel(0, base + PWR_UP);
+
+	/* set phy clocks */
+	dsi_mipi_phy_clks(base, phy, dsi->lanes);
+
+	/* set dsi mode */
+	dsi_set_mode_timing(base, phy, mode, dsi->format);
+
+	/* set video mode type and low power */
+	dsi_set_video_mode_type(base, phy, dsi->mode_flags);
+
+	/* DSI and D-PHY Initialization */
+	writel(DSI_VIDEO_MODE, base + MODE_CFG);
+	writel(BIT(0), base + LPCLK_CTRL);
+	writel(BIT(0), base + PWR_UP);
+}
+
+static void dsi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	void __iomem *base = ctx->base;
+
+	DRM_DEBUG_DRIVER("enter\n");
+	if (!dsi->enable)
+		return;
+
+	writel(0, base + PWR_UP);
+	writel(0, base + LPCLK_CTRL);
+	writel(0, base + PHY_RSTZ);
+	clk_disable_unprepare(ctx->dsi_cfg_clk);
+
+	dsi->enable = false;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void dsi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	int ret;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (dsi->enable)
+		return;
+
+	/* mipi dphy clock enable */
+	ret = clk_prepare_enable(ctx->dsi_cfg_clk);
+	if (ret) {
+		DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
+		return;
+	}
+
+	dsi_mipi_init(dsi);
+
+	dsi->enable = true;
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static void dsi_encoder_mode_set(struct drm_encoder *encoder,
+				 struct drm_display_mode *mode,
+				 struct drm_display_mode *adj_mode)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	drm_mode_copy(&dsi->cur_mode, adj_mode);
+	DRM_DEBUG_DRIVER("exit success.\n");
+}
+
+static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
+				    struct drm_crtc_state *crtc_state,
+				    struct drm_connector_state *conn_state)
+{
+	struct drm_display_mode *mode = &crtc_state->mode;
+
+	DRM_DEBUG_DRIVER("enter.\n");
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+		DRM_ERROR("not support INTERLACE mode\n");
+		return MODE_NO_INTERLACE;
+	}
+
+	/* pixel clock support range is (1190494208/64, 1190494208)Hz */
+	if (mode->clock < 18602 || mode->clock > 1190494) {
+		DRM_ERROR("mode clock not support\n");
+		return MODE_CLOCK_RANGE;
+	}
+
+	DRM_DEBUG_DRIVER("exit success.\n");
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
+	.atomic_check	= dsi_encoder_atomic_check,
+	.mode_set	= dsi_encoder_mode_set,
+	.enable		= dsi_encoder_enable,
+	.disable	= dsi_encoder_disable
+};
+
+static const struct drm_encoder_funcs hisi_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int hisi_drm_encoder_init(struct drm_device *dev,
+				 struct drm_encoder *encoder)
+{
+	int ret;
+
+	encoder->possible_crtcs = 1;
+	ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS);
+	if (ret) {
+		DRM_ERROR("failed to init dsi encoder\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
+
+	return 0;
+}
+
+static int dsi_bind(struct device *dev, struct device *master, void *data)
+{
+	struct dsi_data *ddata = dev_get_drvdata(dev);
+	struct hisi_dsi *dsi = &ddata->dsi;
+	struct drm_device *drm_dev = data;
+	int ret;
+
+	ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void dsi_unbind(struct device *dev, struct device *master, void *data)
+{
+	/* do nothing */
+}
+
+static const struct component_ops dsi_ops = {
+	.bind	= dsi_bind,
+	.unbind	= dsi_unbind,
+};
+
+static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
+{
+	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct resource *res;
+
+
+	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
+	if (IS_ERR(ctx->dsi_cfg_clk)) {
+		DRM_ERROR("failed to get dsi plck clock\n");
+		return PTR_ERR(ctx->dsi_cfg_clk);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ctx->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(ctx->base)) {
+		DRM_ERROR("failed to remap dsi io region\n");
+		return PTR_ERR(ctx->base);
+	}
+
+	return 0;
+}
+
+static int dsi_probe(struct platform_device *pdev)
+{
+	struct dsi_data *data;
+	struct hisi_dsi *dsi;
+	struct dsi_hw_ctx *ctx;
+	int ret;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data) {
+		DRM_ERROR("failed to allocate dsi data.\n");
+		return -ENOMEM;
+	}
+	dsi = &data->dsi;
+	ctx = &data->ctx;
+	dsi->ctx = ctx;
+
+	ret = dsi_parse_dt(pdev, dsi);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, data);
+
+	return component_add(&pdev->dev, &dsi_ops);
+}
+
+static int dsi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &dsi_ops);
+
+	return 0;
+}
+
+static const struct of_device_id dsi_of_match[] = {
+	{.compatible = "hisilicon,hi6220-dsi"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dsi_of_match);
+
+static struct platform_driver dsi_driver = {
+	.probe = dsi_probe,
+	.remove = dsi_remove,
+	.driver = {
+		.name = "hisi-dsi",
+		.owner = THIS_MODULE,
+		.of_match_table = dsi_of_match,
+	},
+};
+
+module_platform_driver(dsi_driver);
+
+MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
new file mode 100644
index 0000000..db8f9df
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __HISI_DSI_REG_H__
+#define __HISI_DSI_REG_H__
+
+/*
+ * regs
+ */
+#define  PWR_UP                  (0x4)   /* Core power-up */
+#define  PHY_IF_CFG              (0xA4)  /* D-PHY interface configuration */
+#define  CLKMGR_CFG              (0x8)   /* the internal clock dividers */
+#define  PHY_RSTZ                (0xA0)  /* D-PHY reset control */
+#define  PHY_TST_CTRL0           (0xB4)  /* D-PHY test interface control 0 */
+#define  PHY_TST_CTRL1           (0xB8)  /* D-PHY test interface control 1 */
+#define  DPI_VCID                (0xC)   /* DPI virtual channel id */
+#define  DPI_COLOR_CODING        (0x10)  /* DPI color coding */
+#define  DPI_CFG_POL             (0x14)  /* DPI polarity configuration */
+#define  VID_HSA_TIME            (0x48)  /* Horizontal Sync Active time */
+#define  VID_HBP_TIME            (0x4C)  /* Horizontal Back Porch time */
+#define  VID_HLINE_TIME          (0x50)  /* Line time */
+#define  VID_VSA_LINES           (0x54)  /* Vertical Sync Active period */
+#define  VID_VBP_LINES           (0x58)  /* Vertical Back Porch period */
+#define  VID_VFP_LINES           (0x5C)  /* Vertical Front Porch period */
+#define  VID_VACTIVE_LINES       (0x60)  /* Vertical resolution */
+#define  VID_PKT_SIZE            (0x3C)  /* Video packet size */
+#define  VID_MODE_CFG            (0x38)  /* Video mode configuration */
+#define  DPI_LP_CMD_TIM          (0x18)  /* Low-power command timing config */
+#define  PHY_TMR_CFG             (0x9C)  /* Data lanes timing configuration */
+#define  BTA_TO_CNT              (0x8C)  /* Response timeout definition */
+#define  PHY_TMR_LPCLK_CFG       (0x98)  /* clock lane timing configuration */
+#define  CLK_DATA_TMR_CFG        (0xCC)
+#define  LPCLK_CTRL              (0x94)  /* Low-power in clock lane */
+#define  PCKHDL_CFG              (0x2C)  /* Packet handler configuration */
+#define  EDPI_CMD_SIZE           (0x64)  /* Size for eDPI packets */
+#define  MODE_CFG                (0x34)  /* Video or Command mode selection */
+#define  PHY_STATUS              (0xB0)  /* D-PHY PPI status interface */
+
+#define	PHY_STOP_WAIT_TIME      (0x30)
+
+/*
+ * regs relevant enum
+ */
+enum dpi_color_coding {
+	DSI_24BITS_1 = 5,
+};
+
+enum dsi_video_mode_type {
+	DSI_NON_BURST_SYNC_PULSES = 0,
+	DSI_NON_BURST_SYNC_EVENTS,
+	DSI_BURST_SYNC_PULSES_1,
+	DSI_BURST_SYNC_PULSES_2
+};
+
+enum dsi_work_mode {
+	DSI_VIDEO_MODE = 0,
+	DSI_COMMAND_MODE
+};
+
+/*
+ * regs Write/Read functions
+ */
+static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
+{
+	writel(reg, base + PHY_TST_CTRL1);
+	/* reg addr written at first */
+	wmb();
+	writel(0x02, base + PHY_TST_CTRL0);
+	/* cmd1 sent for write */
+	wmb();
+	writel(0x00, base + PHY_TST_CTRL0);
+	/* cmd2 sent for write */
+	wmb();
+	writel(val, base + PHY_TST_CTRL1);
+	/* Then write data */
+	wmb();
+	writel(0x02, base + PHY_TST_CTRL0);
+	/* cmd2 sent for write */
+	wmb();
+	writel(0x00, base + PHY_TST_CTRL0);
+}
+
+#endif /* __HISI_DRM_DSI_H__ */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 09/10] drm/hisilicon: Add dsi host driver
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:39   ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: dri-devel, devicetree, daniel, robh, daniel, architt, airlied,
	corbet, catalin.marinas, will.deacon
  Cc: andy.green, xuyiping, linux-doc, w.f, zourongrong, linuxarm,
	xuwei5, bintian.wang, haojian.zhuang, benjamin.gaignard,
	puck.chen, lijianhua, liguozhu, linux-arm-kernel

Add dsi host driver for hi6220 SoC.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 50 ++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index 7a6cf66..066e08d 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -78,6 +78,7 @@ struct dsi_hw_ctx {
 
 struct hisi_dsi {
 	struct drm_encoder encoder;
+	struct mipi_dsi_host host;
 	struct drm_display_mode cur_mode;
 	struct dsi_hw_ctx *ctx;
 	struct mipi_phy_register phy;
@@ -625,6 +626,51 @@ static int hisi_drm_encoder_init(struct drm_device *dev,
 	return 0;
 }
 
+static int dsi_host_attach(struct mipi_dsi_host *host,
+			   struct mipi_dsi_device *mdsi)
+{
+	struct hisi_dsi *dsi = host_to_dsi(host);
+
+	if (mdsi->lanes < 1 || mdsi->lanes > 4) {
+		DRM_ERROR("dsi device params invalid\n");
+		return -EINVAL;
+	}
+
+	dsi->lanes = mdsi->lanes;
+	dsi->format = mdsi->format;
+	dsi->mode_flags = mdsi->mode_flags;
+
+	return 0;
+}
+
+static int dsi_host_detach(struct mipi_dsi_host *host,
+			   struct mipi_dsi_device *mdsi)
+{
+	/* do nothing */
+	return 0;
+}
+
+static struct mipi_dsi_host_ops dsi_host_ops = {
+	.attach = dsi_host_attach,
+	.detach = dsi_host_detach,
+};
+
+static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
+{
+	struct mipi_dsi_host *host = &dsi->host;
+	int ret;
+
+	host->dev = dev;
+	host->ops = &dsi_host_ops;
+	ret = mipi_dsi_host_register(host);
+	if (ret) {
+		DRM_ERROR("failed to register dsi host\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int dsi_bind(struct device *dev, struct device *master, void *data)
 {
 	struct dsi_data *ddata = dev_get_drvdata(dev);
@@ -636,6 +682,10 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
 	if (ret)
 		return ret;
 
+	ret = dsi_host_init(dev, dsi);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
1.9.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 09/10] drm/hisilicon: Add dsi host driver
@ 2015-11-28 10:39   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add dsi host driver for hi6220 SoC.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 50 ++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index 7a6cf66..066e08d 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -78,6 +78,7 @@ struct dsi_hw_ctx {
 
 struct hisi_dsi {
 	struct drm_encoder encoder;
+	struct mipi_dsi_host host;
 	struct drm_display_mode cur_mode;
 	struct dsi_hw_ctx *ctx;
 	struct mipi_phy_register phy;
@@ -625,6 +626,51 @@ static int hisi_drm_encoder_init(struct drm_device *dev,
 	return 0;
 }
 
+static int dsi_host_attach(struct mipi_dsi_host *host,
+			   struct mipi_dsi_device *mdsi)
+{
+	struct hisi_dsi *dsi = host_to_dsi(host);
+
+	if (mdsi->lanes < 1 || mdsi->lanes > 4) {
+		DRM_ERROR("dsi device params invalid\n");
+		return -EINVAL;
+	}
+
+	dsi->lanes = mdsi->lanes;
+	dsi->format = mdsi->format;
+	dsi->mode_flags = mdsi->mode_flags;
+
+	return 0;
+}
+
+static int dsi_host_detach(struct mipi_dsi_host *host,
+			   struct mipi_dsi_device *mdsi)
+{
+	/* do nothing */
+	return 0;
+}
+
+static struct mipi_dsi_host_ops dsi_host_ops = {
+	.attach = dsi_host_attach,
+	.detach = dsi_host_detach,
+};
+
+static int dsi_host_init(struct device *dev, struct hisi_dsi *dsi)
+{
+	struct mipi_dsi_host *host = &dsi->host;
+	int ret;
+
+	host->dev = dev;
+	host->ops = &dsi_host_ops;
+	ret = mipi_dsi_host_register(host);
+	if (ret) {
+		DRM_ERROR("failed to register dsi host\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int dsi_bind(struct device *dev, struct device *master, void *data)
 {
 	struct dsi_data *ddata = dev_get_drvdata(dev);
@@ -636,6 +682,10 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
 	if (ret)
 		return ret;
 
+	ret = dsi_host_init(dev, dsi);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
  2015-11-28 10:38 ` Xinliang Liu
@ 2015-11-28 10:39     ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
	devicetree-u79uwXL29TY76Z2rM5mHXA, daniel-/w4YWyX8dFk,
	robh-DgEjT+Ai2ygdnm+yROfE0A, daniel-rLtY4a/8tF1rovVCs/uTlw,
	architt-sgV2jX0FEOL9JmXXK+q4OQ, airlied-cv59FeDIM0c,
	corbet-T1hC0tSOHrs, catalin.marinas-5wv7dgnIgG8,
	will.deacon-5wv7dgnIgG8
  Cc: linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linuxarm-hv44wF8Li93QT0dZR+AlfA,
	andy.green-QSEj5FYQhm4dnm+yROfE0A,
	haojian.zhuang-QSEj5FYQhm4dnm+yROfE0A,
	liguozhu-C8/M+/jPZTeaMJb+Lgu22Q, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
	w.f-hv44wF8Li93QT0dZR+AlfA, puck.chen-C8/M+/jPZTeaMJb+Lgu22Q,
	bintian.wang-hv44wF8Li93QT0dZR+AlfA,
	benjamin.gaignard-QSEj5FYQhm4dnm+yROfE0A,
	xuyiping-C8/M+/jPZTeaMJb+Lgu22Q,
	kong.kongxinwei-C8/M+/jPZTeaMJb+Lgu22Q,
	zourongrong-hv44wF8Li93QT0dZR+AlfA,
	lijianhua-hv44wF8Li93QT0dZR+AlfA,
	sumit.semwal-QSEj5FYQhm4dnm+yROfE0A, Xinliang Liu

Add support for external HDMI bridge.

Signed-off-by: Xinliang Liu <xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>
Signed-off-by: Andy Green <andy.green-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51 ++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index 066e08d..9e056db 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -78,6 +78,7 @@ struct dsi_hw_ctx {
 
 struct hisi_dsi {
 	struct drm_encoder encoder;
+	struct drm_bridge *bridge;
 	struct mipi_dsi_host host;
 	struct drm_display_mode cur_mode;
 	struct dsi_hw_ctx *ctx;
@@ -671,6 +672,25 @@ 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)
+{
+	struct drm_encoder *encoder = &dsi->encoder;
+	struct drm_bridge *bridge = dsi->bridge;
+	int ret;
+
+	/* associate the bridge to dsi encoder */
+	encoder->bridge = bridge;
+	bridge->encoder = encoder;
+
+	ret = drm_bridge_attach(dev, bridge);
+	if (ret) {
+		DRM_ERROR("failed to attach exteranl bridge\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int dsi_bind(struct device *dev, struct device *master, void *data)
 {
 	struct dsi_data *ddata = dev_get_drvdata(dev);
@@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
 	if (ret)
 		return ret;
 
+	ret = dsi_bridge_init(drm_dev, dsi);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
@@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
 static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
 {
 	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *endpoint, *bridge_node;
+	struct drm_bridge *bridge;
 	struct resource *res;
 
+	/*
+	 * Get the endpoint node. In our case, dsi has one output port
+	 * to which the external HDMI bridge is connected.
+	 */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		DRM_ERROR("no valid endpoint node\n");
+		return -ENODEV;
+	}
+	of_node_put(endpoint);
+
+	bridge_node = of_graph_get_remote_port_parent(endpoint);
+	if (!bridge_node) {
+		DRM_ERROR("no valid bridge node\n");
+		return -ENODEV;
+	}
+	of_node_put(bridge_node);
+
+	bridge = of_drm_find_bridge(bridge_node);
+	if (!bridge) {
+		DRM_INFO("wait for external HDMI bridge driver.\n");
+		return -EPROBE_DEFER;
+	}
+	dsi->bridge = bridge;
 
 	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
 	if (IS_ERR(ctx->dsi_cfg_clk)) {
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
@ 2015-11-28 10:39     ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-11-28 10:39 UTC (permalink / raw)
  To: linux-arm-kernel

Add support for external HDMI bridge.

Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Signed-off-by: Andy Green <andy.green@linaro.org>
---
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51 ++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index 066e08d..9e056db 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -78,6 +78,7 @@ struct dsi_hw_ctx {
 
 struct hisi_dsi {
 	struct drm_encoder encoder;
+	struct drm_bridge *bridge;
 	struct mipi_dsi_host host;
 	struct drm_display_mode cur_mode;
 	struct dsi_hw_ctx *ctx;
@@ -671,6 +672,25 @@ 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)
+{
+	struct drm_encoder *encoder = &dsi->encoder;
+	struct drm_bridge *bridge = dsi->bridge;
+	int ret;
+
+	/* associate the bridge to dsi encoder */
+	encoder->bridge = bridge;
+	bridge->encoder = encoder;
+
+	ret = drm_bridge_attach(dev, bridge);
+	if (ret) {
+		DRM_ERROR("failed to attach exteranl bridge\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static int dsi_bind(struct device *dev, struct device *master, void *data)
 {
 	struct dsi_data *ddata = dev_get_drvdata(dev);
@@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
 	if (ret)
 		return ret;
 
+	ret = dsi_bridge_init(drm_dev, dsi);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
@@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
 static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
 {
 	struct dsi_hw_ctx *ctx = dsi->ctx;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *endpoint, *bridge_node;
+	struct drm_bridge *bridge;
 	struct resource *res;
 
+	/*
+	 * Get the endpoint node. In our case, dsi has one output port
+	 * to which the external HDMI bridge is connected.
+	 */
+	endpoint = of_graph_get_next_endpoint(np, NULL);
+	if (!endpoint) {
+		DRM_ERROR("no valid endpoint node\n");
+		return -ENODEV;
+	}
+	of_node_put(endpoint);
+
+	bridge_node = of_graph_get_remote_port_parent(endpoint);
+	if (!bridge_node) {
+		DRM_ERROR("no valid bridge node\n");
+		return -ENODEV;
+	}
+	of_node_put(bridge_node);
+
+	bridge = of_drm_find_bridge(bridge_node);
+	if (!bridge) {
+		DRM_INFO("wait for external HDMI bridge driver.\n");
+		return -EPROBE_DEFER;
+	}
+	dsi->bridge = bridge;
 
 	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
 	if (IS_ERR(ctx->dsi_cfg_clk)) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 04/10] drm/hisilicon: Add crtc funcs for ADE
  2015-11-28 10:38   ` Xinliang Liu
@ 2015-11-28 15:56       ` Emil Velikov
  -1 siblings, 0 replies; 70+ messages in thread
From: Emil Velikov @ 2015-11-28 15:56 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: ML dri-devel, devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Vetter,
	robh-DgEjT+Ai2ygdnm+yROfE0A, Daniel Stone,
	architt-sgV2jX0FEOL9JmXXK+q4OQ, David Airlie, corbet-T1hC0tSOHrs,
	Catalin Marinas, Will Deacon, andy.green-QSEj5FYQhm4dnm+yROfE0A,
	xuyiping-C8/M+/jPZTeaMJb+Lgu22Q,
	linux-doc-u79uwXL29TY76Z2rM5mHXA, w.f-hv44wF8Li93QT0dZR+AlfA,
	zourongrong-hv44wF8Li93QT0dZR+AlfA,
	linuxarm-hv44wF8Li93QT0dZR+AlfA, xuwei5-C8/M+/jPZTeaMJb+Lgu22Q,
	bintian.wang-hv44wF8Li93QT0dZR+AlfA,
	haojian.zhuang-QSEj5FYQhm4dnm+yROfE0A, Benjamin Gaignard,
	puck.chen-C8/M+/jPZTeaMJb+Lgu22Q,
	lijianhua-hv44wF8Li93QT0dZR+AlfA,
	liguozhu-C8/M+/jPZTeaMJb+Lgu22Q, LAKML

use_maskOn 28 November 2015 at 10:38, Xinliang Liu
<xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> Add crtc funcs and helper funcs for ADE.
>
> Signed-off-by: Xinliang Liu <xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>
> Signed-off-by: Andy Green <andy.green-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---

> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h

> +#define ADE_CTRL                       (0x4)
> +#define ADE_CTRL1                      (0x8C)
> +#define ADE_ROT_SRC_CFG                        (0x10)
> +#define ADE_DISP_SRC_CFG               (0x18)
> +#define ADE_WDMA2_SRC_CFG              (0x1C)
> +#define ADE_SEC_OVLY_SRC_CFG           (0x20)
> +#define ADE_WDMA3_SRC_CFG              (0x24)
> +#define ADE_OVLY1_TRANS_CFG            (0x2C)
> +#define ADE_EN                         (0x100)
> +#define INTR_MASK_CPU_0                        (0xC10)
> +#define INTR_MASK_CPU_1                        (0xC14)
> +#define ADE_FRM_DISGARD_CTRL           (0xA4)
> +/* reset and reload regs */
> +#define ADE_SOFT_RST_SEL0              (0x78)
> +#define ADE_SOFT_RST_SEL1              (0x7C)
> +#define ADE_RELOAD_DIS0                        (0xAC)
> +#define ADE_RELOAD_DIS1                        (0xB0)
> +#define ADE_CH_RDMA_BIT_OFST           (0)
> +#define ADE_CLIP_BIT_OFST              (15)
> +#define ADE_SCL_BIT_OFST               (21)
> +#define ADE_CTRAN_BIT_OFST             (24)
> +#define ADE_OVLY_BIT_OFST              (37) /* 32+5 */
Don't think we have any cases in drm where constants are wrapped in
brackets. Is there any benefit of doing that here ?

> +/* channel regs */
> +#define RD_CH_PE(x)                    (0x1000 + (x) * 0x80)
... and I'm not talking about cases where the macros such as this one.

> +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;
> +};
> +
The struct in the above two unions is missing a level of indentation.


> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c

> +static void ade_ldi_set_mode(struct ade_crtc *acrtc,
> +                            struct drm_display_mode *mode,
> +                            struct drm_display_mode *adj_mode)
> +{
> +       struct ade_hw_ctx *ctx = acrtc->ctx;
> +       void __iomem *base = ctx->base;
> +       u32 out_w = mode->hdisplay;
> +       u32 out_h = mode->vdisplay;
> +       u32 hfp, hbp, hsw, vfp, vbp, vsw;
> +       u32 plr_flags;
> +       int ret;
> +
> +       plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
> +                       ? HISI_LDI_FLAG_NVSYNC : 0;
> +       plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
> +                       ? HISI_LDI_FLAG_NHSYNC : 0;
> +       hfp = mode->hsync_start - mode->hdisplay;
> +       hbp = mode->htotal - mode->hsync_end;
> +       hsw = mode->hsync_end - mode->hsync_start;
> +       vfp = mode->vsync_start - mode->vdisplay;
> +       vbp = mode->vtotal - mode->vsync_end;
> +       vsw = mode->vsync_end - mode->vsync_start;
> +       if (vsw > 15) {
> +               DRM_INFO("vsw exceeded 15\n");

DRM_ERROR or DRM_DEBUG_xx perhaps ?

> +               vsw = 15;
> +       }
> +
> +       writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
> +       /* p3-73 6220V100 pdf:
> +        *  "The configured value is the actual width - 1"
> +        */
> +       writel(hsw - 1, base + LDI_HRZ_CTRL1);
> +       writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
> +       /* p3-74 6220V100 pdf:
> +        *  "The configured value is the actual width - 1"
> +        */
> +       writel(vsw - 1, base + LDI_VRT_CTRL1);
> +
> +       /* p3-75 6220V100 pdf:
> +        *  "The configured value is the actual width - 1"
> +        */
> +       writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
> +              base + LDI_DSP_SIZE);
> +       writel(plr_flags, base + LDI_PLR_CTRL);
> +
> +       ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
> +       /* Success should be guaranteed in aotomic_check
> +        * failer shouldn't happen here
> +        */
> +       if (ret)
> +               DRM_ERROR("set ade_pixel_clk_rate fail\n");
DItto

> +       adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
> +
> +       /* ctran6 setting */
> +       writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
> +       writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
> +       acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
> +       DRM_INFO("set mode: %dx%d\n", out_w, out_h);
> +
DRM_DEBUG_DRIVER ?

> +       /*
> +        * other parameters setting
> +        */
> +       writel(BIT(0), base + LDI_WORK_MODE);
> +       writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
> +              base + LDI_CTRL);
> +       set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
> +}
> +
> +static int ade_power_up(struct ade_hw_ctx *ctx)
> +{
> +       void __iomem *media_base = ctx->media_base;
> +       int ret;
> +
> +       ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
> +       if (ret) {
> +               DRM_ERROR("clk_set_rate ade_core_rate error\n");
How about the following (or alike) less cryptic and more informative
message. Other places could use a similar treatment.

"Failed to set rate X clk (%d)\n", ret ?


> +static void ade_crtc_enable(struct drm_crtc *crtc)
> +{
> +       struct ade_crtc *acrtc = to_ade_crtc(crtc);
> +       struct ade_hw_ctx *ctx = acrtc->ctx;
> +       int ret;
> +
> +       DRM_DEBUG_DRIVER("enter.\n");
Does this and the remaining DEBUG_DRIVER(enter|exit) messages provide
any meaningful input, past the driver development stage ?

> +       if (acrtc->enable)
> +               return;
Esp. since we have cases like this where no message is available.

Regards,
Emil
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 04/10] drm/hisilicon: Add crtc funcs for ADE
@ 2015-11-28 15:56       ` Emil Velikov
  0 siblings, 0 replies; 70+ messages in thread
From: Emil Velikov @ 2015-11-28 15:56 UTC (permalink / raw)
  To: linux-arm-kernel

use_maskOn 28 November 2015 at 10:38, Xinliang Liu
<xinliang.liu@linaro.org> wrote:
> Add crtc funcs and helper funcs for ADE.
>
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---

> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h

> +#define ADE_CTRL                       (0x4)
> +#define ADE_CTRL1                      (0x8C)
> +#define ADE_ROT_SRC_CFG                        (0x10)
> +#define ADE_DISP_SRC_CFG               (0x18)
> +#define ADE_WDMA2_SRC_CFG              (0x1C)
> +#define ADE_SEC_OVLY_SRC_CFG           (0x20)
> +#define ADE_WDMA3_SRC_CFG              (0x24)
> +#define ADE_OVLY1_TRANS_CFG            (0x2C)
> +#define ADE_EN                         (0x100)
> +#define INTR_MASK_CPU_0                        (0xC10)
> +#define INTR_MASK_CPU_1                        (0xC14)
> +#define ADE_FRM_DISGARD_CTRL           (0xA4)
> +/* reset and reload regs */
> +#define ADE_SOFT_RST_SEL0              (0x78)
> +#define ADE_SOFT_RST_SEL1              (0x7C)
> +#define ADE_RELOAD_DIS0                        (0xAC)
> +#define ADE_RELOAD_DIS1                        (0xB0)
> +#define ADE_CH_RDMA_BIT_OFST           (0)
> +#define ADE_CLIP_BIT_OFST              (15)
> +#define ADE_SCL_BIT_OFST               (21)
> +#define ADE_CTRAN_BIT_OFST             (24)
> +#define ADE_OVLY_BIT_OFST              (37) /* 32+5 */
Don't think we have any cases in drm where constants are wrapped in
brackets. Is there any benefit of doing that here ?

> +/* channel regs */
> +#define RD_CH_PE(x)                    (0x1000 + (x) * 0x80)
... and I'm not talking about cases where the macros such as this one.

> +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;
> +};
> +
The struct in the above two unions is missing a level of indentation.


> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c

> +static void ade_ldi_set_mode(struct ade_crtc *acrtc,
> +                            struct drm_display_mode *mode,
> +                            struct drm_display_mode *adj_mode)
> +{
> +       struct ade_hw_ctx *ctx = acrtc->ctx;
> +       void __iomem *base = ctx->base;
> +       u32 out_w = mode->hdisplay;
> +       u32 out_h = mode->vdisplay;
> +       u32 hfp, hbp, hsw, vfp, vbp, vsw;
> +       u32 plr_flags;
> +       int ret;
> +
> +       plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
> +                       ? HISI_LDI_FLAG_NVSYNC : 0;
> +       plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
> +                       ? HISI_LDI_FLAG_NHSYNC : 0;
> +       hfp = mode->hsync_start - mode->hdisplay;
> +       hbp = mode->htotal - mode->hsync_end;
> +       hsw = mode->hsync_end - mode->hsync_start;
> +       vfp = mode->vsync_start - mode->vdisplay;
> +       vbp = mode->vtotal - mode->vsync_end;
> +       vsw = mode->vsync_end - mode->vsync_start;
> +       if (vsw > 15) {
> +               DRM_INFO("vsw exceeded 15\n");

DRM_ERROR or DRM_DEBUG_xx perhaps ?

> +               vsw = 15;
> +       }
> +
> +       writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
> +       /* p3-73 6220V100 pdf:
> +        *  "The configured value is the actual width - 1"
> +        */
> +       writel(hsw - 1, base + LDI_HRZ_CTRL1);
> +       writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
> +       /* p3-74 6220V100 pdf:
> +        *  "The configured value is the actual width - 1"
> +        */
> +       writel(vsw - 1, base + LDI_VRT_CTRL1);
> +
> +       /* p3-75 6220V100 pdf:
> +        *  "The configured value is the actual width - 1"
> +        */
> +       writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
> +              base + LDI_DSP_SIZE);
> +       writel(plr_flags, base + LDI_PLR_CTRL);
> +
> +       ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
> +       /* Success should be guaranteed in aotomic_check
> +        * failer shouldn't happen here
> +        */
> +       if (ret)
> +               DRM_ERROR("set ade_pixel_clk_rate fail\n");
DItto

> +       adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
> +
> +       /* ctran6 setting */
> +       writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
> +       writel(out_w * out_h - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
> +       acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
> +       DRM_INFO("set mode: %dx%d\n", out_w, out_h);
> +
DRM_DEBUG_DRIVER ?

> +       /*
> +        * other parameters setting
> +        */
> +       writel(BIT(0), base + LDI_WORK_MODE);
> +       writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
> +              base + LDI_CTRL);
> +       set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
> +}
> +
> +static int ade_power_up(struct ade_hw_ctx *ctx)
> +{
> +       void __iomem *media_base = ctx->media_base;
> +       int ret;
> +
> +       ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
> +       if (ret) {
> +               DRM_ERROR("clk_set_rate ade_core_rate error\n");
How about the following (or alike) less cryptic and more informative
message. Other places could use a similar treatment.

"Failed to set rate X clk (%d)\n", ret ?


> +static void ade_crtc_enable(struct drm_crtc *crtc)
> +{
> +       struct ade_crtc *acrtc = to_ade_crtc(crtc);
> +       struct ade_hw_ctx *ctx = acrtc->ctx;
> +       int ret;
> +
> +       DRM_DEBUG_DRIVER("enter.\n");
Does this and the remaining DEBUG_DRIVER(enter|exit) messages provide
any meaningful input, past the driver development stage ?

> +       if (acrtc->enable)
> +               return;
Esp. since we have cases like this where no message is available.

Regards,
Emil

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 06/10] drm/hisilicon: Add vblank feature
  2015-11-28 10:39   ` Xinliang Liu
@ 2015-11-30  7:54     ` Daniel Vetter
  -1 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-11-30  7:54 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: linux-doc, catalin.marinas, will.deacon, linuxarm, dri-devel,
	xuwei5, benjamin.gaignard, zourongrong, xuyiping, corbet, w.f,
	lijianhua, devicetree, bintian.wang, puck.chen, linux-arm-kernel,
	andy.green, liguozhu, haojian.zhuang

On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
> Add vblank handle for ADE.
> 
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---
>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
>  3 files changed, 112 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> 
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> index b0976c3..acb11e7 100644
> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
>  	ctx->power_on = false;
>  }
>  
> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
> +						 unsigned int index)

Ugly that you had to add this, but unfortunately necessary :( Fixing up
the drm vblank hooks so that they deal with struct drm_crtc directly is
somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
ways off still.

What might be possible as a follow-up cleanup though is to add
vblank_enable and vblank_disable functions to struct
drm_crtc_helper_funcs. And then provide this code here to map from int
index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
That might be a good intermediate step.

But nothing that needs to be done before merging hisilicon, that's for
sure.

One more comment below.

> +{
> +	unsigned int index_tmp = 0;
> +	struct drm_crtc *crtc;
> +
> +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> +		if (index_tmp == index)
> +			return crtc;
> +
> +		index_tmp++;
> +	}
> +
> +	WARN_ON(true);
> +}
> +
> +int ade_enable_vblank(struct drm_device *dev, int crtc_index)
> +{
> +	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
> +	struct ade_crtc *acrtc = to_ade_crtc(crtc);
> +	struct ade_hw_ctx *ctx = acrtc->ctx;
> +	void __iomem *base = ctx->base;
> +	u32 intr_en;
> +
> +	DRM_INFO("enable_vblank enter.\n");
> +	if (!ctx->power_on)
> +		(void)ade_power_up(ctx);
> +
> +	intr_en = readl(base + LDI_INT_EN);
> +	intr_en |= LDI_ISR_FRAME_END_INT;
> +	writel(intr_en, base + LDI_INT_EN);
>  
> +	return 0;
> +}
> +
> +void ade_disable_vblank(struct drm_device *dev, int crtc_index)
> +{
> +	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
> +	struct ade_crtc *acrtc = to_ade_crtc(crtc);
> +	struct ade_hw_ctx *ctx = acrtc->ctx;
> +	void __iomem *base = ctx->base;
> +	u32 intr_en;
> +
> +	DRM_INFO("disable_vblank enter.\n");
> +	if (!ctx->power_on) {
> +		DRM_ERROR("power is down! vblank disable fail\n");
> +		return;
> +	}
> +	intr_en = readl(base + LDI_INT_EN);
> +	intr_en &= ~LDI_ISR_FRAME_END_INT;
> +	writel(intr_en, base + LDI_INT_EN);
> +}
> +
> +static irqreturn_t ade_irq_handler(int irq, void *data)
> +{
> +	struct ade_crtc *acrtc = data;
> +	struct ade_hw_ctx *ctx = acrtc->ctx;
> +	struct drm_crtc *crtc = &acrtc->base;
> +	struct drm_device *dev = crtc->dev;
> +	void __iomem *base = ctx->base;
> +	u32 status;
> +
> +	status = readl(base + LDI_MSK_INT);
> +	/* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
> +
> +	/* vblank irq */
> +	if (status & LDI_ISR_FRAME_END_INT) {
> +		writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
> +		drm_handle_vblank(dev, drm_crtc_index(crtc));

drm_crtc_handle_vblank please. At least when calling into the vblank code
drivers don't have to do the struct drm_crtc -> int index conversion any
more. Please make sure you do that everywhere, in case I've missed one.

Cheers, Daniel

> +	}
> +
> +	return IRQ_HANDLED;
> +}
>  
>  /*
>   * set modules' reset mode: by software or hardware
> @@ -858,6 +930,12 @@ static int ade_bind(struct device *dev, struct device *master, void *data)
>  	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;
>  }
>  
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> new file mode 100644
> index 0000000..d1d7b5d
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> @@ -0,0 +1,16 @@
> +/*
> + * Copyright (c) 2014-2015 Hisilicon Limited.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __HISI_DRM_ADE_H__
> +#define __HISI_DRM_ADE_H__
> +
> +int ade_enable_vblank(struct drm_device *dev, int crtc_index);
> +void ade_disable_vblank(struct drm_device *dev, int crtc_index);
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> index d0eca80..13f59aa 100644
> --- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> @@ -21,6 +21,7 @@
>  #include <drm/drm_fb_cma_helper.h>
>  #include <drm/drm_atomic_helper.h>
>  
> +#include "hisi_drm_ade.h"
>  #include "hisi_drm_drv.h"
>  
>  #define DRIVER_NAME	"hisi-drm"
> @@ -29,6 +30,7 @@ static int hisi_drm_unload(struct drm_device *dev)
>  {
>  	struct hisi_drm_private *priv = dev->dev_private;
>  
> +	drm_vblank_cleanup(dev);
>  	drm_mode_config_cleanup(dev);
>  	devm_kfree(dev->dev, priv);
>  	dev->dev_private = NULL;
> @@ -76,11 +78,22 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
>  		goto err_mode_config_cleanup;
>  	}
>  
> +	/* vblank init */
> +	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +	if (ret) {
> +		DRM_ERROR("failed to initialize vblank.\n");
> +		goto err_unbind_all;
> +	}
> +	/* with irq_enabled = true, we can use the vblank feature. */
> +	dev->irq_enabled = true;
> +
>  	/* reset all the states of crtc/plane/encoder/connector */
>  	drm_mode_config_reset(dev);
>  
>  	return 0;
>  
> +err_unbind_all:
> +	component_unbind_all(dev->dev, dev);
>  err_mode_config_cleanup:
>  	drm_mode_config_cleanup(dev);
>  	devm_kfree(dev->dev, priv);
> @@ -126,7 +139,7 @@ static int hisi_gem_cma_dumb_create(struct drm_file *file,
>  
>  static struct drm_driver hisi_drm_driver = {
>  	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
> -				  DRIVER_ATOMIC,
> +				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
>  	.load			= hisi_drm_load,
>  	.unload                 = hisi_drm_unload,
>  	.fops			= &hisi_drm_fops,
> @@ -148,6 +161,10 @@ 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",
>  	.date			= "20150718",
> -- 
> 1.9.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 06/10] drm/hisilicon: Add vblank feature
@ 2015-11-30  7:54     ` Daniel Vetter
  0 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-11-30  7:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
> Add vblank handle for ADE.
> 
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---
>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
>  3 files changed, 112 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> 
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> index b0976c3..acb11e7 100644
> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
>  	ctx->power_on = false;
>  }
>  
> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
> +						 unsigned int index)

Ugly that you had to add this, but unfortunately necessary :( Fixing up
the drm vblank hooks so that they deal with struct drm_crtc directly is
somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
ways off still.

What might be possible as a follow-up cleanup though is to add
vblank_enable and vblank_disable functions to struct
drm_crtc_helper_funcs. And then provide this code here to map from int
index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
That might be a good intermediate step.

But nothing that needs to be done before merging hisilicon, that's for
sure.

One more comment below.

> +{
> +	unsigned int index_tmp = 0;
> +	struct drm_crtc *crtc;
> +
> +	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
> +		if (index_tmp == index)
> +			return crtc;
> +
> +		index_tmp++;
> +	}
> +
> +	WARN_ON(true);
> +}
> +
> +int ade_enable_vblank(struct drm_device *dev, int crtc_index)
> +{
> +	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
> +	struct ade_crtc *acrtc = to_ade_crtc(crtc);
> +	struct ade_hw_ctx *ctx = acrtc->ctx;
> +	void __iomem *base = ctx->base;
> +	u32 intr_en;
> +
> +	DRM_INFO("enable_vblank enter.\n");
> +	if (!ctx->power_on)
> +		(void)ade_power_up(ctx);
> +
> +	intr_en = readl(base + LDI_INT_EN);
> +	intr_en |= LDI_ISR_FRAME_END_INT;
> +	writel(intr_en, base + LDI_INT_EN);
>  
> +	return 0;
> +}
> +
> +void ade_disable_vblank(struct drm_device *dev, int crtc_index)
> +{
> +	struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
> +	struct ade_crtc *acrtc = to_ade_crtc(crtc);
> +	struct ade_hw_ctx *ctx = acrtc->ctx;
> +	void __iomem *base = ctx->base;
> +	u32 intr_en;
> +
> +	DRM_INFO("disable_vblank enter.\n");
> +	if (!ctx->power_on) {
> +		DRM_ERROR("power is down! vblank disable fail\n");
> +		return;
> +	}
> +	intr_en = readl(base + LDI_INT_EN);
> +	intr_en &= ~LDI_ISR_FRAME_END_INT;
> +	writel(intr_en, base + LDI_INT_EN);
> +}
> +
> +static irqreturn_t ade_irq_handler(int irq, void *data)
> +{
> +	struct ade_crtc *acrtc = data;
> +	struct ade_hw_ctx *ctx = acrtc->ctx;
> +	struct drm_crtc *crtc = &acrtc->base;
> +	struct drm_device *dev = crtc->dev;
> +	void __iomem *base = ctx->base;
> +	u32 status;
> +
> +	status = readl(base + LDI_MSK_INT);
> +	/* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
> +
> +	/* vblank irq */
> +	if (status & LDI_ISR_FRAME_END_INT) {
> +		writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
> +		drm_handle_vblank(dev, drm_crtc_index(crtc));

drm_crtc_handle_vblank please. At least when calling into the vblank code
drivers don't have to do the struct drm_crtc -> int index conversion any
more. Please make sure you do that everywhere, in case I've missed one.

Cheers, Daniel

> +	}
> +
> +	return IRQ_HANDLED;
> +}
>  
>  /*
>   * set modules' reset mode: by software or hardware
> @@ -858,6 +930,12 @@ static int ade_bind(struct device *dev, struct device *master, void *data)
>  	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;
>  }
>  
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> new file mode 100644
> index 0000000..d1d7b5d
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> @@ -0,0 +1,16 @@
> +/*
> + * Copyright (c) 2014-2015 Hisilicon Limited.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __HISI_DRM_ADE_H__
> +#define __HISI_DRM_ADE_H__
> +
> +int ade_enable_vblank(struct drm_device *dev, int crtc_index);
> +void ade_disable_vblank(struct drm_device *dev, int crtc_index);
> +
> +#endif
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> index d0eca80..13f59aa 100644
> --- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> @@ -21,6 +21,7 @@
>  #include <drm/drm_fb_cma_helper.h>
>  #include <drm/drm_atomic_helper.h>
>  
> +#include "hisi_drm_ade.h"
>  #include "hisi_drm_drv.h"
>  
>  #define DRIVER_NAME	"hisi-drm"
> @@ -29,6 +30,7 @@ static int hisi_drm_unload(struct drm_device *dev)
>  {
>  	struct hisi_drm_private *priv = dev->dev_private;
>  
> +	drm_vblank_cleanup(dev);
>  	drm_mode_config_cleanup(dev);
>  	devm_kfree(dev->dev, priv);
>  	dev->dev_private = NULL;
> @@ -76,11 +78,22 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
>  		goto err_mode_config_cleanup;
>  	}
>  
> +	/* vblank init */
> +	ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
> +	if (ret) {
> +		DRM_ERROR("failed to initialize vblank.\n");
> +		goto err_unbind_all;
> +	}
> +	/* with irq_enabled = true, we can use the vblank feature. */
> +	dev->irq_enabled = true;
> +
>  	/* reset all the states of crtc/plane/encoder/connector */
>  	drm_mode_config_reset(dev);
>  
>  	return 0;
>  
> +err_unbind_all:
> +	component_unbind_all(dev->dev, dev);
>  err_mode_config_cleanup:
>  	drm_mode_config_cleanup(dev);
>  	devm_kfree(dev->dev, priv);
> @@ -126,7 +139,7 @@ static int hisi_gem_cma_dumb_create(struct drm_file *file,
>  
>  static struct drm_driver hisi_drm_driver = {
>  	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
> -				  DRIVER_ATOMIC,
> +				  DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
>  	.load			= hisi_drm_load,
>  	.unload                 = hisi_drm_unload,
>  	.fops			= &hisi_drm_fops,
> @@ -148,6 +161,10 @@ 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",
>  	.date			= "20150718",
> -- 
> 1.9.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem
  2015-11-28 10:38   ` Xinliang Liu
@ 2015-11-30 19:31     ` Rob Herring
  -1 siblings, 0 replies; 70+ messages in thread
From: Rob Herring @ 2015-11-30 19:31 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: linux-doc, catalin.marinas, will.deacon, linuxarm, dri-devel,
	xuwei5, benjamin.gaignard, zourongrong, xuyiping, corbet, w.f,
	lijianhua, devicetree, bintian.wang, puck.chen, linux-arm-kernel,
	andy.green, liguozhu, haojian.zhuang

On Sat, Nov 28, 2015 at 06:38:57PM +0800, Xinliang Liu wrote:
> Add the device tree binding documentation for hi6220 SoC display subsystem.
> drm master device binding doc.
> ADE display controller binding doc.
> DSI controller binding doc.
> 
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---
>  .../bindings/display/hisilicon/hisi-ade.txt        | 42 ++++++++++++++
>  .../bindings/display/hisilicon/hisi-drm.txt        | 66 ++++++++++++++++++++++
>  .../bindings/display/hisilicon/hisi-dsi.txt        | 53 +++++++++++++++++
>  3 files changed, 161 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
> 
> diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
> new file mode 100644
> index 0000000..2777a2c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
> @@ -0,0 +1,42 @@
> +Device-Tree bindings for hisilicon ADE display controller driver
> +
> +ADE (Advanced Display Engine) is the display controller which grab image
> +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.

I think you can use assigned clock properties instead:

assigned-clocks = <&media_ctrl HI6220_ADE_CORE>;
assigned-clock-rates = <360000000>;

I'm not sure about what media_noc corresponds to in clocks list though.

> +
> +
> +A example of HiKey board hi6220 SoC specific DT entry:
> +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>;
> +
> +		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-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>;
> +	};
> diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
> new file mode 100644
> index 0000000..fd93026
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
> @@ -0,0 +1,66 @@
> +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.

There is no need for this in DT. The ADE can be the master device and 
of-graph can link to the DSI node. I have a similar example here[1] 
with a LCD controller block, DSI block and adv7533.

> +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.

Put this on the actually DMA master.

Rob

[1] https://git.linaro.org/people/rob.herring/linux.git pxa1928-drm-v2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem
@ 2015-11-30 19:31     ` Rob Herring
  0 siblings, 0 replies; 70+ messages in thread
From: Rob Herring @ 2015-11-30 19:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Nov 28, 2015 at 06:38:57PM +0800, Xinliang Liu wrote:
> Add the device tree binding documentation for hi6220 SoC display subsystem.
> drm master device binding doc.
> ADE display controller binding doc.
> DSI controller binding doc.
> 
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---
>  .../bindings/display/hisilicon/hisi-ade.txt        | 42 ++++++++++++++
>  .../bindings/display/hisilicon/hisi-drm.txt        | 66 ++++++++++++++++++++++
>  .../bindings/display/hisilicon/hisi-dsi.txt        | 53 +++++++++++++++++
>  3 files changed, 161 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
> 
> diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
> new file mode 100644
> index 0000000..2777a2c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
> @@ -0,0 +1,42 @@
> +Device-Tree bindings for hisilicon ADE display controller driver
> +
> +ADE (Advanced Display Engine) is the display controller which grab image
> +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.

I think you can use assigned clock properties instead:

assigned-clocks = <&media_ctrl HI6220_ADE_CORE>;
assigned-clock-rates = <360000000>;

I'm not sure about what media_noc corresponds to in clocks list though.

> +
> +
> +A example of HiKey board hi6220 SoC specific DT entry:
> +Example:
> +
> +	ade: ade at f4100000 {
> +		compatible = "hisilicon,hi6220-ade";
> +		reg = <0x0 0xf4100000 0x0 0x7800>,
> +		      <0x0 0xf4410000 0x0 0x1000>;
> +		reg-names = "ade_base",
> +			    "media_base";
> +		interrupts = <0 115 4>;
> +
> +		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-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>;
> +	};
> diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
> new file mode 100644
> index 0000000..fd93026
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
> @@ -0,0 +1,66 @@
> +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.

There is no need for this in DT. The ADE can be the master device and 
of-graph can link to the DSI node. I have a similar example here[1] 
with a LCD controller block, DSI block and adv7533.

> +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.

Put this on the actually DMA master.

Rob

[1] https://git.linaro.org/people/rob.herring/linux.git pxa1928-drm-v2

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 04/10] drm/hisilicon: Add crtc funcs for ADE
  2015-11-28 15:56       ` Emil Velikov
  (?)
@ 2015-12-01  2:52       ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01  2:52 UTC (permalink / raw)
  To: Emil Velikov
  Cc: linux-doc, Catalin Marinas, Will Deacon, linuxarm, ML dri-devel,
	Xu Wei, Benjamin Gaignard, zourongrong, Yiping Xu, Jon Corbet,
	Wang Fei, lijianhua, devicetree, Bintian Wang, Feng Chen, LAKML,
	Andy Green, Liguozhu (Kenneth),
	Haojian Zhuang


[-- Attachment #1.1: Type: text/plain, Size: 7928 bytes --]

On 28 November 2015 at 23:56, Emil Velikov <emil.l.velikov@gmail.com> wrote:
​Hi Emil, thank you for review.​

use_maskOn 28 November 2015 at 10:38, Xinliang Liu
> <xinliang.liu@linaro.org> wrote:
> > Add crtc funcs and helper funcs for ADE.
> >
> > Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> > Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> > Signed-off-by: Andy Green <andy.green@linaro.org>
> > ---
>
> > --- /dev/null
> > +++ b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
>
> > +#define ADE_CTRL                       (0x4)
> > +#define ADE_CTRL1                      (0x8C)
> > +#define ADE_ROT_SRC_CFG                        (0x10)
> > +#define ADE_DISP_SRC_CFG               (0x18)
> > +#define ADE_WDMA2_SRC_CFG              (0x1C)
> > +#define ADE_SEC_OVLY_SRC_CFG           (0x20)
> > +#define ADE_WDMA3_SRC_CFG              (0x24)
> > +#define ADE_OVLY1_TRANS_CFG            (0x2C)
> > +#define ADE_EN                         (0x100)
> > +#define INTR_MASK_CPU_0                        (0xC10)
> > +#define INTR_MASK_CPU_1                        (0xC14)
> > +#define ADE_FRM_DISGARD_CTRL           (0xA4)
> > +/* reset and reload regs */
> > +#define ADE_SOFT_RST_SEL0              (0x78)
> > +#define ADE_SOFT_RST_SEL1              (0x7C)
> > +#define ADE_RELOAD_DIS0                        (0xAC)
> > +#define ADE_RELOAD_DIS1                        (0xB0)
> > +#define ADE_CH_RDMA_BIT_OFST           (0)
> > +#define ADE_CLIP_BIT_OFST              (15)
> > +#define ADE_SCL_BIT_OFST               (21)
> > +#define ADE_CTRAN_BIT_OFST             (24)
> > +#define ADE_OVLY_BIT_OFST              (37) /* 32+5 */
> Don't think we have any cases in drm where constants are wrapped in
> brackets. Is there any benefit of doing that here ?
>
Seems no any benefit​, will remove these brackets in v3.


>
> > +/* channel regs */
> > +#define RD_CH_PE(x)                    (0x1000 + (x) * 0x80)
> ... and I'm not talking about cases where the macros such as this one.


> > +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;
> > +};
> > +
> The struct in the above two unions is missing a level of indentation.
>
​yes, will be fixed in v3.​


>
>
> > --- /dev/null
> > +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>
> > +static void ade_ldi_set_mode(struct ade_crtc *acrtc,
> > +                            struct drm_display_mode *mode,
> > +                            struct drm_display_mode *adj_mode)
> > +{
> > +       struct ade_hw_ctx *ctx = acrtc->ctx;
> > +       void __iomem *base = ctx->base;
> > +       u32 out_w = mode->hdisplay;
> > +       u32 out_h = mode->vdisplay;
> > +       u32 hfp, hbp, hsw, vfp, vbp, vsw;
> > +       u32 plr_flags;
> > +       int ret;
> > +
> > +       plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC)
> > +                       ? HISI_LDI_FLAG_NVSYNC : 0;
> > +       plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC)
> > +                       ? HISI_LDI_FLAG_NHSYNC : 0;
> > +       hfp = mode->hsync_start - mode->hdisplay;
> > +       hbp = mode->htotal - mode->hsync_end;
> > +       hsw = mode->hsync_end - mode->hsync_start;
> > +       vfp = mode->vsync_start - mode->vdisplay;
> > +       vbp = mode->vtotal - mode->vsync_end;
> > +       vsw = mode->vsync_end - mode->vsync_start;
> > +       if (vsw > 15) {
> > +               DRM_INFO("vsw exceeded 15\n");
>
> DRM_ERROR or DRM_DEBUG_xx perhaps ?
>
This is not an error hardware still can handle if vsw exceed 15.
You are right maybe ​
​
DRM_DEBUG_DRIVER is better.
​

>
> > +               vsw = 15;
> > +       }
> > +
> > +       writel((hbp << 20) | (hfp << 0), base + LDI_HRZ_CTRL0);
> > +       /* p3-73 6220V100 pdf:
> > +        *  "The configured value is the actual width - 1"
> > +        */
> > +       writel(hsw - 1, base + LDI_HRZ_CTRL1);
> > +       writel((vbp << 20) | (vfp << 0), base + LDI_VRT_CTRL0);
> > +       /* p3-74 6220V100 pdf:
> > +        *  "The configured value is the actual width - 1"
> > +        */
> > +       writel(vsw - 1, base + LDI_VRT_CTRL1);
> > +
> > +       /* p3-75 6220V100 pdf:
> > +        *  "The configured value is the actual width - 1"
> > +        */
> > +       writel(((out_h - 1) << 20) | ((out_w - 1) << 0),
> > +              base + LDI_DSP_SIZE);
> > +       writel(plr_flags, base + LDI_PLR_CTRL);
> > +
> > +       ret = clk_set_rate(ctx->ade_pix_clk, mode->clock * 1000);
> > +       /* Success should be guaranteed in aotomic_check
> > +        * failer shouldn't happen here
> > +        */
> > +       if (ret)
> > +               DRM_ERROR("set ade_pixel_clk_rate fail\n");
> DItto
>
​will use
​
DRM_DEBUG_DRIVER
​ in v3.​
​


>
> > +       adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
> > +
> > +       /* ctran6 setting */
> > +       writel(1, base + ADE_CTRAN_DIS(ADE_CTRAN6));
> > +       writel(out_w * out_h - 1, base +
> ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
> > +       acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + ADE_CTRAN6);
> > +       DRM_INFO("set mode: %dx%d\n", out_w, out_h);
> > +
> ​​
> ​​
> DRM_DEBUG_DRIVER ?
>
​
will use
​
DRM_DEBUG_DRIVER
​ in v3.
​


>
> > +       /*
> > +        * other parameters setting
> > +        */
> > +       writel(BIT(0), base + LDI_WORK_MODE);
> > +       writel((0x3c << 6) | (ADE_OUT_RGB_888 << 3) | BIT(2) | BIT(0),
> > +              base + LDI_CTRL);
> > +       set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
> > +}
> > +
> > +static int ade_power_up(struct ade_hw_ctx *ctx)
> > +{
> > +       void __iomem *media_base = ctx->media_base;
> > +       int ret;
> > +
> > +       ret = clk_set_rate(ctx->ade_core_clk, ctx->ade_core_rate);
> > +       if (ret) {
> > +               DRM_ERROR("clk_set_rate ade_core_rate error\n");
> How about the following (or alike) less cryptic and more informative
> message. Other places could use a similar treatment.
>
> "Failed to set rate X clk (%d)\n", ret ?
>
​yes, good advice. will be fixed in v3.
​


>
>
> > +static void ade_crtc_enable(struct drm_crtc *crtc)
> > +{
> > +       struct ade_crtc *acrtc = to_ade_crtc(crtc);
> > +       struct ade_hw_ctx *ctx = acrtc->ctx;
> > +       int ret;
> > +
> > +       DRM_DEBUG_DRIVER("enter.\n");
> Does this and the remaining
> ​​
> DEBUG_DRIVER(enter|exit) messages provide
> any meaningful input, past the driver
> ​​
> development stage ?
>
> > +       if (acrtc->enable)
> > +               return;
> Esp. since we have cases like this where no message is available.
>
yeap, these
​
 DEBUG_DRIVER(enter|exit) messages​ are for
​
development stage.
Which forgot to be removed. will be removed in v3.

Thanks,
-xinliang


>
> Regards,
> Emil
>

[-- Attachment #1.2: Type: text/html, Size: 14968 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 06/10] drm/hisilicon: Add vblank feature
  2015-11-30  7:54     ` Daniel Vetter
@ 2015-12-01  3:16       ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01  3:16 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: linux-doc, Catalin Marinas, Will Deacon, linuxarm, dri-devel,
	Xu Wei, Benjamin Gaignard, zourongrong, Yiping Xu, Jon Corbet,
	Wang Fei, lijianhua, devicetree, Bintian Wang, Feng Chen, LAKML,
	Andy Green, Liguozhu (Kenneth),
	Haojian Zhuang

On 30 November 2015 at 15:54, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
>> Add vblank handle for ADE.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
>>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
>>  3 files changed, 112 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> index b0976c3..acb11e7 100644
>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
>>       ctx->power_on = false;
>>  }
>>
>> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
>> +                                              unsigned int index)
>
> Ugly that you had to add this, but unfortunately necessary :( Fixing up
> the drm vblank hooks so that they deal with struct drm_crtc directly is
> somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
> ways off still.
>
> What might be possible as a follow-up cleanup though is to add
> vblank_enable and vblank_disable functions to struct
> drm_crtc_helper_funcs. And then provide this code here to map from int
> index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
> That might be a good intermediate step.

I would like to have a try to make this intermediate step patch and
send out for review soon.

> But nothing that needs to be done before merging hisilicon, that's for
> sure.
>
> One more comment below.
>
>> +{
>> +     unsigned int index_tmp = 0;
>> +     struct drm_crtc *crtc;
>> +
>> +     list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> +             if (index_tmp == index)
>> +                     return crtc;
>> +
>> +             index_tmp++;
>> +     }
>> +
>> +     WARN_ON(true);
>> +}
>> +
>> +int ade_enable_vblank(struct drm_device *dev, int crtc_index)
>> +{
>> +     struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
>> +     struct ade_crtc *acrtc = to_ade_crtc(crtc);
>> +     struct ade_hw_ctx *ctx = acrtc->ctx;
>> +     void __iomem *base = ctx->base;
>> +     u32 intr_en;
>> +
>> +     DRM_INFO("enable_vblank enter.\n");
>> +     if (!ctx->power_on)
>> +             (void)ade_power_up(ctx);
>> +
>> +     intr_en = readl(base + LDI_INT_EN);
>> +     intr_en |= LDI_ISR_FRAME_END_INT;
>> +     writel(intr_en, base + LDI_INT_EN);
>>
>> +     return 0;
>> +}
>> +
>> +void ade_disable_vblank(struct drm_device *dev, int crtc_index)
>> +{
>> +     struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
>> +     struct ade_crtc *acrtc = to_ade_crtc(crtc);
>> +     struct ade_hw_ctx *ctx = acrtc->ctx;
>> +     void __iomem *base = ctx->base;
>> +     u32 intr_en;
>> +
>> +     DRM_INFO("disable_vblank enter.\n");
>> +     if (!ctx->power_on) {
>> +             DRM_ERROR("power is down! vblank disable fail\n");
>> +             return;
>> +     }
>> +     intr_en = readl(base + LDI_INT_EN);
>> +     intr_en &= ~LDI_ISR_FRAME_END_INT;
>> +     writel(intr_en, base + LDI_INT_EN);
>> +}
>> +
>> +static irqreturn_t ade_irq_handler(int irq, void *data)
>> +{
>> +     struct ade_crtc *acrtc = data;
>> +     struct ade_hw_ctx *ctx = acrtc->ctx;
>> +     struct drm_crtc *crtc = &acrtc->base;
>> +     struct drm_device *dev = crtc->dev;
>> +     void __iomem *base = ctx->base;
>> +     u32 status;
>> +
>> +     status = readl(base + LDI_MSK_INT);
>> +     /* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
>> +
>> +     /* vblank irq */
>> +     if (status & LDI_ISR_FRAME_END_INT) {
>> +             writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
>> +             drm_handle_vblank(dev, drm_crtc_index(crtc));
>
> drm_crtc_handle_vblank please. At least when calling into the vblank code
> drivers don't have to do the struct drm_crtc -> int index conversion any
> more. Please make sure you do that everywhere, in case I've missed one.

will use drm_crtc_handle_vblank in v3.

Thanks,
-xinliang

>
> Cheers, Daniel
>
>> +     }
>> +
>> +     return IRQ_HANDLED;
>> +}
>>
>>  /*
>>   * set modules' reset mode: by software or hardware
>> @@ -858,6 +930,12 @@ static int ade_bind(struct device *dev, struct device *master, void *data)
>>       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;
>>  }
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
>> new file mode 100644
>> index 0000000..d1d7b5d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
>> @@ -0,0 +1,16 @@
>> +/*
>> + * Copyright (c) 2014-2015 Hisilicon Limited.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#ifndef __HISI_DRM_ADE_H__
>> +#define __HISI_DRM_ADE_H__
>> +
>> +int ade_enable_vblank(struct drm_device *dev, int crtc_index);
>> +void ade_disable_vblank(struct drm_device *dev, int crtc_index);
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>> index d0eca80..13f59aa 100644
>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>> @@ -21,6 +21,7 @@
>>  #include <drm/drm_fb_cma_helper.h>
>>  #include <drm/drm_atomic_helper.h>
>>
>> +#include "hisi_drm_ade.h"
>>  #include "hisi_drm_drv.h"
>>
>>  #define DRIVER_NAME  "hisi-drm"
>> @@ -29,6 +30,7 @@ static int hisi_drm_unload(struct drm_device *dev)
>>  {
>>       struct hisi_drm_private *priv = dev->dev_private;
>>
>> +     drm_vblank_cleanup(dev);
>>       drm_mode_config_cleanup(dev);
>>       devm_kfree(dev->dev, priv);
>>       dev->dev_private = NULL;
>> @@ -76,11 +78,22 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
>>               goto err_mode_config_cleanup;
>>       }
>>
>> +     /* vblank init */
>> +     ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
>> +     if (ret) {
>> +             DRM_ERROR("failed to initialize vblank.\n");
>> +             goto err_unbind_all;
>> +     }
>> +     /* with irq_enabled = true, we can use the vblank feature. */
>> +     dev->irq_enabled = true;
>> +
>>       /* reset all the states of crtc/plane/encoder/connector */
>>       drm_mode_config_reset(dev);
>>
>>       return 0;
>>
>> +err_unbind_all:
>> +     component_unbind_all(dev->dev, dev);
>>  err_mode_config_cleanup:
>>       drm_mode_config_cleanup(dev);
>>       devm_kfree(dev->dev, priv);
>> @@ -126,7 +139,7 @@ static int hisi_gem_cma_dumb_create(struct drm_file *file,
>>
>>  static struct drm_driver hisi_drm_driver = {
>>       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
>> -                               DRIVER_ATOMIC,
>> +                               DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
>>       .load                   = hisi_drm_load,
>>       .unload                 = hisi_drm_unload,
>>       .fops                   = &hisi_drm_fops,
>> @@ -148,6 +161,10 @@ 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",
>>       .date                   = "20150718",
>> --
>> 1.9.1
>>
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 06/10] drm/hisilicon: Add vblank feature
@ 2015-12-01  3:16       ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01  3:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 30 November 2015 at 15:54, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
>> Add vblank handle for ADE.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
>>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
>>  3 files changed, 112 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> index b0976c3..acb11e7 100644
>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
>>       ctx->power_on = false;
>>  }
>>
>> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
>> +                                              unsigned int index)
>
> Ugly that you had to add this, but unfortunately necessary :( Fixing up
> the drm vblank hooks so that they deal with struct drm_crtc directly is
> somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
> ways off still.
>
> What might be possible as a follow-up cleanup though is to add
> vblank_enable and vblank_disable functions to struct
> drm_crtc_helper_funcs. And then provide this code here to map from int
> index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
> That might be a good intermediate step.

I would like to have a try to make this intermediate step patch and
send out for review soon.

> But nothing that needs to be done before merging hisilicon, that's for
> sure.
>
> One more comment below.
>
>> +{
>> +     unsigned int index_tmp = 0;
>> +     struct drm_crtc *crtc;
>> +
>> +     list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
>> +             if (index_tmp == index)
>> +                     return crtc;
>> +
>> +             index_tmp++;
>> +     }
>> +
>> +     WARN_ON(true);
>> +}
>> +
>> +int ade_enable_vblank(struct drm_device *dev, int crtc_index)
>> +{
>> +     struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
>> +     struct ade_crtc *acrtc = to_ade_crtc(crtc);
>> +     struct ade_hw_ctx *ctx = acrtc->ctx;
>> +     void __iomem *base = ctx->base;
>> +     u32 intr_en;
>> +
>> +     DRM_INFO("enable_vblank enter.\n");
>> +     if (!ctx->power_on)
>> +             (void)ade_power_up(ctx);
>> +
>> +     intr_en = readl(base + LDI_INT_EN);
>> +     intr_en |= LDI_ISR_FRAME_END_INT;
>> +     writel(intr_en, base + LDI_INT_EN);
>>
>> +     return 0;
>> +}
>> +
>> +void ade_disable_vblank(struct drm_device *dev, int crtc_index)
>> +{
>> +     struct drm_crtc *crtc = hisi_get_crtc_from_index(dev, crtc_index);
>> +     struct ade_crtc *acrtc = to_ade_crtc(crtc);
>> +     struct ade_hw_ctx *ctx = acrtc->ctx;
>> +     void __iomem *base = ctx->base;
>> +     u32 intr_en;
>> +
>> +     DRM_INFO("disable_vblank enter.\n");
>> +     if (!ctx->power_on) {
>> +             DRM_ERROR("power is down! vblank disable fail\n");
>> +             return;
>> +     }
>> +     intr_en = readl(base + LDI_INT_EN);
>> +     intr_en &= ~LDI_ISR_FRAME_END_INT;
>> +     writel(intr_en, base + LDI_INT_EN);
>> +}
>> +
>> +static irqreturn_t ade_irq_handler(int irq, void *data)
>> +{
>> +     struct ade_crtc *acrtc = data;
>> +     struct ade_hw_ctx *ctx = acrtc->ctx;
>> +     struct drm_crtc *crtc = &acrtc->base;
>> +     struct drm_device *dev = crtc->dev;
>> +     void __iomem *base = ctx->base;
>> +     u32 status;
>> +
>> +     status = readl(base + LDI_MSK_INT);
>> +     /* DRM_INFO("LDI IRQ: status=0x%X\n",status); */
>> +
>> +     /* vblank irq */
>> +     if (status & LDI_ISR_FRAME_END_INT) {
>> +             writel(LDI_ISR_FRAME_END_INT, base + LDI_INT_CLR);
>> +             drm_handle_vblank(dev, drm_crtc_index(crtc));
>
> drm_crtc_handle_vblank please. At least when calling into the vblank code
> drivers don't have to do the struct drm_crtc -> int index conversion any
> more. Please make sure you do that everywhere, in case I've missed one.

will use drm_crtc_handle_vblank in v3.

Thanks,
-xinliang

>
> Cheers, Daniel
>
>> +     }
>> +
>> +     return IRQ_HANDLED;
>> +}
>>
>>  /*
>>   * set modules' reset mode: by software or hardware
>> @@ -858,6 +930,12 @@ static int ade_bind(struct device *dev, struct device *master, void *data)
>>       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;
>>  }
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.h b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
>> new file mode 100644
>> index 0000000..d1d7b5d
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.h
>> @@ -0,0 +1,16 @@
>> +/*
>> + * Copyright (c) 2014-2015 Hisilicon Limited.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#ifndef __HISI_DRM_ADE_H__
>> +#define __HISI_DRM_ADE_H__
>> +
>> +int ade_enable_vblank(struct drm_device *dev, int crtc_index);
>> +void ade_disable_vblank(struct drm_device *dev, int crtc_index);
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>> index d0eca80..13f59aa 100644
>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>> @@ -21,6 +21,7 @@
>>  #include <drm/drm_fb_cma_helper.h>
>>  #include <drm/drm_atomic_helper.h>
>>
>> +#include "hisi_drm_ade.h"
>>  #include "hisi_drm_drv.h"
>>
>>  #define DRIVER_NAME  "hisi-drm"
>> @@ -29,6 +30,7 @@ static int hisi_drm_unload(struct drm_device *dev)
>>  {
>>       struct hisi_drm_private *priv = dev->dev_private;
>>
>> +     drm_vblank_cleanup(dev);
>>       drm_mode_config_cleanup(dev);
>>       devm_kfree(dev->dev, priv);
>>       dev->dev_private = NULL;
>> @@ -76,11 +78,22 @@ static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
>>               goto err_mode_config_cleanup;
>>       }
>>
>> +     /* vblank init */
>> +     ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
>> +     if (ret) {
>> +             DRM_ERROR("failed to initialize vblank.\n");
>> +             goto err_unbind_all;
>> +     }
>> +     /* with irq_enabled = true, we can use the vblank feature. */
>> +     dev->irq_enabled = true;
>> +
>>       /* reset all the states of crtc/plane/encoder/connector */
>>       drm_mode_config_reset(dev);
>>
>>       return 0;
>>
>> +err_unbind_all:
>> +     component_unbind_all(dev->dev, dev);
>>  err_mode_config_cleanup:
>>       drm_mode_config_cleanup(dev);
>>       devm_kfree(dev->dev, priv);
>> @@ -126,7 +139,7 @@ static int hisi_gem_cma_dumb_create(struct drm_file *file,
>>
>>  static struct drm_driver hisi_drm_driver = {
>>       .driver_features        = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
>> -                               DRIVER_ATOMIC,
>> +                               DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
>>       .load                   = hisi_drm_load,
>>       .unload                 = hisi_drm_unload,
>>       .fops                   = &hisi_drm_fops,
>> @@ -148,6 +161,10 @@ 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",
>>       .date                   = "20150718",
>> --
>> 1.9.1
>>
>
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 06/10] drm/hisilicon: Add vblank feature
  2015-12-01  3:16       ` Xinliang Liu
@ 2015-12-01  7:13         ` Daniel Vetter
  -1 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-12-01  7:13 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: Daniel Vetter, dri-devel, devicetree, Rob Herring, Daniel Stone,
	architt, David Airlie, Jon Corbet, Catalin Marinas, Will Deacon,
	linux-doc, LAKML, linuxarm, Andy Green, Haojian Zhuang,
	Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong, zourongrong, lijianhua, Sumit

On Tue, Dec 01, 2015 at 11:16:19AM +0800, Xinliang Liu wrote:
> On 30 November 2015 at 15:54, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
> >> Add vblank handle for ADE.
> >>
> >> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> >> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> >> Signed-off-by: Andy Green <andy.green@linaro.org>
> >> ---
> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
> >>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
> >>  3 files changed, 112 insertions(+), 1 deletion(-)
> >>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> >>
> >> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> index b0976c3..acb11e7 100644
> >> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
> >>       ctx->power_on = false;
> >>  }
> >>
> >> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
> >> +                                              unsigned int index)
> >
> > Ugly that you had to add this, but unfortunately necessary :( Fixing up
> > the drm vblank hooks so that they deal with struct drm_crtc directly is
> > somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
> > ways off still.
> >
> > What might be possible as a follow-up cleanup though is to add
> > vblank_enable and vblank_disable functions to struct
> > drm_crtc_helper_funcs. And then provide this code here to map from int
> > index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
> > That might be a good intermediate step.
> 
> I would like to have a try to make this intermediate step patch and
> send out for review soon.

Awesome, looking forward to reviewing it. If you have questions about
details fastest to ping me on irc (nick: danvet, #dri-devel on
freenode.net).

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 06/10] drm/hisilicon: Add vblank feature
@ 2015-12-01  7:13         ` Daniel Vetter
  0 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-12-01  7:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 01, 2015 at 11:16:19AM +0800, Xinliang Liu wrote:
> On 30 November 2015 at 15:54, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
> >> Add vblank handle for ADE.
> >>
> >> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> >> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> >> Signed-off-by: Andy Green <andy.green@linaro.org>
> >> ---
> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
> >>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
> >>  3 files changed, 112 insertions(+), 1 deletion(-)
> >>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> >>
> >> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> index b0976c3..acb11e7 100644
> >> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
> >>       ctx->power_on = false;
> >>  }
> >>
> >> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
> >> +                                              unsigned int index)
> >
> > Ugly that you had to add this, but unfortunately necessary :( Fixing up
> > the drm vblank hooks so that they deal with struct drm_crtc directly is
> > somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
> > ways off still.
> >
> > What might be possible as a follow-up cleanup though is to add
> > vblank_enable and vblank_disable functions to struct
> > drm_crtc_helper_funcs. And then provide this code here to map from int
> > index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
> > That might be a good intermediate step.
> 
> I would like to have a try to make this intermediate step patch and
> send out for review soon.

Awesome, looking forward to reviewing it. If you have questions about
details fastest to ping me on irc (nick: danvet, #dri-devel on
freenode.net).

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem
  2015-11-30 19:31     ` Rob Herring
@ 2015-12-01  7:17       ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01  7:17 UTC (permalink / raw)
  To: Rob Herring
  Cc: dri-devel, devicetree, Daniel Vetter, Daniel Stone, architt,
	David Airlie, Jon Corbet, Catalin Marinas, Will Deacon,
	linux-doc, LAKML, linuxarm, Andy Green, Haojian Zhuang,
	Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong, zourongrong, lijianhua, Sumit Semwal

On 1 December 2015 at 03:31, Rob Herring <robh@kernel.org> wrote:

Hi Rob, thank you for review.

> On Sat, Nov 28, 2015 at 06:38:57PM +0800, Xinliang Liu wrote:
>> Add the device tree binding documentation for hi6220 SoC display subsystem.
>> drm master device binding doc.
>> ADE display controller binding doc.
>> DSI controller binding doc.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>>  .../bindings/display/hisilicon/hisi-ade.txt        | 42 ++++++++++++++
>>  .../bindings/display/hisilicon/hisi-drm.txt        | 66 ++++++++++++++++++++++
>>  .../bindings/display/hisilicon/hisi-dsi.txt        | 53 +++++++++++++++++
>>  3 files changed, 161 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
>>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
>>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
>>
>> diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
>> new file mode 100644
>> index 0000000..2777a2c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
>> @@ -0,0 +1,42 @@
>> +Device-Tree bindings for hisilicon ADE display controller driver
>> +
>> +ADE (Advanced Display Engine) is the display controller which grab image
>> +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.
>
> I think you can use assigned clock properties instead:
>
> assigned-clocks = <&media_ctrl HI6220_ADE_CORE>;
> assigned-clock-rates = <360000000>;
>
> I'm not sure about what media_noc corresponds to in clocks list though.
>

will use assigned-clocks in v3.

>> +
>> +
>> +A example of HiKey board hi6220 SoC specific DT entry:
>> +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>;
>> +
>> +             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-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>;
>> +     };
>> diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
>> new file mode 100644
>> index 0000000..fd93026
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
>> @@ -0,0 +1,66 @@
>> +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.
>
> There is no need for this in DT. The ADE can be the master device and
> of-graph can link to the DSI node. I have a similar example here[1]
> with a LCD controller block, DSI block and adv7533.

This sounds good, then I can remove the virtual master device.
I will refer to this example and make ADE as the master device in v3.

>
>> +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.
>
> Put this on the actually DMA master.

The DMA modules reside in the begining of each channel(or plane) of ADE.
So I need to put this dma-coherent property to ADE device node, right?

Thanks,
-xinliang

>
> Rob
>
> [1] https://git.linaro.org/people/rob.herring/linux.git pxa1928-drm-v2

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem
@ 2015-12-01  7:17       ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01  7:17 UTC (permalink / raw)
  To: linux-arm-kernel

On 1 December 2015 at 03:31, Rob Herring <robh@kernel.org> wrote:

Hi Rob, thank you for review.

> On Sat, Nov 28, 2015 at 06:38:57PM +0800, Xinliang Liu wrote:
>> Add the device tree binding documentation for hi6220 SoC display subsystem.
>> drm master device binding doc.
>> ADE display controller binding doc.
>> DSI controller binding doc.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>>  .../bindings/display/hisilicon/hisi-ade.txt        | 42 ++++++++++++++
>>  .../bindings/display/hisilicon/hisi-drm.txt        | 66 ++++++++++++++++++++++
>>  .../bindings/display/hisilicon/hisi-dsi.txt        | 53 +++++++++++++++++
>>  3 files changed, 161 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
>>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
>>  create mode 100644 Documentation/devicetree/bindings/display/hisilicon/hisi-dsi.txt
>>
>> diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
>> new file mode 100644
>> index 0000000..2777a2c
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-ade.txt
>> @@ -0,0 +1,42 @@
>> +Device-Tree bindings for hisilicon ADE display controller driver
>> +
>> +ADE (Advanced Display Engine) is the display controller which grab image
>> +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.
>
> I think you can use assigned clock properties instead:
>
> assigned-clocks = <&media_ctrl HI6220_ADE_CORE>;
> assigned-clock-rates = <360000000>;
>
> I'm not sure about what media_noc corresponds to in clocks list though.
>

will use assigned-clocks in v3.

>> +
>> +
>> +A example of HiKey board hi6220 SoC specific DT entry:
>> +Example:
>> +
>> +     ade: ade at f4100000 {
>> +             compatible = "hisilicon,hi6220-ade";
>> +             reg = <0x0 0xf4100000 0x0 0x7800>,
>> +                   <0x0 0xf4410000 0x0 0x1000>;
>> +             reg-names = "ade_base",
>> +                         "media_base";
>> +             interrupts = <0 115 4>;
>> +
>> +             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-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>;
>> +     };
>> diff --git a/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
>> new file mode 100644
>> index 0000000..fd93026
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/hisilicon/hisi-drm.txt
>> @@ -0,0 +1,66 @@
>> +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.
>
> There is no need for this in DT. The ADE can be the master device and
> of-graph can link to the DSI node. I have a similar example here[1]
> with a LCD controller block, DSI block and adv7533.

This sounds good, then I can remove the virtual master device.
I will refer to this example and make ADE as the master device in v3.

>
>> +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.
>
> Put this on the actually DMA master.

The DMA modules reside in the begining of each channel(or plane) of ADE.
So I need to put this dma-coherent property to ADE device node, right?

Thanks,
-xinliang

>
> Rob
>
> [1] https://git.linaro.org/people/rob.herring/linux.git pxa1928-drm-v2

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 08/10] drm/hisilicon: Add dsi encoder driver
  2015-11-28 10:39   ` Xinliang Liu
@ 2015-12-01  8:58     ` Archit Taneja
  -1 siblings, 0 replies; 70+ messages in thread
From: Archit Taneja @ 2015-12-01  8:58 UTC (permalink / raw)
  To: Xinliang Liu, dri-devel, devicetree, daniel, robh, daniel,
	airlied, corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal



On 11/28/2015 04:09 PM, Xinliang Liu wrote:
> Add dsi encoder driver for hi6220 SoC.
>
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---
>   drivers/gpu/drm/hisilicon/Kconfig        |   1 +
>   drivers/gpu/drm/hisilicon/Makefile       |   3 +-
>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 728 +++++++++++++++++++++++++++++++
>   drivers/gpu/drm/hisilicon/hisi_dsi_reg.h |  89 ++++
>   4 files changed, 820 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>
> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
> index 70aa8d1..f1c33c2 100644
> --- a/drivers/gpu/drm/hisilicon/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/Kconfig
> @@ -4,6 +4,7 @@ config DRM_HISI
>   	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.
> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
> index 3433c8b..5083c1f 100644
> --- a/drivers/gpu/drm/hisilicon/Makefile
> +++ b/drivers/gpu/drm/hisilicon/Makefile
> @@ -1,4 +1,5 @@
>   hisi-drm-y := hisi_drm_drv.o \
> -	      hisi_drm_ade.o
> +	      hisi_drm_ade.o \
> +	      hisi_drm_dsi.o
>
>   obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> new file mode 100644
> index 0000000..7a6cf66
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> @@ -0,0 +1,728 @@
> +/*
> + * Hisilicon hi6220 SoC dsi driver
> + *
> + * Copyright (c) 2014-2015 Hisilicon Limited.
> + * Author:
> + *	Xinliang Liu <xinliang.liu@linaro.org>
> + *	Xinliang Liu <z.liuxinliang@hisilicon.com>
> + *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/of_graph.h>
> +
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_encoder_slave.h>
> +#include <drm/drm_atomic_helper.h>
> +
> +#include "hisi_dsi_reg.h"
> +
> +#define MAX_TX_ESC_CLK		   (10)
> +#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
> +#define DEFAULT_MIPI_CLK_RATE   19200000
> +#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
> +#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
> +	      phy->lane_byte_clk_kHz)))
> +
> +#define encoder_to_dsi(encoder) \
> +	container_of(encoder, struct hisi_dsi, encoder)
> +#define host_to_dsi(host) \
> +	container_of(host, struct hisi_dsi, host)
> +
> +struct mipi_phy_register {
> +	u32 clk_t_lpx;
> +	u32 clk_t_hs_prepare;
> +	u32 clk_t_hs_zero;
> +	u32 clk_t_hs_trial;
> +	u32 clk_t_wakeup;
> +	u32 data_t_lpx;
> +	u32 data_t_hs_prepare;
> +	u32 data_t_hs_zero;
> +	u32 data_t_hs_trial;
> +	u32 data_t_ta_go;
> +	u32 data_t_ta_get;
> +	u32 data_t_wakeup;
> +	u32 hstx_ckg_sel;
> +	u32 pll_fbd_div5f;
> +	u32 pll_fbd_div1f;
> +	u32 pll_fbd_2p;
> +	u32 pll_enbwt;
> +	u32 pll_fbd_p;
> +	u32 pll_fbd_s;
> +	u32 pll_pre_div1p;
> +	u32 pll_pre_p;
> +	u32 pll_vco_750M;
> +	u32 pll_lpf_rs;
> +	u32 pll_lpf_cs;
> +	u32 clklp2hs_time;
> +	u32 clkhs2lp_time;
> +	u32 lp2hs_time;
> +	u32 hs2lp_time;
> +	u32 clk_to_data_delay;
> +	u32 data_to_clk_delay;
> +	u32 lane_byte_clk_kHz;
> +	u32 clk_division;
> +};
> +
> +struct dsi_hw_ctx {
> +	void __iomem *base;
> +	struct clk *dsi_cfg_clk;
> +};
> +
> +struct hisi_dsi {
> +	struct drm_encoder encoder;
> +	struct drm_display_mode cur_mode;
> +	struct dsi_hw_ctx *ctx;
> +	struct mipi_phy_register phy;
> +
> +	u32 lanes;
> +	enum mipi_dsi_pixel_format format;
> +	unsigned long mode_flags;
> +	bool enable;
> +};
> +
> +struct dsi_data {
> +	struct hisi_dsi dsi;
> +	struct dsi_hw_ctx ctx;
> +};
> +
> +struct dsi_phy_seq_info {
> +	u32 min_range_kHz;
> +	u32 max_range_kHz;
> +	u32 pll_vco_750M;
> +	u32 hstx_ckg_sel;
> +};
> +
> +static const struct dsi_phy_seq_info dphy_seq_info[] = {
> +	{   46000,    62000,   1,    7 },
> +	{   62000,    93000,   0,    7 },
> +	{   93000,   125000,   1,    6 },
> +	{  125000,   187000,   0,    6 },
> +	{  187000,   250000,   1,    5 },
> +	{  250000,   375000,   0,    5 },
> +	{  375000,   500000,   1,    4 },
> +	{  500000,   750000,   0,    4 },
> +	{  750000,  1000000,   1,    0 },
> +	{ 1000000,  1500000,   0,    0 }
> +};
> +
> +static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
> +					     struct mipi_phy_register *phy)
> +{
> +	u32 ui = 0;
> +	u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
> +	u32 i = 0;
> +	u32 q_pll = 1;
> +	u32 m_pll = 0;
> +	u32 n_pll = 0;
> +	u32 r_pll = 1;
> +	u32 m_n = 0;
> +	u32 m_n_int = 0;
> +	u64 f_kHz;
> +	u64 temp;
> +	u64 tmp_kHz = phy_freq_kHz;
> +
> +	do {
> +		f_kHz = tmp_kHz;
> +
> +		/* Find the PLL clock range from the table */
> +		for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
> +			if (f_kHz > dphy_seq_info[i].min_range_kHz &&
> +			    f_kHz <= dphy_seq_info[i].max_range_kHz)
> +				break;
> +
> +		if (i == ARRAY_SIZE(dphy_seq_info)) {
> +			DRM_ERROR("%lldkHz out of range\n", f_kHz);
> +			return;
> +		}
> +
> +		phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
> +		phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
> +
> +		if (phy->hstx_ckg_sel <= 7 &&
> +		    phy->hstx_ckg_sel >= 4)
> +			q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
> +
> +		temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
> +		m_n_int = temp / (u64)1000000000;
> +		m_n = (temp % (u64)1000000000) / (u64)100000000;
> +
> +		if (m_n_int % 2 == 0) {
> +			if (m_n * 6 >= 50) {
> +				n_pll = 2;
> +				m_pll = (m_n_int + 1) * n_pll;
> +			} else if (m_n * 6 >= 30) {
> +				n_pll = 3;
> +				m_pll = m_n_int * n_pll + 2;
> +			} else {
> +				n_pll = 1;
> +				m_pll = m_n_int * n_pll;
> +			}
> +		} else {
> +			if (m_n * 6 >= 50) {
> +				n_pll = 1;
> +				m_pll = (m_n_int + 1) * n_pll;
> +			} else if (m_n * 6 >= 30) {
> +				n_pll = 1;
> +				m_pll = (m_n_int + 1) * n_pll;
> +			} else if (m_n * 6 >= 10) {
> +				n_pll = 3;
> +				m_pll = m_n_int * n_pll + 1;
> +			} else {
> +				n_pll = 2;
> +				m_pll = m_n_int * n_pll;
> +			}
> +		}
> +
> +		if (n_pll == 1) {
> +			phy->pll_fbd_p = 0;
> +			phy->pll_pre_div1p = 1;
> +		} else {
> +			phy->pll_fbd_p = n_pll;
> +			phy->pll_pre_div1p = 0;
> +		}
> +
> +		if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
> +			r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
> +
> +		if (m_pll == 2) {
> +			phy->pll_pre_p = 0;
> +			phy->pll_fbd_s = 0;
> +			phy->pll_fbd_div1f = 0;
> +			phy->pll_fbd_div5f = 1;
> +		} else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
> +			phy->pll_pre_p = m_pll / (2 * r_pll);
> +			phy->pll_fbd_s = 0;
> +			phy->pll_fbd_div1f = 1;
> +			phy->pll_fbd_div5f = 0;
> +		} else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
> +			if (((m_pll / (2 * r_pll)) % 2) == 0) {
> +				phy->pll_pre_p =
> +					(m_pll / (2 * r_pll)) / 2 - 1;
> +				phy->pll_fbd_s =
> +					(m_pll / (2 * r_pll)) % 2 + 2;
> +			} else {
> +				phy->pll_pre_p =
> +					(m_pll / (2 * r_pll)) / 2;
> +				phy->pll_fbd_s =
> +					(m_pll / (2 * r_pll)) % 2;
> +			}
> +			phy->pll_fbd_div1f = 0;
> +			phy->pll_fbd_div5f = 0;
> +		} else {
> +			phy->pll_pre_p = 0;
> +			phy->pll_fbd_s = 0;
> +			phy->pll_fbd_div1f = 0;
> +			phy->pll_fbd_div5f = 1;
> +		}
> +
> +		f_kHz = (u64)1000000000 * (u64)m_pll /
> +			((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
> +
> +		if (f_kHz >= phy_freq_kHz)
> +			break;
> +
> +		tmp_kHz += 10;
> +
> +	} while (1);
> +
> +	ui = 1000000 / f_kHz;
> +
> +	phy->clk_t_lpx = ROUND(50, 8 * ui);
> +	phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
> +
> +	phy->clk_t_hs_zero = ROUND(262, 8 * ui);
> +	phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
> +	phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
> +	if (phy->clk_t_wakeup > 0xff)
> +		phy->clk_t_wakeup = 0xff;
> +	phy->data_t_wakeup = phy->clk_t_wakeup;
> +	phy->data_t_lpx = phy->clk_t_lpx;
> +	phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
> +	phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
> +	phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
> +	phy->data_t_ta_go = 3;
> +	phy->data_t_ta_get = 4;
> +
> +	phy->pll_enbwt = 1;
> +	phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
> +	phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
> +	phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
> +	phy->hs2lp_time = phy->clkhs2lp_time;
> +	phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
> +	phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
> +				phy->clkhs2lp_time;
> +
> +	phy->lane_byte_clk_kHz = f_kHz / 8;
> +	phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
> +	if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
> +		phy->clk_division++;
> +}
> +
> +static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
> +{
> +	u32 val;
> +
> +	/* TODO: only support RGB888 now, to support more */
> +	switch (format) {
> +	case MIPI_DSI_FMT_RGB888:
> +		val = DSI_24BITS_1;
> +		break;
> +	default:
> +		val = DSI_24BITS_1;
> +		break;
> +	}
> +
> +	return val;
> +}
> +
> +static void dsi_mipi_phy_clks(void __iomem *base,
> +			      struct mipi_phy_register *phy,
> +			      u32 lanes)
> +{
> +	u32 delay_count;
> +	bool is_ready;
> +	u32 val;
> +	u32 i;
> +
> +	/* set lanes value */
> +	val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
> +	writel(val, base + PHY_IF_CFG);
> +
> +	/* set phy clk division */
> +	val = readl(base + CLKMGR_CFG) | phy->clk_division;
> +	writel(val, base + CLKMGR_CFG);
> +
> +	/* clean up phy set param */
> +	writel(0, base + PHY_RSTZ);
> +	writel(0, base + PHY_TST_CTRL0);
> +	writel(1, base + PHY_TST_CTRL0);
> +	writel(0, base + PHY_TST_CTRL0);
> +
> +	/* clock lane Timing control - TLPX */
> +	dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
> +
> +	/* clock lane Timing control - THS-PREPARE */
> +	dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
> +
> +	/* clock lane Timing control - THS-ZERO */
> +	dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
> +
> +	/* clock lane Timing control - THS-TRAIL */
> +	dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
> +
> +	/* clock lane Timing control - TWAKEUP */
> +	dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
> +
> +	/* data lane */
> +	for (i = 0; i < lanes; i++) {
> +		/* Timing control - TLPX*/
> +		dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
> +
> +		/* Timing control - THS-PREPARE */
> +		dsi_phy_tst_set(base, 0x10021 + (i << 4),
> +				phy->data_t_hs_prepare);
> +
> +		/* Timing control - THS-ZERO */
> +		dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
> +
> +		/* Timing control - THS-TRAIL */
> +		dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
> +
> +		/* Timing control - TTA-GO */
> +		dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
> +
> +		/* Timing control - TTA-GET */
> +		dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
> +
> +		/*  Timing control - TWAKEUP */
> +		dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
> +	}
> +
> +	/* physical configuration I  */
> +	dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
> +
> +	/* physical configuration pll II  */
> +	val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
> +				(phy->pll_fbd_2p << 1) + phy->pll_enbwt;
> +	dsi_phy_tst_set(base, 0x10063, val);
> +
> +	/* physical configuration pll II  */
> +	dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
> +
> +	/* physical configuration pll III  */
> +	dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
> +
> +	/*physical configuration pll IV*/
> +	val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
> +	dsi_phy_tst_set(base, 0x10066, val);
> +
> +	/*physical configuration pll V*/

It would be nice to fix the comment spacing for uniformity.

> +	val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
> +					phy->pll_lpf_cs + BIT(5);
> +	dsi_phy_tst_set(base, 0x10067, val);
> +
> +	writel(BIT(2), base + PHY_RSTZ);
> +	udelay(1);
> +	writel(BIT(2) | BIT(0), base + PHY_RSTZ);
> +	udelay(1);
> +	writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
> +	usleep_range(1000, 1500);
> +
> +	/* wait for phy's clock ready */
> +	delay_count = 0;
> +	is_ready = false;
> +	while (1) {
> +		val = readl(base +  PHY_STATUS);
> +		if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
> +			is_ready = (delay_count < 100) ? true : false;
> +			delay_count = 0;
> +			break;
> +		}
> +
> +		udelay(1);
> +		++delay_count;
> +	}

You could simplify this a bit:

	delay_count = 100
	while (delay_count) {
	...
	--delay_count;
	}

	if (!delay_count)
		DRM_INFO("...");
> +
> +	if (!is_ready)
> +		DRM_INFO("phylock and phystopstateclklane is not ready.\n");
> +}
> +
> +static void dsi_set_mode_timing(void __iomem *base,
> +				struct mipi_phy_register *phy,
> +				struct drm_display_mode *mode,
> +				enum mipi_dsi_pixel_format format)
> +{
> +	u32 hfp, hbp, hsw, vfp, vbp, vsw;
> +	u32 hline_time;
> +	u32 hsa_time;
> +	u32 hbp_time;
> +	u32 pixel_clk_kHz;
> +	int htot, vtot;
> +	u32 val;
> +
> +	/* DSI color coding setting */
> +	val = dsi_get_dpi_color_coding(format);
> +	writel(val, base + DPI_COLOR_CODING);
> +
> +	/* DSI format and pol setting */
> +	val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
> +	val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
> +	writel(val, base +  DPI_CFG_POL);
> +
> +	/*
> +	 * The DSI IP accepts vertical timing using lines as normal,
> +	 * but horizontal timing is a mixture of pixel-clocks for the
> +	 * active region and byte-lane clocks for the blanking-related
> +	 * timings.  hfp is specified as the total hline_time in byte-
> +	 * lane clocks minus hsa, hbp and active.
> +	 */
> +	pixel_clk_kHz = mode->clock;
> +	htot = mode->htotal;
> +	vtot = mode->vtotal;
> +	hfp = mode->hsync_start - mode->hdisplay;
> +	hbp = mode->htotal - mode->hsync_end;
> +	hsw = mode->hsync_end - mode->hsync_start;
> +	vfp = mode->vsync_start - mode->vdisplay;
> +	vbp = mode->vtotal - mode->vsync_end;
> +	vsw = mode->vsync_end - mode->vsync_start;
> +	if (vsw > 15) {
> +		DRM_INFO("vsw exceeded 15\n");
> +		vtot -= vsw - 15;
> +		vsw = 15;
> +	}
> +
> +	hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
> +	hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
> +	hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
> +		      pixel_clk_kHz;
> +
> +	if ((R(hline_time) / 1000) > htot) {
> +		DRM_INFO("--: hline_time=%d\n", hline_time);
> +		hline_time--;
> +	}
> +
> +	if ((R(hline_time) / 1000) < htot) {

Could we use a better macro name here? Also, it would be nice to pass
the phy argument to it too. Maybe even move the divide by 1000 in the macro.

> +		DRM_INFO("++: hline_time=%d\n", hline_time);
> +		hline_time++;
> +	}
> +
> +	/* all specified in byte-lane clocks */
> +	writel(hsa_time, base + VID_HSA_TIME);
> +	writel(hbp_time, base + VID_HBP_TIME);
> +	writel(hline_time, base + VID_HLINE_TIME);
> +
> +	writel(vsw, base + VID_VSA_LINES);
> +	writel(vbp, base + VID_VBP_LINES);
> +	writel(vfp, base + VID_VFP_LINES);
> +	writel(mode->vdisplay, base + VID_VACTIVE_LINES);
> +	writel(mode->hdisplay, base + VID_PKT_SIZE);
> +}
> +
> +static void dsi_set_video_mode_type(void __iomem *base,
> +				    struct mipi_phy_register *phy,
> +				    unsigned long flags)
> +{
> +	u32 val;
> +	u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
> +		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +	u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
> +		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +	u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
> +
> +	/*
> +	 * choose video type
> +	 */
> +	if ((flags & mode_mask) == non_burst_sync_pulse)
> +		val = DSI_NON_BURST_SYNC_PULSES;
> +	else if ((flags & mode_mask) == non_burst_sync_event)
> +		val = DSI_NON_BURST_SYNC_EVENTS;
> +	else
> +		val = DSI_BURST_SYNC_PULSES_1;
> +
> +	writel(val, base + VID_MODE_CFG);
> +	/* TODO: to support LCD panel need to set LP command transfer */
> +}
> +
> +static void dsi_mipi_init(struct hisi_dsi *dsi)
> +{
> +	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	struct mipi_phy_register *phy = &dsi->phy;
> +	struct drm_display_mode *mode = &dsi->cur_mode;
> +	void __iomem *base = ctx->base;
> +	u32 dphy_freq_kHz;
> +
> +	/* count phy params */
> +	dphy_freq_kHz = mode->clock * 24 / dsi->lanes;

Maybe replace the 24 above with the bpp in use for future compatibility?

> +	set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
> +
> +	/* reset Core */
> +	writel(0, base + PWR_UP);
> +
> +	/* set phy clocks */
> +	dsi_mipi_phy_clks(base, phy, dsi->lanes);
> +
> +	/* set dsi mode */
> +	dsi_set_mode_timing(base, phy, mode, dsi->format);
> +
> +	/* set video mode type and low power */
> +	dsi_set_video_mode_type(base, phy, dsi->mode_flags);
> +
> +	/* DSI and D-PHY Initialization */
> +	writel(DSI_VIDEO_MODE, base + MODE_CFG);
> +	writel(BIT(0), base + LPCLK_CTRL);
> +	writel(BIT(0), base + PWR_UP);
> +}
> +
> +static void dsi_encoder_disable(struct drm_encoder *encoder)
> +{
> +	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
> +	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	void __iomem *base = ctx->base;
> +
> +	DRM_DEBUG_DRIVER("enter\n");
> +	if (!dsi->enable)
> +		return;
> +
> +	writel(0, base + PWR_UP);
> +	writel(0, base + LPCLK_CTRL);
> +	writel(0, base + PHY_RSTZ);
> +	clk_disable_unprepare(ctx->dsi_cfg_clk);
> +
> +	dsi->enable = false;
> +	DRM_DEBUG_DRIVER("exit success.\n");
> +}
> +
> +static void dsi_encoder_enable(struct drm_encoder *encoder)
> +{
> +	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
> +	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	int ret;
> +
> +	DRM_DEBUG_DRIVER("enter.\n");
> +	if (dsi->enable)
> +		return;
> +
> +	/* mipi dphy clock enable */
> +	ret = clk_prepare_enable(ctx->dsi_cfg_clk);
> +	if (ret) {
> +		DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
> +		return;
> +	}
> +
> +	dsi_mipi_init(dsi);
> +
> +	dsi->enable = true;
> +	DRM_DEBUG_DRIVER("exit success.\n");
> +}
> +
> +static void dsi_encoder_mode_set(struct drm_encoder *encoder,
> +				 struct drm_display_mode *mode,
> +				 struct drm_display_mode *adj_mode)
> +{
> +	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
> +
> +	DRM_DEBUG_DRIVER("enter.\n");
> +	drm_mode_copy(&dsi->cur_mode, adj_mode);
> +	DRM_DEBUG_DRIVER("exit success.\n");
> +}
> +
> +static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
> +				    struct drm_crtc_state *crtc_state,
> +				    struct drm_connector_state *conn_state)
> +{
> +	struct drm_display_mode *mode = &crtc_state->mode;
> +
> +	DRM_DEBUG_DRIVER("enter.\n");
> +	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
> +		DRM_ERROR("not support INTERLACE mode\n");
> +		return MODE_NO_INTERLACE;
> +	}
> +
> +	/* pixel clock support range is (1190494208/64, 1190494208)Hz */
> +	if (mode->clock < 18602 || mode->clock > 1190494) {

I don't think we need to worry about the maximum limit if we support 
pixel clocks up to 1190 Mhz :)

> +		DRM_ERROR("mode clock not support\n");
> +		return MODE_CLOCK_RANGE;
> +	}
> +
> +	DRM_DEBUG_DRIVER("exit success.\n");
> +	return 0;
> +}
> +
> +static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
> +	.atomic_check	= dsi_encoder_atomic_check,
> +	.mode_set	= dsi_encoder_mode_set,
> +	.enable		= dsi_encoder_enable,
> +	.disable	= dsi_encoder_disable
> +};
> +
> +static const struct drm_encoder_funcs hisi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +static int hisi_drm_encoder_init(struct drm_device *dev,
> +				 struct drm_encoder *encoder)
> +{
> +	int ret;
> +
> +	encoder->possible_crtcs = 1;
> +	ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
> +			       DRM_MODE_ENCODER_TMDS);

We should have the encoder as DRM_MODE_ENCODER_DSI here, even if the
connector is finally hdmi.

> +	if (ret) {
> +		DRM_ERROR("failed to init dsi encoder\n");
> +		return ret;
> +	}
> +
> +	drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
> +
> +	return 0;
> +}
> +
> +static int dsi_bind(struct device *dev, struct device *master, void *data)
> +{
> +	struct dsi_data *ddata = dev_get_drvdata(dev);
> +	struct hisi_dsi *dsi = &ddata->dsi;
> +	struct drm_device *drm_dev = data;
> +	int ret;
> +
> +	ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void dsi_unbind(struct device *dev, struct device *master, void *data)
> +{
> +	/* do nothing */
> +}
> +
> +static const struct component_ops dsi_ops = {
> +	.bind	= dsi_bind,
> +	.unbind	= dsi_unbind,
> +};
> +
> +static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
> +{
> +	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	struct resource *res;
> +
> +
> +	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
> +	if (IS_ERR(ctx->dsi_cfg_clk)) {
> +		DRM_ERROR("failed to get dsi plck clock\n");
> +		return PTR_ERR(ctx->dsi_cfg_clk);
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	ctx->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(ctx->base)) {
> +		DRM_ERROR("failed to remap dsi io region\n");
> +		return PTR_ERR(ctx->base);
> +	}
> +
> +	return 0;
> +}
> +
> +static int dsi_probe(struct platform_device *pdev)
> +{
> +	struct dsi_data *data;
> +	struct hisi_dsi *dsi;
> +	struct dsi_hw_ctx *ctx;
> +	int ret;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data) {
> +		DRM_ERROR("failed to allocate dsi data.\n");
> +		return -ENOMEM;
> +	}
> +	dsi = &data->dsi;
> +	ctx = &data->ctx;
> +	dsi->ctx = ctx;
> +
> +	ret = dsi_parse_dt(pdev, dsi);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	return component_add(&pdev->dev, &dsi_ops);
> +}
> +
> +static int dsi_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &dsi_ops);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id dsi_of_match[] = {
> +	{.compatible = "hisilicon,hi6220-dsi"},
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, dsi_of_match);
> +
> +static struct platform_driver dsi_driver = {
> +	.probe = dsi_probe,
> +	.remove = dsi_remove,
> +	.driver = {
> +		.name = "hisi-dsi",
> +		.owner = THIS_MODULE,
> +		.of_match_table = dsi_of_match,
> +	},
> +};
> +
> +module_platform_driver(dsi_driver);
> +
> +MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
> +MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
> +MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
> +MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
> new file mode 100644
> index 0000000..db8f9df
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
> @@ -0,0 +1,89 @@
> +/*
> + * Copyright (c) 2014-2015 Hisilicon Limited.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __HISI_DSI_REG_H__
> +#define __HISI_DSI_REG_H__
> +
> +/*
> + * regs
> + */
> +#define  PWR_UP                  (0x4)   /* Core power-up */
> +#define  PHY_IF_CFG              (0xA4)  /* D-PHY interface configuration */
> +#define  CLKMGR_CFG              (0x8)   /* the internal clock dividers */
> +#define  PHY_RSTZ                (0xA0)  /* D-PHY reset control */
> +#define  PHY_TST_CTRL0           (0xB4)  /* D-PHY test interface control 0 */
> +#define  PHY_TST_CTRL1           (0xB8)  /* D-PHY test interface control 1 */
> +#define  DPI_VCID                (0xC)   /* DPI virtual channel id */
> +#define  DPI_COLOR_CODING        (0x10)  /* DPI color coding */
> +#define  DPI_CFG_POL             (0x14)  /* DPI polarity configuration */
> +#define  VID_HSA_TIME            (0x48)  /* Horizontal Sync Active time */
> +#define  VID_HBP_TIME            (0x4C)  /* Horizontal Back Porch time */
> +#define  VID_HLINE_TIME          (0x50)  /* Line time */
> +#define  VID_VSA_LINES           (0x54)  /* Vertical Sync Active period */
> +#define  VID_VBP_LINES           (0x58)  /* Vertical Back Porch period */
> +#define  VID_VFP_LINES           (0x5C)  /* Vertical Front Porch period */
> +#define  VID_VACTIVE_LINES       (0x60)  /* Vertical resolution */
> +#define  VID_PKT_SIZE            (0x3C)  /* Video packet size */
> +#define  VID_MODE_CFG            (0x38)  /* Video mode configuration */
> +#define  DPI_LP_CMD_TIM          (0x18)  /* Low-power command timing config */
> +#define  PHY_TMR_CFG             (0x9C)  /* Data lanes timing configuration */
> +#define  BTA_TO_CNT              (0x8C)  /* Response timeout definition */
> +#define  PHY_TMR_LPCLK_CFG       (0x98)  /* clock lane timing configuration */
> +#define  CLK_DATA_TMR_CFG        (0xCC)
> +#define  LPCLK_CTRL              (0x94)  /* Low-power in clock lane */
> +#define  PCKHDL_CFG              (0x2C)  /* Packet handler configuration */
> +#define  EDPI_CMD_SIZE           (0x64)  /* Size for eDPI packets */
> +#define  MODE_CFG                (0x34)  /* Video or Command mode selection */
> +#define  PHY_STATUS              (0xB0)  /* D-PHY PPI status interface */
> +
> +#define	PHY_STOP_WAIT_TIME      (0x30)
> +
> +/*
> + * regs relevant enum
> + */
> +enum dpi_color_coding {
> +	DSI_24BITS_1 = 5,
> +};
> +
> +enum dsi_video_mode_type {
> +	DSI_NON_BURST_SYNC_PULSES = 0,
> +	DSI_NON_BURST_SYNC_EVENTS,
> +	DSI_BURST_SYNC_PULSES_1,
> +	DSI_BURST_SYNC_PULSES_2
> +};
> +
> +enum dsi_work_mode {
> +	DSI_VIDEO_MODE = 0,
> +	DSI_COMMAND_MODE
> +};
> +
> +/*
> + * regs Write/Read functions
> + */
> +static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
> +{
> +	writel(reg, base + PHY_TST_CTRL1);
> +	/* reg addr written at first */
> +	wmb();
> +	writel(0x02, base + PHY_TST_CTRL0);
> +	/* cmd1 sent for write */
> +	wmb();
> +	writel(0x00, base + PHY_TST_CTRL0);
> +	/* cmd2 sent for write */
> +	wmb();
> +	writel(val, base + PHY_TST_CTRL1);
> +	/* Then write data */
> +	wmb();
> +	writel(0x02, base + PHY_TST_CTRL0);
> +	/* cmd2 sent for write */
> +	wmb();
> +	writel(0x00, base + PHY_TST_CTRL0);
> +}
> +

This doesn't look like something that should be inlined. Maybe move it 
to hisi_drm_dsi.c?

> +#endif /* __HISI_DRM_DSI_H__ */
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 08/10] drm/hisilicon: Add dsi encoder driver
@ 2015-12-01  8:58     ` Archit Taneja
  0 siblings, 0 replies; 70+ messages in thread
From: Archit Taneja @ 2015-12-01  8:58 UTC (permalink / raw)
  To: linux-arm-kernel



On 11/28/2015 04:09 PM, Xinliang Liu wrote:
> Add dsi encoder driver for hi6220 SoC.
>
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---
>   drivers/gpu/drm/hisilicon/Kconfig        |   1 +
>   drivers/gpu/drm/hisilicon/Makefile       |   3 +-
>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 728 +++++++++++++++++++++++++++++++
>   drivers/gpu/drm/hisilicon/hisi_dsi_reg.h |  89 ++++
>   4 files changed, 820 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>
> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
> index 70aa8d1..f1c33c2 100644
> --- a/drivers/gpu/drm/hisilicon/Kconfig
> +++ b/drivers/gpu/drm/hisilicon/Kconfig
> @@ -4,6 +4,7 @@ config DRM_HISI
>   	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.
> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
> index 3433c8b..5083c1f 100644
> --- a/drivers/gpu/drm/hisilicon/Makefile
> +++ b/drivers/gpu/drm/hisilicon/Makefile
> @@ -1,4 +1,5 @@
>   hisi-drm-y := hisi_drm_drv.o \
> -	      hisi_drm_ade.o
> +	      hisi_drm_ade.o \
> +	      hisi_drm_dsi.o
>
>   obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> new file mode 100644
> index 0000000..7a6cf66
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> @@ -0,0 +1,728 @@
> +/*
> + * Hisilicon hi6220 SoC dsi driver
> + *
> + * Copyright (c) 2014-2015 Hisilicon Limited.
> + * Author:
> + *	Xinliang Liu <xinliang.liu@linaro.org>
> + *	Xinliang Liu <z.liuxinliang@hisilicon.com>
> + *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/of_graph.h>
> +
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_mipi_dsi.h>
> +#include <drm/drm_encoder_slave.h>
> +#include <drm/drm_atomic_helper.h>
> +
> +#include "hisi_dsi_reg.h"
> +
> +#define MAX_TX_ESC_CLK		   (10)
> +#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
> +#define DEFAULT_MIPI_CLK_RATE   19200000
> +#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE / 1000))
> +#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
> +	      phy->lane_byte_clk_kHz)))
> +
> +#define encoder_to_dsi(encoder) \
> +	container_of(encoder, struct hisi_dsi, encoder)
> +#define host_to_dsi(host) \
> +	container_of(host, struct hisi_dsi, host)
> +
> +struct mipi_phy_register {
> +	u32 clk_t_lpx;
> +	u32 clk_t_hs_prepare;
> +	u32 clk_t_hs_zero;
> +	u32 clk_t_hs_trial;
> +	u32 clk_t_wakeup;
> +	u32 data_t_lpx;
> +	u32 data_t_hs_prepare;
> +	u32 data_t_hs_zero;
> +	u32 data_t_hs_trial;
> +	u32 data_t_ta_go;
> +	u32 data_t_ta_get;
> +	u32 data_t_wakeup;
> +	u32 hstx_ckg_sel;
> +	u32 pll_fbd_div5f;
> +	u32 pll_fbd_div1f;
> +	u32 pll_fbd_2p;
> +	u32 pll_enbwt;
> +	u32 pll_fbd_p;
> +	u32 pll_fbd_s;
> +	u32 pll_pre_div1p;
> +	u32 pll_pre_p;
> +	u32 pll_vco_750M;
> +	u32 pll_lpf_rs;
> +	u32 pll_lpf_cs;
> +	u32 clklp2hs_time;
> +	u32 clkhs2lp_time;
> +	u32 lp2hs_time;
> +	u32 hs2lp_time;
> +	u32 clk_to_data_delay;
> +	u32 data_to_clk_delay;
> +	u32 lane_byte_clk_kHz;
> +	u32 clk_division;
> +};
> +
> +struct dsi_hw_ctx {
> +	void __iomem *base;
> +	struct clk *dsi_cfg_clk;
> +};
> +
> +struct hisi_dsi {
> +	struct drm_encoder encoder;
> +	struct drm_display_mode cur_mode;
> +	struct dsi_hw_ctx *ctx;
> +	struct mipi_phy_register phy;
> +
> +	u32 lanes;
> +	enum mipi_dsi_pixel_format format;
> +	unsigned long mode_flags;
> +	bool enable;
> +};
> +
> +struct dsi_data {
> +	struct hisi_dsi dsi;
> +	struct dsi_hw_ctx ctx;
> +};
> +
> +struct dsi_phy_seq_info {
> +	u32 min_range_kHz;
> +	u32 max_range_kHz;
> +	u32 pll_vco_750M;
> +	u32 hstx_ckg_sel;
> +};
> +
> +static const struct dsi_phy_seq_info dphy_seq_info[] = {
> +	{   46000,    62000,   1,    7 },
> +	{   62000,    93000,   0,    7 },
> +	{   93000,   125000,   1,    6 },
> +	{  125000,   187000,   0,    6 },
> +	{  187000,   250000,   1,    5 },
> +	{  250000,   375000,   0,    5 },
> +	{  375000,   500000,   1,    4 },
> +	{  500000,   750000,   0,    4 },
> +	{  750000,  1000000,   1,    0 },
> +	{ 1000000,  1500000,   0,    0 }
> +};
> +
> +static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
> +					     struct mipi_phy_register *phy)
> +{
> +	u32 ui = 0;
> +	u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
> +	u32 i = 0;
> +	u32 q_pll = 1;
> +	u32 m_pll = 0;
> +	u32 n_pll = 0;
> +	u32 r_pll = 1;
> +	u32 m_n = 0;
> +	u32 m_n_int = 0;
> +	u64 f_kHz;
> +	u64 temp;
> +	u64 tmp_kHz = phy_freq_kHz;
> +
> +	do {
> +		f_kHz = tmp_kHz;
> +
> +		/* Find the PLL clock range from the table */
> +		for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
> +			if (f_kHz > dphy_seq_info[i].min_range_kHz &&
> +			    f_kHz <= dphy_seq_info[i].max_range_kHz)
> +				break;
> +
> +		if (i == ARRAY_SIZE(dphy_seq_info)) {
> +			DRM_ERROR("%lldkHz out of range\n", f_kHz);
> +			return;
> +		}
> +
> +		phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
> +		phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
> +
> +		if (phy->hstx_ckg_sel <= 7 &&
> +		    phy->hstx_ckg_sel >= 4)
> +			q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
> +
> +		temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
> +		m_n_int = temp / (u64)1000000000;
> +		m_n = (temp % (u64)1000000000) / (u64)100000000;
> +
> +		if (m_n_int % 2 == 0) {
> +			if (m_n * 6 >= 50) {
> +				n_pll = 2;
> +				m_pll = (m_n_int + 1) * n_pll;
> +			} else if (m_n * 6 >= 30) {
> +				n_pll = 3;
> +				m_pll = m_n_int * n_pll + 2;
> +			} else {
> +				n_pll = 1;
> +				m_pll = m_n_int * n_pll;
> +			}
> +		} else {
> +			if (m_n * 6 >= 50) {
> +				n_pll = 1;
> +				m_pll = (m_n_int + 1) * n_pll;
> +			} else if (m_n * 6 >= 30) {
> +				n_pll = 1;
> +				m_pll = (m_n_int + 1) * n_pll;
> +			} else if (m_n * 6 >= 10) {
> +				n_pll = 3;
> +				m_pll = m_n_int * n_pll + 1;
> +			} else {
> +				n_pll = 2;
> +				m_pll = m_n_int * n_pll;
> +			}
> +		}
> +
> +		if (n_pll == 1) {
> +			phy->pll_fbd_p = 0;
> +			phy->pll_pre_div1p = 1;
> +		} else {
> +			phy->pll_fbd_p = n_pll;
> +			phy->pll_pre_div1p = 0;
> +		}
> +
> +		if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
> +			r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
> +
> +		if (m_pll == 2) {
> +			phy->pll_pre_p = 0;
> +			phy->pll_fbd_s = 0;
> +			phy->pll_fbd_div1f = 0;
> +			phy->pll_fbd_div5f = 1;
> +		} else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) {
> +			phy->pll_pre_p = m_pll / (2 * r_pll);
> +			phy->pll_fbd_s = 0;
> +			phy->pll_fbd_div1f = 1;
> +			phy->pll_fbd_div5f = 0;
> +		} else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) {
> +			if (((m_pll / (2 * r_pll)) % 2) == 0) {
> +				phy->pll_pre_p =
> +					(m_pll / (2 * r_pll)) / 2 - 1;
> +				phy->pll_fbd_s =
> +					(m_pll / (2 * r_pll)) % 2 + 2;
> +			} else {
> +				phy->pll_pre_p =
> +					(m_pll / (2 * r_pll)) / 2;
> +				phy->pll_fbd_s =
> +					(m_pll / (2 * r_pll)) % 2;
> +			}
> +			phy->pll_fbd_div1f = 0;
> +			phy->pll_fbd_div5f = 0;
> +		} else {
> +			phy->pll_pre_p = 0;
> +			phy->pll_fbd_s = 0;
> +			phy->pll_fbd_div1f = 0;
> +			phy->pll_fbd_div5f = 1;
> +		}
> +
> +		f_kHz = (u64)1000000000 * (u64)m_pll /
> +			((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
> +
> +		if (f_kHz >= phy_freq_kHz)
> +			break;
> +
> +		tmp_kHz += 10;
> +
> +	} while (1);
> +
> +	ui = 1000000 / f_kHz;
> +
> +	phy->clk_t_lpx = ROUND(50, 8 * ui);
> +	phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
> +
> +	phy->clk_t_hs_zero = ROUND(262, 8 * ui);
> +	phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
> +	phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
> +	if (phy->clk_t_wakeup > 0xff)
> +		phy->clk_t_wakeup = 0xff;
> +	phy->data_t_wakeup = phy->clk_t_wakeup;
> +	phy->data_t_lpx = phy->clk_t_lpx;
> +	phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
> +	phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
> +	phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
> +	phy->data_t_ta_go = 3;
> +	phy->data_t_ta_get = 4;
> +
> +	phy->pll_enbwt = 1;
> +	phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
> +	phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
> +	phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
> +	phy->hs2lp_time = phy->clkhs2lp_time;
> +	phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
> +	phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
> +				phy->clkhs2lp_time;
> +
> +	phy->lane_byte_clk_kHz = f_kHz / 8;
> +	phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
> +	if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
> +		phy->clk_division++;
> +}
> +
> +static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
> +{
> +	u32 val;
> +
> +	/* TODO: only support RGB888 now, to support more */
> +	switch (format) {
> +	case MIPI_DSI_FMT_RGB888:
> +		val = DSI_24BITS_1;
> +		break;
> +	default:
> +		val = DSI_24BITS_1;
> +		break;
> +	}
> +
> +	return val;
> +}
> +
> +static void dsi_mipi_phy_clks(void __iomem *base,
> +			      struct mipi_phy_register *phy,
> +			      u32 lanes)
> +{
> +	u32 delay_count;
> +	bool is_ready;
> +	u32 val;
> +	u32 i;
> +
> +	/* set lanes value */
> +	val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
> +	writel(val, base + PHY_IF_CFG);
> +
> +	/* set phy clk division */
> +	val = readl(base + CLKMGR_CFG) | phy->clk_division;
> +	writel(val, base + CLKMGR_CFG);
> +
> +	/* clean up phy set param */
> +	writel(0, base + PHY_RSTZ);
> +	writel(0, base + PHY_TST_CTRL0);
> +	writel(1, base + PHY_TST_CTRL0);
> +	writel(0, base + PHY_TST_CTRL0);
> +
> +	/* clock lane Timing control - TLPX */
> +	dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
> +
> +	/* clock lane Timing control - THS-PREPARE */
> +	dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
> +
> +	/* clock lane Timing control - THS-ZERO */
> +	dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
> +
> +	/* clock lane Timing control - THS-TRAIL */
> +	dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
> +
> +	/* clock lane Timing control - TWAKEUP */
> +	dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
> +
> +	/* data lane */
> +	for (i = 0; i < lanes; i++) {
> +		/* Timing control - TLPX*/
> +		dsi_phy_tst_set(base, 0x10020 + (i << 4), phy->data_t_lpx);
> +
> +		/* Timing control - THS-PREPARE */
> +		dsi_phy_tst_set(base, 0x10021 + (i << 4),
> +				phy->data_t_hs_prepare);
> +
> +		/* Timing control - THS-ZERO */
> +		dsi_phy_tst_set(base, 0x10022 + (i << 4), phy->data_t_hs_zero);
> +
> +		/* Timing control - THS-TRAIL */
> +		dsi_phy_tst_set(base, 0x10023 + (i << 4), phy->data_t_hs_trial);
> +
> +		/* Timing control - TTA-GO */
> +		dsi_phy_tst_set(base, 0x10024 + (i << 4), phy->data_t_ta_go);
> +
> +		/* Timing control - TTA-GET */
> +		dsi_phy_tst_set(base, 0x10025 + (i << 4), phy->data_t_ta_get);
> +
> +		/*  Timing control - TWAKEUP */
> +		dsi_phy_tst_set(base, 0x10026 + (i << 4), phy->data_t_wakeup);
> +	}
> +
> +	/* physical configuration I  */
> +	dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
> +
> +	/* physical configuration pll II  */
> +	val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
> +				(phy->pll_fbd_2p << 1) + phy->pll_enbwt;
> +	dsi_phy_tst_set(base, 0x10063, val);
> +
> +	/* physical configuration pll II  */
> +	dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
> +
> +	/* physical configuration pll III  */
> +	dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
> +
> +	/*physical configuration pll IV*/
> +	val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
> +	dsi_phy_tst_set(base, 0x10066, val);
> +
> +	/*physical configuration pll V*/

It would be nice to fix the comment spacing for uniformity.

> +	val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
> +					phy->pll_lpf_cs + BIT(5);
> +	dsi_phy_tst_set(base, 0x10067, val);
> +
> +	writel(BIT(2), base + PHY_RSTZ);
> +	udelay(1);
> +	writel(BIT(2) | BIT(0), base + PHY_RSTZ);
> +	udelay(1);
> +	writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
> +	usleep_range(1000, 1500);
> +
> +	/* wait for phy's clock ready */
> +	delay_count = 0;
> +	is_ready = false;
> +	while (1) {
> +		val = readl(base +  PHY_STATUS);
> +		if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
> +			is_ready = (delay_count < 100) ? true : false;
> +			delay_count = 0;
> +			break;
> +		}
> +
> +		udelay(1);
> +		++delay_count;
> +	}

You could simplify this a bit:

	delay_count = 100
	while (delay_count) {
	...
	--delay_count;
	}

	if (!delay_count)
		DRM_INFO("...");
> +
> +	if (!is_ready)
> +		DRM_INFO("phylock and phystopstateclklane is not ready.\n");
> +}
> +
> +static void dsi_set_mode_timing(void __iomem *base,
> +				struct mipi_phy_register *phy,
> +				struct drm_display_mode *mode,
> +				enum mipi_dsi_pixel_format format)
> +{
> +	u32 hfp, hbp, hsw, vfp, vbp, vsw;
> +	u32 hline_time;
> +	u32 hsa_time;
> +	u32 hbp_time;
> +	u32 pixel_clk_kHz;
> +	int htot, vtot;
> +	u32 val;
> +
> +	/* DSI color coding setting */
> +	val = dsi_get_dpi_color_coding(format);
> +	writel(val, base + DPI_COLOR_CODING);
> +
> +	/* DSI format and pol setting */
> +	val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
> +	val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
> +	writel(val, base +  DPI_CFG_POL);
> +
> +	/*
> +	 * The DSI IP accepts vertical timing using lines as normal,
> +	 * but horizontal timing is a mixture of pixel-clocks for the
> +	 * active region and byte-lane clocks for the blanking-related
> +	 * timings.  hfp is specified as the total hline_time in byte-
> +	 * lane clocks minus hsa, hbp and active.
> +	 */
> +	pixel_clk_kHz = mode->clock;
> +	htot = mode->htotal;
> +	vtot = mode->vtotal;
> +	hfp = mode->hsync_start - mode->hdisplay;
> +	hbp = mode->htotal - mode->hsync_end;
> +	hsw = mode->hsync_end - mode->hsync_start;
> +	vfp = mode->vsync_start - mode->vdisplay;
> +	vbp = mode->vtotal - mode->vsync_end;
> +	vsw = mode->vsync_end - mode->vsync_start;
> +	if (vsw > 15) {
> +		DRM_INFO("vsw exceeded 15\n");
> +		vtot -= vsw - 15;
> +		vsw = 15;
> +	}
> +
> +	hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
> +	hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
> +	hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
> +		      pixel_clk_kHz;
> +
> +	if ((R(hline_time) / 1000) > htot) {
> +		DRM_INFO("--: hline_time=%d\n", hline_time);
> +		hline_time--;
> +	}
> +
> +	if ((R(hline_time) / 1000) < htot) {

Could we use a better macro name here? Also, it would be nice to pass
the phy argument to it too. Maybe even move the divide by 1000 in the macro.

> +		DRM_INFO("++: hline_time=%d\n", hline_time);
> +		hline_time++;
> +	}
> +
> +	/* all specified in byte-lane clocks */
> +	writel(hsa_time, base + VID_HSA_TIME);
> +	writel(hbp_time, base + VID_HBP_TIME);
> +	writel(hline_time, base + VID_HLINE_TIME);
> +
> +	writel(vsw, base + VID_VSA_LINES);
> +	writel(vbp, base + VID_VBP_LINES);
> +	writel(vfp, base + VID_VFP_LINES);
> +	writel(mode->vdisplay, base + VID_VACTIVE_LINES);
> +	writel(mode->hdisplay, base + VID_PKT_SIZE);
> +}
> +
> +static void dsi_set_video_mode_type(void __iomem *base,
> +				    struct mipi_phy_register *phy,
> +				    unsigned long flags)
> +{
> +	u32 val;
> +	u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
> +		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +	u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
> +		MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +	u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
> +
> +	/*
> +	 * choose video type
> +	 */
> +	if ((flags & mode_mask) == non_burst_sync_pulse)
> +		val = DSI_NON_BURST_SYNC_PULSES;
> +	else if ((flags & mode_mask) == non_burst_sync_event)
> +		val = DSI_NON_BURST_SYNC_EVENTS;
> +	else
> +		val = DSI_BURST_SYNC_PULSES_1;
> +
> +	writel(val, base + VID_MODE_CFG);
> +	/* TODO: to support LCD panel need to set LP command transfer */
> +}
> +
> +static void dsi_mipi_init(struct hisi_dsi *dsi)
> +{
> +	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	struct mipi_phy_register *phy = &dsi->phy;
> +	struct drm_display_mode *mode = &dsi->cur_mode;
> +	void __iomem *base = ctx->base;
> +	u32 dphy_freq_kHz;
> +
> +	/* count phy params */
> +	dphy_freq_kHz = mode->clock * 24 / dsi->lanes;

Maybe replace the 24 above with the bpp in use for future compatibility?

> +	set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
> +
> +	/* reset Core */
> +	writel(0, base + PWR_UP);
> +
> +	/* set phy clocks */
> +	dsi_mipi_phy_clks(base, phy, dsi->lanes);
> +
> +	/* set dsi mode */
> +	dsi_set_mode_timing(base, phy, mode, dsi->format);
> +
> +	/* set video mode type and low power */
> +	dsi_set_video_mode_type(base, phy, dsi->mode_flags);
> +
> +	/* DSI and D-PHY Initialization */
> +	writel(DSI_VIDEO_MODE, base + MODE_CFG);
> +	writel(BIT(0), base + LPCLK_CTRL);
> +	writel(BIT(0), base + PWR_UP);
> +}
> +
> +static void dsi_encoder_disable(struct drm_encoder *encoder)
> +{
> +	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
> +	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	void __iomem *base = ctx->base;
> +
> +	DRM_DEBUG_DRIVER("enter\n");
> +	if (!dsi->enable)
> +		return;
> +
> +	writel(0, base + PWR_UP);
> +	writel(0, base + LPCLK_CTRL);
> +	writel(0, base + PHY_RSTZ);
> +	clk_disable_unprepare(ctx->dsi_cfg_clk);
> +
> +	dsi->enable = false;
> +	DRM_DEBUG_DRIVER("exit success.\n");
> +}
> +
> +static void dsi_encoder_enable(struct drm_encoder *encoder)
> +{
> +	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
> +	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	int ret;
> +
> +	DRM_DEBUG_DRIVER("enter.\n");
> +	if (dsi->enable)
> +		return;
> +
> +	/* mipi dphy clock enable */
> +	ret = clk_prepare_enable(ctx->dsi_cfg_clk);
> +	if (ret) {
> +		DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
> +		return;
> +	}
> +
> +	dsi_mipi_init(dsi);
> +
> +	dsi->enable = true;
> +	DRM_DEBUG_DRIVER("exit success.\n");
> +}
> +
> +static void dsi_encoder_mode_set(struct drm_encoder *encoder,
> +				 struct drm_display_mode *mode,
> +				 struct drm_display_mode *adj_mode)
> +{
> +	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
> +
> +	DRM_DEBUG_DRIVER("enter.\n");
> +	drm_mode_copy(&dsi->cur_mode, adj_mode);
> +	DRM_DEBUG_DRIVER("exit success.\n");
> +}
> +
> +static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
> +				    struct drm_crtc_state *crtc_state,
> +				    struct drm_connector_state *conn_state)
> +{
> +	struct drm_display_mode *mode = &crtc_state->mode;
> +
> +	DRM_DEBUG_DRIVER("enter.\n");
> +	if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
> +		DRM_ERROR("not support INTERLACE mode\n");
> +		return MODE_NO_INTERLACE;
> +	}
> +
> +	/* pixel clock support range is (1190494208/64, 1190494208)Hz */
> +	if (mode->clock < 18602 || mode->clock > 1190494) {

I don't think we need to worry about the maximum limit if we support 
pixel clocks up to 1190 Mhz :)

> +		DRM_ERROR("mode clock not support\n");
> +		return MODE_CLOCK_RANGE;
> +	}
> +
> +	DRM_DEBUG_DRIVER("exit success.\n");
> +	return 0;
> +}
> +
> +static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
> +	.atomic_check	= dsi_encoder_atomic_check,
> +	.mode_set	= dsi_encoder_mode_set,
> +	.enable		= dsi_encoder_enable,
> +	.disable	= dsi_encoder_disable
> +};
> +
> +static const struct drm_encoder_funcs hisi_encoder_funcs = {
> +	.destroy = drm_encoder_cleanup,
> +};
> +
> +static int hisi_drm_encoder_init(struct drm_device *dev,
> +				 struct drm_encoder *encoder)
> +{
> +	int ret;
> +
> +	encoder->possible_crtcs = 1;
> +	ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
> +			       DRM_MODE_ENCODER_TMDS);

We should have the encoder as DRM_MODE_ENCODER_DSI here, even if the
connector is finally hdmi.

> +	if (ret) {
> +		DRM_ERROR("failed to init dsi encoder\n");
> +		return ret;
> +	}
> +
> +	drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
> +
> +	return 0;
> +}
> +
> +static int dsi_bind(struct device *dev, struct device *master, void *data)
> +{
> +	struct dsi_data *ddata = dev_get_drvdata(dev);
> +	struct hisi_dsi *dsi = &ddata->dsi;
> +	struct drm_device *drm_dev = data;
> +	int ret;
> +
> +	ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void dsi_unbind(struct device *dev, struct device *master, void *data)
> +{
> +	/* do nothing */
> +}
> +
> +static const struct component_ops dsi_ops = {
> +	.bind	= dsi_bind,
> +	.unbind	= dsi_unbind,
> +};
> +
> +static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
> +{
> +	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	struct resource *res;
> +
> +
> +	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
> +	if (IS_ERR(ctx->dsi_cfg_clk)) {
> +		DRM_ERROR("failed to get dsi plck clock\n");
> +		return PTR_ERR(ctx->dsi_cfg_clk);
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	ctx->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(ctx->base)) {
> +		DRM_ERROR("failed to remap dsi io region\n");
> +		return PTR_ERR(ctx->base);
> +	}
> +
> +	return 0;
> +}
> +
> +static int dsi_probe(struct platform_device *pdev)
> +{
> +	struct dsi_data *data;
> +	struct hisi_dsi *dsi;
> +	struct dsi_hw_ctx *ctx;
> +	int ret;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data) {
> +		DRM_ERROR("failed to allocate dsi data.\n");
> +		return -ENOMEM;
> +	}
> +	dsi = &data->dsi;
> +	ctx = &data->ctx;
> +	dsi->ctx = ctx;
> +
> +	ret = dsi_parse_dt(pdev, dsi);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, data);
> +
> +	return component_add(&pdev->dev, &dsi_ops);
> +}
> +
> +static int dsi_remove(struct platform_device *pdev)
> +{
> +	component_del(&pdev->dev, &dsi_ops);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id dsi_of_match[] = {
> +	{.compatible = "hisilicon,hi6220-dsi"},
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, dsi_of_match);
> +
> +static struct platform_driver dsi_driver = {
> +	.probe = dsi_probe,
> +	.remove = dsi_remove,
> +	.driver = {
> +		.name = "hisi-dsi",
> +		.owner = THIS_MODULE,
> +		.of_match_table = dsi_of_match,
> +	},
> +};
> +
> +module_platform_driver(dsi_driver);
> +
> +MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
> +MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
> +MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
> +MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
> new file mode 100644
> index 0000000..db8f9df
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
> @@ -0,0 +1,89 @@
> +/*
> + * Copyright (c) 2014-2015 Hisilicon Limited.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + */
> +
> +#ifndef __HISI_DSI_REG_H__
> +#define __HISI_DSI_REG_H__
> +
> +/*
> + * regs
> + */
> +#define  PWR_UP                  (0x4)   /* Core power-up */
> +#define  PHY_IF_CFG              (0xA4)  /* D-PHY interface configuration */
> +#define  CLKMGR_CFG              (0x8)   /* the internal clock dividers */
> +#define  PHY_RSTZ                (0xA0)  /* D-PHY reset control */
> +#define  PHY_TST_CTRL0           (0xB4)  /* D-PHY test interface control 0 */
> +#define  PHY_TST_CTRL1           (0xB8)  /* D-PHY test interface control 1 */
> +#define  DPI_VCID                (0xC)   /* DPI virtual channel id */
> +#define  DPI_COLOR_CODING        (0x10)  /* DPI color coding */
> +#define  DPI_CFG_POL             (0x14)  /* DPI polarity configuration */
> +#define  VID_HSA_TIME            (0x48)  /* Horizontal Sync Active time */
> +#define  VID_HBP_TIME            (0x4C)  /* Horizontal Back Porch time */
> +#define  VID_HLINE_TIME          (0x50)  /* Line time */
> +#define  VID_VSA_LINES           (0x54)  /* Vertical Sync Active period */
> +#define  VID_VBP_LINES           (0x58)  /* Vertical Back Porch period */
> +#define  VID_VFP_LINES           (0x5C)  /* Vertical Front Porch period */
> +#define  VID_VACTIVE_LINES       (0x60)  /* Vertical resolution */
> +#define  VID_PKT_SIZE            (0x3C)  /* Video packet size */
> +#define  VID_MODE_CFG            (0x38)  /* Video mode configuration */
> +#define  DPI_LP_CMD_TIM          (0x18)  /* Low-power command timing config */
> +#define  PHY_TMR_CFG             (0x9C)  /* Data lanes timing configuration */
> +#define  BTA_TO_CNT              (0x8C)  /* Response timeout definition */
> +#define  PHY_TMR_LPCLK_CFG       (0x98)  /* clock lane timing configuration */
> +#define  CLK_DATA_TMR_CFG        (0xCC)
> +#define  LPCLK_CTRL              (0x94)  /* Low-power in clock lane */
> +#define  PCKHDL_CFG              (0x2C)  /* Packet handler configuration */
> +#define  EDPI_CMD_SIZE           (0x64)  /* Size for eDPI packets */
> +#define  MODE_CFG                (0x34)  /* Video or Command mode selection */
> +#define  PHY_STATUS              (0xB0)  /* D-PHY PPI status interface */
> +
> +#define	PHY_STOP_WAIT_TIME      (0x30)
> +
> +/*
> + * regs relevant enum
> + */
> +enum dpi_color_coding {
> +	DSI_24BITS_1 = 5,
> +};
> +
> +enum dsi_video_mode_type {
> +	DSI_NON_BURST_SYNC_PULSES = 0,
> +	DSI_NON_BURST_SYNC_EVENTS,
> +	DSI_BURST_SYNC_PULSES_1,
> +	DSI_BURST_SYNC_PULSES_2
> +};
> +
> +enum dsi_work_mode {
> +	DSI_VIDEO_MODE = 0,
> +	DSI_COMMAND_MODE
> +};
> +
> +/*
> + * regs Write/Read functions
> + */
> +static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
> +{
> +	writel(reg, base + PHY_TST_CTRL1);
> +	/* reg addr written at first */
> +	wmb();
> +	writel(0x02, base + PHY_TST_CTRL0);
> +	/* cmd1 sent for write */
> +	wmb();
> +	writel(0x00, base + PHY_TST_CTRL0);
> +	/* cmd2 sent for write */
> +	wmb();
> +	writel(val, base + PHY_TST_CTRL1);
> +	/* Then write data */
> +	wmb();
> +	writel(0x02, base + PHY_TST_CTRL0);
> +	/* cmd2 sent for write */
> +	wmb();
> +	writel(0x00, base + PHY_TST_CTRL0);
> +}
> +

This doesn't look like something that should be inlined. Maybe move it 
to hisi_drm_dsi.c?

> +#endif /* __HISI_DRM_DSI_H__ */
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
  2015-11-28 10:39     ` Xinliang Liu
@ 2015-12-01  9:04       ` Archit Taneja
  -1 siblings, 0 replies; 70+ messages in thread
From: Archit Taneja @ 2015-12-01  9:04 UTC (permalink / raw)
  To: Xinliang Liu, dri-devel, devicetree, daniel, robh, daniel,
	airlied, corbet, catalin.marinas, will.deacon
  Cc: linux-doc, linux-arm-kernel, linuxarm, andy.green,
	haojian.zhuang, liguozhu, xuwei5, w.f, puck.chen, bintian.wang,
	benjamin.gaignard, xuyiping, kong.kongxinwei, zourongrong,
	lijianhua, sumit.semwal



On 11/28/2015 04:09 PM, Xinliang Liu wrote:
> Add support for external HDMI bridge.
>
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---
>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51 ++++++++++++++++++++++++++++++++
>   1 file changed, 51 insertions(+)
>
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> index 066e08d..9e056db 100644
> --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> @@ -78,6 +78,7 @@ struct dsi_hw_ctx {
>
>   struct hisi_dsi {
>   	struct drm_encoder encoder;
> +	struct drm_bridge *bridge;
>   	struct mipi_dsi_host host;
>   	struct drm_display_mode cur_mode;
>   	struct dsi_hw_ctx *ctx;
> @@ -671,6 +672,25 @@ 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)
> +{
> +	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");

s/exteranl/external

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>   static int dsi_bind(struct device *dev, struct device *master, void *data)
>   {
>   	struct dsi_data *ddata = dev_get_drvdata(dev);
> @@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
>   	if (ret)
>   		return ret;
>
> +	ret = dsi_bridge_init(drm_dev, dsi);
> +	if (ret)
> +		return ret;
> +
>   	return 0;
>   }
>
> @@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
>   static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
>   {
>   	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *endpoint, *bridge_node;
> +	struct drm_bridge *bridge;
>   	struct resource *res;
>
> +	/*
> +	 * Get the endpoint node. In our case, dsi has one output port
> +	 * to which the external HDMI bridge is connected.
> +	 */
> +	endpoint = of_graph_get_next_endpoint(np, NULL);
> +	if (!endpoint) {
> +		DRM_ERROR("no valid endpoint node\n");
> +		return -ENODEV;
> +	}
> +	of_node_put(endpoint);
> +
> +	bridge_node = of_graph_get_remote_port_parent(endpoint);
> +	if (!bridge_node) {
> +		DRM_ERROR("no valid bridge node\n");
> +		return -ENODEV;
> +	}
> +	of_node_put(bridge_node);
> +
> +	bridge = of_drm_find_bridge(bridge_node);
> +	if (!bridge) {
> +		DRM_INFO("wait for external HDMI bridge driver.\n");
> +		return -EPROBE_DEFER;
> +	}
> +	dsi->bridge = bridge;

This could be left for later, but it would be better if the dsi driver
registers even if the bridge driver module isn't inserted yet, or
happens much later in boot.

We could achieve this by trying to attach the bridge (done in 
dsi_bridge_init) in the dsi_host_attach callback instead of having it
in dsi_bind.

Thanks,
Archit

>
>   	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>   	if (IS_ERR(ctx->dsi_cfg_clk)) {
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
@ 2015-12-01  9:04       ` Archit Taneja
  0 siblings, 0 replies; 70+ messages in thread
From: Archit Taneja @ 2015-12-01  9:04 UTC (permalink / raw)
  To: linux-arm-kernel



On 11/28/2015 04:09 PM, Xinliang Liu wrote:
> Add support for external HDMI bridge.
>
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---
>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51 ++++++++++++++++++++++++++++++++
>   1 file changed, 51 insertions(+)
>
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> index 066e08d..9e056db 100644
> --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> @@ -78,6 +78,7 @@ struct dsi_hw_ctx {
>
>   struct hisi_dsi {
>   	struct drm_encoder encoder;
> +	struct drm_bridge *bridge;
>   	struct mipi_dsi_host host;
>   	struct drm_display_mode cur_mode;
>   	struct dsi_hw_ctx *ctx;
> @@ -671,6 +672,25 @@ 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)
> +{
> +	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");

s/exteranl/external

> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>   static int dsi_bind(struct device *dev, struct device *master, void *data)
>   {
>   	struct dsi_data *ddata = dev_get_drvdata(dev);
> @@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
>   	if (ret)
>   		return ret;
>
> +	ret = dsi_bridge_init(drm_dev, dsi);
> +	if (ret)
> +		return ret;
> +
>   	return 0;
>   }
>
> @@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
>   static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi *dsi)
>   {
>   	struct dsi_hw_ctx *ctx = dsi->ctx;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *endpoint, *bridge_node;
> +	struct drm_bridge *bridge;
>   	struct resource *res;
>
> +	/*
> +	 * Get the endpoint node. In our case, dsi has one output port
> +	 * to which the external HDMI bridge is connected.
> +	 */
> +	endpoint = of_graph_get_next_endpoint(np, NULL);
> +	if (!endpoint) {
> +		DRM_ERROR("no valid endpoint node\n");
> +		return -ENODEV;
> +	}
> +	of_node_put(endpoint);
> +
> +	bridge_node = of_graph_get_remote_port_parent(endpoint);
> +	if (!bridge_node) {
> +		DRM_ERROR("no valid bridge node\n");
> +		return -ENODEV;
> +	}
> +	of_node_put(bridge_node);
> +
> +	bridge = of_drm_find_bridge(bridge_node);
> +	if (!bridge) {
> +		DRM_INFO("wait for external HDMI bridge driver.\n");
> +		return -EPROBE_DEFER;
> +	}
> +	dsi->bridge = bridge;

This could be left for later, but it would be better if the dsi driver
registers even if the bridge driver module isn't inserted yet, or
happens much later in boot.

We could achieve this by trying to attach the bridge (done in 
dsi_bridge_init) in the dsi_host_attach callback instead of having it
in dsi_bind.

Thanks,
Archit

>
>   	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>   	if (IS_ERR(ctx->dsi_cfg_clk)) {
>

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 06/10] drm/hisilicon: Add vblank feature
  2015-12-01  7:13         ` Daniel Vetter
@ 2015-12-01 10:34           ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 10:34 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: dri-devel, devicetree, Rob Herring, Daniel Stone, architt,
	David Airlie, Jon Corbet, Catalin Marinas, Will Deacon,
	linux-doc, LAKML, linuxarm, Andy Green, Haojian Zhuang,
	Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong, zourongrong, lijianhua, Sumit Semwal

On 1 December 2015 at 15:13, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Tue, Dec 01, 2015 at 11:16:19AM +0800, Xinliang Liu wrote:
>> On 30 November 2015 at 15:54, Daniel Vetter <daniel@ffwll.ch> wrote:
>> > On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
>> >> Add vblank handle for ADE.
>> >>
>> >> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> >> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> >> Signed-off-by: Andy Green <andy.green@linaro.org>
>> >> ---
>> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
>> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
>> >>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
>> >>  3 files changed, 112 insertions(+), 1 deletion(-)
>> >>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
>> >>
>> >> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> >> index b0976c3..acb11e7 100644
>> >> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> >> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> >> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
>> >>       ctx->power_on = false;
>> >>  }
>> >>
>> >> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
>> >> +                                              unsigned int index)
>> >
>> > Ugly that you had to add this, but unfortunately necessary :( Fixing up
>> > the drm vblank hooks so that they deal with struct drm_crtc directly is
>> > somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
>> > ways off still.
>> >
>> > What might be possible as a follow-up cleanup though is to add
>> > vblank_enable and vblank_disable functions to struct
>> > drm_crtc_helper_funcs. And then provide this code here to map from int
>> > index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
>> > That might be a good intermediate step.
>>
>> I would like to have a try to make this intermediate step patch and
>> send out for review soon.
>
> Awesome, looking forward to reviewing it. If you have questions about
> details fastest to ping me on irc (nick: danvet, #dri-devel on
> freenode.net).

Great!  What't your time zone. So that I can ping you in right time.

Thanks,
-xinliang

>
> Cheers, Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 06/10] drm/hisilicon: Add vblank feature
@ 2015-12-01 10:34           ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 10:34 UTC (permalink / raw)
  To: linux-arm-kernel

On 1 December 2015 at 15:13, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Tue, Dec 01, 2015 at 11:16:19AM +0800, Xinliang Liu wrote:
>> On 30 November 2015 at 15:54, Daniel Vetter <daniel@ffwll.ch> wrote:
>> > On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
>> >> Add vblank handle for ADE.
>> >>
>> >> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> >> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> >> Signed-off-by: Andy Green <andy.green@linaro.org>
>> >> ---
>> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
>> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
>> >>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
>> >>  3 files changed, 112 insertions(+), 1 deletion(-)
>> >>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
>> >>
>> >> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> >> index b0976c3..acb11e7 100644
>> >> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> >> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
>> >> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
>> >>       ctx->power_on = false;
>> >>  }
>> >>
>> >> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
>> >> +                                              unsigned int index)
>> >
>> > Ugly that you had to add this, but unfortunately necessary :( Fixing up
>> > the drm vblank hooks so that they deal with struct drm_crtc directly is
>> > somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
>> > ways off still.
>> >
>> > What might be possible as a follow-up cleanup though is to add
>> > vblank_enable and vblank_disable functions to struct
>> > drm_crtc_helper_funcs. And then provide this code here to map from int
>> > index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
>> > That might be a good intermediate step.
>>
>> I would like to have a try to make this intermediate step patch and
>> send out for review soon.
>
> Awesome, looking forward to reviewing it. If you have questions about
> details fastest to ping me on irc (nick: danvet, #dri-devel on
> freenode.net).

Great!  What't your time zone. So that I can ping you in right time.

Thanks,
-xinliang

>
> Cheers, Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 08/10] drm/hisilicon: Add dsi encoder driver
  2015-12-01  8:58     ` Archit Taneja
@ 2015-12-01 11:16         ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 11:16 UTC (permalink / raw)
  To: Archit Taneja
  Cc: dri-devel, devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Vetter,
	Rob Herring, Daniel Stone, David Airlie, Jon Corbet,
	Catalin Marinas, Will Deacon, linux-doc-u79uwXL29TY76Z2rM5mHXA,
	LAKML, linuxarm-hv44wF8Li93QT0dZR+AlfA, Andy Green,
	Haojian Zhuang, Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong, zourongrong-hv44wF8Li93QT0dZR+AlfA,
	lijianhua-hv44wF8Li93QT0dZR+AlfA, Sumit Semwal

On 1 December 2015 at 16:58, Archit Taneja <architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org> wrote:

Hi Archit , thank you for review.

>
>
> On 11/28/2015 04:09 PM, Xinliang Liu wrote:
>>
>> Add dsi encoder driver for hi6220 SoC.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>
>> Signed-off-by: Andy Green <andy.green-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> ---
>>   drivers/gpu/drm/hisilicon/Kconfig        |   1 +
>>   drivers/gpu/drm/hisilicon/Makefile       |   3 +-
>>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 728
>> +++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hisi_dsi_reg.h |  89 ++++
>>   4 files changed, 820 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/Kconfig
>> b/drivers/gpu/drm/hisilicon/Kconfig
>> index 70aa8d1..f1c33c2 100644
>> --- a/drivers/gpu/drm/hisilicon/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/Kconfig
>> @@ -4,6 +4,7 @@ config DRM_HISI
>>         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.
>> diff --git a/drivers/gpu/drm/hisilicon/Makefile
>> b/drivers/gpu/drm/hisilicon/Makefile
>> index 3433c8b..5083c1f 100644
>> --- a/drivers/gpu/drm/hisilicon/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/Makefile
>> @@ -1,4 +1,5 @@
>>   hisi-drm-y := hisi_drm_drv.o \
>> -             hisi_drm_ade.o
>> +             hisi_drm_ade.o \
>> +             hisi_drm_dsi.o
>>
>>   obj-$(CONFIG_DRM_HISI)        += hisi-drm.o
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> new file mode 100644
>> index 0000000..7a6cf66
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> @@ -0,0 +1,728 @@
>> +/*
>> + * Hisilicon hi6220 SoC dsi driver
>> + *
>> + * Copyright (c) 2014-2015 Hisilicon Limited.
>> + * Author:
>> + *     Xinliang Liu <xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> + *     Xinliang Liu <z.liuxinliang-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>
>> + *     Xinwei Kong <kong.kongxinwei-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/component.h>
>> +#include <linux/of_graph.h>
>> +
>> +#include <drm/drm_crtc_helper.h>
>> +#include <drm/drm_mipi_dsi.h>
>> +#include <drm/drm_encoder_slave.h>
>> +#include <drm/drm_atomic_helper.h>
>> +
>> +#include "hisi_dsi_reg.h"
>> +
>> +#define MAX_TX_ESC_CLK            (10)
>> +#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
>> +#define DEFAULT_MIPI_CLK_RATE   19200000
>> +#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE /
>> 1000))
>> +#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
>> +             phy->lane_byte_clk_kHz)))
>> +
>> +#define encoder_to_dsi(encoder) \
>> +       container_of(encoder, struct hisi_dsi, encoder)
>> +#define host_to_dsi(host) \
>> +       container_of(host, struct hisi_dsi, host)
>> +
>> +struct mipi_phy_register {
>> +       u32 clk_t_lpx;
>> +       u32 clk_t_hs_prepare;
>> +       u32 clk_t_hs_zero;
>> +       u32 clk_t_hs_trial;
>> +       u32 clk_t_wakeup;
>> +       u32 data_t_lpx;
>> +       u32 data_t_hs_prepare;
>> +       u32 data_t_hs_zero;
>> +       u32 data_t_hs_trial;
>> +       u32 data_t_ta_go;
>> +       u32 data_t_ta_get;
>> +       u32 data_t_wakeup;
>> +       u32 hstx_ckg_sel;
>> +       u32 pll_fbd_div5f;
>> +       u32 pll_fbd_div1f;
>> +       u32 pll_fbd_2p;
>> +       u32 pll_enbwt;
>> +       u32 pll_fbd_p;
>> +       u32 pll_fbd_s;
>> +       u32 pll_pre_div1p;
>> +       u32 pll_pre_p;
>> +       u32 pll_vco_750M;
>> +       u32 pll_lpf_rs;
>> +       u32 pll_lpf_cs;
>> +       u32 clklp2hs_time;
>> +       u32 clkhs2lp_time;
>> +       u32 lp2hs_time;
>> +       u32 hs2lp_time;
>> +       u32 clk_to_data_delay;
>> +       u32 data_to_clk_delay;
>> +       u32 lane_byte_clk_kHz;
>> +       u32 clk_division;
>> +};
>> +
>> +struct dsi_hw_ctx {
>> +       void __iomem *base;
>> +       struct clk *dsi_cfg_clk;
>> +};
>> +
>> +struct hisi_dsi {
>> +       struct drm_encoder encoder;
>> +       struct drm_display_mode cur_mode;
>> +       struct dsi_hw_ctx *ctx;
>> +       struct mipi_phy_register phy;
>> +
>> +       u32 lanes;
>> +       enum mipi_dsi_pixel_format format;
>> +       unsigned long mode_flags;
>> +       bool enable;
>> +};
>> +
>> +struct dsi_data {
>> +       struct hisi_dsi dsi;
>> +       struct dsi_hw_ctx ctx;
>> +};
>> +
>> +struct dsi_phy_seq_info {
>> +       u32 min_range_kHz;
>> +       u32 max_range_kHz;
>> +       u32 pll_vco_750M;
>> +       u32 hstx_ckg_sel;
>> +};
>> +
>> +static const struct dsi_phy_seq_info dphy_seq_info[] = {
>> +       {   46000,    62000,   1,    7 },
>> +       {   62000,    93000,   0,    7 },
>> +       {   93000,   125000,   1,    6 },
>> +       {  125000,   187000,   0,    6 },
>> +       {  187000,   250000,   1,    5 },
>> +       {  250000,   375000,   0,    5 },
>> +       {  375000,   500000,   1,    4 },
>> +       {  500000,   750000,   0,    4 },
>> +       {  750000,  1000000,   1,    0 },
>> +       { 1000000,  1500000,   0,    0 }
>> +};
>> +
>> +static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
>> +                                            struct mipi_phy_register
>> *phy)
>> +{
>> +       u32 ui = 0;
>> +       u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
>> +       u32 i = 0;
>> +       u32 q_pll = 1;
>> +       u32 m_pll = 0;
>> +       u32 n_pll = 0;
>> +       u32 r_pll = 1;
>> +       u32 m_n = 0;
>> +       u32 m_n_int = 0;
>> +       u64 f_kHz;
>> +       u64 temp;
>> +       u64 tmp_kHz = phy_freq_kHz;
>> +
>> +       do {
>> +               f_kHz = tmp_kHz;
>> +
>> +               /* Find the PLL clock range from the table */
>> +               for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
>> +                       if (f_kHz > dphy_seq_info[i].min_range_kHz &&
>> +                           f_kHz <= dphy_seq_info[i].max_range_kHz)
>> +                               break;
>> +
>> +               if (i == ARRAY_SIZE(dphy_seq_info)) {
>> +                       DRM_ERROR("%lldkHz out of range\n", f_kHz);
>> +                       return;
>> +               }
>> +
>> +               phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
>> +               phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
>> +
>> +               if (phy->hstx_ckg_sel <= 7 &&
>> +                   phy->hstx_ckg_sel >= 4)
>> +                       q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
>> +
>> +               temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
>> +               m_n_int = temp / (u64)1000000000;
>> +               m_n = (temp % (u64)1000000000) / (u64)100000000;
>> +
>> +               if (m_n_int % 2 == 0) {
>> +                       if (m_n * 6 >= 50) {
>> +                               n_pll = 2;
>> +                               m_pll = (m_n_int + 1) * n_pll;
>> +                       } else if (m_n * 6 >= 30) {
>> +                               n_pll = 3;
>> +                               m_pll = m_n_int * n_pll + 2;
>> +                       } else {
>> +                               n_pll = 1;
>> +                               m_pll = m_n_int * n_pll;
>> +                       }
>> +               } else {
>> +                       if (m_n * 6 >= 50) {
>> +                               n_pll = 1;
>> +                               m_pll = (m_n_int + 1) * n_pll;
>> +                       } else if (m_n * 6 >= 30) {
>> +                               n_pll = 1;
>> +                               m_pll = (m_n_int + 1) * n_pll;
>> +                       } else if (m_n * 6 >= 10) {
>> +                               n_pll = 3;
>> +                               m_pll = m_n_int * n_pll + 1;
>> +                       } else {
>> +                               n_pll = 2;
>> +                               m_pll = m_n_int * n_pll;
>> +                       }
>> +               }
>> +
>> +               if (n_pll == 1) {
>> +                       phy->pll_fbd_p = 0;
>> +                       phy->pll_pre_div1p = 1;
>> +               } else {
>> +                       phy->pll_fbd_p = n_pll;
>> +                       phy->pll_pre_div1p = 0;
>> +               }
>> +
>> +               if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
>> +                       r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
>> +
>> +               if (m_pll == 2) {
>> +                       phy->pll_pre_p = 0;
>> +                       phy->pll_fbd_s = 0;
>> +                       phy->pll_fbd_div1f = 0;
>> +                       phy->pll_fbd_div5f = 1;
>> +               } else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 *
>> r_pll) {
>> +                       phy->pll_pre_p = m_pll / (2 * r_pll);
>> +                       phy->pll_fbd_s = 0;
>> +                       phy->pll_fbd_div1f = 1;
>> +                       phy->pll_fbd_div5f = 0;
>> +               } else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 *
>> r_pll) {
>> +                       if (((m_pll / (2 * r_pll)) % 2) == 0) {
>> +                               phy->pll_pre_p =
>> +                                       (m_pll / (2 * r_pll)) / 2 - 1;
>> +                               phy->pll_fbd_s =
>> +                                       (m_pll / (2 * r_pll)) % 2 + 2;
>> +                       } else {
>> +                               phy->pll_pre_p =
>> +                                       (m_pll / (2 * r_pll)) / 2;
>> +                               phy->pll_fbd_s =
>> +                                       (m_pll / (2 * r_pll)) % 2;
>> +                       }
>> +                       phy->pll_fbd_div1f = 0;
>> +                       phy->pll_fbd_div5f = 0;
>> +               } else {
>> +                       phy->pll_pre_p = 0;
>> +                       phy->pll_fbd_s = 0;
>> +                       phy->pll_fbd_div1f = 0;
>> +                       phy->pll_fbd_div5f = 1;
>> +               }
>> +
>> +               f_kHz = (u64)1000000000 * (u64)m_pll /
>> +                       ((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
>> +
>> +               if (f_kHz >= phy_freq_kHz)
>> +                       break;
>> +
>> +               tmp_kHz += 10;
>> +
>> +       } while (1);
>> +
>> +       ui = 1000000 / f_kHz;
>> +
>> +       phy->clk_t_lpx = ROUND(50, 8 * ui);
>> +       phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
>> +
>> +       phy->clk_t_hs_zero = ROUND(262, 8 * ui);
>> +       phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
>> +       phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
>> +       if (phy->clk_t_wakeup > 0xff)
>> +               phy->clk_t_wakeup = 0xff;
>> +       phy->data_t_wakeup = phy->clk_t_wakeup;
>> +       phy->data_t_lpx = phy->clk_t_lpx;
>> +       phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
>> +       phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
>> +       phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
>> +       phy->data_t_ta_go = 3;
>> +       phy->data_t_ta_get = 4;
>> +
>> +       phy->pll_enbwt = 1;
>> +       phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
>> +       phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
>> +       phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
>> +       phy->hs2lp_time = phy->clkhs2lp_time;
>> +       phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
>> +       phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
>> +                               phy->clkhs2lp_time;
>> +
>> +       phy->lane_byte_clk_kHz = f_kHz / 8;
>> +       phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
>> +       if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
>> +               phy->clk_division++;
>> +}
>> +
>> +static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
>> +{
>> +       u32 val;
>> +
>> +       /* TODO: only support RGB888 now, to support more */
>> +       switch (format) {
>> +       case MIPI_DSI_FMT_RGB888:
>> +               val = DSI_24BITS_1;
>> +               break;
>> +       default:
>> +               val = DSI_24BITS_1;
>> +               break;
>> +       }
>> +
>> +       return val;
>> +}
>> +
>> +static void dsi_mipi_phy_clks(void __iomem *base,
>> +                             struct mipi_phy_register *phy,
>> +                             u32 lanes)
>> +{
>> +       u32 delay_count;
>> +       bool is_ready;
>> +       u32 val;
>> +       u32 i;
>> +
>> +       /* set lanes value */
>> +       val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
>> +       writel(val, base + PHY_IF_CFG);
>> +
>> +       /* set phy clk division */
>> +       val = readl(base + CLKMGR_CFG) | phy->clk_division;
>> +       writel(val, base + CLKMGR_CFG);
>> +
>> +       /* clean up phy set param */
>> +       writel(0, base + PHY_RSTZ);
>> +       writel(0, base + PHY_TST_CTRL0);
>> +       writel(1, base + PHY_TST_CTRL0);
>> +       writel(0, base + PHY_TST_CTRL0);
>> +
>> +       /* clock lane Timing control - TLPX */
>> +       dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
>> +
>> +       /* clock lane Timing control - THS-PREPARE */
>> +       dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
>> +
>> +       /* clock lane Timing control - THS-ZERO */
>> +       dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
>> +
>> +       /* clock lane Timing control - THS-TRAIL */
>> +       dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
>> +
>> +       /* clock lane Timing control - TWAKEUP */
>> +       dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
>> +
>> +       /* data lane */
>> +       for (i = 0; i < lanes; i++) {
>> +               /* Timing control - TLPX*/
>> +               dsi_phy_tst_set(base, 0x10020 + (i << 4),
>> phy->data_t_lpx);
>> +
>> +               /* Timing control - THS-PREPARE */
>> +               dsi_phy_tst_set(base, 0x10021 + (i << 4),
>> +                               phy->data_t_hs_prepare);
>> +
>> +               /* Timing control - THS-ZERO */
>> +               dsi_phy_tst_set(base, 0x10022 + (i << 4),
>> phy->data_t_hs_zero);
>> +
>> +               /* Timing control - THS-TRAIL */
>> +               dsi_phy_tst_set(base, 0x10023 + (i << 4),
>> phy->data_t_hs_trial);
>> +
>> +               /* Timing control - TTA-GO */
>> +               dsi_phy_tst_set(base, 0x10024 + (i << 4),
>> phy->data_t_ta_go);
>> +
>> +               /* Timing control - TTA-GET */
>> +               dsi_phy_tst_set(base, 0x10025 + (i << 4),
>> phy->data_t_ta_get);
>> +
>> +               /*  Timing control - TWAKEUP */
>> +               dsi_phy_tst_set(base, 0x10026 + (i << 4),
>> phy->data_t_wakeup);
>> +       }
>> +
>> +       /* physical configuration I  */
>> +       dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
>> +
>> +       /* physical configuration pll II  */
>> +       val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
>> +                               (phy->pll_fbd_2p << 1) + phy->pll_enbwt;
>> +       dsi_phy_tst_set(base, 0x10063, val);
>> +
>> +       /* physical configuration pll II  */
>> +       dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
>> +
>> +       /* physical configuration pll III  */
>> +       dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
>> +
>> +       /*physical configuration pll IV*/
>> +       val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
>> +       dsi_phy_tst_set(base, 0x10066, val);
>> +
>> +       /*physical configuration pll V*/
>
>
> It would be nice to fix the comment spacing for uniformity.
>

will be fixed in v3.

>
>> +       val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
>> +                                       phy->pll_lpf_cs + BIT(5);
>> +       dsi_phy_tst_set(base, 0x10067, val);
>> +
>> +       writel(BIT(2), base + PHY_RSTZ);
>> +       udelay(1);
>> +       writel(BIT(2) | BIT(0), base + PHY_RSTZ);
>> +       udelay(1);
>> +       writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
>> +       usleep_range(1000, 1500);
>> +
>> +       /* wait for phy's clock ready */
>> +       delay_count = 0;
>> +       is_ready = false;
>> +       while (1) {
>> +               val = readl(base +  PHY_STATUS);
>> +               if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
>> +                       is_ready = (delay_count < 100) ? true : false;
>> +                       delay_count = 0;
>> +                       break;
>> +               }
>> +
>> +               udelay(1);
>> +               ++delay_count;
>> +       }
>
>
> You could simplify this a bit:
>
>         delay_count = 100
>         while (delay_count) {
>         ...
>         --delay_count;
>         }
>
>         if (!delay_count)
>                 DRM_INFO("...");
>

Great! This looks much more clearly. will be fixed in v3.

>> +
>> +       if (!is_ready)
>> +               DRM_INFO("phylock and phystopstateclklane is not
>> ready.\n");
>> +}
>> +
>> +static void dsi_set_mode_timing(void __iomem *base,
>> +                               struct mipi_phy_register *phy,
>> +                               struct drm_display_mode *mode,
>> +                               enum mipi_dsi_pixel_format format)
>> +{
>> +       u32 hfp, hbp, hsw, vfp, vbp, vsw;
>> +       u32 hline_time;
>> +       u32 hsa_time;
>> +       u32 hbp_time;
>> +       u32 pixel_clk_kHz;
>> +       int htot, vtot;
>> +       u32 val;
>> +
>> +       /* DSI color coding setting */
>> +       val = dsi_get_dpi_color_coding(format);
>> +       writel(val, base + DPI_COLOR_CODING);
>> +
>> +       /* DSI format and pol setting */
>> +       val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
>> +       val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
>> +       writel(val, base +  DPI_CFG_POL);
>> +
>> +       /*
>> +        * The DSI IP accepts vertical timing using lines as normal,
>> +        * but horizontal timing is a mixture of pixel-clocks for the
>> +        * active region and byte-lane clocks for the blanking-related
>> +        * timings.  hfp is specified as the total hline_time in byte-
>> +        * lane clocks minus hsa, hbp and active.
>> +        */
>> +       pixel_clk_kHz = mode->clock;
>> +       htot = mode->htotal;
>> +       vtot = mode->vtotal;
>> +       hfp = mode->hsync_start - mode->hdisplay;
>> +       hbp = mode->htotal - mode->hsync_end;
>> +       hsw = mode->hsync_end - mode->hsync_start;
>> +       vfp = mode->vsync_start - mode->vdisplay;
>> +       vbp = mode->vtotal - mode->vsync_end;
>> +       vsw = mode->vsync_end - mode->vsync_start;
>> +       if (vsw > 15) {
>> +               DRM_INFO("vsw exceeded 15\n");
>> +               vtot -= vsw - 15;
>> +               vsw = 15;
>> +       }
>> +
>> +       hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
>> +       hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
>> +       hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
>> +                     pixel_clk_kHz;
>> +
>> +       if ((R(hline_time) / 1000) > htot) {
>> +               DRM_INFO("--: hline_time=%d\n", hline_time);
>> +               hline_time--;
>> +       }
>> +
>> +       if ((R(hline_time) / 1000) < htot) {
>
>
> Could we use a better macro name here? Also, it would be nice to pass
> the phy argument to it too. Maybe even move the divide by 1000 in the macro.
>

Great idea! will be fixed in v3.

>
>> +               DRM_INFO("++: hline_time=%d\n", hline_time);
>> +               hline_time++;
>> +       }
>> +
>> +       /* all specified in byte-lane clocks */
>> +       writel(hsa_time, base + VID_HSA_TIME);
>> +       writel(hbp_time, base + VID_HBP_TIME);
>> +       writel(hline_time, base + VID_HLINE_TIME);
>> +
>> +       writel(vsw, base + VID_VSA_LINES);
>> +       writel(vbp, base + VID_VBP_LINES);
>> +       writel(vfp, base + VID_VFP_LINES);
>> +       writel(mode->vdisplay, base + VID_VACTIVE_LINES);
>> +       writel(mode->hdisplay, base + VID_PKT_SIZE);
>> +}
>> +
>> +static void dsi_set_video_mode_type(void __iomem *base,
>> +                                   struct mipi_phy_register *phy,
>> +                                   unsigned long flags)
>> +{
>> +       u32 val;
>> +       u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
>> +               MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> +       u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
>> +               MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> +       u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
>> +
>> +       /*
>> +        * choose video type
>> +        */
>> +       if ((flags & mode_mask) == non_burst_sync_pulse)
>> +               val = DSI_NON_BURST_SYNC_PULSES;
>> +       else if ((flags & mode_mask) == non_burst_sync_event)
>> +               val = DSI_NON_BURST_SYNC_EVENTS;
>> +       else
>> +               val = DSI_BURST_SYNC_PULSES_1;
>> +
>> +       writel(val, base + VID_MODE_CFG);
>> +       /* TODO: to support LCD panel need to set LP command transfer */
>> +}
>> +
>> +static void dsi_mipi_init(struct hisi_dsi *dsi)
>> +{
>> +       struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       struct mipi_phy_register *phy = &dsi->phy;
>> +       struct drm_display_mode *mode = &dsi->cur_mode;
>> +       void __iomem *base = ctx->base;
>> +       u32 dphy_freq_kHz;
>> +
>> +       /* count phy params */
>> +       dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
>
>
> Maybe replace the 24 above with the bpp in use for future compatibility?
>

Yes, it is bpp. will be replaced by bpp in v3.

>
>> +       set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
>> +
>> +       /* reset Core */
>> +       writel(0, base + PWR_UP);
>> +
>> +       /* set phy clocks */
>> +       dsi_mipi_phy_clks(base, phy, dsi->lanes);
>> +
>> +       /* set dsi mode */
>> +       dsi_set_mode_timing(base, phy, mode, dsi->format);
>> +
>> +       /* set video mode type and low power */
>> +       dsi_set_video_mode_type(base, phy, dsi->mode_flags);
>> +
>> +       /* DSI and D-PHY Initialization */
>> +       writel(DSI_VIDEO_MODE, base + MODE_CFG);
>> +       writel(BIT(0), base + LPCLK_CTRL);
>> +       writel(BIT(0), base + PWR_UP);
>> +}
>> +
>> +static void dsi_encoder_disable(struct drm_encoder *encoder)
>> +{
>> +       struct hisi_dsi *dsi = encoder_to_dsi(encoder);
>> +       struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       void __iomem *base = ctx->base;
>> +
>> +       DRM_DEBUG_DRIVER("enter\n");
>> +       if (!dsi->enable)
>> +               return;
>> +
>> +       writel(0, base + PWR_UP);
>> +       writel(0, base + LPCLK_CTRL);
>> +       writel(0, base + PHY_RSTZ);
>> +       clk_disable_unprepare(ctx->dsi_cfg_clk);
>> +
>> +       dsi->enable = false;
>> +       DRM_DEBUG_DRIVER("exit success.\n");
>> +}
>> +
>> +static void dsi_encoder_enable(struct drm_encoder *encoder)
>> +{
>> +       struct hisi_dsi *dsi = encoder_to_dsi(encoder);
>> +       struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       int ret;
>> +
>> +       DRM_DEBUG_DRIVER("enter.\n");
>> +       if (dsi->enable)
>> +               return;
>> +
>> +       /* mipi dphy clock enable */
>> +       ret = clk_prepare_enable(ctx->dsi_cfg_clk);
>> +       if (ret) {
>> +               DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
>> +               return;
>> +       }
>> +
>> +       dsi_mipi_init(dsi);
>> +
>> +       dsi->enable = true;
>> +       DRM_DEBUG_DRIVER("exit success.\n");
>> +}
>> +
>> +static void dsi_encoder_mode_set(struct drm_encoder *encoder,
>> +                                struct drm_display_mode *mode,
>> +                                struct drm_display_mode *adj_mode)
>> +{
>> +       struct hisi_dsi *dsi = encoder_to_dsi(encoder);
>> +
>> +       DRM_DEBUG_DRIVER("enter.\n");
>> +       drm_mode_copy(&dsi->cur_mode, adj_mode);
>> +       DRM_DEBUG_DRIVER("exit success.\n");
>> +}
>> +
>> +static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
>> +                                   struct drm_crtc_state *crtc_state,
>> +                                   struct drm_connector_state
>> *conn_state)
>> +{
>> +       struct drm_display_mode *mode = &crtc_state->mode;
>> +
>> +       DRM_DEBUG_DRIVER("enter.\n");
>> +       if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
>> +               DRM_ERROR("not support INTERLACE mode\n");
>> +               return MODE_NO_INTERLACE;
>> +       }
>> +
>> +       /* pixel clock support range is (1190494208/64, 1190494208)Hz */
>> +       if (mode->clock < 18602 || mode->clock > 1190494) {
>
>
> I don't think we need to worry about the maximum limit if we support pixel
> clocks up to 1190 Mhz :)

yea, 1190Mhz is too larger.  will be fixed in v3.

>
>
>> +               DRM_ERROR("mode clock not support\n");
>> +               return MODE_CLOCK_RANGE;
>> +       }
>> +
>> +       DRM_DEBUG_DRIVER("exit success.\n");
>> +       return 0;
>> +}
>> +
>> +static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs =
>> {
>> +       .atomic_check   = dsi_encoder_atomic_check,
>> +       .mode_set       = dsi_encoder_mode_set,
>> +       .enable         = dsi_encoder_enable,
>> +       .disable        = dsi_encoder_disable
>> +};
>> +
>> +static const struct drm_encoder_funcs hisi_encoder_funcs = {
>> +       .destroy = drm_encoder_cleanup,
>> +};
>> +
>> +static int hisi_drm_encoder_init(struct drm_device *dev,
>> +                                struct drm_encoder *encoder)
>> +{
>> +       int ret;
>> +
>> +       encoder->possible_crtcs = 1;
>> +       ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
>> +                              DRM_MODE_ENCODER_TMDS);
>
>
> We should have the encoder as DRM_MODE_ENCODER_DSI here, even if the
> connector is finally hdmi.

Correct! will be fixed in v3.

>
>
>> +       if (ret) {
>> +               DRM_ERROR("failed to init dsi encoder\n");
>> +               return ret;
>> +       }
>> +
>> +       drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
>> +
>> +       return 0;
>> +}
>> +
>> +static int dsi_bind(struct device *dev, struct device *master, void
>> *data)
>> +{
>> +       struct dsi_data *ddata = dev_get_drvdata(dev);
>> +       struct hisi_dsi *dsi = &ddata->dsi;
>> +       struct drm_device *drm_dev = data;
>> +       int ret;
>> +
>> +       ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
>> +       if (ret)
>> +               return ret;
>> +
>> +       return 0;
>> +}
>> +
>> +static void dsi_unbind(struct device *dev, struct device *master, void
>> *data)
>> +{
>> +       /* do nothing */
>> +}
>> +
>> +static const struct component_ops dsi_ops = {
>> +       .bind   = dsi_bind,
>> +       .unbind = dsi_unbind,
>> +};
>> +
>> +static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi
>> *dsi)
>> +{
>> +       struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       struct resource *res;
>> +
>> +
>> +       ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>> +       if (IS_ERR(ctx->dsi_cfg_clk)) {
>> +               DRM_ERROR("failed to get dsi plck clock\n");
>> +               return PTR_ERR(ctx->dsi_cfg_clk);
>> +       }
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       ctx->base = devm_ioremap_resource(&pdev->dev, res);
>> +       if (IS_ERR(ctx->base)) {
>> +               DRM_ERROR("failed to remap dsi io region\n");
>> +               return PTR_ERR(ctx->base);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int dsi_probe(struct platform_device *pdev)
>> +{
>> +       struct dsi_data *data;
>> +       struct hisi_dsi *dsi;
>> +       struct dsi_hw_ctx *ctx;
>> +       int ret;
>> +
>> +       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>> +       if (!data) {
>> +               DRM_ERROR("failed to allocate dsi data.\n");
>> +               return -ENOMEM;
>> +       }
>> +       dsi = &data->dsi;
>> +       ctx = &data->ctx;
>> +       dsi->ctx = ctx;
>> +
>> +       ret = dsi_parse_dt(pdev, dsi);
>> +       if (ret)
>> +               return ret;
>> +
>> +       platform_set_drvdata(pdev, data);
>> +
>> +       return component_add(&pdev->dev, &dsi_ops);
>> +}
>> +
>> +static int dsi_remove(struct platform_device *pdev)
>> +{
>> +       component_del(&pdev->dev, &dsi_ops);
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct of_device_id dsi_of_match[] = {
>> +       {.compatible = "hisilicon,hi6220-dsi"},
>> +       { }
>> +};
>> +MODULE_DEVICE_TABLE(of, dsi_of_match);
>> +
>> +static struct platform_driver dsi_driver = {
>> +       .probe = dsi_probe,
>> +       .remove = dsi_remove,
>> +       .driver = {
>> +               .name = "hisi-dsi",
>> +               .owner = THIS_MODULE,
>> +               .of_match_table = dsi_of_match,
>> +       },
>> +};
>> +
>> +module_platform_driver(dsi_driver);
>> +
>> +MODULE_AUTHOR("Xinliang Liu <xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>");
>> +MODULE_AUTHOR("Xinliang Liu <z.liuxinliang-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>");
>> +MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>");
>> +MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>> b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>> new file mode 100644
>> index 0000000..db8f9df
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>> @@ -0,0 +1,89 @@
>> +/*
>> + * Copyright (c) 2014-2015 Hisilicon Limited.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#ifndef __HISI_DSI_REG_H__
>> +#define __HISI_DSI_REG_H__
>> +
>> +/*
>> + * regs
>> + */
>> +#define  PWR_UP                  (0x4)   /* Core power-up */
>> +#define  PHY_IF_CFG              (0xA4)  /* D-PHY interface configuration
>> */
>> +#define  CLKMGR_CFG              (0x8)   /* the internal clock dividers
>> */
>> +#define  PHY_RSTZ                (0xA0)  /* D-PHY reset control */
>> +#define  PHY_TST_CTRL0           (0xB4)  /* D-PHY test interface control
>> 0 */
>> +#define  PHY_TST_CTRL1           (0xB8)  /* D-PHY test interface control
>> 1 */
>> +#define  DPI_VCID                (0xC)   /* DPI virtual channel id */
>> +#define  DPI_COLOR_CODING        (0x10)  /* DPI color coding */
>> +#define  DPI_CFG_POL             (0x14)  /* DPI polarity configuration */
>> +#define  VID_HSA_TIME            (0x48)  /* Horizontal Sync Active time
>> */
>> +#define  VID_HBP_TIME            (0x4C)  /* Horizontal Back Porch time */
>> +#define  VID_HLINE_TIME          (0x50)  /* Line time */
>> +#define  VID_VSA_LINES           (0x54)  /* Vertical Sync Active period
>> */
>> +#define  VID_VBP_LINES           (0x58)  /* Vertical Back Porch period */
>> +#define  VID_VFP_LINES           (0x5C)  /* Vertical Front Porch period
>> */
>> +#define  VID_VACTIVE_LINES       (0x60)  /* Vertical resolution */
>> +#define  VID_PKT_SIZE            (0x3C)  /* Video packet size */
>> +#define  VID_MODE_CFG            (0x38)  /* Video mode configuration */
>> +#define  DPI_LP_CMD_TIM          (0x18)  /* Low-power command timing
>> config */
>> +#define  PHY_TMR_CFG             (0x9C)  /* Data lanes timing
>> configuration */
>> +#define  BTA_TO_CNT              (0x8C)  /* Response timeout definition
>> */
>> +#define  PHY_TMR_LPCLK_CFG       (0x98)  /* clock lane timing
>> configuration */
>> +#define  CLK_DATA_TMR_CFG        (0xCC)
>> +#define  LPCLK_CTRL              (0x94)  /* Low-power in clock lane */
>> +#define  PCKHDL_CFG              (0x2C)  /* Packet handler configuration
>> */
>> +#define  EDPI_CMD_SIZE           (0x64)  /* Size for eDPI packets */
>> +#define  MODE_CFG                (0x34)  /* Video or Command mode
>> selection */
>> +#define  PHY_STATUS              (0xB0)  /* D-PHY PPI status interface */
>> +
>> +#define        PHY_STOP_WAIT_TIME      (0x30)
>> +
>> +/*
>> + * regs relevant enum
>> + */
>> +enum dpi_color_coding {
>> +       DSI_24BITS_1 = 5,
>> +};
>> +
>> +enum dsi_video_mode_type {
>> +       DSI_NON_BURST_SYNC_PULSES = 0,
>> +       DSI_NON_BURST_SYNC_EVENTS,
>> +       DSI_BURST_SYNC_PULSES_1,
>> +       DSI_BURST_SYNC_PULSES_2
>> +};
>> +
>> +enum dsi_work_mode {
>> +       DSI_VIDEO_MODE = 0,
>> +       DSI_COMMAND_MODE
>> +};
>> +
>> +/*
>> + * regs Write/Read functions
>> + */
>> +static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
>> +{
>> +       writel(reg, base + PHY_TST_CTRL1);
>> +       /* reg addr written at first */
>> +       wmb();
>> +       writel(0x02, base + PHY_TST_CTRL0);
>> +       /* cmd1 sent for write */
>> +       wmb();
>> +       writel(0x00, base + PHY_TST_CTRL0);
>> +       /* cmd2 sent for write */
>> +       wmb();
>> +       writel(val, base + PHY_TST_CTRL1);
>> +       /* Then write data */
>> +       wmb();
>> +       writel(0x02, base + PHY_TST_CTRL0);
>> +       /* cmd2 sent for write */
>> +       wmb();
>> +       writel(0x00, base + PHY_TST_CTRL0);
>> +}
>> +
>
>
> This doesn't look like something that should be inlined. Maybe move it to
> hisi_drm_dsi.c?

yes, you are right. will be fixed in v3.

Thanks,
-xinliang

>
>> +#endif /* __HISI_DRM_DSI_H__ */
>>
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 08/10] drm/hisilicon: Add dsi encoder driver
@ 2015-12-01 11:16         ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 11:16 UTC (permalink / raw)
  To: linux-arm-kernel

On 1 December 2015 at 16:58, Archit Taneja <architt@codeaurora.org> wrote:

Hi Archit , thank you for review.

>
>
> On 11/28/2015 04:09 PM, Xinliang Liu wrote:
>>
>> Add dsi encoder driver for hi6220 SoC.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>>   drivers/gpu/drm/hisilicon/Kconfig        |   1 +
>>   drivers/gpu/drm/hisilicon/Makefile       |   3 +-
>>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 728
>> +++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/hisilicon/hisi_dsi_reg.h |  89 ++++
>>   4 files changed, 820 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/Kconfig
>> b/drivers/gpu/drm/hisilicon/Kconfig
>> index 70aa8d1..f1c33c2 100644
>> --- a/drivers/gpu/drm/hisilicon/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/Kconfig
>> @@ -4,6 +4,7 @@ config DRM_HISI
>>         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.
>> diff --git a/drivers/gpu/drm/hisilicon/Makefile
>> b/drivers/gpu/drm/hisilicon/Makefile
>> index 3433c8b..5083c1f 100644
>> --- a/drivers/gpu/drm/hisilicon/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/Makefile
>> @@ -1,4 +1,5 @@
>>   hisi-drm-y := hisi_drm_drv.o \
>> -             hisi_drm_ade.o
>> +             hisi_drm_ade.o \
>> +             hisi_drm_dsi.o
>>
>>   obj-$(CONFIG_DRM_HISI)        += hisi-drm.o
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> new file mode 100644
>> index 0000000..7a6cf66
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> @@ -0,0 +1,728 @@
>> +/*
>> + * Hisilicon hi6220 SoC dsi driver
>> + *
>> + * Copyright (c) 2014-2015 Hisilicon Limited.
>> + * Author:
>> + *     Xinliang Liu <xinliang.liu@linaro.org>
>> + *     Xinliang Liu <z.liuxinliang@hisilicon.com>
>> + *     Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/component.h>
>> +#include <linux/of_graph.h>
>> +
>> +#include <drm/drm_crtc_helper.h>
>> +#include <drm/drm_mipi_dsi.h>
>> +#include <drm/drm_encoder_slave.h>
>> +#include <drm/drm_atomic_helper.h>
>> +
>> +#include "hisi_dsi_reg.h"
>> +
>> +#define MAX_TX_ESC_CLK            (10)
>> +#define ROUND(x, y) ((x) / (y) + ((x) % (y) * 10 / (y) >= 5 ? 1 : 0))
>> +#define DEFAULT_MIPI_CLK_RATE   19200000
>> +#define DEFAULT_MIPI_CLK_PERIOD_PS (1000000000 / (DEFAULT_MIPI_CLK_RATE /
>> 1000))
>> +#define R(x) ((u32)((((u64)(x) * (u64)1000 * (u64)mode->clock) / \
>> +             phy->lane_byte_clk_kHz)))
>> +
>> +#define encoder_to_dsi(encoder) \
>> +       container_of(encoder, struct hisi_dsi, encoder)
>> +#define host_to_dsi(host) \
>> +       container_of(host, struct hisi_dsi, host)
>> +
>> +struct mipi_phy_register {
>> +       u32 clk_t_lpx;
>> +       u32 clk_t_hs_prepare;
>> +       u32 clk_t_hs_zero;
>> +       u32 clk_t_hs_trial;
>> +       u32 clk_t_wakeup;
>> +       u32 data_t_lpx;
>> +       u32 data_t_hs_prepare;
>> +       u32 data_t_hs_zero;
>> +       u32 data_t_hs_trial;
>> +       u32 data_t_ta_go;
>> +       u32 data_t_ta_get;
>> +       u32 data_t_wakeup;
>> +       u32 hstx_ckg_sel;
>> +       u32 pll_fbd_div5f;
>> +       u32 pll_fbd_div1f;
>> +       u32 pll_fbd_2p;
>> +       u32 pll_enbwt;
>> +       u32 pll_fbd_p;
>> +       u32 pll_fbd_s;
>> +       u32 pll_pre_div1p;
>> +       u32 pll_pre_p;
>> +       u32 pll_vco_750M;
>> +       u32 pll_lpf_rs;
>> +       u32 pll_lpf_cs;
>> +       u32 clklp2hs_time;
>> +       u32 clkhs2lp_time;
>> +       u32 lp2hs_time;
>> +       u32 hs2lp_time;
>> +       u32 clk_to_data_delay;
>> +       u32 data_to_clk_delay;
>> +       u32 lane_byte_clk_kHz;
>> +       u32 clk_division;
>> +};
>> +
>> +struct dsi_hw_ctx {
>> +       void __iomem *base;
>> +       struct clk *dsi_cfg_clk;
>> +};
>> +
>> +struct hisi_dsi {
>> +       struct drm_encoder encoder;
>> +       struct drm_display_mode cur_mode;
>> +       struct dsi_hw_ctx *ctx;
>> +       struct mipi_phy_register phy;
>> +
>> +       u32 lanes;
>> +       enum mipi_dsi_pixel_format format;
>> +       unsigned long mode_flags;
>> +       bool enable;
>> +};
>> +
>> +struct dsi_data {
>> +       struct hisi_dsi dsi;
>> +       struct dsi_hw_ctx ctx;
>> +};
>> +
>> +struct dsi_phy_seq_info {
>> +       u32 min_range_kHz;
>> +       u32 max_range_kHz;
>> +       u32 pll_vco_750M;
>> +       u32 hstx_ckg_sel;
>> +};
>> +
>> +static const struct dsi_phy_seq_info dphy_seq_info[] = {
>> +       {   46000,    62000,   1,    7 },
>> +       {   62000,    93000,   0,    7 },
>> +       {   93000,   125000,   1,    6 },
>> +       {  125000,   187000,   0,    6 },
>> +       {  187000,   250000,   1,    5 },
>> +       {  250000,   375000,   0,    5 },
>> +       {  375000,   500000,   1,    4 },
>> +       {  500000,   750000,   0,    4 },
>> +       {  750000,  1000000,   1,    0 },
>> +       { 1000000,  1500000,   0,    0 }
>> +};
>> +
>> +static void set_dsi_phy_rate_equal_or_faster(u32 phy_freq_kHz,
>> +                                            struct mipi_phy_register
>> *phy)
>> +{
>> +       u32 ui = 0;
>> +       u32 cfg_clk_ps = DEFAULT_MIPI_CLK_PERIOD_PS;
>> +       u32 i = 0;
>> +       u32 q_pll = 1;
>> +       u32 m_pll = 0;
>> +       u32 n_pll = 0;
>> +       u32 r_pll = 1;
>> +       u32 m_n = 0;
>> +       u32 m_n_int = 0;
>> +       u64 f_kHz;
>> +       u64 temp;
>> +       u64 tmp_kHz = phy_freq_kHz;
>> +
>> +       do {
>> +               f_kHz = tmp_kHz;
>> +
>> +               /* Find the PLL clock range from the table */
>> +               for (i = 0; i < ARRAY_SIZE(dphy_seq_info); i++)
>> +                       if (f_kHz > dphy_seq_info[i].min_range_kHz &&
>> +                           f_kHz <= dphy_seq_info[i].max_range_kHz)
>> +                               break;
>> +
>> +               if (i == ARRAY_SIZE(dphy_seq_info)) {
>> +                       DRM_ERROR("%lldkHz out of range\n", f_kHz);
>> +                       return;
>> +               }
>> +
>> +               phy->pll_vco_750M = dphy_seq_info[i].pll_vco_750M;
>> +               phy->hstx_ckg_sel = dphy_seq_info[i].hstx_ckg_sel;
>> +
>> +               if (phy->hstx_ckg_sel <= 7 &&
>> +                   phy->hstx_ckg_sel >= 4)
>> +                       q_pll = 0x10 >> (7 - phy->hstx_ckg_sel);
>> +
>> +               temp = f_kHz * (u64)q_pll * (u64)cfg_clk_ps;
>> +               m_n_int = temp / (u64)1000000000;
>> +               m_n = (temp % (u64)1000000000) / (u64)100000000;
>> +
>> +               if (m_n_int % 2 == 0) {
>> +                       if (m_n * 6 >= 50) {
>> +                               n_pll = 2;
>> +                               m_pll = (m_n_int + 1) * n_pll;
>> +                       } else if (m_n * 6 >= 30) {
>> +                               n_pll = 3;
>> +                               m_pll = m_n_int * n_pll + 2;
>> +                       } else {
>> +                               n_pll = 1;
>> +                               m_pll = m_n_int * n_pll;
>> +                       }
>> +               } else {
>> +                       if (m_n * 6 >= 50) {
>> +                               n_pll = 1;
>> +                               m_pll = (m_n_int + 1) * n_pll;
>> +                       } else if (m_n * 6 >= 30) {
>> +                               n_pll = 1;
>> +                               m_pll = (m_n_int + 1) * n_pll;
>> +                       } else if (m_n * 6 >= 10) {
>> +                               n_pll = 3;
>> +                               m_pll = m_n_int * n_pll + 1;
>> +                       } else {
>> +                               n_pll = 2;
>> +                               m_pll = m_n_int * n_pll;
>> +                       }
>> +               }
>> +
>> +               if (n_pll == 1) {
>> +                       phy->pll_fbd_p = 0;
>> +                       phy->pll_pre_div1p = 1;
>> +               } else {
>> +                       phy->pll_fbd_p = n_pll;
>> +                       phy->pll_pre_div1p = 0;
>> +               }
>> +
>> +               if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4)
>> +                       r_pll = 0x10 >> (7 - phy->pll_fbd_2p);
>> +
>> +               if (m_pll == 2) {
>> +                       phy->pll_pre_p = 0;
>> +                       phy->pll_fbd_s = 0;
>> +                       phy->pll_fbd_div1f = 0;
>> +                       phy->pll_fbd_div5f = 1;
>> +               } else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 *
>> r_pll) {
>> +                       phy->pll_pre_p = m_pll / (2 * r_pll);
>> +                       phy->pll_fbd_s = 0;
>> +                       phy->pll_fbd_div1f = 1;
>> +                       phy->pll_fbd_div5f = 0;
>> +               } else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 *
>> r_pll) {
>> +                       if (((m_pll / (2 * r_pll)) % 2) == 0) {
>> +                               phy->pll_pre_p =
>> +                                       (m_pll / (2 * r_pll)) / 2 - 1;
>> +                               phy->pll_fbd_s =
>> +                                       (m_pll / (2 * r_pll)) % 2 + 2;
>> +                       } else {
>> +                               phy->pll_pre_p =
>> +                                       (m_pll / (2 * r_pll)) / 2;
>> +                               phy->pll_fbd_s =
>> +                                       (m_pll / (2 * r_pll)) % 2;
>> +                       }
>> +                       phy->pll_fbd_div1f = 0;
>> +                       phy->pll_fbd_div5f = 0;
>> +               } else {
>> +                       phy->pll_pre_p = 0;
>> +                       phy->pll_fbd_s = 0;
>> +                       phy->pll_fbd_div1f = 0;
>> +                       phy->pll_fbd_div5f = 1;
>> +               }
>> +
>> +               f_kHz = (u64)1000000000 * (u64)m_pll /
>> +                       ((u64)cfg_clk_ps * (u64)n_pll * (u64)q_pll);
>> +
>> +               if (f_kHz >= phy_freq_kHz)
>> +                       break;
>> +
>> +               tmp_kHz += 10;
>> +
>> +       } while (1);
>> +
>> +       ui = 1000000 / f_kHz;
>> +
>> +       phy->clk_t_lpx = ROUND(50, 8 * ui);
>> +       phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1;
>> +
>> +       phy->clk_t_hs_zero = ROUND(262, 8 * ui);
>> +       phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1);
>> +       phy->clk_t_wakeup = ROUND(1000000, (cfg_clk_ps / 1000) - 1);
>> +       if (phy->clk_t_wakeup > 0xff)
>> +               phy->clk_t_wakeup = 0xff;
>> +       phy->data_t_wakeup = phy->clk_t_wakeup;
>> +       phy->data_t_lpx = phy->clk_t_lpx;
>> +       phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1;
>> +       phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui);
>> +       phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1);
>> +       phy->data_t_ta_go = 3;
>> +       phy->data_t_ta_get = 4;
>> +
>> +       phy->pll_enbwt = 1;
>> +       phy->clklp2hs_time = ROUND(407, 8 * ui) + 12;
>> +       phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui);
>> +       phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1;
>> +       phy->hs2lp_time = phy->clkhs2lp_time;
>> +       phy->clk_to_data_delay = 1 + phy->clklp2hs_time;
>> +       phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) +
>> +                               phy->clkhs2lp_time;
>> +
>> +       phy->lane_byte_clk_kHz = f_kHz / 8;
>> +       phy->clk_division = phy->lane_byte_clk_kHz / MAX_TX_ESC_CLK;
>> +       if (phy->lane_byte_clk_kHz % MAX_TX_ESC_CLK)
>> +               phy->clk_division++;
>> +}
>> +
>> +static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format)
>> +{
>> +       u32 val;
>> +
>> +       /* TODO: only support RGB888 now, to support more */
>> +       switch (format) {
>> +       case MIPI_DSI_FMT_RGB888:
>> +               val = DSI_24BITS_1;
>> +               break;
>> +       default:
>> +               val = DSI_24BITS_1;
>> +               break;
>> +       }
>> +
>> +       return val;
>> +}
>> +
>> +static void dsi_mipi_phy_clks(void __iomem *base,
>> +                             struct mipi_phy_register *phy,
>> +                             u32 lanes)
>> +{
>> +       u32 delay_count;
>> +       bool is_ready;
>> +       u32 val;
>> +       u32 i;
>> +
>> +       /* set lanes value */
>> +       val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8);
>> +       writel(val, base + PHY_IF_CFG);
>> +
>> +       /* set phy clk division */
>> +       val = readl(base + CLKMGR_CFG) | phy->clk_division;
>> +       writel(val, base + CLKMGR_CFG);
>> +
>> +       /* clean up phy set param */
>> +       writel(0, base + PHY_RSTZ);
>> +       writel(0, base + PHY_TST_CTRL0);
>> +       writel(1, base + PHY_TST_CTRL0);
>> +       writel(0, base + PHY_TST_CTRL0);
>> +
>> +       /* clock lane Timing control - TLPX */
>> +       dsi_phy_tst_set(base, 0x10010, phy->clk_t_lpx);
>> +
>> +       /* clock lane Timing control - THS-PREPARE */
>> +       dsi_phy_tst_set(base, 0x10011, phy->clk_t_hs_prepare);
>> +
>> +       /* clock lane Timing control - THS-ZERO */
>> +       dsi_phy_tst_set(base, 0x10012, phy->clk_t_hs_zero);
>> +
>> +       /* clock lane Timing control - THS-TRAIL */
>> +       dsi_phy_tst_set(base, 0x10013, phy->clk_t_hs_trial);
>> +
>> +       /* clock lane Timing control - TWAKEUP */
>> +       dsi_phy_tst_set(base, 0x10014, phy->clk_t_wakeup);
>> +
>> +       /* data lane */
>> +       for (i = 0; i < lanes; i++) {
>> +               /* Timing control - TLPX*/
>> +               dsi_phy_tst_set(base, 0x10020 + (i << 4),
>> phy->data_t_lpx);
>> +
>> +               /* Timing control - THS-PREPARE */
>> +               dsi_phy_tst_set(base, 0x10021 + (i << 4),
>> +                               phy->data_t_hs_prepare);
>> +
>> +               /* Timing control - THS-ZERO */
>> +               dsi_phy_tst_set(base, 0x10022 + (i << 4),
>> phy->data_t_hs_zero);
>> +
>> +               /* Timing control - THS-TRAIL */
>> +               dsi_phy_tst_set(base, 0x10023 + (i << 4),
>> phy->data_t_hs_trial);
>> +
>> +               /* Timing control - TTA-GO */
>> +               dsi_phy_tst_set(base, 0x10024 + (i << 4),
>> phy->data_t_ta_go);
>> +
>> +               /* Timing control - TTA-GET */
>> +               dsi_phy_tst_set(base, 0x10025 + (i << 4),
>> phy->data_t_ta_get);
>> +
>> +               /*  Timing control - TWAKEUP */
>> +               dsi_phy_tst_set(base, 0x10026 + (i << 4),
>> phy->data_t_wakeup);
>> +       }
>> +
>> +       /* physical configuration I  */
>> +       dsi_phy_tst_set(base, 0x10060, phy->hstx_ckg_sel);
>> +
>> +       /* physical configuration pll II  */
>> +       val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) +
>> +                               (phy->pll_fbd_2p << 1) + phy->pll_enbwt;
>> +       dsi_phy_tst_set(base, 0x10063, val);
>> +
>> +       /* physical configuration pll II  */
>> +       dsi_phy_tst_set(base, 0x10064, phy->pll_fbd_p);
>> +
>> +       /* physical configuration pll III  */
>> +       dsi_phy_tst_set(base, 0x10065, phy->pll_fbd_s);
>> +
>> +       /*physical configuration pll IV*/
>> +       val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
>> +       dsi_phy_tst_set(base, 0x10066, val);
>> +
>> +       /*physical configuration pll V*/
>
>
> It would be nice to fix the comment spacing for uniformity.
>

will be fixed in v3.

>
>> +       val = (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) +
>> +                                       phy->pll_lpf_cs + BIT(5);
>> +       dsi_phy_tst_set(base, 0x10067, val);
>> +
>> +       writel(BIT(2), base + PHY_RSTZ);
>> +       udelay(1);
>> +       writel(BIT(2) | BIT(0), base + PHY_RSTZ);
>> +       udelay(1);
>> +       writel(BIT(2) | BIT(1) | BIT(0), base + PHY_RSTZ);
>> +       usleep_range(1000, 1500);
>> +
>> +       /* wait for phy's clock ready */
>> +       delay_count = 0;
>> +       is_ready = false;
>> +       while (1) {
>> +               val = readl(base +  PHY_STATUS);
>> +               if (((BIT(0) | BIT(2)) & val) || delay_count > 100) {
>> +                       is_ready = (delay_count < 100) ? true : false;
>> +                       delay_count = 0;
>> +                       break;
>> +               }
>> +
>> +               udelay(1);
>> +               ++delay_count;
>> +       }
>
>
> You could simplify this a bit:
>
>         delay_count = 100
>         while (delay_count) {
>         ...
>         --delay_count;
>         }
>
>         if (!delay_count)
>                 DRM_INFO("...");
>

Great! This looks much more clearly. will be fixed in v3.

>> +
>> +       if (!is_ready)
>> +               DRM_INFO("phylock and phystopstateclklane is not
>> ready.\n");
>> +}
>> +
>> +static void dsi_set_mode_timing(void __iomem *base,
>> +                               struct mipi_phy_register *phy,
>> +                               struct drm_display_mode *mode,
>> +                               enum mipi_dsi_pixel_format format)
>> +{
>> +       u32 hfp, hbp, hsw, vfp, vbp, vsw;
>> +       u32 hline_time;
>> +       u32 hsa_time;
>> +       u32 hbp_time;
>> +       u32 pixel_clk_kHz;
>> +       int htot, vtot;
>> +       u32 val;
>> +
>> +       /* DSI color coding setting */
>> +       val = dsi_get_dpi_color_coding(format);
>> +       writel(val, base + DPI_COLOR_CODING);
>> +
>> +       /* DSI format and pol setting */
>> +       val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2;
>> +       val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1;
>> +       writel(val, base +  DPI_CFG_POL);
>> +
>> +       /*
>> +        * The DSI IP accepts vertical timing using lines as normal,
>> +        * but horizontal timing is a mixture of pixel-clocks for the
>> +        * active region and byte-lane clocks for the blanking-related
>> +        * timings.  hfp is specified as the total hline_time in byte-
>> +        * lane clocks minus hsa, hbp and active.
>> +        */
>> +       pixel_clk_kHz = mode->clock;
>> +       htot = mode->htotal;
>> +       vtot = mode->vtotal;
>> +       hfp = mode->hsync_start - mode->hdisplay;
>> +       hbp = mode->htotal - mode->hsync_end;
>> +       hsw = mode->hsync_end - mode->hsync_start;
>> +       vfp = mode->vsync_start - mode->vdisplay;
>> +       vbp = mode->vtotal - mode->vsync_end;
>> +       vsw = mode->vsync_end - mode->vsync_start;
>> +       if (vsw > 15) {
>> +               DRM_INFO("vsw exceeded 15\n");
>> +               vtot -= vsw - 15;
>> +               vsw = 15;
>> +       }
>> +
>> +       hsa_time = (hsw * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
>> +       hbp_time = (hbp * phy->lane_byte_clk_kHz) / pixel_clk_kHz;
>> +       hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
>> +                     pixel_clk_kHz;
>> +
>> +       if ((R(hline_time) / 1000) > htot) {
>> +               DRM_INFO("--: hline_time=%d\n", hline_time);
>> +               hline_time--;
>> +       }
>> +
>> +       if ((R(hline_time) / 1000) < htot) {
>
>
> Could we use a better macro name here? Also, it would be nice to pass
> the phy argument to it too. Maybe even move the divide by 1000 in the macro.
>

Great idea! will be fixed in v3.

>
>> +               DRM_INFO("++: hline_time=%d\n", hline_time);
>> +               hline_time++;
>> +       }
>> +
>> +       /* all specified in byte-lane clocks */
>> +       writel(hsa_time, base + VID_HSA_TIME);
>> +       writel(hbp_time, base + VID_HBP_TIME);
>> +       writel(hline_time, base + VID_HLINE_TIME);
>> +
>> +       writel(vsw, base + VID_VSA_LINES);
>> +       writel(vbp, base + VID_VBP_LINES);
>> +       writel(vfp, base + VID_VFP_LINES);
>> +       writel(mode->vdisplay, base + VID_VACTIVE_LINES);
>> +       writel(mode->hdisplay, base + VID_PKT_SIZE);
>> +}
>> +
>> +static void dsi_set_video_mode_type(void __iomem *base,
>> +                                   struct mipi_phy_register *phy,
>> +                                   unsigned long flags)
>> +{
>> +       u32 val;
>> +       u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
>> +               MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> +       u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO |
>> +               MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>> +       u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO;
>> +
>> +       /*
>> +        * choose video type
>> +        */
>> +       if ((flags & mode_mask) == non_burst_sync_pulse)
>> +               val = DSI_NON_BURST_SYNC_PULSES;
>> +       else if ((flags & mode_mask) == non_burst_sync_event)
>> +               val = DSI_NON_BURST_SYNC_EVENTS;
>> +       else
>> +               val = DSI_BURST_SYNC_PULSES_1;
>> +
>> +       writel(val, base + VID_MODE_CFG);
>> +       /* TODO: to support LCD panel need to set LP command transfer */
>> +}
>> +
>> +static void dsi_mipi_init(struct hisi_dsi *dsi)
>> +{
>> +       struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       struct mipi_phy_register *phy = &dsi->phy;
>> +       struct drm_display_mode *mode = &dsi->cur_mode;
>> +       void __iomem *base = ctx->base;
>> +       u32 dphy_freq_kHz;
>> +
>> +       /* count phy params */
>> +       dphy_freq_kHz = mode->clock * 24 / dsi->lanes;
>
>
> Maybe replace the 24 above with the bpp in use for future compatibility?
>

Yes, it is bpp. will be replaced by bpp in v3.

>
>> +       set_dsi_phy_rate_equal_or_faster(dphy_freq_kHz, phy);
>> +
>> +       /* reset Core */
>> +       writel(0, base + PWR_UP);
>> +
>> +       /* set phy clocks */
>> +       dsi_mipi_phy_clks(base, phy, dsi->lanes);
>> +
>> +       /* set dsi mode */
>> +       dsi_set_mode_timing(base, phy, mode, dsi->format);
>> +
>> +       /* set video mode type and low power */
>> +       dsi_set_video_mode_type(base, phy, dsi->mode_flags);
>> +
>> +       /* DSI and D-PHY Initialization */
>> +       writel(DSI_VIDEO_MODE, base + MODE_CFG);
>> +       writel(BIT(0), base + LPCLK_CTRL);
>> +       writel(BIT(0), base + PWR_UP);
>> +}
>> +
>> +static void dsi_encoder_disable(struct drm_encoder *encoder)
>> +{
>> +       struct hisi_dsi *dsi = encoder_to_dsi(encoder);
>> +       struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       void __iomem *base = ctx->base;
>> +
>> +       DRM_DEBUG_DRIVER("enter\n");
>> +       if (!dsi->enable)
>> +               return;
>> +
>> +       writel(0, base + PWR_UP);
>> +       writel(0, base + LPCLK_CTRL);
>> +       writel(0, base + PHY_RSTZ);
>> +       clk_disable_unprepare(ctx->dsi_cfg_clk);
>> +
>> +       dsi->enable = false;
>> +       DRM_DEBUG_DRIVER("exit success.\n");
>> +}
>> +
>> +static void dsi_encoder_enable(struct drm_encoder *encoder)
>> +{
>> +       struct hisi_dsi *dsi = encoder_to_dsi(encoder);
>> +       struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       int ret;
>> +
>> +       DRM_DEBUG_DRIVER("enter.\n");
>> +       if (dsi->enable)
>> +               return;
>> +
>> +       /* mipi dphy clock enable */
>> +       ret = clk_prepare_enable(ctx->dsi_cfg_clk);
>> +       if (ret) {
>> +               DRM_ERROR("fail to enable dsi_cfg_clk: %d\n", ret);
>> +               return;
>> +       }
>> +
>> +       dsi_mipi_init(dsi);
>> +
>> +       dsi->enable = true;
>> +       DRM_DEBUG_DRIVER("exit success.\n");
>> +}
>> +
>> +static void dsi_encoder_mode_set(struct drm_encoder *encoder,
>> +                                struct drm_display_mode *mode,
>> +                                struct drm_display_mode *adj_mode)
>> +{
>> +       struct hisi_dsi *dsi = encoder_to_dsi(encoder);
>> +
>> +       DRM_DEBUG_DRIVER("enter.\n");
>> +       drm_mode_copy(&dsi->cur_mode, adj_mode);
>> +       DRM_DEBUG_DRIVER("exit success.\n");
>> +}
>> +
>> +static int dsi_encoder_atomic_check(struct drm_encoder *encoder,
>> +                                   struct drm_crtc_state *crtc_state,
>> +                                   struct drm_connector_state
>> *conn_state)
>> +{
>> +       struct drm_display_mode *mode = &crtc_state->mode;
>> +
>> +       DRM_DEBUG_DRIVER("enter.\n");
>> +       if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
>> +               DRM_ERROR("not support INTERLACE mode\n");
>> +               return MODE_NO_INTERLACE;
>> +       }
>> +
>> +       /* pixel clock support range is (1190494208/64, 1190494208)Hz */
>> +       if (mode->clock < 18602 || mode->clock > 1190494) {
>
>
> I don't think we need to worry about the maximum limit if we support pixel
> clocks up to 1190 Mhz :)

yea, 1190Mhz is too larger.  will be fixed in v3.

>
>
>> +               DRM_ERROR("mode clock not support\n");
>> +               return MODE_CLOCK_RANGE;
>> +       }
>> +
>> +       DRM_DEBUG_DRIVER("exit success.\n");
>> +       return 0;
>> +}
>> +
>> +static const struct drm_encoder_helper_funcs hisi_encoder_helper_funcs =
>> {
>> +       .atomic_check   = dsi_encoder_atomic_check,
>> +       .mode_set       = dsi_encoder_mode_set,
>> +       .enable         = dsi_encoder_enable,
>> +       .disable        = dsi_encoder_disable
>> +};
>> +
>> +static const struct drm_encoder_funcs hisi_encoder_funcs = {
>> +       .destroy = drm_encoder_cleanup,
>> +};
>> +
>> +static int hisi_drm_encoder_init(struct drm_device *dev,
>> +                                struct drm_encoder *encoder)
>> +{
>> +       int ret;
>> +
>> +       encoder->possible_crtcs = 1;
>> +       ret = drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
>> +                              DRM_MODE_ENCODER_TMDS);
>
>
> We should have the encoder as DRM_MODE_ENCODER_DSI here, even if the
> connector is finally hdmi.

Correct! will be fixed in v3.

>
>
>> +       if (ret) {
>> +               DRM_ERROR("failed to init dsi encoder\n");
>> +               return ret;
>> +       }
>> +
>> +       drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
>> +
>> +       return 0;
>> +}
>> +
>> +static int dsi_bind(struct device *dev, struct device *master, void
>> *data)
>> +{
>> +       struct dsi_data *ddata = dev_get_drvdata(dev);
>> +       struct hisi_dsi *dsi = &ddata->dsi;
>> +       struct drm_device *drm_dev = data;
>> +       int ret;
>> +
>> +       ret = hisi_drm_encoder_init(drm_dev, &dsi->encoder);
>> +       if (ret)
>> +               return ret;
>> +
>> +       return 0;
>> +}
>> +
>> +static void dsi_unbind(struct device *dev, struct device *master, void
>> *data)
>> +{
>> +       /* do nothing */
>> +}
>> +
>> +static const struct component_ops dsi_ops = {
>> +       .bind   = dsi_bind,
>> +       .unbind = dsi_unbind,
>> +};
>> +
>> +static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi
>> *dsi)
>> +{
>> +       struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       struct resource *res;
>> +
>> +
>> +       ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>> +       if (IS_ERR(ctx->dsi_cfg_clk)) {
>> +               DRM_ERROR("failed to get dsi plck clock\n");
>> +               return PTR_ERR(ctx->dsi_cfg_clk);
>> +       }
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       ctx->base = devm_ioremap_resource(&pdev->dev, res);
>> +       if (IS_ERR(ctx->base)) {
>> +               DRM_ERROR("failed to remap dsi io region\n");
>> +               return PTR_ERR(ctx->base);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int dsi_probe(struct platform_device *pdev)
>> +{
>> +       struct dsi_data *data;
>> +       struct hisi_dsi *dsi;
>> +       struct dsi_hw_ctx *ctx;
>> +       int ret;
>> +
>> +       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>> +       if (!data) {
>> +               DRM_ERROR("failed to allocate dsi data.\n");
>> +               return -ENOMEM;
>> +       }
>> +       dsi = &data->dsi;
>> +       ctx = &data->ctx;
>> +       dsi->ctx = ctx;
>> +
>> +       ret = dsi_parse_dt(pdev, dsi);
>> +       if (ret)
>> +               return ret;
>> +
>> +       platform_set_drvdata(pdev, data);
>> +
>> +       return component_add(&pdev->dev, &dsi_ops);
>> +}
>> +
>> +static int dsi_remove(struct platform_device *pdev)
>> +{
>> +       component_del(&pdev->dev, &dsi_ops);
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct of_device_id dsi_of_match[] = {
>> +       {.compatible = "hisilicon,hi6220-dsi"},
>> +       { }
>> +};
>> +MODULE_DEVICE_TABLE(of, dsi_of_match);
>> +
>> +static struct platform_driver dsi_driver = {
>> +       .probe = dsi_probe,
>> +       .remove = dsi_remove,
>> +       .driver = {
>> +               .name = "hisi-dsi",
>> +               .owner = THIS_MODULE,
>> +               .of_match_table = dsi_of_match,
>> +       },
>> +};
>> +
>> +module_platform_driver(dsi_driver);
>> +
>> +MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>");
>> +MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>");
>> +MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
>> +MODULE_DESCRIPTION("hisilicon hi6220 SoC dsi driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>> b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>> new file mode 100644
>> index 0000000..db8f9df
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>> @@ -0,0 +1,89 @@
>> +/*
>> + * Copyright (c) 2014-2015 Hisilicon Limited.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + *
>> + */
>> +
>> +#ifndef __HISI_DSI_REG_H__
>> +#define __HISI_DSI_REG_H__
>> +
>> +/*
>> + * regs
>> + */
>> +#define  PWR_UP                  (0x4)   /* Core power-up */
>> +#define  PHY_IF_CFG              (0xA4)  /* D-PHY interface configuration
>> */
>> +#define  CLKMGR_CFG              (0x8)   /* the internal clock dividers
>> */
>> +#define  PHY_RSTZ                (0xA0)  /* D-PHY reset control */
>> +#define  PHY_TST_CTRL0           (0xB4)  /* D-PHY test interface control
>> 0 */
>> +#define  PHY_TST_CTRL1           (0xB8)  /* D-PHY test interface control
>> 1 */
>> +#define  DPI_VCID                (0xC)   /* DPI virtual channel id */
>> +#define  DPI_COLOR_CODING        (0x10)  /* DPI color coding */
>> +#define  DPI_CFG_POL             (0x14)  /* DPI polarity configuration */
>> +#define  VID_HSA_TIME            (0x48)  /* Horizontal Sync Active time
>> */
>> +#define  VID_HBP_TIME            (0x4C)  /* Horizontal Back Porch time */
>> +#define  VID_HLINE_TIME          (0x50)  /* Line time */
>> +#define  VID_VSA_LINES           (0x54)  /* Vertical Sync Active period
>> */
>> +#define  VID_VBP_LINES           (0x58)  /* Vertical Back Porch period */
>> +#define  VID_VFP_LINES           (0x5C)  /* Vertical Front Porch period
>> */
>> +#define  VID_VACTIVE_LINES       (0x60)  /* Vertical resolution */
>> +#define  VID_PKT_SIZE            (0x3C)  /* Video packet size */
>> +#define  VID_MODE_CFG            (0x38)  /* Video mode configuration */
>> +#define  DPI_LP_CMD_TIM          (0x18)  /* Low-power command timing
>> config */
>> +#define  PHY_TMR_CFG             (0x9C)  /* Data lanes timing
>> configuration */
>> +#define  BTA_TO_CNT              (0x8C)  /* Response timeout definition
>> */
>> +#define  PHY_TMR_LPCLK_CFG       (0x98)  /* clock lane timing
>> configuration */
>> +#define  CLK_DATA_TMR_CFG        (0xCC)
>> +#define  LPCLK_CTRL              (0x94)  /* Low-power in clock lane */
>> +#define  PCKHDL_CFG              (0x2C)  /* Packet handler configuration
>> */
>> +#define  EDPI_CMD_SIZE           (0x64)  /* Size for eDPI packets */
>> +#define  MODE_CFG                (0x34)  /* Video or Command mode
>> selection */
>> +#define  PHY_STATUS              (0xB0)  /* D-PHY PPI status interface */
>> +
>> +#define        PHY_STOP_WAIT_TIME      (0x30)
>> +
>> +/*
>> + * regs relevant enum
>> + */
>> +enum dpi_color_coding {
>> +       DSI_24BITS_1 = 5,
>> +};
>> +
>> +enum dsi_video_mode_type {
>> +       DSI_NON_BURST_SYNC_PULSES = 0,
>> +       DSI_NON_BURST_SYNC_EVENTS,
>> +       DSI_BURST_SYNC_PULSES_1,
>> +       DSI_BURST_SYNC_PULSES_2
>> +};
>> +
>> +enum dsi_work_mode {
>> +       DSI_VIDEO_MODE = 0,
>> +       DSI_COMMAND_MODE
>> +};
>> +
>> +/*
>> + * regs Write/Read functions
>> + */
>> +static inline void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val)
>> +{
>> +       writel(reg, base + PHY_TST_CTRL1);
>> +       /* reg addr written at first */
>> +       wmb();
>> +       writel(0x02, base + PHY_TST_CTRL0);
>> +       /* cmd1 sent for write */
>> +       wmb();
>> +       writel(0x00, base + PHY_TST_CTRL0);
>> +       /* cmd2 sent for write */
>> +       wmb();
>> +       writel(val, base + PHY_TST_CTRL1);
>> +       /* Then write data */
>> +       wmb();
>> +       writel(0x02, base + PHY_TST_CTRL0);
>> +       /* cmd2 sent for write */
>> +       wmb();
>> +       writel(0x00, base + PHY_TST_CTRL0);
>> +}
>> +
>
>
> This doesn't look like something that should be inlined. Maybe move it to
> hisi_drm_dsi.c?

yes, you are right. will be fixed in v3.

Thanks,
-xinliang

>
>> +#endif /* __HISI_DRM_DSI_H__ */
>>
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 06/10] drm/hisilicon: Add vblank feature
  2015-12-01 10:34           ` Xinliang Liu
@ 2015-12-01 12:54             ` Daniel Vetter
  -1 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-12-01 12:54 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: Daniel Vetter, dri-devel, devicetree, Rob Herring, Daniel Stone,
	architt, David Airlie, Jon Corbet, Catalin Marinas, Will Deacon,
	linux-doc, LAKML, linuxarm, Andy Green, Haojian Zhuang,
	Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong, zourongrong, lijianhua, Sumit

On Tue, Dec 01, 2015 at 06:34:43PM +0800, Xinliang Liu wrote:
> On 1 December 2015 at 15:13, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Tue, Dec 01, 2015 at 11:16:19AM +0800, Xinliang Liu wrote:
> >> On 30 November 2015 at 15:54, Daniel Vetter <daniel@ffwll.ch> wrote:
> >> > On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
> >> >> Add vblank handle for ADE.
> >> >>
> >> >> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> >> >> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> >> >> Signed-off-by: Andy Green <andy.green@linaro.org>
> >> >> ---
> >> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
> >> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
> >> >>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
> >> >>  3 files changed, 112 insertions(+), 1 deletion(-)
> >> >>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> >> >>
> >> >> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> >> index b0976c3..acb11e7 100644
> >> >> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> >> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> >> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
> >> >>       ctx->power_on = false;
> >> >>  }
> >> >>
> >> >> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
> >> >> +                                              unsigned int index)
> >> >
> >> > Ugly that you had to add this, but unfortunately necessary :( Fixing up
> >> > the drm vblank hooks so that they deal with struct drm_crtc directly is
> >> > somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
> >> > ways off still.
> >> >
> >> > What might be possible as a follow-up cleanup though is to add
> >> > vblank_enable and vblank_disable functions to struct
> >> > drm_crtc_helper_funcs. And then provide this code here to map from int
> >> > index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
> >> > That might be a good intermediate step.
> >>
> >> I would like to have a try to make this intermediate step patch and
> >> send out for review soon.
> >
> > Awesome, looking forward to reviewing it. If you have questions about
> > details fastest to ping me on irc (nick: danvet, #dri-devel on
> > freenode.net).
> 
> Great!  What't your time zone. So that I can ping you in right time.

Europe, GMT+1.

Cheers, Daniel

> 
> Thanks,
> -xinliang
> 
> >
> > Cheers, Daniel
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 06/10] drm/hisilicon: Add vblank feature
@ 2015-12-01 12:54             ` Daniel Vetter
  0 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-12-01 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 01, 2015 at 06:34:43PM +0800, Xinliang Liu wrote:
> On 1 December 2015 at 15:13, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Tue, Dec 01, 2015 at 11:16:19AM +0800, Xinliang Liu wrote:
> >> On 30 November 2015 at 15:54, Daniel Vetter <daniel@ffwll.ch> wrote:
> >> > On Sat, Nov 28, 2015 at 06:39:01PM +0800, Xinliang Liu wrote:
> >> >> Add vblank handle for ADE.
> >> >>
> >> >> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> >> >> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> >> >> Signed-off-by: Andy Green <andy.green@linaro.org>
> >> >> ---
> >> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.c | 78 ++++++++++++++++++++++++++++++++
> >> >>  drivers/gpu/drm/hisilicon/hisi_drm_ade.h | 16 +++++++
> >> >>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 19 +++++++-
> >> >>  3 files changed, 112 insertions(+), 1 deletion(-)
> >> >>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_ade.h
> >> >>
> >> >> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> >> index b0976c3..acb11e7 100644
> >> >> --- a/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> >> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_ade.c
> >> >> @@ -267,7 +267,79 @@ static void ade_power_down(struct ade_hw_ctx *ctx)
> >> >>       ctx->power_on = false;
> >> >>  }
> >> >>
> >> >> +static struct drm_crtc *hisi_get_crtc_from_index(struct drm_device *dev,
> >> >> +                                              unsigned int index)
> >> >
> >> > Ugly that you had to add this, but unfortunately necessary :( Fixing up
> >> > the drm vblank hooks so that they deal with struct drm_crtc directly is
> >> > somewhere on my todo. But drm_irq.c is still a bit a mess, so this is some
> >> > ways off still.
> >> >
> >> > What might be possible as a follow-up cleanup though is to add
> >> > vblank_enable and vblank_disable functions to struct
> >> > drm_crtc_helper_funcs. And then provide this code here to map from int
> >> > index to struct drm_crtc * as helpers in a new drm_vblank_helper.c file.
> >> > That might be a good intermediate step.
> >>
> >> I would like to have a try to make this intermediate step patch and
> >> send out for review soon.
> >
> > Awesome, looking forward to reviewing it. If you have questions about
> > details fastest to ping me on irc (nick: danvet, #dri-devel on
> > freenode.net).
> 
> Great!  What't your time zone. So that I can ping you in right time.

Europe, GMT+1.

Cheers, Daniel

> 
> Thanks,
> -xinliang
> 
> >
> > Cheers, Daniel
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem
  2015-12-01  7:17       ` Xinliang Liu
@ 2015-12-01 13:58         ` Rob Herring
  -1 siblings, 0 replies; 70+ messages in thread
From: Rob Herring @ 2015-12-01 13:58 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: dri-devel, devicetree, Daniel Vetter, Daniel Stone,
	Archit Taneja, David Airlie, Jon Corbet, Catalin Marinas,
	Will Deacon, linux-doc, LAKML, Linuxarm, Andy Green,
	Haojian Zhuang, Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong

On Tue, Dec 1, 2015 at 1:17 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> On 1 December 2015 at 03:31, Rob Herring <robh@kernel.org> wrote:
>
> Hi Rob, thank you for review.
>
>> On Sat, Nov 28, 2015 at 06:38:57PM +0800, Xinliang Liu wrote:
>>> Add the device tree binding documentation for hi6220 SoC display subsystem.
>>> drm master device binding doc.
>>> ADE display controller binding doc.
>>> DSI controller binding doc.

>>> +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.
>>
>> Put this on the actually DMA master.
>
> The DMA modules reside in the begining of each channel(or plane) of ADE.
> So I need to put this dma-coherent property to ADE device node, right?

Right.

Rob

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem
@ 2015-12-01 13:58         ` Rob Herring
  0 siblings, 0 replies; 70+ messages in thread
From: Rob Herring @ 2015-12-01 13:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 1, 2015 at 1:17 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> On 1 December 2015 at 03:31, Rob Herring <robh@kernel.org> wrote:
>
> Hi Rob, thank you for review.
>
>> On Sat, Nov 28, 2015 at 06:38:57PM +0800, Xinliang Liu wrote:
>>> Add the device tree binding documentation for hi6220 SoC display subsystem.
>>> drm master device binding doc.
>>> ADE display controller binding doc.
>>> DSI controller binding doc.

>>> +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.
>>
>> Put this on the actually DMA master.
>
> The DMA modules reside in the begining of each channel(or plane) of ADE.
> So I need to put this dma-coherent property to ADE device node, right?

Right.

Rob

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
  2015-12-01  9:04       ` Archit Taneja
@ 2015-12-01 14:50         ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 14:50 UTC (permalink / raw)
  To: Archit Taneja
  Cc: dri-devel, devicetree, Daniel Vetter, Rob Herring, Daniel Stone,
	David Airlie, Jon Corbet, Catalin Marinas, Will Deacon,
	linux-doc, LAKML, linuxarm, Andy Green, Haojian Zhuang,
	Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong, zourongrong, lijianhua, Sumit Semwal

On 1 December 2015 at 17:04, Archit Taneja <architt@codeaurora.org> wrote:
>
>
> On 11/28/2015 04:09 PM, Xinliang Liu wrote:
>>
>> Add support for external HDMI bridge.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51
>> ++++++++++++++++++++++++++++++++
>>   1 file changed, 51 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> index 066e08d..9e056db 100644
>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> @@ -78,6 +78,7 @@ struct dsi_hw_ctx {
>>
>>   struct hisi_dsi {
>>         struct drm_encoder encoder;
>> +       struct drm_bridge *bridge;
>>         struct mipi_dsi_host host;
>>         struct drm_display_mode cur_mode;
>>         struct dsi_hw_ctx *ctx;
>> @@ -671,6 +672,25 @@ 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)
>> +{
>> +       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");
>
>
> s/exteranl/external
>

will be fixed in v3.

>
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>>   static int dsi_bind(struct device *dev, struct device *master, void
>> *data)
>>   {
>>         struct dsi_data *ddata = dev_get_drvdata(dev);
>> @@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct device
>> *master, void *data)
>>         if (ret)
>>                 return ret;
>>
>> +       ret = dsi_bridge_init(drm_dev, dsi);
>> +       if (ret)
>> +               return ret;
>> +
>>         return 0;
>>   }
>>
>> @@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
>>   static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi
>> *dsi)
>>   {
>>         struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       struct device_node *np = pdev->dev.of_node;
>> +       struct device_node *endpoint, *bridge_node;
>> +       struct drm_bridge *bridge;
>>         struct resource *res;
>>
>> +       /*
>> +        * Get the endpoint node. In our case, dsi has one output port
>> +        * to which the external HDMI bridge is connected.
>> +        */
>> +       endpoint = of_graph_get_next_endpoint(np, NULL);
>> +       if (!endpoint) {
>> +               DRM_ERROR("no valid endpoint node\n");
>> +               return -ENODEV;
>> +       }
>> +       of_node_put(endpoint);
>> +
>> +       bridge_node = of_graph_get_remote_port_parent(endpoint);
>> +       if (!bridge_node) {
>> +               DRM_ERROR("no valid bridge node\n");
>> +               return -ENODEV;
>> +       }
>> +       of_node_put(bridge_node);
>> +
>> +       bridge = of_drm_find_bridge(bridge_node);
>> +       if (!bridge) {
>> +               DRM_INFO("wait for external HDMI bridge driver.\n");
>> +               return -EPROBE_DEFER;
>> +       }
>> +       dsi->bridge = bridge;
>
>
> This could be left for later, but it would be better if the dsi driver
> registers even if the bridge driver module isn't inserted yet, or
> happens much later in boot.
>
> We could achieve this by trying to attach the bridge (done in
> dsi_bridge_init) in the dsi_host_attach callback instead of having it
> in dsi_bind.

Do you mean that it is the right time or place to attach the bridge in
dsi_host_attach callback.
Why? Because at this time bridge driver must be register?

Thanks,
-xinliang

>
> Thanks,
> Archit
>
>>
>>         ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>>         if (IS_ERR(ctx->dsi_cfg_clk)) {
>>
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
@ 2015-12-01 14:50         ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 14:50 UTC (permalink / raw)
  To: linux-arm-kernel

On 1 December 2015 at 17:04, Archit Taneja <architt@codeaurora.org> wrote:
>
>
> On 11/28/2015 04:09 PM, Xinliang Liu wrote:
>>
>> Add support for external HDMI bridge.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51
>> ++++++++++++++++++++++++++++++++
>>   1 file changed, 51 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> index 066e08d..9e056db 100644
>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>> @@ -78,6 +78,7 @@ struct dsi_hw_ctx {
>>
>>   struct hisi_dsi {
>>         struct drm_encoder encoder;
>> +       struct drm_bridge *bridge;
>>         struct mipi_dsi_host host;
>>         struct drm_display_mode cur_mode;
>>         struct dsi_hw_ctx *ctx;
>> @@ -671,6 +672,25 @@ 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)
>> +{
>> +       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");
>
>
> s/exteranl/external
>

will be fixed in v3.

>
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>>   static int dsi_bind(struct device *dev, struct device *master, void
>> *data)
>>   {
>>         struct dsi_data *ddata = dev_get_drvdata(dev);
>> @@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct device
>> *master, void *data)
>>         if (ret)
>>                 return ret;
>>
>> +       ret = dsi_bridge_init(drm_dev, dsi);
>> +       if (ret)
>> +               return ret;
>> +
>>         return 0;
>>   }
>>
>> @@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
>>   static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi
>> *dsi)
>>   {
>>         struct dsi_hw_ctx *ctx = dsi->ctx;
>> +       struct device_node *np = pdev->dev.of_node;
>> +       struct device_node *endpoint, *bridge_node;
>> +       struct drm_bridge *bridge;
>>         struct resource *res;
>>
>> +       /*
>> +        * Get the endpoint node. In our case, dsi has one output port
>> +        * to which the external HDMI bridge is connected.
>> +        */
>> +       endpoint = of_graph_get_next_endpoint(np, NULL);
>> +       if (!endpoint) {
>> +               DRM_ERROR("no valid endpoint node\n");
>> +               return -ENODEV;
>> +       }
>> +       of_node_put(endpoint);
>> +
>> +       bridge_node = of_graph_get_remote_port_parent(endpoint);
>> +       if (!bridge_node) {
>> +               DRM_ERROR("no valid bridge node\n");
>> +               return -ENODEV;
>> +       }
>> +       of_node_put(bridge_node);
>> +
>> +       bridge = of_drm_find_bridge(bridge_node);
>> +       if (!bridge) {
>> +               DRM_INFO("wait for external HDMI bridge driver.\n");
>> +               return -EPROBE_DEFER;
>> +       }
>> +       dsi->bridge = bridge;
>
>
> This could be left for later, but it would be better if the dsi driver
> registers even if the bridge driver module isn't inserted yet, or
> happens much later in boot.
>
> We could achieve this by trying to attach the bridge (done in
> dsi_bridge_init) in the dsi_host_attach callback instead of having it
> in dsi_bind.

Do you mean that it is the right time or place to attach the bridge in
dsi_host_attach callback.
Why? Because at this time bridge driver must be register?

Thanks,
-xinliang

>
> Thanks,
> Archit
>
>>
>>         ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>>         if (IS_ERR(ctx->dsi_cfg_clk)) {
>>
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
  2015-12-01 14:50         ` Xinliang Liu
@ 2015-12-02  8:20           ` Archit Taneja
  -1 siblings, 0 replies; 70+ messages in thread
From: Archit Taneja @ 2015-12-02  8:20 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: dri-devel, devicetree, Daniel Vetter, Rob Herring, Daniel Stone,
	David Airlie, Jon Corbet, Catalin Marinas, Will Deacon,
	linux-doc, LAKML, linuxarm, Andy Green, Haojian Zhuang,
	Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong, zourongrong, lijianhua, Sumit Semwal



On 12/01/2015 08:20 PM, Xinliang Liu wrote:
> On 1 December 2015 at 17:04, Archit Taneja <architt@codeaurora.org> wrote:
>>
>>
>> On 11/28/2015 04:09 PM, Xinliang Liu wrote:
>>>
>>> Add support for external HDMI bridge.
>>>
>>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>>> Signed-off-by: Andy Green <andy.green@linaro.org>
>>> ---
>>>    drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51
>>> ++++++++++++++++++++++++++++++++
>>>    1 file changed, 51 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>> b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>> index 066e08d..9e056db 100644
>>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>> @@ -78,6 +78,7 @@ struct dsi_hw_ctx {
>>>
>>>    struct hisi_dsi {
>>>          struct drm_encoder encoder;
>>> +       struct drm_bridge *bridge;
>>>          struct mipi_dsi_host host;
>>>          struct drm_display_mode cur_mode;
>>>          struct dsi_hw_ctx *ctx;
>>> @@ -671,6 +672,25 @@ 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)
>>> +{
>>> +       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");
>>
>>
>> s/exteranl/external
>>
>
> will be fixed in v3.
>
>>
>>> +               return ret;
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>>    static int dsi_bind(struct device *dev, struct device *master, void
>>> *data)
>>>    {
>>>          struct dsi_data *ddata = dev_get_drvdata(dev);
>>> @@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct device
>>> *master, void *data)
>>>          if (ret)
>>>                  return ret;
>>>
>>> +       ret = dsi_bridge_init(drm_dev, dsi);
>>> +       if (ret)
>>> +               return ret;
>>> +
>>>          return 0;
>>>    }
>>>
>>> @@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
>>>    static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi
>>> *dsi)
>>>    {
>>>          struct dsi_hw_ctx *ctx = dsi->ctx;
>>> +       struct device_node *np = pdev->dev.of_node;
>>> +       struct device_node *endpoint, *bridge_node;
>>> +       struct drm_bridge *bridge;
>>>          struct resource *res;
>>>
>>> +       /*
>>> +        * Get the endpoint node. In our case, dsi has one output port
>>> +        * to which the external HDMI bridge is connected.
>>> +        */
>>> +       endpoint = of_graph_get_next_endpoint(np, NULL);
>>> +       if (!endpoint) {
>>> +               DRM_ERROR("no valid endpoint node\n");
>>> +               return -ENODEV;
>>> +       }
>>> +       of_node_put(endpoint);
>>> +
>>> +       bridge_node = of_graph_get_remote_port_parent(endpoint);
>>> +       if (!bridge_node) {
>>> +               DRM_ERROR("no valid bridge node\n");
>>> +               return -ENODEV;
>>> +       }
>>> +       of_node_put(bridge_node);
>>> +
>>> +       bridge = of_drm_find_bridge(bridge_node);
>>> +       if (!bridge) {
>>> +               DRM_INFO("wait for external HDMI bridge driver.\n");
>>> +               return -EPROBE_DEFER;
>>> +       }
>>> +       dsi->bridge = bridge;
>>
>>
>> This could be left for later, but it would be better if the dsi driver
>> registers even if the bridge driver module isn't inserted yet, or
>> happens much later in boot.
>>
>> We could achieve this by trying to attach the bridge (done in
>> dsi_bridge_init) in the dsi_host_attach callback instead of having it
>> in dsi_bind.
>
> Do you mean that it is the right time or place to attach the bridge in
> dsi_host_attach callback.
> Why? Because at this time bridge driver must be register?

The bridge/panel drivers generally call drm_bridge_add/drm_panel_add and 
mipi_dsi_attach() during probe.

If the driver calls drm_bridge_add() before mipi_dsi_attach() in probe,
then 'of_drm_find_bridge()' should succeed in the callback. This, 
however, is prone to all sorts of race conditions and hence not the
best solution.

In the case of panels, a dsi host can always create a dummy connector,
and search for a panel (of_drm_find_panel) in its 'detect' helper.
Unfortunately, we don't have a free connector in the case of bridges.
The connector are, in most cases, created by the bridge driver itself,
and the dsi host driver has no say over the connector ops.

I don't have a better solution yet, hence I said it could be left for
later :)

Archit

>
> Thanks,
> -xinliang
>
>>
>> Thanks,
>> Archit
>>
>>>
>>>          ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>>>          if (IS_ERR(ctx->dsi_cfg_clk)) {
>>>
>>
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
>> hosted by The Linux Foundation

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
@ 2015-12-02  8:20           ` Archit Taneja
  0 siblings, 0 replies; 70+ messages in thread
From: Archit Taneja @ 2015-12-02  8:20 UTC (permalink / raw)
  To: linux-arm-kernel



On 12/01/2015 08:20 PM, Xinliang Liu wrote:
> On 1 December 2015 at 17:04, Archit Taneja <architt@codeaurora.org> wrote:
>>
>>
>> On 11/28/2015 04:09 PM, Xinliang Liu wrote:
>>>
>>> Add support for external HDMI bridge.
>>>
>>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>>> Signed-off-by: Andy Green <andy.green@linaro.org>
>>> ---
>>>    drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51
>>> ++++++++++++++++++++++++++++++++
>>>    1 file changed, 51 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>> b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>> index 066e08d..9e056db 100644
>>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>> @@ -78,6 +78,7 @@ struct dsi_hw_ctx {
>>>
>>>    struct hisi_dsi {
>>>          struct drm_encoder encoder;
>>> +       struct drm_bridge *bridge;
>>>          struct mipi_dsi_host host;
>>>          struct drm_display_mode cur_mode;
>>>          struct dsi_hw_ctx *ctx;
>>> @@ -671,6 +672,25 @@ 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)
>>> +{
>>> +       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");
>>
>>
>> s/exteranl/external
>>
>
> will be fixed in v3.
>
>>
>>> +               return ret;
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>>    static int dsi_bind(struct device *dev, struct device *master, void
>>> *data)
>>>    {
>>>          struct dsi_data *ddata = dev_get_drvdata(dev);
>>> @@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct device
>>> *master, void *data)
>>>          if (ret)
>>>                  return ret;
>>>
>>> +       ret = dsi_bridge_init(drm_dev, dsi);
>>> +       if (ret)
>>> +               return ret;
>>> +
>>>          return 0;
>>>    }
>>>
>>> @@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
>>>    static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi
>>> *dsi)
>>>    {
>>>          struct dsi_hw_ctx *ctx = dsi->ctx;
>>> +       struct device_node *np = pdev->dev.of_node;
>>> +       struct device_node *endpoint, *bridge_node;
>>> +       struct drm_bridge *bridge;
>>>          struct resource *res;
>>>
>>> +       /*
>>> +        * Get the endpoint node. In our case, dsi has one output port
>>> +        * to which the external HDMI bridge is connected.
>>> +        */
>>> +       endpoint = of_graph_get_next_endpoint(np, NULL);
>>> +       if (!endpoint) {
>>> +               DRM_ERROR("no valid endpoint node\n");
>>> +               return -ENODEV;
>>> +       }
>>> +       of_node_put(endpoint);
>>> +
>>> +       bridge_node = of_graph_get_remote_port_parent(endpoint);
>>> +       if (!bridge_node) {
>>> +               DRM_ERROR("no valid bridge node\n");
>>> +               return -ENODEV;
>>> +       }
>>> +       of_node_put(bridge_node);
>>> +
>>> +       bridge = of_drm_find_bridge(bridge_node);
>>> +       if (!bridge) {
>>> +               DRM_INFO("wait for external HDMI bridge driver.\n");
>>> +               return -EPROBE_DEFER;
>>> +       }
>>> +       dsi->bridge = bridge;
>>
>>
>> This could be left for later, but it would be better if the dsi driver
>> registers even if the bridge driver module isn't inserted yet, or
>> happens much later in boot.
>>
>> We could achieve this by trying to attach the bridge (done in
>> dsi_bridge_init) in the dsi_host_attach callback instead of having it
>> in dsi_bind.
>
> Do you mean that it is the right time or place to attach the bridge in
> dsi_host_attach callback.
> Why? Because at this time bridge driver must be register?

The bridge/panel drivers generally call drm_bridge_add/drm_panel_add and 
mipi_dsi_attach() during probe.

If the driver calls drm_bridge_add() before mipi_dsi_attach() in probe,
then 'of_drm_find_bridge()' should succeed in the callback. This, 
however, is prone to all sorts of race conditions and hence not the
best solution.

In the case of panels, a dsi host can always create a dummy connector,
and search for a panel (of_drm_find_panel) in its 'detect' helper.
Unfortunately, we don't have a free connector in the case of bridges.
The connector are, in most cases, created by the bridge driver itself,
and the dsi host driver has no say over the connector ops.

I don't have a better solution yet, hence I said it could be left for
later :)

Archit

>
> Thanks,
> -xinliang
>
>>
>> Thanks,
>> Archit
>>
>>>
>>>          ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>>>          if (IS_ERR(ctx->dsi_cfg_clk)) {
>>>
>>
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
>> hosted by The Linux Foundation

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
  2015-12-02  8:20           ` Archit Taneja
@ 2015-12-02 11:24               ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-02 11:24 UTC (permalink / raw)
  To: Archit Taneja
  Cc: dri-devel, devicetree-u79uwXL29TY76Z2rM5mHXA, Daniel Vetter,
	Rob Herring, Daniel Stone, David Airlie, Jon Corbet,
	Catalin Marinas, Will Deacon, linux-doc-u79uwXL29TY76Z2rM5mHXA,
	LAKML, linuxarm-hv44wF8Li93QT0dZR+AlfA, Andy Green,
	Haojian Zhuang, Liguozhu (Kenneth),
	Xu Wei, Wang Fei, Feng Chen, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, XinWei Kong, zourongrong-hv44wF8Li93QT0dZR+AlfA,
	lijianhua-hv44wF8Li93QT0dZR+AlfA, Sumit Semwal

On 2 December 2015 at 16:20, Archit Taneja <architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org> wrote:
>
>
> On 12/01/2015 08:20 PM, Xinliang Liu wrote:
>>
>> On 1 December 2015 at 17:04, Archit Taneja <architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org> wrote:
>>>
>>>
>>>
>>> On 11/28/2015 04:09 PM, Xinliang Liu wrote:
>>>>
>>>>
>>>> Add support for external HDMI bridge.
>>>>
>>>> Signed-off-by: Xinliang Liu <xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>>>> Signed-off-by: Xinwei Kong <kong.kongxinwei-C8/M+/jPZTeaMJb+Lgu22Q@public.gmane.org>
>>>> Signed-off-by: Andy Green <andy.green-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>>>> ---
>>>>    drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51
>>>> ++++++++++++++++++++++++++++++++
>>>>    1 file changed, 51 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>>> b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>>> index 066e08d..9e056db 100644
>>>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>>> @@ -78,6 +78,7 @@ struct dsi_hw_ctx {
>>>>
>>>>    struct hisi_dsi {
>>>>          struct drm_encoder encoder;
>>>> +       struct drm_bridge *bridge;
>>>>          struct mipi_dsi_host host;
>>>>          struct drm_display_mode cur_mode;
>>>>          struct dsi_hw_ctx *ctx;
>>>> @@ -671,6 +672,25 @@ 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)
>>>> +{
>>>> +       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");
>>>
>>>
>>>
>>> s/exteranl/external
>>>
>>
>> will be fixed in v3.
>>
>>>
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>>>>    static int dsi_bind(struct device *dev, struct device *master, void
>>>> *data)
>>>>    {
>>>>          struct dsi_data *ddata = dev_get_drvdata(dev);
>>>> @@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct
>>>> device
>>>> *master, void *data)
>>>>          if (ret)
>>>>                  return ret;
>>>>
>>>> +       ret = dsi_bridge_init(drm_dev, dsi);
>>>> +       if (ret)
>>>> +               return ret;
>>>> +
>>>>          return 0;
>>>>    }
>>>>
>>>> @@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
>>>>    static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi
>>>> *dsi)
>>>>    {
>>>>          struct dsi_hw_ctx *ctx = dsi->ctx;
>>>> +       struct device_node *np = pdev->dev.of_node;
>>>> +       struct device_node *endpoint, *bridge_node;
>>>> +       struct drm_bridge *bridge;
>>>>          struct resource *res;
>>>>
>>>> +       /*
>>>> +        * Get the endpoint node. In our case, dsi has one output port
>>>> +        * to which the external HDMI bridge is connected.
>>>> +        */
>>>> +       endpoint = of_graph_get_next_endpoint(np, NULL);
>>>> +       if (!endpoint) {
>>>> +               DRM_ERROR("no valid endpoint node\n");
>>>> +               return -ENODEV;
>>>> +       }
>>>> +       of_node_put(endpoint);
>>>> +
>>>> +       bridge_node = of_graph_get_remote_port_parent(endpoint);
>>>> +       if (!bridge_node) {
>>>> +               DRM_ERROR("no valid bridge node\n");
>>>> +               return -ENODEV;
>>>> +       }
>>>> +       of_node_put(bridge_node);
>>>> +
>>>> +       bridge = of_drm_find_bridge(bridge_node);
>>>> +       if (!bridge) {
>>>> +               DRM_INFO("wait for external HDMI bridge driver.\n");
>>>> +               return -EPROBE_DEFER;
>>>> +       }
>>>> +       dsi->bridge = bridge;
>>>
>>>
>>>
>>> This could be left for later, but it would be better if the dsi driver
>>> registers even if the bridge driver module isn't inserted yet, or
>>> happens much later in boot.
>>>
>>> We could achieve this by trying to attach the bridge (done in
>>> dsi_bridge_init) in the dsi_host_attach callback instead of having it
>>> in dsi_bind.
>>
>>
>> Do you mean that it is the right time or place to attach the bridge in
>> dsi_host_attach callback.
>> Why? Because at this time bridge driver must be register?
>
>
> The bridge/panel drivers generally call drm_bridge_add/drm_panel_add and
> mipi_dsi_attach() during probe.
>
> If the driver calls drm_bridge_add() before mipi_dsi_attach() in probe,
> then 'of_drm_find_bridge()' should succeed in the callback. This, however,
> is prone to all sorts of race conditions and hence not the
> best solution.
>
> In the case of panels, a dsi host can always create a dummy connector,
> and search for a panel (of_drm_find_panel) in its 'detect' helper.
> Unfortunately, we don't have a free connector in the case of bridges.
> The connector are, in most cases, created by the bridge driver itself,
> and the dsi host driver has no say over the connector ops.
>
> I don't have a better solution yet, hence I said it could be left for
> later :)

Understand, This is an Initialization dependence of two drivers. One
driver need to do something after other driver init.
I don't think there is a best solution. I prefer to keep waiting in probe stage.

Thanks,
-xinliang

>
> Archit
>
>
>>
>> Thanks,
>> -xinliang
>>
>>>
>>> Thanks,
>>> Archit
>>>
>>>>
>>>>          ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>>>>          if (IS_ERR(ctx->dsi_cfg_clk)) {
>>>>
>>>
>>> --
>>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
>>> Forum,
>>> hosted by The Linux Foundation
>
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 10/10] drm/hisilicon: Add support for external bridge
@ 2015-12-02 11:24               ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-02 11:24 UTC (permalink / raw)
  To: linux-arm-kernel

On 2 December 2015 at 16:20, Archit Taneja <architt@codeaurora.org> wrote:
>
>
> On 12/01/2015 08:20 PM, Xinliang Liu wrote:
>>
>> On 1 December 2015 at 17:04, Archit Taneja <architt@codeaurora.org> wrote:
>>>
>>>
>>>
>>> On 11/28/2015 04:09 PM, Xinliang Liu wrote:
>>>>
>>>>
>>>> Add support for external HDMI bridge.
>>>>
>>>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>>>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>>>> Signed-off-by: Andy Green <andy.green@linaro.org>
>>>> ---
>>>>    drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 51
>>>> ++++++++++++++++++++++++++++++++
>>>>    1 file changed, 51 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>>> b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>>> index 066e08d..9e056db 100644
>>>> --- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>>>> @@ -78,6 +78,7 @@ struct dsi_hw_ctx {
>>>>
>>>>    struct hisi_dsi {
>>>>          struct drm_encoder encoder;
>>>> +       struct drm_bridge *bridge;
>>>>          struct mipi_dsi_host host;
>>>>          struct drm_display_mode cur_mode;
>>>>          struct dsi_hw_ctx *ctx;
>>>> @@ -671,6 +672,25 @@ 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)
>>>> +{
>>>> +       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");
>>>
>>>
>>>
>>> s/exteranl/external
>>>
>>
>> will be fixed in v3.
>>
>>>
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       return 0;
>>>> +}
>>>> +
>>>>    static int dsi_bind(struct device *dev, struct device *master, void
>>>> *data)
>>>>    {
>>>>          struct dsi_data *ddata = dev_get_drvdata(dev);
>>>> @@ -686,6 +706,10 @@ static int dsi_bind(struct device *dev, struct
>>>> device
>>>> *master, void *data)
>>>>          if (ret)
>>>>                  return ret;
>>>>
>>>> +       ret = dsi_bridge_init(drm_dev, dsi);
>>>> +       if (ret)
>>>> +               return ret;
>>>> +
>>>>          return 0;
>>>>    }
>>>>
>>>> @@ -702,8 +726,35 @@ static const struct component_ops dsi_ops = {
>>>>    static int dsi_parse_dt(struct platform_device *pdev, struct hisi_dsi
>>>> *dsi)
>>>>    {
>>>>          struct dsi_hw_ctx *ctx = dsi->ctx;
>>>> +       struct device_node *np = pdev->dev.of_node;
>>>> +       struct device_node *endpoint, *bridge_node;
>>>> +       struct drm_bridge *bridge;
>>>>          struct resource *res;
>>>>
>>>> +       /*
>>>> +        * Get the endpoint node. In our case, dsi has one output port
>>>> +        * to which the external HDMI bridge is connected.
>>>> +        */
>>>> +       endpoint = of_graph_get_next_endpoint(np, NULL);
>>>> +       if (!endpoint) {
>>>> +               DRM_ERROR("no valid endpoint node\n");
>>>> +               return -ENODEV;
>>>> +       }
>>>> +       of_node_put(endpoint);
>>>> +
>>>> +       bridge_node = of_graph_get_remote_port_parent(endpoint);
>>>> +       if (!bridge_node) {
>>>> +               DRM_ERROR("no valid bridge node\n");
>>>> +               return -ENODEV;
>>>> +       }
>>>> +       of_node_put(bridge_node);
>>>> +
>>>> +       bridge = of_drm_find_bridge(bridge_node);
>>>> +       if (!bridge) {
>>>> +               DRM_INFO("wait for external HDMI bridge driver.\n");
>>>> +               return -EPROBE_DEFER;
>>>> +       }
>>>> +       dsi->bridge = bridge;
>>>
>>>
>>>
>>> This could be left for later, but it would be better if the dsi driver
>>> registers even if the bridge driver module isn't inserted yet, or
>>> happens much later in boot.
>>>
>>> We could achieve this by trying to attach the bridge (done in
>>> dsi_bridge_init) in the dsi_host_attach callback instead of having it
>>> in dsi_bind.
>>
>>
>> Do you mean that it is the right time or place to attach the bridge in
>> dsi_host_attach callback.
>> Why? Because at this time bridge driver must be register?
>
>
> The bridge/panel drivers generally call drm_bridge_add/drm_panel_add and
> mipi_dsi_attach() during probe.
>
> If the driver calls drm_bridge_add() before mipi_dsi_attach() in probe,
> then 'of_drm_find_bridge()' should succeed in the callback. This, however,
> is prone to all sorts of race conditions and hence not the
> best solution.
>
> In the case of panels, a dsi host can always create a dummy connector,
> and search for a panel (of_drm_find_panel) in its 'detect' helper.
> Unfortunately, we don't have a free connector in the case of bridges.
> The connector are, in most cases, created by the bridge driver itself,
> and the dsi host driver has no say over the connector ops.
>
> I don't have a better solution yet, hence I said it could be left for
> later :)

Understand, This is an Initialization dependence of two drivers. One
driver need to do something after other driver init.
I don't think there is a best solution. I prefer to keep waiting in probe stage.

Thanks,
-xinliang

>
> Archit
>
>
>>
>> Thanks,
>> -xinliang
>>
>>>
>>> Thanks,
>>> Archit
>>>
>>>>
>>>>          ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
>>>>          if (IS_ERR(ctx->dsi_cfg_clk)) {
>>>>
>>>
>>> --
>>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
>>> Forum,
>>> hosted by The Linux Foundation
>
>
> --
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> hosted by The Linux Foundation

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-11-28 10:38   ` Xinliang Liu
@ 2015-12-03 16:21     ` Rob Herring
  -1 siblings, 0 replies; 70+ messages in thread
From: Rob Herring @ 2015-12-03 16:21 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: dri-devel, devicetree, Daniel Vetter, Daniel Stone,
	Archit Taneja, David Airlie, Jonathan Corbet, Catalin Marinas,
	Will Deacon, linux-doc, linux-arm-kernel, Linuxarm, Andy Green,
	Haojian Zhuang, Liguozhu (Kenneth),
	Wei Xu, w.f, Chen Feng, Bintian Wang, Benjamin Gaignard,
	Yiping Xu, Xinwei

On Sat, Nov 28, 2015 at 4:38 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> Add DRM master driver for hi6220 SoC which used in HiKey board.
> Add dumb buffer feature.
> Add prime dmabuf feature.
>
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---

> +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);

BTW, is args->bpp supposed to be bits or bytes? I'm using your dumb bo
support in drm_gralloc which does bytes as that is what
gralloc_drm_get_bpp returns. The virtio-gpu driver does bits. I'm
guessing bits is correct.

Rob

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-12-03 16:21     ` Rob Herring
  0 siblings, 0 replies; 70+ messages in thread
From: Rob Herring @ 2015-12-03 16:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Nov 28, 2015 at 4:38 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> Add DRM master driver for hi6220 SoC which used in HiKey board.
> Add dumb buffer feature.
> Add prime dmabuf feature.
>
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
> ---

> +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);

BTW, is args->bpp supposed to be bits or bytes? I'm using your dumb bo
support in drm_gralloc which does bytes as that is what
gralloc_drm_get_bpp returns. The virtio-gpu driver does bits. I'm
guessing bits is correct.

Rob

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-12-03 16:21     ` Rob Herring
@ 2015-12-05  1:25       ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-05  1:25 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-doc, Catalin Marinas, Will Deacon, Linuxarm, dri-devel,
	Wei Xu, Benjamin Gaignard, zourongrong, Yiping Xu,
	Jonathan Corbet, Wang Fei, lijianhua, devicetree, Bintian Wang,
	Chen Feng, linux-arm-kernel, Andy Green, Liguozhu (Kenneth),
	Haojian Zhuang

On 4 December 2015 at 00:21, Rob Herring <robh@kernel.org> wrote:
> On Sat, Nov 28, 2015 at 4:38 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
>> Add DRM master driver for hi6220 SoC which used in HiKey board.
>> Add dumb buffer feature.
>> Add prime dmabuf feature.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>
>> +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);
>
> BTW, is args->bpp supposed to be bits or bytes? I'm using your dumb bo
> support in drm_gralloc which does bytes as that is what
> gralloc_drm_get_bpp returns. The virtio-gpu driver does bits. I'm
> guessing bits is correct.

yes, it is bits. And pitch is bytes.

>
> Rob
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-12-05  1:25       ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-05  1:25 UTC (permalink / raw)
  To: linux-arm-kernel

On 4 December 2015 at 00:21, Rob Herring <robh@kernel.org> wrote:
> On Sat, Nov 28, 2015 at 4:38 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
>> Add DRM master driver for hi6220 SoC which used in HiKey board.
>> Add dumb buffer feature.
>> Add prime dmabuf feature.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
>> ---
>
>> +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);
>
> BTW, is args->bpp supposed to be bits or bytes? I'm using your dumb bo
> support in drm_gralloc which does bytes as that is what
> gralloc_drm_get_bpp returns. The virtio-gpu driver does bits. I'm
> guessing bits is correct.

yes, it is bits. And pitch is bytes.

>
> Rob

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-12-01 10:52     ` Xinliang Liu
@ 2015-12-01 12:54       ` Daniel Vetter
  -1 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-12-01 12:54 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: Daniel Vetter, Emil Velikov, ML dri-devel, devicetree,
	Rob Herring, Daniel Stone, architt, David Airlie, Jon Corbet,
	Catalin Marinas, Will Deacon, Andy Green, Yiping Xu, linux-doc,
	Wang Fei, zourongrong, linuxarm, Xu Wei, Bintian Wang,
	Haojian Zhuang, Benjamin Gaignard, Feng Chen, lijianhua,
	Liguozhu (Kenneth),
	LAKML

On Tue, Dec 01, 2015 at 06:52:20PM +0800, Xinliang Liu wrote:
> On 30 November 2015 at 15:46, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
> >> Hi Xinliang,
> >>
> >> On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> >> > Add DRM master driver for hi6220 SoC which used in HiKey board.
> >> > Add dumb buffer feature.
> >> > Add prime dmabuf feature.
> >> >
> >> > Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> >> > Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> >> > Signed-off-by: Andy Green <andy.green@linaro.org>
> >> Your s-o-b should be the bottom of the list. There was a presentation
> >> (ages ago) from Greg KH, who nicely described the order as a "chain of
> >> command" or "guilt path". Looks like the rest of the series could use
> >> this tweak.
> >>
> >> > ---
> >> >  drivers/gpu/drm/Kconfig                  |   2 +
> >> >  drivers/gpu/drm/Makefile                 |   1 +
> >> >  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
> >> >  drivers/gpu/drm/hisilicon/Makefile       |   3 +
> >> >  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
> >> >  5 files changed, 229 insertions(+)
> >> >  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
> >> >  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
> >> >  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> >> >
> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> > index 8773fad..038aae8 100644
> >> > --- a/drivers/gpu/drm/Kconfig
> >> > +++ b/drivers/gpu/drm/Kconfig
> >> > @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
> >> >  source "drivers/gpu/drm/imx/Kconfig"
> >> >
> >> >  source "drivers/gpu/drm/vc4/Kconfig"
> >> > +
> >> > +source "drivers/gpu/drm/hisilicon/Kconfig"
> >> I could swear that we can a patch that sorts these alphabetically,
> >> although it doesn't seem to have made it upstream yet :-(
> >>
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> >>
> >> > +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
> >> > +{
> >> The use of .load (and .unload?) callbacks is not recommended. Take a
> >> look at Laurent Pinchart's patch [1] about the whys and hows on the
> >> topic
> >>
> >> > +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
> >> > +                                            struct drm_gem_object *obj,
> >> > +                                            int flags)
> >> > +{
> >> > +       /* we want to be able to write in mmapped buffer */
> >> > +       flags |= O_RDWR;
> >> Erm... something feels fishy here. Out of the existing 15 drivers
> >> setting up the prime callbacks only one (sti) does a similar thing. So
> >> either everyone else is missing something obvious or hisilicon and sti
> >> can rework their inner working to remove this (dare I say it) hack.
> >
> > Mmap on drm dma-bufs doesn't work, and fairly intentionally. There's been
> > some rfc patch series to address this:
> >
> > http://lists.freedesktop.org/archives/dri-devel/2015-August/089263.html
> >
> > Unfortunately it seems stuck with getting the userspace piece in shape.
> > Might be best to ping Tiago for an update.
> >
> > Meanwhile please don't do this in drivers ;-)
> 
> It seems Tiago's patch is the best way to fix mmap issue.
> I'll ping him, hope he will repsonse.
> 
> >
> >> > +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);
> >> > +
> >> I'm not sure you want this kind of dependency of an out of tree driver
> >> upstream. If this is some limitation on the display engine so be it,
> >> but tailoring things for an external module seems like a very bad
> >> idea.
> >
> > Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
> > go upstream to fix this ...
> 
> Oh! I have use dumb buffers for rendering now. What does dumb buffer
> mean and what's dumb buffers  for?
> For rendering buffer requirements how should I do then?

Dumb buffers are really just a very thin in-kernel abstraction for boot
splash screens. As soon as you have real userspace (surfaceflinger, gl es,
whatever) the idea is that an allocator in userspace (like gralloc, gbm or
similar) figures out the allocation constraints and where to allocate
things exactly. Maybe that includes allocating from dumb buffers with
special knowledge (by increasing x/y perhaps), but most likely that means
you either allocate from your proprietary/out-of-tree gpu render driver or
some other central allocator like ion.

Anyway, adding hacks to the dumb buffer which are meant to facilite
sharing with other devices, or using it for anything else than a boot
splash is a no-go. DRM has made the design decision that gpu rendering is
too vendor-specific at the kernel level to make such generic interfaces
possible, and that allocation problems can only be solved properly in
userspace.

For your case specifically first step is to get an open-source mali driver
released, since that the basic requirement for upstream drm to design new
solutions in any area. Hence why I mentioned that ;-)

Kernel modesetting drivers don't need that since for those we have a
well-defined ABI and already existing userspace like X or Wayland which
can use it.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-12-01 12:54       ` Daniel Vetter
  0 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-12-01 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Dec 01, 2015 at 06:52:20PM +0800, Xinliang Liu wrote:
> On 30 November 2015 at 15:46, Daniel Vetter <daniel@ffwll.ch> wrote:
> > On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
> >> Hi Xinliang,
> >>
> >> On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> >> > Add DRM master driver for hi6220 SoC which used in HiKey board.
> >> > Add dumb buffer feature.
> >> > Add prime dmabuf feature.
> >> >
> >> > Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> >> > Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> >> > Signed-off-by: Andy Green <andy.green@linaro.org>
> >> Your s-o-b should be the bottom of the list. There was a presentation
> >> (ages ago) from Greg KH, who nicely described the order as a "chain of
> >> command" or "guilt path". Looks like the rest of the series could use
> >> this tweak.
> >>
> >> > ---
> >> >  drivers/gpu/drm/Kconfig                  |   2 +
> >> >  drivers/gpu/drm/Makefile                 |   1 +
> >> >  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
> >> >  drivers/gpu/drm/hisilicon/Makefile       |   3 +
> >> >  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
> >> >  5 files changed, 229 insertions(+)
> >> >  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
> >> >  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
> >> >  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> >> >
> >> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> >> > index 8773fad..038aae8 100644
> >> > --- a/drivers/gpu/drm/Kconfig
> >> > +++ b/drivers/gpu/drm/Kconfig
> >> > @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
> >> >  source "drivers/gpu/drm/imx/Kconfig"
> >> >
> >> >  source "drivers/gpu/drm/vc4/Kconfig"
> >> > +
> >> > +source "drivers/gpu/drm/hisilicon/Kconfig"
> >> I could swear that we can a patch that sorts these alphabetically,
> >> although it doesn't seem to have made it upstream yet :-(
> >>
> >> > --- /dev/null
> >> > +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> >>
> >> > +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
> >> > +{
> >> The use of .load (and .unload?) callbacks is not recommended. Take a
> >> look at Laurent Pinchart's patch [1] about the whys and hows on the
> >> topic
> >>
> >> > +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
> >> > +                                            struct drm_gem_object *obj,
> >> > +                                            int flags)
> >> > +{
> >> > +       /* we want to be able to write in mmapped buffer */
> >> > +       flags |= O_RDWR;
> >> Erm... something feels fishy here. Out of the existing 15 drivers
> >> setting up the prime callbacks only one (sti) does a similar thing. So
> >> either everyone else is missing something obvious or hisilicon and sti
> >> can rework their inner working to remove this (dare I say it) hack.
> >
> > Mmap on drm dma-bufs doesn't work, and fairly intentionally. There's been
> > some rfc patch series to address this:
> >
> > http://lists.freedesktop.org/archives/dri-devel/2015-August/089263.html
> >
> > Unfortunately it seems stuck with getting the userspace piece in shape.
> > Might be best to ping Tiago for an update.
> >
> > Meanwhile please don't do this in drivers ;-)
> 
> It seems Tiago's patch is the best way to fix mmap issue.
> I'll ping him, hope he will repsonse.
> 
> >
> >> > +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);
> >> > +
> >> I'm not sure you want this kind of dependency of an out of tree driver
> >> upstream. If this is some limitation on the display engine so be it,
> >> but tailoring things for an external module seems like a very bad
> >> idea.
> >
> > Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
> > go upstream to fix this ...
> 
> Oh! I have use dumb buffers for rendering now. What does dumb buffer
> mean and what's dumb buffers  for?
> For rendering buffer requirements how should I do then?

Dumb buffers are really just a very thin in-kernel abstraction for boot
splash screens. As soon as you have real userspace (surfaceflinger, gl es,
whatever) the idea is that an allocator in userspace (like gralloc, gbm or
similar) figures out the allocation constraints and where to allocate
things exactly. Maybe that includes allocating from dumb buffers with
special knowledge (by increasing x/y perhaps), but most likely that means
you either allocate from your proprietary/out-of-tree gpu render driver or
some other central allocator like ion.

Anyway, adding hacks to the dumb buffer which are meant to facilite
sharing with other devices, or using it for anything else than a boot
splash is a no-go. DRM has made the design decision that gpu rendering is
too vendor-specific at the kernel level to make such generic interfaces
possible, and that allocation problems can only be solved properly in
userspace.

For your case specifically first step is to get an open-source mali driver
released, since that the basic requirement for upstream drm to design new
solutions in any area. Hence why I mentioned that ;-)

Kernel modesetting drivers don't need that since for those we have a
well-defined ABI and already existing userspace like X or Wayland which
can use it.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-11-30  7:46   ` Daniel Vetter
@ 2015-12-01 10:52     ` Xinliang Liu
  -1 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 10:52 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Emil Velikov, ML dri-devel, devicetree, Rob Herring,
	Daniel Stone, architt, David Airlie, Jon Corbet, Catalin Marinas,
	Will Deacon, Andy Green, Yiping Xu, linux-doc, Wang Fei,
	zourongrong, linuxarm, Xu Wei, Bintian Wang, Haojian Zhuang,
	Benjamin Gaignard, Feng Chen, lijianhua, Liguozhu (Kenneth),
	LAKML

On 30 November 2015 at 15:46, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
>> Hi Xinliang,
>>
>> On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
>> > Add DRM master driver for hi6220 SoC which used in HiKey board.
>> > Add dumb buffer feature.
>> > Add prime dmabuf feature.
>> >
>> > Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> > Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> > Signed-off-by: Andy Green <andy.green@linaro.org>
>> Your s-o-b should be the bottom of the list. There was a presentation
>> (ages ago) from Greg KH, who nicely described the order as a "chain of
>> command" or "guilt path". Looks like the rest of the series could use
>> this tweak.
>>
>> > ---
>> >  drivers/gpu/drm/Kconfig                  |   2 +
>> >  drivers/gpu/drm/Makefile                 |   1 +
>> >  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
>> >  drivers/gpu/drm/hisilicon/Makefile       |   3 +
>> >  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
>> >  5 files changed, 229 insertions(+)
>> >  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
>> >  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
>> >  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>> >
>> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> > index 8773fad..038aae8 100644
>> > --- a/drivers/gpu/drm/Kconfig
>> > +++ b/drivers/gpu/drm/Kconfig
>> > @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
>> >  source "drivers/gpu/drm/imx/Kconfig"
>> >
>> >  source "drivers/gpu/drm/vc4/Kconfig"
>> > +
>> > +source "drivers/gpu/drm/hisilicon/Kconfig"
>> I could swear that we can a patch that sorts these alphabetically,
>> although it doesn't seem to have made it upstream yet :-(
>>
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>>
>> > +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
>> > +{
>> The use of .load (and .unload?) callbacks is not recommended. Take a
>> look at Laurent Pinchart's patch [1] about the whys and hows on the
>> topic
>>
>> > +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
>> > +                                            struct drm_gem_object *obj,
>> > +                                            int flags)
>> > +{
>> > +       /* we want to be able to write in mmapped buffer */
>> > +       flags |= O_RDWR;
>> Erm... something feels fishy here. Out of the existing 15 drivers
>> setting up the prime callbacks only one (sti) does a similar thing. So
>> either everyone else is missing something obvious or hisilicon and sti
>> can rework their inner working to remove this (dare I say it) hack.
>
> Mmap on drm dma-bufs doesn't work, and fairly intentionally. There's been
> some rfc patch series to address this:
>
> http://lists.freedesktop.org/archives/dri-devel/2015-August/089263.html
>
> Unfortunately it seems stuck with getting the userspace piece in shape.
> Might be best to ping Tiago for an update.
>
> Meanwhile please don't do this in drivers ;-)

It seems Tiago's patch is the best way to fix mmap issue.
I'll ping him, hope he will repsonse.

>
>> > +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);
>> > +
>> I'm not sure you want this kind of dependency of an out of tree driver
>> upstream. If this is some limitation on the display engine so be it,
>> but tailoring things for an external module seems like a very bad
>> idea.
>
> Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
> go upstream to fix this ...

Oh! I have use dumb buffers for rendering now. What does dumb buffer
mean and what's dumb buffers  for?
For rendering buffer requirements how should I do then?

Thanks,
-xinliang

> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-12-01 10:52     ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 10:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 30 November 2015 at 15:46, Daniel Vetter <daniel@ffwll.ch> wrote:
> On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
>> Hi Xinliang,
>>
>> On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
>> > Add DRM master driver for hi6220 SoC which used in HiKey board.
>> > Add dumb buffer feature.
>> > Add prime dmabuf feature.
>> >
>> > Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> > Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> > Signed-off-by: Andy Green <andy.green@linaro.org>
>> Your s-o-b should be the bottom of the list. There was a presentation
>> (ages ago) from Greg KH, who nicely described the order as a "chain of
>> command" or "guilt path". Looks like the rest of the series could use
>> this tweak.
>>
>> > ---
>> >  drivers/gpu/drm/Kconfig                  |   2 +
>> >  drivers/gpu/drm/Makefile                 |   1 +
>> >  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
>> >  drivers/gpu/drm/hisilicon/Makefile       |   3 +
>> >  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
>> >  5 files changed, 229 insertions(+)
>> >  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
>> >  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
>> >  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>> >
>> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> > index 8773fad..038aae8 100644
>> > --- a/drivers/gpu/drm/Kconfig
>> > +++ b/drivers/gpu/drm/Kconfig
>> > @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
>> >  source "drivers/gpu/drm/imx/Kconfig"
>> >
>> >  source "drivers/gpu/drm/vc4/Kconfig"
>> > +
>> > +source "drivers/gpu/drm/hisilicon/Kconfig"
>> I could swear that we can a patch that sorts these alphabetically,
>> although it doesn't seem to have made it upstream yet :-(
>>
>> > --- /dev/null
>> > +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>>
>> > +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
>> > +{
>> The use of .load (and .unload?) callbacks is not recommended. Take a
>> look at Laurent Pinchart's patch [1] about the whys and hows on the
>> topic
>>
>> > +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
>> > +                                            struct drm_gem_object *obj,
>> > +                                            int flags)
>> > +{
>> > +       /* we want to be able to write in mmapped buffer */
>> > +       flags |= O_RDWR;
>> Erm... something feels fishy here. Out of the existing 15 drivers
>> setting up the prime callbacks only one (sti) does a similar thing. So
>> either everyone else is missing something obvious or hisilicon and sti
>> can rework their inner working to remove this (dare I say it) hack.
>
> Mmap on drm dma-bufs doesn't work, and fairly intentionally. There's been
> some rfc patch series to address this:
>
> http://lists.freedesktop.org/archives/dri-devel/2015-August/089263.html
>
> Unfortunately it seems stuck with getting the userspace piece in shape.
> Might be best to ping Tiago for an update.
>
> Meanwhile please don't do this in drivers ;-)

It seems Tiago's patch is the best way to fix mmap issue.
I'll ping him, hope he will repsonse.

>
>> > +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);
>> > +
>> I'm not sure you want this kind of dependency of an out of tree driver
>> upstream. If this is some limitation on the display engine so be it,
>> but tailoring things for an external module seems like a very bad
>> idea.
>
> Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
> go upstream to fix this ...

Oh! I have use dumb buffers for rendering now. What does dumb buffer
mean and what's dumb buffers  for?
For rendering buffer requirements how should I do then?

Thanks,
-xinliang

> -Daniel
> --
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-11-28 15:25 [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver Emil Velikov
@ 2015-12-01 10:18   ` Xinliang Liu
  2015-12-01 10:18   ` Xinliang Liu
  1 sibling, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 10:18 UTC (permalink / raw)
  To: Emil Velikov
  Cc: ML dri-devel, devicetree, Daniel Vetter, Rob Herring,
	Daniel Stone, architt, David Airlie, Jon Corbet, Catalin Marinas,
	Will Deacon, Andy Green, Yiping Xu, linux-doc, Wang Fei,
	zourongrong, linuxarm, Xu Wei, Bintian Wang, Haojian Zhuang,
	Benjamin Gaignard, Feng Chen, lijianhua, Liguozhu (Kenneth),
	LAKML

On 28 November 2015 at 23:25, Emil Velikov <emil.l.velikov@gmail.com> wrote:

Hi Emil, thanks again for review.

> Hi Xinliang,
>
> On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
>> Add DRM master driver for hi6220 SoC which used in HiKey board.
>> Add dumb buffer feature.
>> Add prime dmabuf feature.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
> Your s-o-b should be the bottom of the list. There was a presentation
> (ages ago) from Greg KH, who nicely described the order as a "chain of
> command" or "guilt path". Looks like the rest of the series could use
> this tweak.

will fixed in v3.

>
>> ---
>>  drivers/gpu/drm/Kconfig                  |   2 +
>>  drivers/gpu/drm/Makefile                 |   1 +
>>  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
>>  drivers/gpu/drm/hisilicon/Makefile       |   3 +
>>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
>>  5 files changed, 229 insertions(+)
>>  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
>>  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
>>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 8773fad..038aae8 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
>>  source "drivers/gpu/drm/imx/Kconfig"
>>
>>  source "drivers/gpu/drm/vc4/Kconfig"
>> +
>> +source "drivers/gpu/drm/hisilicon/Kconfig"
> I could swear that we can a patch that sorts these alphabetically,
> although it doesn't seem to have made it upstream yet :-(

Yes, as there are so many drm drivers now, it's time to do this work I think.
I'll try to send a separate patch for this soon.

>
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>
>> +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
>> +{
> The use of .load (and .unload?) callbacks is not recommended. Take a
> look at Laurent Pinchart's patch [1] about the whys and hows on the
> topic

will removed .load/unload in v3.

>
>> +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
>> +                                            struct drm_gem_object *obj,
>> +                                            int flags)
>> +{
>> +       /* we want to be able to write in mmapped buffer */
>> +       flags |= O_RDWR;
> Erm... something feels fishy here. Out of the existing 15 drivers
> setting up the prime callbacks only one (sti) does a similar thing. So
> either everyone else is missing something obvious or hisilicon and sti
> can rework their inner working to remove this (dare I say it) hack.

I would talk to sti guys about this. Not sure how to handle this now.

>
>> +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);
>> +
> I'm not sure you want this kind of dependency of an out of tree driver
> upstream. If this is some limitation on the display engine so be it,
> but tailoring things for an external module seems like a very bad
> idea.

I can move this mali dependency to user drivers (such as gralloc and
xf86-video-armsoc).
Do you think it is reasonable?

>
>> +       return drm_gem_cma_dumb_create_internal(file, dev, args);
>> +}
>
>> +static int hisi_drm_bind(struct device *dev)
>> +{
>> +       dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
>> +       return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
> As pointed out by the the kernel doc - drm_platform_init is deprecated.
>

will remove drm_platform_init in v3.

Thanks,
-xinliang

>
> Regards,
> Emil
>
> [1] http://lists.freedesktop.org/archives/dri-devel/2015-November/095466.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-12-01 10:18   ` Xinliang Liu
  0 siblings, 0 replies; 70+ messages in thread
From: Xinliang Liu @ 2015-12-01 10:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 28 November 2015 at 23:25, Emil Velikov <emil.l.velikov@gmail.com> wrote:

Hi Emil, thanks again for review.

> Hi Xinliang,
>
> On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
>> Add DRM master driver for hi6220 SoC which used in HiKey board.
>> Add dumb buffer feature.
>> Add prime dmabuf feature.
>>
>> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
>> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
>> Signed-off-by: Andy Green <andy.green@linaro.org>
> Your s-o-b should be the bottom of the list. There was a presentation
> (ages ago) from Greg KH, who nicely described the order as a "chain of
> command" or "guilt path". Looks like the rest of the series could use
> this tweak.

will fixed in v3.

>
>> ---
>>  drivers/gpu/drm/Kconfig                  |   2 +
>>  drivers/gpu/drm/Makefile                 |   1 +
>>  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
>>  drivers/gpu/drm/hisilicon/Makefile       |   3 +
>>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
>>  5 files changed, 229 insertions(+)
>>  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
>>  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
>>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 8773fad..038aae8 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
>>  source "drivers/gpu/drm/imx/Kconfig"
>>
>>  source "drivers/gpu/drm/vc4/Kconfig"
>> +
>> +source "drivers/gpu/drm/hisilicon/Kconfig"
> I could swear that we can a patch that sorts these alphabetically,
> although it doesn't seem to have made it upstream yet :-(

Yes, as there are so many drm drivers now, it's time to do this work I think.
I'll try to send a separate patch for this soon.

>
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>
>> +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
>> +{
> The use of .load (and .unload?) callbacks is not recommended. Take a
> look at Laurent Pinchart's patch [1] about the whys and hows on the
> topic

will removed .load/unload in v3.

>
>> +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
>> +                                            struct drm_gem_object *obj,
>> +                                            int flags)
>> +{
>> +       /* we want to be able to write in mmapped buffer */
>> +       flags |= O_RDWR;
> Erm... something feels fishy here. Out of the existing 15 drivers
> setting up the prime callbacks only one (sti) does a similar thing. So
> either everyone else is missing something obvious or hisilicon and sti
> can rework their inner working to remove this (dare I say it) hack.

I would talk to sti guys about this. Not sure how to handle this now.

>
>> +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);
>> +
> I'm not sure you want this kind of dependency of an out of tree driver
> upstream. If this is some limitation on the display engine so be it,
> but tailoring things for an external module seems like a very bad
> idea.

I can move this mali dependency to user drivers (such as gralloc and
xf86-video-armsoc).
Do you think it is reasonable?

>
>> +       return drm_gem_cma_dumb_create_internal(file, dev, args);
>> +}
>
>> +static int hisi_drm_bind(struct device *dev)
>> +{
>> +       dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
>> +       return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
> As pointed out by the the kernel doc - drm_platform_init is deprecated.
>

will remove drm_platform_init in v3.

Thanks,
-xinliang

>
> Regards,
> Emil
>
> [1] http://lists.freedesktop.org/archives/dri-devel/2015-November/095466.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-11-30 17:25     ` Rob Herring
@ 2015-12-01  7:12       ` Daniel Vetter
  -1 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-12-01  7:12 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-doc, Catalin Marinas, Will Deacon, linuxarm, ML dri-devel,
	xuwei5, Benjamin Gaignard, zourongrong, xuyiping, corbet, w.f,
	lijianhua, devicetree, bintian.wang, puck.chen, LAKML,
	andy.green, Emil Velikov, liguozhu, haojian.zhuang

On Mon, Nov 30, 2015 at 11:25:28AM -0600, Rob Herring wrote:
> On Mon, Nov 30, 2015 at 08:46:03AM +0100, Daniel Vetter wrote:
> > On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
> > > Hi Xinliang,
> > > 
> > > On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> > > > Add DRM master driver for hi6220 SoC which used in HiKey board.
> > > > Add dumb buffer feature.
> > > > Add prime dmabuf feature.
> > > >
> 
> > > > +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);
> > > > +
> > > I'm not sure you want this kind of dependency of an out of tree driver
> > > upstream. If this is some limitation on the display engine so be it,
> > > but tailoring things for an external module seems like a very bad
> > > idea.
> > 
> > Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
> > go upstream to fix this ...
> 
> I believe this is copy-n-paste from Rockchip driver.
> 
> I'm curious why there is not a common interface for rendering buffers at 
> least for systems without graphics memory like most ARM systems. Are the 
> requirements of GPU so diverse that things like pitch alignment can't be 
> parameterized?

pitch requirements is generally the least worry. The real fun starts with
tiling modes and how all that stuff interacts. Atm the only solution we
have is "userspace needs to know" in form of either gralloc (android) or
gbm (cros, desktop linux). There have been ideas to for describing buffer
limits, but nothing concrete yet.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-12-01  7:12       ` Daniel Vetter
  0 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-12-01  7:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 30, 2015 at 11:25:28AM -0600, Rob Herring wrote:
> On Mon, Nov 30, 2015 at 08:46:03AM +0100, Daniel Vetter wrote:
> > On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
> > > Hi Xinliang,
> > > 
> > > On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> > > > Add DRM master driver for hi6220 SoC which used in HiKey board.
> > > > Add dumb buffer feature.
> > > > Add prime dmabuf feature.
> > > >
> 
> > > > +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);
> > > > +
> > > I'm not sure you want this kind of dependency of an out of tree driver
> > > upstream. If this is some limitation on the display engine so be it,
> > > but tailoring things for an external module seems like a very bad
> > > idea.
> > 
> > Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
> > go upstream to fix this ...
> 
> I believe this is copy-n-paste from Rockchip driver.
> 
> I'm curious why there is not a common interface for rendering buffers at 
> least for systems without graphics memory like most ARM systems. Are the 
> requirements of GPU so diverse that things like pitch alignment can't be 
> parameterized?

pitch requirements is generally the least worry. The real fun starts with
tiling modes and how all that stuff interacts. Atm the only solution we
have is "userspace needs to know" in form of either gralloc (android) or
gbm (cros, desktop linux). There have been ideas to for describing buffer
limits, but nothing concrete yet.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-11-30  7:46   ` Daniel Vetter
@ 2015-11-30 17:25     ` Rob Herring
  -1 siblings, 0 replies; 70+ messages in thread
From: Rob Herring @ 2015-11-30 17:25 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: linux-doc, Catalin Marinas, Will Deacon, linuxarm, ML dri-devel,
	xuwei5, Benjamin Gaignard, zourongrong, xuyiping, corbet, w.f,
	lijianhua, devicetree, bintian.wang, puck.chen, LAKML,
	andy.green, Emil Velikov, liguozhu, haojian.zhuang

On Mon, Nov 30, 2015 at 08:46:03AM +0100, Daniel Vetter wrote:
> On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
> > Hi Xinliang,
> > 
> > On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> > > Add DRM master driver for hi6220 SoC which used in HiKey board.
> > > Add dumb buffer feature.
> > > Add prime dmabuf feature.
> > >

> > > +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);
> > > +
> > I'm not sure you want this kind of dependency of an out of tree driver
> > upstream. If this is some limitation on the display engine so be it,
> > but tailoring things for an external module seems like a very bad
> > idea.
> 
> Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
> go upstream to fix this ...

I believe this is copy-n-paste from Rockchip driver.

I'm curious why there is not a common interface for rendering buffers at 
least for systems without graphics memory like most ARM systems. Are the 
requirements of GPU so diverse that things like pitch alignment can't be 
parameterized?

Rob
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-11-30 17:25     ` Rob Herring
  0 siblings, 0 replies; 70+ messages in thread
From: Rob Herring @ 2015-11-30 17:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 30, 2015 at 08:46:03AM +0100, Daniel Vetter wrote:
> On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
> > Hi Xinliang,
> > 
> > On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> > > Add DRM master driver for hi6220 SoC which used in HiKey board.
> > > Add dumb buffer feature.
> > > Add prime dmabuf feature.
> > >

> > > +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);
> > > +
> > I'm not sure you want this kind of dependency of an out of tree driver
> > upstream. If this is some limitation on the display engine so be it,
> > but tailoring things for an external module seems like a very bad
> > idea.
> 
> Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
> go upstream to fix this ...

I believe this is copy-n-paste from Rockchip driver.

I'm curious why there is not a common interface for rendering buffers at 
least for systems without graphics memory like most ARM systems. Are the 
requirements of GPU so diverse that things like pitch alignment can't be 
parameterized?

Rob

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
  2015-11-28 15:25 [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver Emil Velikov
@ 2015-11-30  7:46   ` Daniel Vetter
  2015-12-01 10:18   ` Xinliang Liu
  1 sibling, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-11-30  7:46 UTC (permalink / raw)
  To: Emil Velikov
  Cc: linux-doc, Catalin Marinas, Will Deacon, linuxarm, ML dri-devel,
	xuwei5, Benjamin Gaignard, zourongrong, xuyiping, corbet, w.f,
	lijianhua, devicetree, bintian.wang, puck.chen, LAKML,
	andy.green, liguozhu, haojian.zhuang

On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
> Hi Xinliang,
> 
> On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> > Add DRM master driver for hi6220 SoC which used in HiKey board.
> > Add dumb buffer feature.
> > Add prime dmabuf feature.
> >
> > Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> > Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> > Signed-off-by: Andy Green <andy.green@linaro.org>
> Your s-o-b should be the bottom of the list. There was a presentation
> (ages ago) from Greg KH, who nicely described the order as a "chain of
> command" or "guilt path". Looks like the rest of the series could use
> this tweak.
> 
> > ---
> >  drivers/gpu/drm/Kconfig                  |   2 +
> >  drivers/gpu/drm/Makefile                 |   1 +
> >  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
> >  drivers/gpu/drm/hisilicon/Makefile       |   3 +
> >  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
> >  5 files changed, 229 insertions(+)
> >  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
> >  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
> >  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> >
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index 8773fad..038aae8 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
> >  source "drivers/gpu/drm/imx/Kconfig"
> >
> >  source "drivers/gpu/drm/vc4/Kconfig"
> > +
> > +source "drivers/gpu/drm/hisilicon/Kconfig"
> I could swear that we can a patch that sorts these alphabetically,
> although it doesn't seem to have made it upstream yet :-(
> 
> > --- /dev/null
> > +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> 
> > +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
> > +{
> The use of .load (and .unload?) callbacks is not recommended. Take a
> look at Laurent Pinchart's patch [1] about the whys and hows on the
> topic
> 
> > +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
> > +                                            struct drm_gem_object *obj,
> > +                                            int flags)
> > +{
> > +       /* we want to be able to write in mmapped buffer */
> > +       flags |= O_RDWR;
> Erm... something feels fishy here. Out of the existing 15 drivers
> setting up the prime callbacks only one (sti) does a similar thing. So
> either everyone else is missing something obvious or hisilicon and sti
> can rework their inner working to remove this (dare I say it) hack.

Mmap on drm dma-bufs doesn't work, and fairly intentionally. There's been
some rfc patch series to address this:

http://lists.freedesktop.org/archives/dri-devel/2015-August/089263.html

Unfortunately it seems stuck with getting the userspace piece in shape.
Might be best to ping Tiago for an update.

Meanwhile please don't do this in drivers ;-)

> > +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);
> > +
> I'm not sure you want this kind of dependency of an out of tree driver
> upstream. If this is some limitation on the display engine so be it,
> but tailoring things for an external module seems like a very bad
> idea.

Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
go upstream to fix this ...
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-11-30  7:46   ` Daniel Vetter
  0 siblings, 0 replies; 70+ messages in thread
From: Daniel Vetter @ 2015-11-30  7:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Nov 28, 2015 at 03:25:35PM +0000, Emil Velikov wrote:
> Hi Xinliang,
> 
> On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> > Add DRM master driver for hi6220 SoC which used in HiKey board.
> > Add dumb buffer feature.
> > Add prime dmabuf feature.
> >
> > Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> > Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> > Signed-off-by: Andy Green <andy.green@linaro.org>
> Your s-o-b should be the bottom of the list. There was a presentation
> (ages ago) from Greg KH, who nicely described the order as a "chain of
> command" or "guilt path". Looks like the rest of the series could use
> this tweak.
> 
> > ---
> >  drivers/gpu/drm/Kconfig                  |   2 +
> >  drivers/gpu/drm/Makefile                 |   1 +
> >  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
> >  drivers/gpu/drm/hisilicon/Makefile       |   3 +
> >  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
> >  5 files changed, 229 insertions(+)
> >  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
> >  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
> >  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> >
> > diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> > index 8773fad..038aae8 100644
> > --- a/drivers/gpu/drm/Kconfig
> > +++ b/drivers/gpu/drm/Kconfig
> > @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
> >  source "drivers/gpu/drm/imx/Kconfig"
> >
> >  source "drivers/gpu/drm/vc4/Kconfig"
> > +
> > +source "drivers/gpu/drm/hisilicon/Kconfig"
> I could swear that we can a patch that sorts these alphabetically,
> although it doesn't seem to have made it upstream yet :-(
> 
> > --- /dev/null
> > +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
> 
> > +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
> > +{
> The use of .load (and .unload?) callbacks is not recommended. Take a
> look at Laurent Pinchart's patch [1] about the whys and hows on the
> topic
> 
> > +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
> > +                                            struct drm_gem_object *obj,
> > +                                            int flags)
> > +{
> > +       /* we want to be able to write in mmapped buffer */
> > +       flags |= O_RDWR;
> Erm... something feels fishy here. Out of the existing 15 drivers
> setting up the prime callbacks only one (sti) does a similar thing. So
> either everyone else is missing something obvious or hisilicon and sti
> can rework their inner working to remove this (dare I say it) hack.

Mmap on drm dma-bufs doesn't work, and fairly intentionally. There's been
some rfc patch series to address this:

http://lists.freedesktop.org/archives/dri-devel/2015-August/089263.html

Unfortunately it seems stuck with getting the userspace piece in shape.
Might be best to ping Tiago for an update.

Meanwhile please don't do this in drivers ;-)

> > +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);
> > +
> I'm not sure you want this kind of dependency of an out of tree driver
> upstream. If this is some limitation on the display engine so be it,
> but tailoring things for an external module seems like a very bad
> idea.

Yup, nacked. dumb_create is for dumb buffers, not rendering. Mali needs to
go upstream to fix this ...
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver
@ 2015-11-28 15:25 Emil Velikov
  2015-11-30  7:46   ` Daniel Vetter
  2015-12-01 10:18   ` Xinliang Liu
  0 siblings, 2 replies; 70+ messages in thread
From: Emil Velikov @ 2015-11-28 15:25 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: linux-doc, Catalin Marinas, Will Deacon, linuxarm, ML dri-devel,
	xuwei5, Benjamin Gaignard, zourongrong, xuyiping, corbet, w.f,
	lijianhua, devicetree, bintian.wang, puck.chen, LAKML,
	andy.green, liguozhu, haojian.zhuang

Hi Xinliang,

On 28 November 2015 at 10:38, Xinliang Liu <xinliang.liu@linaro.org> wrote:
> Add DRM master driver for hi6220 SoC which used in HiKey board.
> Add dumb buffer feature.
> Add prime dmabuf feature.
>
> Signed-off-by: Xinliang Liu <xinliang.liu@linaro.org>
> Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
> Signed-off-by: Andy Green <andy.green@linaro.org>
Your s-o-b should be the bottom of the list. There was a presentation
(ages ago) from Greg KH, who nicely described the order as a "chain of
command" or "guilt path". Looks like the rest of the series could use
this tweak.

> ---
>  drivers/gpu/drm/Kconfig                  |   2 +
>  drivers/gpu/drm/Makefile                 |   1 +
>  drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
>  drivers/gpu/drm/hisilicon/Makefile       |   3 +
>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 214 +++++++++++++++++++++++++++++++
>  5 files changed, 229 insertions(+)
>  create mode 100644 drivers/gpu/drm/hisilicon/Kconfig
>  create mode 100644 drivers/gpu/drm/hisilicon/Makefile
>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 8773fad..038aae8 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -274,3 +274,5 @@ source "drivers/gpu/drm/amd/amdkfd/Kconfig"
>  source "drivers/gpu/drm/imx/Kconfig"
>
>  source "drivers/gpu/drm/vc4/Kconfig"
> +
> +source "drivers/gpu/drm/hisilicon/Kconfig"
I could swear that we can a patch that sorts these alphabetically,
although it doesn't seem to have made it upstream yet :-(

> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c

> +static int hisi_drm_load(struct drm_device *dev, unsigned long flags)
> +{
The use of .load (and .unload?) callbacks is not recommended. Take a
look at Laurent Pinchart's patch [1] about the whys and hows on the
topic

> +static struct dma_buf *hisi_gem_prime_export(struct drm_device *dev,
> +                                            struct drm_gem_object *obj,
> +                                            int flags)
> +{
> +       /* we want to be able to write in mmapped buffer */
> +       flags |= O_RDWR;
Erm... something feels fishy here. Out of the existing 15 drivers
setting up the prime callbacks only one (sti) does a similar thing. So
either everyone else is missing something obvious or hisilicon and sti
can rework their inner working to remove this (dare I say it) hack.

> +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);
> +
I'm not sure you want this kind of dependency of an out of tree driver
upstream. If this is some limitation on the display engine so be it,
but tailoring things for an external module seems like a very bad
idea.

> +       return drm_gem_cma_dumb_create_internal(file, dev, args);
> +}

> +static int hisi_drm_bind(struct device *dev)
> +{
> +       dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
> +       return drm_platform_init(&hisi_drm_driver, to_platform_device(dev));
As pointed out by the the kernel doc - drm_platform_init is deprecated.


Regards,
Emil

[1] http://lists.freedesktop.org/archives/dri-devel/2015-November/095466.html
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 70+ messages in thread

end of thread, other threads:[~2015-12-05  1:25 UTC | newest]

Thread overview: 70+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-28 10:38 [PATCH v2 00/10] Add New DRM Driver for HiSilicon hi6220 SoC Xinliang Liu
2015-11-28 10:38 ` Xinliang Liu
2015-11-28 10:38 ` [PATCH v2 01/10] arm64: dts: hisilicon: Add display subsystem DT nodes for hi6220 Xinliang Liu
2015-11-28 10:38   ` Xinliang Liu
2015-11-28 10:38 ` [PATCH v2 02/10] drm/hisilicon: Add DT binding docs for hi6220 display subsystem Xinliang Liu
2015-11-28 10:38   ` Xinliang Liu
2015-11-30 19:31   ` Rob Herring
2015-11-30 19:31     ` Rob Herring
2015-12-01  7:17     ` Xinliang Liu
2015-12-01  7:17       ` Xinliang Liu
2015-12-01 13:58       ` Rob Herring
2015-12-01 13:58         ` Rob Herring
2015-11-28 10:38 ` [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver Xinliang Liu
2015-11-28 10:38   ` Xinliang Liu
2015-12-03 16:21   ` Rob Herring
2015-12-03 16:21     ` Rob Herring
2015-12-05  1:25     ` Xinliang Liu
2015-12-05  1:25       ` Xinliang Liu
2015-11-28 10:38 ` [PATCH v2 04/10] drm/hisilicon: Add crtc funcs for ADE Xinliang Liu
2015-11-28 10:38   ` Xinliang Liu
     [not found]   ` <1448707145-69348-5-git-send-email-xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2015-11-28 15:56     ` Emil Velikov
2015-11-28 15:56       ` Emil Velikov
2015-12-01  2:52       ` Xinliang Liu
2015-11-28 10:39 ` [PATCH v2 05/10] drm/hisilicon: Add plane " Xinliang Liu
2015-11-28 10:39   ` Xinliang Liu
2015-11-28 10:39 ` [PATCH v2 06/10] drm/hisilicon: Add vblank feature Xinliang Liu
2015-11-28 10:39   ` Xinliang Liu
2015-11-30  7:54   ` Daniel Vetter
2015-11-30  7:54     ` Daniel Vetter
2015-12-01  3:16     ` Xinliang Liu
2015-12-01  3:16       ` Xinliang Liu
2015-12-01  7:13       ` Daniel Vetter
2015-12-01  7:13         ` Daniel Vetter
2015-12-01 10:34         ` Xinliang Liu
2015-12-01 10:34           ` Xinliang Liu
2015-12-01 12:54           ` Daniel Vetter
2015-12-01 12:54             ` Daniel Vetter
2015-11-28 10:39 ` [PATCH v2 07/10] drm/hisilicon: Add cma fbdev and hotplug Xinliang Liu
2015-11-28 10:39   ` Xinliang Liu
2015-11-28 10:39 ` [PATCH v2 08/10] drm/hisilicon: Add dsi encoder driver Xinliang Liu
2015-11-28 10:39   ` Xinliang Liu
2015-12-01  8:58   ` Archit Taneja
2015-12-01  8:58     ` Archit Taneja
     [not found]     ` <565D612A.1010307-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-12-01 11:16       ` Xinliang Liu
2015-12-01 11:16         ` Xinliang Liu
2015-11-28 10:39 ` [PATCH v2 09/10] drm/hisilicon: Add dsi host driver Xinliang Liu
2015-11-28 10:39   ` Xinliang Liu
     [not found] ` <1448707145-69348-1-git-send-email-xinliang.liu-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
2015-11-28 10:39   ` [PATCH v2 10/10] drm/hisilicon: Add support for external bridge Xinliang Liu
2015-11-28 10:39     ` Xinliang Liu
2015-12-01  9:04     ` Archit Taneja
2015-12-01  9:04       ` Archit Taneja
2015-12-01 14:50       ` Xinliang Liu
2015-12-01 14:50         ` Xinliang Liu
2015-12-02  8:20         ` Archit Taneja
2015-12-02  8:20           ` Archit Taneja
     [not found]           ` <565EA9D4.4090905-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-12-02 11:24             ` Xinliang Liu
2015-12-02 11:24               ` Xinliang Liu
2015-11-28 15:25 [PATCH v2 03/10] drm/hisilicon: Add hisilicon DRM master driver Emil Velikov
2015-11-30  7:46 ` Daniel Vetter
2015-11-30  7:46   ` Daniel Vetter
2015-11-30 17:25   ` Rob Herring
2015-11-30 17:25     ` Rob Herring
2015-12-01  7:12     ` Daniel Vetter
2015-12-01  7:12       ` Daniel Vetter
2015-12-01 10:52   ` Xinliang Liu
2015-12-01 10:52     ` Xinliang Liu
2015-12-01 12:54     ` Daniel Vetter
2015-12-01 12:54       ` Daniel Vetter
2015-12-01 10:18 ` Xinliang Liu
2015-12-01 10:18   ` Xinliang Liu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.