linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC
@ 2015-09-15  9:37 Xinwei Kong
  2015-09-15  9:37 ` [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver Xinwei Kong
                   ` (8 more replies)
  0 siblings, 9 replies; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

  These patch set adds a new drm driver for Hisilicon's 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.

1. 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 or pipes, 3 overlay and a LDI.
  - A channel/pipe looks like: DMA-->clip-->scale-->ctrans/csc.
  - Overlay 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.

2. Software Detail
  About the software organization and implementation detail:
We have a main drm platform driver (hisi_drm_drv.c), ade platform driver
(hisi_ade.c) and a dsi platform driver (hisi_drm_dsi.c). Ade driver
implements the plane and crtc driver interfaces and dsi implements the
encoder and connector driver interfaces. We take advantage of component
framework to initialize each driver.
  In order to support multi coming Hisilicon's SoCs, we plan to separate
common driver code and SoC specific implemented code as possiple as we can.
We abstract an ops for each component(crtc, plane, encoder and connector)
to reuse the common interface implementation logic (FIXME: Not sure if we
can achieve this target and if it is good or not). Thus, we put these
common driver code into hisi_drm_drv/crtc/plane/encoder/connector.c files.

Xinwei Kong (8):
  dt-bindings: Document the hi6220 bindings for DRM driver
  drm: hisilicon: Add new DRM driver for hisilicon Soc
  drm: hisilicon: Add the link to DRM/KMS interface
  drm: hisilicon: fill interface function of plane\crtc part
  drm: hisilicon: fill interface function of encoder\connector part
  drm: hisilicon: Add support for fbdev
  drm: hisilicon: Add support for vblank
  dts: hisilicon: Add drm driver device dts config for HiKey board

 .../devicetree/bindings/gpu/hisilicon,hi6220.txt   |   69 +
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi          |   34 +
 arch/arm64/configs/defconfig                       |    5 +
 drivers/gpu/drm/Kconfig                            |    2 +
 drivers/gpu/drm/Makefile                           |    1 +
 drivers/gpu/drm/hisilicon/Kconfig                  |   32 +
 drivers/gpu/drm/hisilicon/Makefile                 |   12 +
 drivers/gpu/drm/hisilicon/hisi_ade.c               | 1360 ++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_ade_reg.h           |  208 +++
 drivers/gpu/drm/hisilicon/hisi_drm_connector.c     |  128 ++
 drivers/gpu/drm/hisilicon/hisi_drm_connector.h     |   33 +
 drivers/gpu/drm/hisilicon/hisi_drm_crtc.c          |  315 +++++
 drivers/gpu/drm/hisilicon/hisi_drm_crtc.h          |   64 +
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c           |  220 ++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.h           |   36 +
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c           |  829 ++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_encoder.c       |  117 ++
 drivers/gpu/drm/hisilicon/hisi_drm_encoder.h       |   41 +
 drivers/gpu/drm/hisilicon/hisi_drm_fb.c            |  175 +++
 drivers/gpu/drm/hisilicon/hisi_drm_fb.h            |   33 +
 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c         |  395 ++++++
 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h         |   24 +
 drivers/gpu/drm/hisilicon/hisi_drm_plane.c         |  257 ++++
 drivers/gpu/drm/hisilicon/hisi_drm_plane.h         |   55 +
 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h           |   91 ++
 25 files changed, 4536 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpu/hisilicon,hi6220.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.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_ade_reg.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_connector.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_connector.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_crtc.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_drm_encoder.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_encoder.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fb.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fb.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_plane.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_plane.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h

-- 
1.9.1



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

* [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
@ 2015-09-15  9:37 ` Xinwei Kong
  2015-09-15 18:11   ` Rob Herring
  2015-09-15  9:37 ` [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc Xinwei Kong
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

This adds documentation of device tree bindings for the
Graphics Processing Unit of 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>
Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
Signed-off-by: Yu Gong <gongyu@hisilicon.com>
---
 .../devicetree/bindings/gpu/hisilicon,hi6220.txt   | 69 ++++++++++++++++++++++
 1 file changed, 69 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt

diff --git a/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
new file mode 100644
index 0000000..173ac63
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
@@ -0,0 +1,69 @@
+ * Hisilicon hi6220 Graphics Processing Unit for HiKey board
+
+ ** display-subsystem: Master device for binding DRM sub-components
+    This master device is parent node and it will be responsible to bind all
+    sub-components devices node.
+    - Required properties :
+      - compatible: "hisilicon,display-subsystem".
+      - #address-cells, #size-cells: Must be present if the device has sub-nodes.
+      - ranges: to allow probing of subdevices.
+      - dma-coherent: Present if dma operations are coherent.
+
+ ** ade: Graphic overlay, Graphic post-processing, display timing control.
+    This device is child node of display-subsystem
+    - Required properties :
+      - compatible: "hisilicon,hi6220-ade".
+      - reg: physical base address of the ADE register and length of memory
+	region.
+      - reg-names: Should contain the reg names "ade_base" and "media_base".
+      - interrupt: The interrupt number to the cpu. Defines the interrupt
+        by ADE.
+      - clocks: The clocks needed by the ADE module.
+      - clock-names: the name of the clocks.
+
+ ** dsi: support mipi dsi interface
+    This device is child node of display-subsystem
+    - Required properties :
+      - compatible: "hisilicon,hi6220-dsi".
+      - reg: physical base address of the DSI register and length of memory
+	region.
+      - clocks: The clocks needed by the DSI module.
+      - clock-names: the name of the clocks.
+      -	encoder-slave: phandles to a 'encoder-slave' subnode which DSI connect
+        ADV7533 in order to support hdmi display.
+
+Example:
+
+	display-subsystem {
+		compatible = "hisilicon,display-subsystem";
+		#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>;
+
+			clocks = <&media_ctrl HI6220_ADE_CORE>,
+				 <&media_ctrl HI6220_CODEC_JPEG>,
+				 <&media_ctrl HI6220_ADE_PIX_SRC>;
+			/*clock name*/
+			clock-names  = "clk_ade_core",
+				       "aclk_codec_jpeg_src",
+				       "clk_ade_pix";
+		};
+
+		dsi {
+			compatible = "hisilicon,hi6220-dsi";
+			reg = <0x0 0xf4107800 0x0 0x100>;
+			clocks = <&media_ctrl  HI6220_DSI_PCLK>;
+			clock-names = "pclk_dsi";
+			encoder-slave = <&adv7533>;
+		};
+	};
+
-- 
1.9.1



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

* [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
  2015-09-15  9:37 ` [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver Xinwei Kong
@ 2015-09-15  9:37 ` Xinwei Kong
  2015-09-17 11:13   ` Archit Taneja
  2015-09-15  9:37 ` [PATCH RFC 3/8] drm: hisilicon: Add the link to DRM/KMS interface Xinwei Kong
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

This patch creates this driver itself and register all the sub-components
which is from DTS inode, this driver uses components framework mechanism
to bind all the sub-components.

This patch also introduces a memory manager for hisilison drm. As cma
framebuffer helpers can no more be used.

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>
Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
Signed-off-by: Yu Gong <gongyu@hisilicon.com>
---
 arch/arm64/configs/defconfig             |   5 +
 drivers/gpu/drm/Kconfig                  |   2 +
 drivers/gpu/drm/Makefile                 |   1 +
 drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
 drivers/gpu/drm/hisilicon/Makefile       |   7 ++
 drivers/gpu/drm/hisilicon/hisi_ade.c     | 166 +++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 206 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 131 ++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_fb.c  | 156 +++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_fb.h  |  26 ++++
 10 files changed, 709 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_ade.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fb.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fb.h

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 4e17e7e..c2ea280 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -146,6 +146,8 @@ CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_SYSCON=y
 CONFIG_LEDS_TRIGGERS=y
 CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
+
 CONFIG_LEDS_TRIGGER_CPU=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_EFI=y
@@ -199,3 +201,6 @@ CONFIG_CRYPTO_GHASH_ARM64_CE=y
 CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
 CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
 CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_DRM=y
+CONFIG_DRM_HISI=y
+# CONFIG_DRM_HISI_FBDEV is not set
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c46ca31..31ee120 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -240,3 +240,5 @@ source "drivers/gpu/drm/sti/Kconfig"
 source "drivers/gpu/drm/amd/amdkfd/Kconfig"
 
 source "drivers/gpu/drm/imx/Kconfig"
+
+source "drivers/gpu/drm/hisilicon/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 5713d05..47936d4 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_DRM_MSM) += msm/
 obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-$(CONFIG_DRM_STI) += sti/
 obj-$(CONFIG_DRM_IMX) += imx/
+obj-$(CONFIG_DRM_HISI) += hisilicon/
 obj-y			+= i2c/
 obj-y			+= panel/
 obj-y			+= bridge/
diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
new file mode 100644
index 0000000..60b42e4
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -0,0 +1,9 @@
+config DRM_HISI
+	tristate "DRM Support for Hisilicon Terminal SoCs Platform"
+	depends on DRM
+	select DRM_KMS_HELPER
+	select DRM_GEM_CMA_HELPER
+	help
+	  Choose this option if you have a hisilicon terminal chipset.
+	  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..3f042fd
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -0,0 +1,7 @@
+hisi-drm-y := hisi_drm_drv.o \
+	      hisi_ade.o \
+	      hisi_drm_dsi.o \
+	      hisi_drm_fb.o \
+
+obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
+
diff --git a/drivers/gpu/drm/hisilicon/hisi_ade.c b/drivers/gpu/drm/hisilicon/hisi_ade.c
new file mode 100644
index 0000000..9b58d20
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_ade.c
@@ -0,0 +1,166 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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 <drm/drm_gem_cma_helper.h>
+
+struct ade_hardware_context {
+	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 hisi_ade {
+	struct ade_hardware_context ctx;
+};
+
+static int ade_dts_parse(struct platform_device *pdev,
+			 struct ade_hardware_context *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 clock\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 pixel 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_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_probe(struct platform_device *pdev)
+{
+	struct hisi_ade *ade;
+	int ret;
+
+	ade = devm_kzalloc(&pdev->dev, sizeof(*ade), GFP_KERNEL);
+	if (!ade) {
+		DRM_ERROR("failed to alloc hisi_ade\n");
+		return -ENOMEM;
+	}
+
+	ret = ade_dts_parse(pdev, &ade->ctx);
+	if (ret) {
+		DRM_ERROR("failed to parse ade 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("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@huawei.com>");
+MODULE_DESCRIPTION("hisilicon SoC DRM 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
new file mode 100644
index 0000000..0983ad7
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -0,0 +1,206 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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_atomic_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "hisi_drm_fb.h"
+
+#define DRIVER_NAME	"hisi-drm"
+
+static int hisi_drm_unload(struct drm_device *dev)
+{
+	drm_vblank_cleanup(dev);
+	drm_mode_config_cleanup(dev);
+	dev->dev_private = NULL;
+
+	return 0;
+}
+
+static const struct drm_mode_config_funcs hisi_drm_mode_config_funcs = {
+	.fb_create = hisi_drm_fb_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;
+
+	/* debug setting
+	drm_debug = DRM_UT_DRIVER|DRM_UT_KMS; */
+
+	/* dev->mode_config initialization */
+	drm_mode_config_init(dev);
+	hisi_drm_mode_config_init(dev);
+
+	/* only support one crtc now */
+	ret = drm_vblank_init(dev, 1);
+	if (ret)
+		goto out_err;
+
+	ret = component_bind_all(dev->dev, dev);
+	if (ret)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	hisi_drm_unload(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_drm_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 struct drm_driver hisi_drm_driver = {
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME
+				| DRIVER_HAVE_IRQ,
+	.load			= hisi_drm_load,
+	.unload                 = hisi_drm_unload,
+	.fops			= &hisi_drm_fops,
+	.set_busid		= drm_platform_set_busid,
+
+	.gem_free_object	= drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+	.dumb_create		= drm_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_drm_gem_prime_export,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.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 Terminal SoCs DRM Driver",
+	.date			= "20150830",
+	.major			= 1,
+	.minor			= 0,
+};
+
+/* -----------------------------------------------------------------------------
+ * Platform driver
+ */
+
+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,display-subsystem", },
+	{ /* 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("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@huawei.com>");
+MODULE_DESCRIPTION("hisilicon SoC DRM driver");
+MODULE_LICENSE("GPL v2");
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..a8dbaad
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -0,0 +1,131 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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 <drm/drm_mipi_dsi.h>
+#include <drm/drm_encoder_slave.h>
+
+#define DSI_24BITS_1               (5)
+
+struct hisi_dsi {
+	u32 lanes;
+	u32 format;
+	u32 date_enable_pol;
+	u32 mode_flags;
+	u8 color_mode;
+	void *ctx;
+};
+
+struct hisi_dsi_context {
+	struct hisi_dsi dsi;
+	struct clk *dsi_cfg_clk;
+	struct drm_device *dev;
+
+	void __iomem *base;
+	int nominal_pixel_clk_kHz;
+};
+
+static int hisi_dsi_bind(struct device *dev, struct device *master,
+			 void *data)
+{
+	int ret = 0;
+
+	return ret;
+}
+
+static void hisi_dsi_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+	/* do nothing */
+}
+
+static const struct component_ops hisi_dsi_ops = {
+	.bind	= hisi_dsi_bind,
+	.unbind	= hisi_dsi_unbind,
+};
+
+static int hisi_dsi_probe(struct platform_device *pdev)
+{
+	struct hisi_dsi_context *ctx;
+	struct hisi_dsi *dsi;
+	struct resource *res;
+	struct device_node *slave_node;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		DRM_ERROR("failed to allocate hisi dsi context.\n");
+		ret = -ENOMEM;
+	}
+
+	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
+	if (IS_ERR(ctx->dsi_cfg_clk)) {
+		DRM_ERROR("failed to parse the dsi config clock\n");
+		ret = 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");
+		ret = PTR_ERR(ctx->base);
+	}
+
+	slave_node = of_parse_phandle(np, "encoder-slave", 0);
+	if (!slave_node) {
+		DRM_ERROR("failed to parse the slave encoder node\n");
+		return -EINVAL;
+	}
+
+	dsi = &ctx->dsi;
+	dsi->ctx = ctx;
+	dsi->lanes = 3;
+	dsi->date_enable_pol = 0;
+	dsi->color_mode = DSI_24BITS_1;
+	dsi->format = MIPI_DSI_FMT_RGB888;
+	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+
+	return component_add(&pdev->dev, &hisi_dsi_ops);
+}
+
+static int hisi_dsi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &hisi_dsi_ops);
+
+	return 0;
+}
+
+static const struct of_device_id hisi_dsi_of_match[] = {
+	{.compatible = "hisilicon,hi6220-dsi"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, hisi_dsi_of_match);
+
+static struct platform_driver hisi_dsi_driver = {
+	.probe = hisi_dsi_probe,
+	.remove = hisi_dsi_remove,
+	.driver = {
+		.name = "hisi-dsi",
+		.owner = THIS_MODULE,
+		.of_match_table = hisi_dsi_of_match,
+	},
+};
+
+module_platform_driver(hisi_dsi_driver);
+
+MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>");
+MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@huawei.com>");
+MODULE_DESCRIPTION("hisilicon SoC DRM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fb.c b/drivers/gpu/drm/hisilicon/hisi_drm_fb.c
new file mode 100644
index 0000000..5dace8b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fb.c
@@ -0,0 +1,156 @@
+/*
+ * Hisilicon Terminal SoCs drm fbdev driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: z.liuxinliang@huawei.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 <drm/drm_gem_cma_helper.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "hisi_drm_fb.h"
+
+struct hisi_drm_fb *to_hisi_drm_fb(struct drm_framebuffer *fb)
+{
+	return container_of(fb, struct hisi_drm_fb, fb);
+}
+
+void hisi_drm_fb_destroy(struct drm_framebuffer *fb)
+{
+	struct hisi_drm_fb *hisi_fb = to_hisi_drm_fb(fb);
+	int i;
+
+	for (i = 0; i < 4; i++) {
+		if (hisi_fb->obj[i])
+			drm_gem_object_unreference_unlocked
+				(&hisi_fb->obj[i]->base);
+	}
+
+	drm_framebuffer_cleanup(fb);
+	kfree(hisi_fb);
+}
+
+static int hisi_drm_fb_create_handle(struct drm_framebuffer *fb,
+				     struct drm_file *file_priv,
+				     unsigned int *handle)
+{
+	struct hisi_drm_fb *hisi_fb = to_hisi_drm_fb(fb);
+
+	return drm_gem_handle_create(file_priv,
+			&hisi_fb->obj[0]->base, handle);
+}
+
+static int hisi_drm_fb_dirty(struct drm_framebuffer *fb,
+			     struct drm_file *file_priv,
+			     unsigned flags,
+			     unsigned color,
+			     struct drm_clip_rect *clips,
+			     unsigned num_clips)
+{
+	/* TODO */
+	return 0;
+}
+
+static struct drm_framebuffer_funcs hisi_drm_fb_funcs = {
+	.destroy	= hisi_drm_fb_destroy,
+	.create_handle	= hisi_drm_fb_create_handle,
+	.dirty		= hisi_drm_fb_dirty,
+};
+
+struct hisi_drm_fb *hisi_drm_fb_alloc(struct drm_device *dev,
+				      struct drm_mode_fb_cmd2 *mode_cmd,
+				      struct drm_gem_cma_object **obj,
+				      unsigned int num_planes, bool is_fbdev_fb)
+{
+	struct hisi_drm_fb *hisi_fb;
+	int ret;
+	int i;
+
+	hisi_fb = kzalloc(sizeof(*hisi_fb), GFP_KERNEL);
+	if (!hisi_fb)
+		return ERR_PTR(-ENOMEM);
+
+	hisi_fb->is_fbdev_fb = is_fbdev_fb;
+	drm_helper_mode_fill_fb_struct(&hisi_fb->fb, mode_cmd);
+
+	for (i = 0; i < num_planes; i++)
+		hisi_fb->obj[i] = obj[i];
+
+	ret = drm_framebuffer_init(dev, &hisi_fb->fb, &hisi_drm_fb_funcs);
+	if (ret) {
+		DRM_ERROR("Failed to initialize framebuffer: %d\n", ret);
+		kfree(hisi_fb);
+		return ERR_PTR(ret);
+	}
+
+	return hisi_fb;
+}
+
+/**
+ * hisi_drm_fb_create() - (struct drm_mode_config_funcs *)->fb_create callback
+ *function
+ * If your hardware has special alignment or pitch requirements these should be
+ * checked before calling this function.
+ */
+
+struct drm_framebuffer *hisi_drm_fb_create(struct drm_device *dev,
+					   struct drm_file *file_priv,
+					   struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	struct hisi_drm_fb *hisi_fb;
+	struct drm_gem_cma_object *objs[4];
+	struct drm_gem_object *obj;
+	unsigned int hsub;
+	unsigned int vsub;
+	int ret;
+	int i;
+
+	/* TODO: Need to use ion heaps to create frame buffer?? */
+
+	hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
+	vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
+
+	for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) {
+		unsigned int width = mode_cmd->width / (i ? hsub : 1);
+		unsigned int height = mode_cmd->height / (i ? vsub : 1);
+		unsigned int min_size;
+
+		obj = drm_gem_object_lookup(dev, file_priv,
+					    mode_cmd->handles[i]);
+		if (!obj) {
+			DRM_ERROR("Failed to lookup GEM object\n");
+			ret = -ENXIO;
+			goto err_gem_object_unreference;
+		}
+
+		min_size = (height - 1) * mode_cmd->pitches[i]
+		     + width * drm_format_plane_cpp(mode_cmd->pixel_format, i)
+		     + mode_cmd->offsets[i];
+
+		if (obj->size < min_size) {
+			drm_gem_object_unreference_unlocked(obj);
+			ret = -EINVAL;
+			goto err_gem_object_unreference;
+		}
+		objs[i] = to_drm_gem_cma_obj(obj);
+	}
+
+	hisi_fb = hisi_drm_fb_alloc(dev, mode_cmd, objs, i, false);
+	if (IS_ERR(hisi_fb)) {
+		ret = PTR_ERR(hisi_fb);
+		goto err_gem_object_unreference;
+	}
+
+	return &hisi_fb->fb;
+
+err_gem_object_unreference:
+	for (i--; i >= 0; i--)
+		drm_gem_object_unreference_unlocked(&objs[i]->base);
+	return ERR_PTR(ret);
+}
+
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fb.h b/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
new file mode 100644
index 0000000..1db1289
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
@@ -0,0 +1,26 @@
+/*
+ * Hisilicon Terminal SoCs drm fbdev driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: z.liuxinliang@huawei.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.
+ *
+ */
+
+#ifndef __HISI_DRM_FB_H__
+#define __HISI_DRM_FB_H__
+
+struct hisi_drm_fb {
+	struct drm_framebuffer		fb;
+	struct drm_gem_cma_object	*obj[4];
+	bool is_fbdev_fb;
+};
+
+struct drm_framebuffer *hisi_drm_fb_create(struct drm_device *dev,
+					   struct drm_file *file_priv,
+					   struct drm_mode_fb_cmd2 *mode_cmd);
+
+#endif /* __HISI_DRM_FB_H__ */
-- 
1.9.1



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

* [PATCH RFC 3/8] drm: hisilicon: Add the link to DRM/KMS interface
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
  2015-09-15  9:37 ` [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver Xinwei Kong
  2015-09-15  9:37 ` [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc Xinwei Kong
@ 2015-09-15  9:37 ` Xinwei Kong
  2015-09-15  9:37 ` [PATCH RFC 4/8] drm: hisilicon: fill interface function of plane\crtc part Xinwei Kong
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

This patch makes the link with DRM/KMS interface by initializing the drm
plane/crtc/encoder/connector and adding the drm plane/crtc/encoder/
connector helper.

This patch is compatible with different hisilicon platform such as Hikey
series of boards and other series of boards.

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>
Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
Signed-off-by: Yu Gong <gongyu@hisilicon.com>
---
 drivers/gpu/drm/hisilicon/Makefile             |   4 +
 drivers/gpu/drm/hisilicon/hisi_ade.c           |  44 +++++
 drivers/gpu/drm/hisilicon/hisi_ade_reg.h       |  27 +++
 drivers/gpu/drm/hisilicon/hisi_drm_connector.c |  90 ++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_connector.h |  25 +++
 drivers/gpu/drm/hisilicon/hisi_drm_crtc.c      | 179 ++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_crtc.h      |  45 +++++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.h       |  36 ++++
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c       |  13 ++
 drivers/gpu/drm/hisilicon/hisi_drm_encoder.c   |  65 +++++++
 drivers/gpu/drm/hisilicon/hisi_drm_encoder.h   |  22 +++
 drivers/gpu/drm/hisilicon/hisi_drm_plane.c     | 240 +++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_plane.h     |  51 ++++++
 13 files changed, 841 insertions(+)
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_ade_reg.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_connector.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_connector.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_encoder.h
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_plane.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_plane.h

diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index 3f042fd..aa522f8 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -1,6 +1,10 @@
 hisi-drm-y := hisi_drm_drv.o \
 	      hisi_ade.o \
 	      hisi_drm_dsi.o \
+	      hisi_drm_plane.o \
+	      hisi_drm_crtc.o \
+	      hisi_drm_encoder.o \
+	      hisi_drm_connector.o \
 	      hisi_drm_fb.o \
 
 obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
diff --git a/drivers/gpu/drm/hisilicon/hisi_ade.c b/drivers/gpu/drm/hisilicon/hisi_ade.c
index 9b58d20..148ed2f 100644
--- a/drivers/gpu/drm/hisilicon/hisi_ade.c
+++ b/drivers/gpu/drm/hisilicon/hisi_ade.c
@@ -15,6 +15,16 @@
 
 #include <drm/drm_gem_cma_helper.h>
 
+#include "hisi_drm_plane.h"
+#include "hisi_drm_crtc.h"
+#include "hisi_ade_reg.h"
+
+#define PRIMARY_CH      (ADE_CH1)
+
+struct ade_crtc {
+	struct hisi_crtc base;
+};
+
 struct ade_hardware_context {
 	void __iomem  *base;
 	void __iomem  *media_base;
@@ -30,6 +40,8 @@ struct ade_hardware_context {
 };
 
 struct hisi_ade {
+	struct ade_crtc acrtc;
+	struct hisi_plane hplane[ADE_CH_NUM];
 	struct ade_hardware_context ctx;
 };
 
@@ -99,6 +111,38 @@ static int ade_dts_parse(struct platform_device *pdev,
 
 static int ade_bind(struct device *dev, struct device *master, void *data)
 {
+	struct hisi_ade *ade = dev_get_drvdata(dev);
+	struct ade_hardware_context *ctx = &ade->ctx;
+	struct hisi_crtc *hcrtc = &ade->acrtc.base;
+	struct drm_device *drm_dev = (struct drm_device *)data;
+	struct hisi_plane *hplane;
+	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 < 1; i++) {
+		hplane = &ade->hplane[i];
+		hplane->ch = i;
+		hplane->ctx = ctx;
+		type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
+			DRM_PLANE_TYPE_OVERLAY;
+
+		ret = hisi_drm_plane_init(drm_dev, hplane, type);
+		if (ret)
+			return ret;
+	}
+
+	/* crtc init */
+	hcrtc->ctx = ctx;
+	ret = hisi_drm_crtc_init(drm_dev, hcrtc, &ade->hplane[PRIMARY_CH].base);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
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..bdf3c3b
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
@@ -0,0 +1,27 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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__
+
+enum ade_channel {
+	ADE_CH1 = 0,	/* channel 1 for primary plane */
+	ADE_CH2,
+	ADE_CH3,
+	ADE_CH4,
+	ADE_CH5,
+	ADE_CH6,
+	ADE_DISP,
+	ADE_CH_NUM
+};
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_connector.c b/drivers/gpu/drm/hisilicon/hisi_drm_connector.c
new file mode 100644
index 0000000..62efdc7
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_connector.c
@@ -0,0 +1,90 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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 <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "hisi_drm_encoder.h"
+#include "hisi_drm_connector.h"
+
+#define to_hisi_connector(connector) \
+	container_of(connector, struct hisi_connector, connector)
+
+int hisi_drm_connector_mode_valid(struct drm_connector *connector,
+				  struct drm_display_mode *mode)
+{
+	int ret = MODE_OK;
+
+	return ret;
+}
+
+struct drm_encoder *
+hisi_drm_best_encoder(struct drm_connector *connector)
+{
+	struct hisi_connector *hconnector = to_hisi_connector(connector);
+	struct drm_encoder *encoder = hconnector->encoder;
+
+	return encoder;
+}
+
+int hisi_drm_get_modes(struct drm_connector *connector)
+{
+	int count = 0;
+
+	return count;
+}
+
+static struct drm_connector_helper_funcs hisi_drm_connector_helper_funcs = {
+	.get_modes = hisi_drm_get_modes,
+	.best_encoder =  hisi_drm_best_encoder,
+	.mode_valid = hisi_drm_connector_mode_valid,
+};
+
+void hisi_drm_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+enum drm_connector_status
+hisi_drm_detect(struct drm_connector *connector, bool force)
+{
+	enum drm_connector_status status = connector_status_unknown;
+
+	return status;
+}
+
+static struct drm_connector_funcs hisi_drm_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = hisi_drm_detect,
+	.destroy = hisi_drm_connector_destroy,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+void hisi_drm_connector_init(struct drm_device *dev,
+			     struct drm_encoder *encoder,
+			     struct drm_connector *connector)
+{
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+	connector->dpms = DRM_MODE_DPMS_OFF;
+	drm_connector_init(encoder->dev, connector, &hisi_drm_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
+	drm_connector_helper_add(connector, &hisi_drm_connector_helper_funcs);
+	drm_connector_register(connector);
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	drm_mode_config_reset(dev);
+}
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_connector.h b/drivers/gpu/drm/hisilicon/hisi_drm_connector.h
new file mode 100644
index 0000000..114391c
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_connector.h
@@ -0,0 +1,25 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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_CONNECTOR_H__
+#define __HISI_DRM_CONNECTOR_H__
+
+struct hisi_connector {
+	struct drm_connector connector;
+	struct drm_encoder *encoder;
+};
+
+void hisi_drm_connector_init(struct drm_device *dev,
+			     struct drm_encoder *encoder,
+			     struct drm_connector *connector);
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
new file mode 100644
index 0000000..ad13614
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
@@ -0,0 +1,179 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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 <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
+
+#include "hisi_drm_drv.h"
+#include "hisi_drm_crtc.h"
+
+static void  hisi_drm_crtc_enable(struct drm_crtc *crtc)
+{
+}
+
+static void hisi_drm_crtc_disable(struct drm_crtc *crtc)
+{
+}
+
+static void hisi_drm_crtc_mode_prepare(struct drm_crtc *crtc)
+{
+}
+
+static bool hisi_drm_crtc_mode_fixup(struct drm_crtc *crtc,
+				     const struct drm_display_mode *mode,
+				     struct drm_display_mode *adj_mode)
+{
+	bool ret = true;
+
+	return ret;
+}
+
+static void hisi_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+}
+
+static void hisi_crtc_atomic_begin(struct drm_crtc *crtc)
+{
+}
+
+static void hisi_crtc_atomic_flush(struct drm_crtc *crtc)
+{
+}
+
+static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
+	.enable		= hisi_drm_crtc_enable,
+	.disable	= hisi_drm_crtc_disable,
+	.prepare	= hisi_drm_crtc_mode_prepare,
+	.mode_fixup	= hisi_drm_crtc_mode_fixup,
+	.mode_set_nofb	= hisi_drm_crtc_mode_set_nofb,
+	.atomic_begin	= hisi_crtc_atomic_begin,
+	.atomic_flush	= hisi_crtc_atomic_flush,
+};
+
+static void hisi_drm_crtc_destroy(struct drm_crtc *c)
+{
+	drm_crtc_cleanup(c);
+}
+
+static void hisi_crtc_atomic_reset(struct drm_crtc *crtc)
+{
+	struct hisi_crtc_state *state;
+
+	if (crtc->state)
+		kfree(to_hisi_crtc_state(crtc->state));
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	/* set to default value */
+	state->comp_type = COMPOSITION_UNKNOWN;
+
+	crtc->state = &state->base;
+	crtc->state->crtc = crtc;
+}
+
+static struct drm_crtc_state *
+hisi_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
+{
+	struct hisi_crtc_state *state;
+	struct hisi_crtc_state *copy;
+
+	if (WARN_ON(!crtc->state))
+		return NULL;
+
+	state = to_hisi_crtc_state(crtc->state);
+	copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	__drm_atomic_helper_crtc_duplicate_state(crtc, &copy->base);
+
+	return &copy->base;
+}
+
+static void hisi_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+					   struct drm_crtc_state *state)
+{
+	__drm_atomic_helper_crtc_destroy_state(crtc, state);
+	kfree(to_hisi_crtc_state(state));
+}
+
+static int hisi_crtc_atomic_set_property(struct drm_crtc *crtc,
+					 struct drm_crtc_state *state,
+					 struct drm_property *property,
+					 uint64_t val)
+{
+	struct hisi_drm_private *priv = crtc->dev->dev_private;
+	struct hisi_crtc_state *hstate = to_hisi_crtc_state(state);
+
+	if (property == priv->comp_type_prop)
+		hstate->comp_type = val;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int hisi_crtc_atomic_get_property(struct drm_crtc *crtc,
+					 const struct drm_crtc_state *state,
+					 struct drm_property *property,
+					 uint64_t *val)
+{
+	struct hisi_drm_private *priv = crtc->dev->dev_private;
+	struct hisi_crtc_state *hstate = to_hisi_crtc_state(state);
+
+	if (property == priv->comp_type_prop)
+		*val =	hstate->comp_type;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct drm_crtc_funcs crtc_funcs = {
+	.destroy	= hisi_drm_crtc_destroy,
+	.set_config	= drm_atomic_helper_set_config,
+	.page_flip	= drm_atomic_helper_page_flip,
+	.reset		= hisi_crtc_atomic_reset,
+	.set_property = drm_atomic_helper_crtc_set_property,
+	.atomic_duplicate_state	= hisi_crtc_atomic_duplicate_state,
+	.atomic_destroy_state	= hisi_crtc_atomic_destroy_state,
+	.atomic_set_property = hisi_crtc_atomic_set_property,
+	.atomic_get_property = hisi_crtc_atomic_get_property,
+};
+
+int hisi_drm_crtc_init(struct drm_device *dev,
+		       struct hisi_crtc *hcrtc,
+		       struct drm_plane *plane)
+{
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+	int ret;
+
+	ret = drm_crtc_init_with_planes(dev, &hcrtc->base, plane,
+					NULL, &crtc_funcs);
+	if (ret) {
+		DRM_ERROR("failed to init crtc.\n");
+		return ret;
+	}
+
+	drm_crtc_helper_add(&hcrtc->base, &crtc_helper_funcs);
+
+	if (ops->install_properties) {
+		ret = ops->install_properties(dev, hcrtc);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
new file mode 100644
index 0000000..989cb1f
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
@@ -0,0 +1,45 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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_CRTC_H__
+#define __HISI_DRM_CRTC_H__
+
+#define to_hisi_crtc_state(state) \
+		container_of(state, struct hisi_crtc_state, base)
+
+enum composotion_type {
+	COMPOSITION_UNKNOWN	= 0,
+	COMPOSITION_GLES	= 1,
+	COMPOSITION_HWC		= 2,
+	COMPOSITION_MIXED	= 3
+};
+
+struct hisi_crtc {
+	struct drm_crtc base;
+	void *ops;
+	void *ctx;
+};
+
+struct hisi_crtc_ops {
+	int (*install_properties)(struct drm_device *dev,
+				  struct hisi_crtc *hcrtc);
+};
+
+struct hisi_crtc_state {
+	struct drm_crtc_state base;
+	u8 comp_type;
+};
+
+int hisi_drm_crtc_init(struct drm_device *dev, struct hisi_crtc *crtc,
+		       struct drm_plane *plane);
+
+#endif
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..0b96357
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.h
@@ -0,0 +1,36 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *
+ * 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 {
+	struct hisi_drm_fbdev	*fbdev;
+
+	/* plane properties */
+	struct drm_property *zpos_prop;
+	struct drm_property *alpha_prop;
+	struct drm_property *blend_prop;
+
+	/*
+	* read only capabilities properties
+	* 0: unsupport
+	* 1: support
+	*/
+	struct drm_property *cap_scl_prop;
+	struct drm_property *cap_rot_prop;
+
+	/* crtc properties */
+	struct drm_property *comp_type_prop;
+};
+
+#endif /* __HISI_DRM_DRV_H__ */
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index a8dbaad..046fd8e 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -16,9 +16,15 @@
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_encoder_slave.h>
 
+#include "hisi_drm_encoder.h"
+#include "hisi_drm_connector.h"
+
 #define DSI_24BITS_1               (5)
 
 struct hisi_dsi {
+	struct hisi_encoder hisi_encoder;
+	struct hisi_connector hisi_connector;
+
 	u32 lanes;
 	u32 format;
 	u32 date_enable_pol;
@@ -39,8 +45,15 @@ struct hisi_dsi_context {
 static int hisi_dsi_bind(struct device *dev, struct device *master,
 			 void *data)
 {
+	struct hisi_dsi_context *ctx = dev_get_drvdata(dev);
 	int ret = 0;
 
+	ctx->dev = data;
+
+	hisi_drm_encoder_init(ctx->dev, &ctx->dsi.hisi_encoder.base.base);
+
+	hisi_drm_connector_init(ctx->dev, &ctx->dsi.hisi_encoder.base.base,
+				&ctx->dsi.hisi_connector.connector);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
new file mode 100644
index 0000000..89fc73d
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
@@ -0,0 +1,65 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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 <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "hisi_drm_encoder.h"
+
+void hisi_drm_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+void hisi_drm_encoder_enable(struct drm_encoder *encoder)
+{
+}
+
+void hisi_drm_encoder_mode_set(struct drm_encoder *encoder,
+			       struct drm_display_mode *mode,
+			       struct drm_display_mode *adjusted_mode)
+{
+}
+
+bool
+hisi_drm_encoder_mode_fixup(struct drm_encoder *encoder,
+			    const struct drm_display_mode *mode,
+			    struct drm_display_mode *adjusted_mode)
+{
+	bool ret = true;
+
+	return ret;
+}
+
+void hisi_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+}
+
+static struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
+	.mode_fixup	= hisi_drm_encoder_mode_fixup,
+	.mode_set	= hisi_drm_encoder_mode_set,
+	.enable		= hisi_drm_encoder_enable,
+	.disable	= hisi_drm_encoder_disable
+};
+
+static struct drm_encoder_funcs hisi_encoder_funcs = {
+	.destroy = hisi_drm_encoder_destroy
+};
+
+void hisi_drm_encoder_init(struct drm_device *dev,
+			   struct drm_encoder *encoder)
+{
+	encoder->possible_crtcs = 1;
+
+	drm_encoder_init(dev, encoder, &hisi_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS);
+	drm_encoder_helper_add(encoder, &hisi_encoder_helper_funcs);
+}
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_encoder.h b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.h
new file mode 100644
index 0000000..31c04e4
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.h
@@ -0,0 +1,22 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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_ENCODER_H__
+#define __HISI_DRM_ENCODER_H__
+
+struct hisi_encoder {
+	struct drm_encoder_slave base;
+};
+
+void hisi_drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder);
+
+#endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_plane.c b/drivers/gpu/drm/hisilicon/hisi_drm_plane.c
new file mode 100644
index 0000000..af040b6
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_plane.c
@@ -0,0 +1,240 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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 <drm/drmP.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic.h>
+
+#include "hisi_drm_drv.h"
+#include "hisi_drm_plane.h"
+
+#define to_hisi_plane(plane) \
+		container_of(plane, struct hisi_plane, base)
+
+static void hisi_plane_atomic_disable(struct drm_plane *plane,
+				      struct drm_plane_state *old_state)
+{
+}
+
+static void hisi_plane_atomic_update(struct drm_plane *plane,
+				     struct drm_plane_state *old_state)
+{
+}
+
+int hisi_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;
+	u32 crtc_w = state->crtc_w;
+	u32 crtc_h = state->crtc_h;
+	int crtc_x = state->crtc_x;
+	int crtc_y = state->crtc_y;
+
+	if (!crtc || !fb)
+		return 0;
+
+	if (state->rotation != BIT(DRM_ROTATE_0)) {
+		DRM_ERROR("Rotation not support!!!\n");
+		return -EINVAL;
+	}
+
+	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;
+}
+
+void hisi_plane_cleanup_fb(struct drm_plane *plane,
+			   struct drm_framebuffer *fb,
+			   const struct drm_plane_state *old_state)
+{
+}
+
+int hisi_plane_prepare_fb(struct drm_plane *p,
+			  struct drm_framebuffer *fb,
+			  const struct drm_plane_state *new_state)
+{
+	return 0;
+}
+
+static const struct drm_plane_helper_funcs hisi_plane_helper_funcs = {
+	.prepare_fb = hisi_plane_prepare_fb,
+	.cleanup_fb = hisi_plane_cleanup_fb,
+	.atomic_check = hisi_plane_atomic_check,
+	.atomic_update = hisi_plane_atomic_update,
+	.atomic_disable = hisi_plane_atomic_disable,
+};
+
+void hisi_plane_destroy(struct drm_plane *plane)
+{
+	drm_plane_cleanup(plane);
+}
+
+static void hisi_plane_atomic_reset(struct drm_plane *plane)
+{
+	struct hisi_plane_state *state;
+
+	if (plane->state && plane->state->fb)
+		drm_framebuffer_unreference(plane->state->fb);
+
+	if (plane->state)
+		kfree(to_hisi_plane_state(plane->state));
+
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state)
+		return;
+
+	/* set to default value */
+	state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 :
+		drm_plane_index(plane);
+	state->base.rotation = BIT(DRM_ROTATE_0);
+	state->alpha = 255;
+	state->blend = ALPHA_BLENDING_NONE;
+
+	plane->state = &state->base;
+	plane->state->plane = plane;
+}
+
+static struct drm_plane_state *
+hisi_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+	struct hisi_plane_state *hstate;
+	struct hisi_plane_state *copy;
+
+	if (WARN_ON(!plane->state))
+		return NULL;
+
+	hstate = to_hisi_plane_state(plane->state);
+	copy = kmemdup(hstate, sizeof(*hstate), GFP_KERNEL);
+	if (!copy)
+		return NULL;
+
+	__drm_atomic_helper_plane_duplicate_state(plane, &copy->base);
+
+	return &copy->base;
+}
+
+static void hisi_plane_atomic_destroy_state(struct drm_plane *plane,
+					    struct drm_plane_state *state)
+{
+	__drm_atomic_helper_plane_destroy_state(plane, state);
+	kfree(to_hisi_plane_state(state));
+}
+
+static int hisi_plane_atomic_set_property(struct drm_plane *plane,
+					  struct drm_plane_state *state,
+					  struct drm_property *property,
+					  uint64_t val)
+{
+	struct hisi_drm_private *priv = plane->dev->dev_private;
+	struct hisi_plane_state *hstate = to_hisi_plane_state(state);
+
+	if (property == priv->zpos_prop)
+		hstate->zpos = val;
+	else if (property == priv->alpha_prop)
+		hstate->alpha = val;
+	else if (property == priv->blend_prop)
+		hstate->blend = val;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static int hisi_plane_atomic_get_property(struct drm_plane *plane,
+					  const struct drm_plane_state *state,
+					  struct drm_property *property,
+					  uint64_t *val)
+{
+	struct hisi_drm_private *priv = plane->dev->dev_private;
+	const struct hisi_plane_state *hstate = to_hisi_plane_state(state);
+
+	if (property == priv->zpos_prop)
+		*val = hstate->zpos;
+	else if (property == priv->alpha_prop)
+		*val = hstate->alpha;
+	else if (property == priv->blend_prop)
+		*val = hstate->blend;
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct drm_plane_funcs hisi_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 = hisi_plane_destroy,
+	.reset = hisi_plane_atomic_reset,
+	.atomic_duplicate_state = hisi_plane_atomic_duplicate_state,
+	.atomic_destroy_state = hisi_plane_atomic_destroy_state,
+	.atomic_set_property = hisi_plane_atomic_set_property,
+	.atomic_get_property = hisi_plane_atomic_get_property,
+};
+
+int hisi_drm_plane_init(struct drm_device *dev,
+			struct hisi_plane *hplane,
+			enum drm_plane_type type)
+{
+	struct hisi_plane_funcs *ops = hplane->ops;
+	const u32 *fmts;
+	u32 fmts_cnt;
+	int ret = 0;
+
+	/* get  properties */
+	fmts_cnt = ops->get_properties(hplane->ch, &fmts);
+	if (ret)
+		return ret;
+	ret = drm_universal_plane_init(dev, &hplane->base, 1,
+				       &hisi_plane_funcs,
+				       fmts, fmts_cnt, type);
+	if (ret) {
+		DRM_ERROR("fail to init plane, ch: %d\n", hplane->ch);
+		return ret;
+	}
+
+	drm_plane_helper_add(&hplane->base, &hisi_plane_helper_funcs);
+
+	/* install overlay plane properties */
+	if (type == DRM_PLANE_TYPE_OVERLAY && ops->install_properties) {
+		ret = ops->install_properties(dev, hplane);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_plane.h b/drivers/gpu/drm/hisilicon/hisi_drm_plane.h
new file mode 100644
index 0000000..70ee845
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_plane.h
@@ -0,0 +1,51 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
+ *
+ * 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_PLANE_H__
+#define __HISI_DRM_PLANE_H__
+
+#define to_hisi_plane_state(s)  container_of(s, struct hisi_plane_state, base)
+
+enum {
+	/* no blending */
+	ALPHA_BLENDING_NONE     = 0x0100,
+	/* ONE / ONE_MINUS_SRC_ALPHA */
+	ALPHA_BLENDING_PREMULT  = 0x0105,
+	/* SRC_ALPHA / ONE_MINUS_SRC_ALPHA */
+	ALPHA_BLENDING_COVERAGE = 0x0405
+};
+
+struct hisi_plane {
+	struct drm_plane base;
+	void *ops;
+	void *ctx;
+	u8 ch; /* channel or pipe */
+};
+
+struct hisi_plane_funcs {
+	u32 (*get_properties)(u8 ch, const u32 **formats);
+	int (*install_properties)(struct drm_device *dev,
+				  struct hisi_plane *hplane);
+};
+
+int hisi_drm_plane_init(struct drm_device *dev, struct hisi_plane *hplane,
+			enum drm_plane_type type);
+
+/* plane structs  */
+struct hisi_plane_state {
+	struct drm_plane_state base;
+	u8 zpos;  /* z order */
+	u8 alpha; /* Alpha value applied to the whole plane */
+	u32 blend; /* blending cases: none, premult and coverage */
+};
+
+#endif
-- 
1.9.1



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

* [PATCH RFC 4/8] drm: hisilicon: fill interface function of plane\crtc part
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
                   ` (2 preceding siblings ...)
  2015-09-15  9:37 ` [PATCH RFC 3/8] drm: hisilicon: Add the link to DRM/KMS interface Xinwei Kong
@ 2015-09-15  9:37 ` Xinwei Kong
  2015-09-15  9:37 ` [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part Xinwei Kong
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

This patch uses ADE module which is responsibe for graphic overlay, graphic
post-processing, display timing control within hi6220 SoC to implement the
plane\ctrc interface of DRM\KMS.

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>
Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
Signed-off-by: Yu Gong <gongyu@hisilicon.com>
---
 drivers/gpu/drm/hisilicon/hisi_ade.c       | 1087 +++++++++++++++++++++++++++-
 drivers/gpu/drm/hisilicon/hisi_ade_reg.h   |  181 +++++
 drivers/gpu/drm/hisilicon/hisi_drm_crtc.c  |   47 ++
 drivers/gpu/drm/hisilicon/hisi_drm_crtc.h  |   12 +
 drivers/gpu/drm/hisilicon/hisi_drm_fb.c    |   21 +-
 drivers/gpu/drm/hisilicon/hisi_drm_fb.h    |    2 +
 drivers/gpu/drm/hisilicon/hisi_drm_plane.c |   17 +
 drivers/gpu/drm/hisilicon/hisi_drm_plane.h |    4 +
 8 files changed, 1368 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/hisilicon/hisi_ade.c b/drivers/gpu/drm/hisilicon/hisi_ade.c
index 148ed2f..2ea3f8f 100644
--- a/drivers/gpu/drm/hisilicon/hisi_ade.c
+++ b/drivers/gpu/drm/hisilicon/hisi_ade.c
@@ -13,16 +13,29 @@
 #include <linux/clk.h>
 #include <linux/component.h>
 
+#include <drm/drmP.h>
+#include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
+#include "hisi_drm_drv.h"
 #include "hisi_drm_plane.h"
 #include "hisi_drm_crtc.h"
+#include "hisi_drm_fb.h"
 #include "hisi_ade_reg.h"
 
 #define PRIMARY_CH      (ADE_CH1)
 
+#define ADE_CHANNEL_SCALE_UNSUPPORT      0
+#define ADE_CHANNEL_SCALE_SUPPORT        1
+
+#define to_ade_crtc(hcrtc) container_of(hcrtc, struct ade_crtc, base)
+
 struct ade_crtc {
 	struct hisi_crtc base;
+	struct drm_display_mode *dmode;
+
+	u32 ch_mask;
+	u64 use_mask;
 };
 
 struct ade_hardware_context {
@@ -45,6 +58,1070 @@ struct hisi_ade {
 	struct ade_hardware_context 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 },
+	/* packed YCbCr */
+	{ DRM_FORMAT_YUYV, ADE_YUYV },
+	{ DRM_FORMAT_YVYU, ADE_YVYU },
+	{ DRM_FORMAT_UYVY, ADE_UYVY },
+	{ DRM_FORMAT_VYUY, ADE_VYUY },
+	/* 2 plane YCbCr */
+	{ DRM_FORMAT_NV12, ADE_NV12 },
+	{ DRM_FORMAT_NV21, ADE_NV21 },
+	/* 3 plane YCbCr */
+	{ DRM_FORMAT_YUV444, ADE_YUV444 },
+};
+
+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
+};
+
+static const u32 channel_formats2[] = {
+	/* channel 5,6 */
+	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, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, DRM_FORMAT_UYVY,
+	DRM_FORMAT_VYUY, DRM_FORMAT_NV12, DRM_FORMAT_NV21, DRM_FORMAT_YUV444
+};
+
+static const u32 channel_formats3[] = {
+	/* disp channel 7 */
+	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, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, DRM_FORMAT_UYVY,
+	DRM_FORMAT_VYUY, DRM_FORMAT_YUV444
+};
+
+/*
+ * 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_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	u32 mask0 = (u32)acrtc->use_mask;
+	u32 mask1 = (u32)(acrtc->use_mask >> 32);
+
+	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_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	u32 out_w = acrtc->dmode->hdisplay;
+	u32 out_h = acrtc->dmode->vdisplay;
+	u32 val;
+
+	/* display source setting */
+	writel(TOP_DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
+
+	/* 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);
+
+	/* set reset mode:soft or hw, and reload modules */
+	ade_set_reset_and_reload(acrtc);
+
+	/* enable ade */
+	wmb();
+	writel(ADE_ENABLE, base + ADE_EN);
+
+	wmb(); /* memory barrier */
+	val = ADE_ENABLE;
+	val |= readl(base + LDI_CTRL);
+	writel(val, base + LDI_CTRL);
+
+	/* dsi pixel on */
+	set_reg(base + LDI_HDMI_DSI_GT, 0x0, 1, 0);
+}
+
+static void ade_init(struct ade_hardware_context *ctx)
+{
+	void __iomem *base = ctx->base;
+	u32 val;
+
+	/* enable clk gate */
+	val = 0x01;
+	val |= readl(base + ADE_CTRL1);
+	writel(val, base + ADE_CTRL1);
+
+	/* 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 */
+	val = 0x01;
+	val |= readl(base + ADE_CTRL);
+	writel(val, base + ADE_CTRL);
+}
+
+static void ade_ldi_set_mode(struct ade_hardware_context *ctx,
+			     struct drm_display_mode *mode)
+{
+	void __iomem *base = ctx->base;
+	u32 hfp, hbp, hsw, vfp, vbp, vsw;
+	u32 plr_flags;
+	u32 val;
+
+	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_ERROR("%s: vsw exceeded 15\n", __func__);
+		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(((mode->vdisplay - 1) << 20) | ((mode->hdisplay - 1) << 0),
+	       base + LDI_DSP_SIZE);
+	writel(plr_flags, base + LDI_PLR_CTRL);
+
+	/*
+	 * other parameters setting
+	 */
+	writel(BIT(0), base + LDI_WORK_MODE);
+	val = 0x3c << 6;
+	val |= ADE_OUT_RGB_888 << 3 | BIT(2) | BIT(0);
+	writel(val, base + LDI_CTRL);
+
+	set_reg(base + LDI_DE_SPACE_LOW, 0x1, 1, 1);
+}
+
+static int ade_power_up(struct ade_hardware_context *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("Cannot set rate (%dHz) for ade core clk\n",
+			  ctx->ade_core_rate);
+		return ret;
+	}
+	ret = clk_set_rate(ctx->media_noc_clk, ctx->media_noc_rate);
+	if (ret) {
+		DRM_ERROR("Cannot set rate (%dHz) for media noc clk\n",
+			  ctx->media_noc_rate);
+		return ret;
+	}
+	ret = clk_prepare_enable(ctx->media_noc_clk);
+	if (ret) {
+		DRM_ERROR("fail to enable media_noc_clk: %d\n", ret);
+		return ret;
+	}
+
+	writel(0x20, media_base + SC_MEDIA_RSTDIS);
+
+	ret = clk_prepare_enable(ctx->ade_core_clk);
+	if (ret) {
+		DRM_ERROR("fail to enabel ade_core_clk: %d\n", ret);
+		return ret;
+	}
+
+	ade_init(ctx);
+
+	ctx->power_on = true;
+
+	return 0;
+}
+
+static void ade_power_down(struct ade_hardware_context *ctx)
+{
+	void __iomem *base = ctx->base;
+	void __iomem *media_base = ctx->media_base;
+	u32 val;
+
+	/* disable LDI*/
+	val = ADE_DISABLE;
+	val |= readl(base + LDI_CTRL);
+	writel(val, base + LDI_CTRL);
+
+	/* dsi pixel off */
+	set_reg(base + LDI_HDMI_DSI_GT, 0x1, 1, 0);
+
+	/* ade clock off */
+	clk_disable_unprepare(ctx->ade_core_clk);
+	writel(0x20, media_base + SC_MEDIA_RSTEN);
+	clk_disable_unprepare(ctx->media_noc_clk);
+
+	ctx->power_on = false;
+}
+
+static void ade_crtc_enable(struct hisi_crtc *hcrtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(hcrtc);
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+	int ret;
+
+	if (!ctx->power_on) {
+		ret = ade_power_up(ctx);
+		if (ret) {
+			DRM_ERROR("%s: failed to power up ade\n", __func__);
+			return;
+		}
+	}
+
+	ade_display_commit(acrtc);
+}
+
+static void ade_crtc_disable(struct hisi_crtc *hcrtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(hcrtc);
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+
+	ade_power_down(ctx);
+
+	acrtc->ch_mask = 0;
+	acrtc->use_mask = 0;
+}
+
+bool ade_crtc_mode_fixup(struct hisi_crtc *hcrtc,
+			 const struct drm_display_mode *mode,
+			 struct drm_display_mode *adj_mode)
+{
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+	u32 clock_kHz = mode->clock;
+	int ret;
+
+	if (!ctx->power_on) {
+		ret = ade_power_up(ctx);
+		if (ret) {
+			DRM_ERROR("%s: failed to power up ade\n", __func__);
+			return ret;
+		}
+	}
+
+	do {
+		ret = clk_set_rate(ctx->ade_pix_clk, clock_kHz * 1000);
+		if (ret) {
+			DRM_ERROR("Cannot set rate (%dHz) for ade pixel clk\n",
+				  clock_kHz * 1000);
+			return false;
+		}
+
+		adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
+
+		/* This avoids a bad 720p DSI clock with 1.2GHz DPI PLL */
+		if (adj_mode->clock != 72000)
+			break;
+
+		clock_kHz += 10;
+	} while (1);
+
+	return true;
+}
+
+void ade_crtc_mode_set_nofb(struct hisi_crtc *hcrtc)
+{
+	struct ade_crtc *acrtc = to_ade_crtc(hcrtc);
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+
+	acrtc->dmode = &hcrtc->base.state->mode;
+
+	ade_ldi_set_mode(ctx, &hcrtc->base.state->mode);
+}
+
+void ade_crtc_atomic_begin(struct hisi_crtc *hcrtc)
+{
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+	int ret;
+
+	if (!ctx->power_on) {
+		ret = ade_power_up(ctx);
+		if (ret) {
+			DRM_ERROR("%s: failed to power up ade\n", __func__);
+			return;
+		}
+	}
+}
+
+void ade_crtc_atomic_flush(struct hisi_crtc *hcrtc)
+
+{
+	struct ade_crtc *acrtc = to_ade_crtc(hcrtc);
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+	void __iomem *base = ctx->base;
+
+	/* commit to  display: LDI input setting */
+	if (hcrtc->enable) {
+		/* set reset and reload */
+		ade_set_reset_and_reload(acrtc);
+		/* flush ade regitsters */
+		wmb();
+		writel(ADE_ENABLE, base + ADE_EN);
+	}
+}
+
+void ade_crtc_mode_prepare(struct hisi_crtc *hcrtc)
+{
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+	int ret;
+
+	if (!ctx->power_on) {
+		ret = ade_power_up(ctx);
+		if (ret) {
+			DRM_ERROR("%s: failed to power up ade\n", __func__);
+			return;
+		}
+	}
+}
+
+u32 ade_get_channel_formats(u8 ch, const u32 **formats)
+{
+	switch (ch) {
+	case ADE_CH1:
+	case ADE_CH2:
+	case ADE_CH3:
+	case ADE_CH4:
+		*formats = channel_formats1;
+		return ARRAY_SIZE(channel_formats1);
+	case ADE_CH5:
+	case ADE_CH6:
+		*formats = channel_formats2;
+		return ARRAY_SIZE(channel_formats2);
+	case ADE_DISP:
+		*formats = channel_formats3;
+		return ARRAY_SIZE(channel_formats3);
+	default:
+		DRM_ERROR("no this channel %d\n", ch);
+		*formats = NULL;
+		return 0;
+	}
+}
+
+static const struct drm_prop_enum_list ade_ch_scale_list[] = {
+	{ ADE_CHANNEL_SCALE_UNSUPPORT, "unsupport" },
+	{ ADE_CHANNEL_SCALE_SUPPORT, "support" },
+};
+
+static const struct drm_prop_enum_list ade_ch_blend_list[] = {
+	{ ALPHA_BLENDING_NONE, "blending none" },
+	{ ALPHA_BLENDING_PREMULT, "blending premult" },
+	{ ALPHA_BLENDING_COVERAGE, "blending coverage" }
+};
+
+static const struct drm_prop_enum_list ade_rotation_enum_list[] = {
+	{ DRM_ROTATE_0,   "rotate-0" },
+	{ DRM_ROTATE_90,  "rotate-90" },
+	{ DRM_ROTATE_180, "rotate-180" },
+	{ DRM_ROTATE_270, "rotate-270" },
+	{ DRM_REFLECT_X,  "reflect-x" },
+	{ DRM_REFLECT_Y,  "reflect-y" },
+};
+
+static const struct drm_prop_enum_list ade_composition_type_enum_list[] = {
+	{ COMPOSITION_UNKNOWN, "composition unknown" },
+	{ COMPOSITION_GLES, "composition GLES" },
+	{ COMPOSITION_HWC, "composition hwc" },
+	{ COMPOSITION_MIXED, "composition mixed" }
+};
+
+int ade_install_plane_properties(struct drm_device *dev,
+				 struct hisi_plane *hplane)
+{
+	struct hisi_drm_private *priv = dev->dev_private;
+	struct drm_mode_object *obj = &hplane->base.base;
+	struct drm_property *prop;
+	u8 ch = hplane->ch;
+	u64 prop_val;
+
+	/* create and attach scale capablity properties */
+	prop = priv->cap_scl_prop;
+	if (!prop) {
+		prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+						"cap_scl",
+						ade_ch_scale_list,
+						ARRAY_SIZE(ade_ch_scale_list));
+		if (!prop)
+			return 0;
+
+		priv->cap_scl_prop = prop;
+	}
+
+	switch (ch) {
+	case ADE_CH5:
+	case ADE_CH6:
+		prop_val = ADE_CHANNEL_SCALE_SUPPORT;
+		break;
+	default:
+		prop_val = ADE_CHANNEL_SCALE_UNSUPPORT;
+		break;
+	}
+	drm_object_attach_property(obj, prop, prop_val);
+
+	/* create and attach rotation capablity properties */
+	prop = priv->cap_rot_prop;
+	if (!prop) {
+		prop = drm_property_create_bitmask(
+			dev, 0, "cap_rot",
+			ade_rotation_enum_list,
+			ARRAY_SIZE(ade_rotation_enum_list),
+			BIT(DRM_ROTATE_0) | BIT(DRM_ROTATE_90) |
+			BIT(DRM_ROTATE_180) | BIT(DRM_ROTATE_270) |
+			BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
+		if (!prop)
+			return 0;
+
+		priv->cap_rot_prop = prop;
+	}
+
+	switch (ch) {
+	case ADE_CH5:
+	case ADE_CH6:
+		prop_val = BIT(DRM_ROTATE_0) | BIT(DRM_ROTATE_90) |
+			BIT(DRM_ROTATE_180) | BIT(DRM_ROTATE_270) |
+			BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y);
+		break;
+	default:
+		prop_val = BIT(DRM_ROTATE_0);
+		break;
+	}
+	drm_object_attach_property(obj, prop, prop_val);
+
+	/* create and attach zpos properties */
+	prop = priv->zpos_prop;
+	if (!prop) {
+		prop = drm_property_create_range(dev, 0, "zpos", 0,
+						 ADE_CH_NUM - 1);
+		if (!prop)
+			return 0;
+
+		priv->zpos_prop = prop;
+	}
+	drm_object_attach_property(obj, prop, ch);
+
+	/* create and attach rotation properties */
+	prop = dev->mode_config.rotation_property;
+	if (!prop) {
+		prop = drm_mode_create_rotation_property(
+				dev,
+				BIT(DRM_ROTATE_0) | BIT(DRM_ROTATE_90) |
+				BIT(DRM_ROTATE_180) | BIT(DRM_ROTATE_270) |
+				BIT(DRM_REFLECT_X) | BIT(DRM_REFLECT_Y));
+		if (!prop)
+			return 0;
+		dev->mode_config.rotation_property = prop;
+	}
+	drm_object_attach_property(obj, prop, DRM_ROTATE_0);
+
+	/* create and attach alpha properties */
+	prop = priv->alpha_prop;
+	if (!prop) {
+		prop = drm_property_create_range(dev, 0, "alpha", 0, 255);
+		if (!prop)
+			return 0;
+
+		priv->alpha_prop = prop;
+	}
+	drm_object_attach_property(obj, prop, 255);
+
+	/* create and attach blending properties */
+	prop = priv->blend_prop;
+	if (!prop) {
+		prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+						"blend",
+						ade_ch_blend_list,
+						ARRAY_SIZE(ade_ch_blend_list));
+		if (!prop)
+			return 0;
+
+		priv->blend_prop = prop;
+	}
+	drm_object_attach_property(obj, prop, ALPHA_BLENDING_NONE);
+
+	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 */
+	return ADE_FORMAT_NOT_SUPPORT;
+}
+
+static bool ade_is_need_csc(u32 fmt)
+{
+	switch (fmt) {
+	case ADE_YUYV:
+	case ADE_YVYU:
+	case ADE_UYVY:
+	case ADE_VYUY:
+	case ADE_YUV444:
+	case ADE_NV12:
+	case ADE_NV21:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static void ade_rdma_set(struct ade_crtc *acrtc, struct drm_framebuffer *fb,
+			 u32 ch, u32 y, u32 in_h, u32 fmt, u32 rotation)
+{
+	u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
+	struct drm_gem_cma_object *obj = hisi_drm_fb_get_gem_obj(fb, 0);
+	struct ade_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	u32 stride = fb->pitches[0];
+	u32 addr = (u32)obj->paddr + y * stride;
+
+	/* get reg offset */
+	switch (ch) {
+	case ADE_DISP:
+		reg_ctrl = RD_CH_DISP_CTRL;
+		reg_addr = RD_CH_DISP_ADDR;
+		reg_size = RD_CH_DISP_SIZE;
+		reg_stride = RD_CH_DISP_STRIDE;
+		reg_space = RD_CH_DISP_SPACE;
+		reg_en = RD_CH_DISP_EN;
+		break;
+	default:
+		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);
+		break;
+	}
+
+	/*  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_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	u32 reg_en;
+
+	/* get reg offset */
+	switch (ch) {
+	case ADE_DISP:
+		reg_en = RD_CH_DISP_EN;
+		break;
+	default:
+		reg_en = RD_CH_EN(ch);
+		break;
+	}
+
+	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_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	u32 disable_val;
+	u32 clip_left;
+	u32 clip_right;
+
+	/* ADE_DISP channel has no clip module */
+	if (ch == ADE_DISP)
+		return;
+
+	/* 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;
+	}
+
+	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_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+
+	if (ch == ADE_DISP)
+		return;
+
+	writel(1, base + ADE_CLIP_DISABLE(ch));
+	acrtc->use_mask &= ~BIT(ADE_CLIP_BIT_OFST + ch);
+}
+
+static void ade_scale_set(struct ade_crtc *acrtc, u32 ch,
+			  u32 in_w, u32 in_h,
+			  u32 *out_w, u32 *out_h)
+{
+	struct ade_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	bool need_scale = false;
+	u32 o_w, o_h;
+	u32 ctrl_val;
+	u8 x;
+
+	switch (ch) {
+	case ADE_CH5:
+		x = ADE_SCL3;
+		break;
+	case ADE_CH6:
+		x = ADE_SCL1;
+		break;
+	default: /* channel 1,2,3,4,disp has no scale capability */
+		return;
+	}
+
+	if (!need_scale) {/* bypass */
+		ctrl_val = 0x400;
+		o_w = in_w;
+		o_h = in_h;
+	}
+
+	writel(ctrl_val, base + ADE_SCL_CTRL(x));
+	writel((in_h - 1) << 16 | (in_w - 1), base + ADE_SCL_IRES(x));
+	writel((o_h - 1) << 16 | (o_w - 1), base + ADE_SCL_ORES(x));
+	writel(1, base + ADE_SCL_START(x));
+
+	*out_w = o_w;
+	*out_h = o_h;
+
+	acrtc->use_mask |= BIT(ADE_SCL_BIT_OFST + x);
+}
+
+static void ade_scale_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	u8 x;
+
+	switch (ch) {
+	case ADE_CH5:
+		x = ADE_SCL3;
+		break;
+	case ADE_CH6:
+		x = ADE_SCL1;
+		break;
+	default: /* channel 1,2,3,4,disp has no scale capability */
+		return;
+	}
+
+	writel(0, base + ADE_SCL_START(x));
+
+	acrtc->use_mask &= ~BIT(ADE_SCL_BIT_OFST + x);
+}
+
+/* corlor space converting */
+static void ade_ctran_set(struct ade_crtc *acrtc, u32 ch,
+			  u32 in_w, u32 in_h,
+			  u32 fmt)
+{
+	struct ade_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	bool need_ctran = ade_is_need_csc(fmt);
+	u8 x;
+
+	switch (ch) {
+	case ADE_DISP:
+		x = ADE_CTRAN5;
+		break;
+	case ADE_CH5:
+		x = ADE_CTRAN1;
+		break;
+	case ADE_CH6:
+		x = ADE_CTRAN2;
+		break;
+	default: /* channel 1,2,3,4 has no csc capability */
+		return;
+	}
+
+	if (!need_ctran) {/* bypass */
+		writel(1, base + ADE_CTRAN_DIS(x));
+		writel(in_w * in_h - 1, base + ADE_CTRAN_IMAGE_SIZE(x));
+	}
+
+	acrtc->use_mask |= BIT(ADE_CTRAN_BIT_OFST + x);
+}
+
+static void ade_ctran_disable(struct ade_crtc *acrtc, u32 ch)
+{
+	struct ade_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	u8 x;
+
+	switch (ch) {
+	case ADE_DISP:
+		x = ADE_CTRAN5;
+		break;
+	case ADE_CH5:
+		x = ADE_CTRAN1;
+		break;
+	case ADE_CH6:
+		x = ADE_CTRAN2;
+		break;
+	default: /* channel 1,2,3,4 has no csc capability */
+		return;
+	}
+
+	writel(1, base + ADE_CTRAN_DIS(x));
+
+	acrtc->use_mask &= ~BIT(ADE_CTRAN_BIT_OFST + x);
+}
+
+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 blend, 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 < 0xFF)
+		*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_1; /* 1 - alpha */
+
+	switch (blend) {
+	case ALPHA_BLENDING_PREMULT:
+		break;
+	case ALPHA_BLENDING_COVERAGE:
+		*alp_sel = ADE_ALP_MUL_COEFF_0; /* alpha */
+		break;
+	case ALPHA_BLENDING_NONE:
+		*under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
+		break;
+	default:
+		DRM_ERROR("unsupport blending=0x%X\n", blend);
+		break;
+	}
+}
+
+static void ade_overlay_set(struct ade_crtc *acrtc, u8 ch, u8 zpos, u32 x0,
+			    u32 y0, u32 in_w, u32 in_h, u32 blend,
+			    u8 glb_alpha, u32 fmt)
+{
+	struct ade_hardware_context *ctx = acrtc->base.ctx;
+	struct hisi_crtc_state *
+		state = to_hisi_crtc_state(acrtc->base.base.state);
+	void __iomem *base = ctx->base;
+	u8 comp_type = state->comp_type;
+	u8 ovly_ch = zpos;
+	u8 x = ADE_OVLY2;
+	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(blend, fmt, glb_alpha, &alp_mode,
+				&alp_sel, &under_alp_sel);
+
+	/*
+	 * when all the HWC layers are composed by HWC, target layer(aka primary
+	 * plane) should be ignored. So make primary plane transparent.
+	 */
+
+	if (ch == PRIMARY_CH) {
+		if (comp_type == COMPOSITION_HWC)
+			alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
+		else if (comp_type == COMPOSITION_GLES)
+			under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
+	}
+
+	/* 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;
+	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+	val = (x + 1) << (ovly_ch * 4) | readl(base + ADE_OVLY_CTL);
+	writel(val, base + ADE_OVLY_CTL);
+
+	if (ch == ADE_DISP)
+		writel(1, base + ADE_CTRAN5_TRANS_CFG);
+
+	/* 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, u8 zpos)
+{
+	struct ade_hardware_context *ctx = acrtc->base.ctx;
+	void __iomem *base = ctx->base;
+	u8 ovly_ch = zpos;
+	u32 val;
+
+	val = ~BIT(6) & readl(base + ADE_OVLY_CH_CTL(ovly_ch));
+	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
+
+	val = ~(0x3 << (ovly_ch * 4)) & readl(base + ADE_OVLY_CTL);
+	writel(val, base + ADE_OVLY_CTL);
+
+	if (ch == ADE_DISP)
+		writel(0, base + ADE_CTRAN5_TRANS_CFG);
+}
+
+/*
+ * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->overlay
+ */
+static void ade_update_channel(struct hisi_plane *hplane,
+			       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)
+{
+	struct drm_plane_state	*state = hplane->base.state;
+	struct hisi_plane_state *hstate = to_hisi_plane_state(state);
+	u8 ch = hplane->ch;
+	u8 zpos = hstate->zpos;
+	u8 glb_alpha = hstate->alpha;
+	u32 blend = hstate->blend;
+	u32 rotation = state->rotation;
+	u32 fmt = ade_get_format(fb->pixel_format);
+	u32 in_w;
+	u32 in_h;
+	u32 out_w;
+	u32 out_h;
+
+	/* 1) DMA setting */
+	in_w = src_w;
+	in_h = src_h;
+	ade_rdma_set(acrtc, fb, ch, src_y, in_h, fmt, rotation);
+
+	/* 2) clip setting */
+	ade_clip_set(acrtc, ch, fb->width, src_x, in_w, in_h);
+
+	/* 3) scale setting */
+	out_w = crtc_w;
+	out_h = crtc_h;
+	ade_scale_set(acrtc, ch, in_w, in_h, &out_w, &out_h);
+
+	/* 4) ctran/csc setting */
+	in_w = out_w;
+	in_h = out_h;
+	ade_ctran_set(acrtc, ch, in_w, in_h, fmt);
+
+	/* 5) overlay routing setting */
+	ade_overlay_set(acrtc, ch, zpos, crtc_x, crtc_y, in_w, in_h, blend,
+			glb_alpha, fmt);
+
+	acrtc->ch_mask |= BIT(ch);
+}
+
+static void ade_disable_channel(struct hisi_plane *hplane,
+				struct ade_crtc *acrtc)
+{
+	struct drm_plane_state  *state = hplane->base.state;
+	struct hisi_plane_state *hstate = to_hisi_plane_state(state);
+	u32 ch = hplane->ch;
+	u8 zpos = hstate->zpos;
+
+	/* reset state */
+	hstate->zpos = hplane->base.type == DRM_PLANE_TYPE_PRIMARY ? 0 :
+		drm_plane_index(&hplane->base);
+	state->rotation = BIT(DRM_ROTATE_0);
+	hstate->alpha = 255;
+	hstate->blend = ALPHA_BLENDING_NONE;
+
+	/*
+	 * 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 scale */
+	ade_scale_disable(acrtc, ch);
+
+	/* disable ctran */
+	ade_ctran_disable(acrtc, ch);
+
+	/* disable overlay routing */
+	ade_overlay_disable(acrtc, ch, zpos);
+
+	acrtc->ch_mask &= ~BIT(ch);
+}
+
+void ade_plane_atomic_disable(struct hisi_plane *hplane,
+			      struct drm_plane_state *old_state)
+{
+	struct hisi_crtc *hcrtc = to_hisi_crtc(old_state->crtc);
+	struct ade_crtc *acrtc = to_ade_crtc(hcrtc);
+
+	ade_disable_channel(hplane, acrtc);
+}
+
+void ade_plane_atomic_update(struct hisi_plane *hplane,
+			     struct drm_plane_state *old_state)
+{
+	struct drm_plane *plane = &hplane->base;
+	struct drm_plane_state	*state	= plane->state;
+	struct hisi_crtc *hcrtc = to_hisi_crtc(state->crtc);
+	struct ade_crtc *acrtc = to_ade_crtc(hcrtc);
+
+	ade_update_channel(hplane, 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);
+}
+
+int ade_install_crtc_properties(struct drm_device *dev,
+				struct hisi_crtc *hcrtc)
+{
+	struct hisi_drm_private *priv = dev->dev_private;
+	struct drm_mode_object *obj = &hcrtc->base.base;
+	struct drm_property *prop;
+
+	/* create and attach composition type properties */
+	prop = priv->comp_type_prop;
+	if (!prop) {
+		prop = drm_property_create_enum(
+				dev, 0,	"comp_type",
+				ade_composition_type_enum_list,
+				ARRAY_SIZE(ade_composition_type_enum_list));
+		if (!prop)
+			return 0;
+
+		priv->comp_type_prop = prop;
+	}
+	drm_object_attach_property(obj, prop, COMPOSITION_UNKNOWN);
+
+	return 0;
+}
+
+static struct hisi_crtc_ops ade_crtc_ops = {
+	.enable = ade_crtc_enable,
+	.disable = ade_crtc_disable,
+	.mode_prepare = ade_crtc_mode_prepare,
+	.mode_fixup = ade_crtc_mode_fixup,
+	.mode_set_nofb = ade_crtc_mode_set_nofb,
+	.atomic_begin = ade_crtc_atomic_begin,
+	.atomic_flush = ade_crtc_atomic_flush,
+	.install_properties = ade_install_crtc_properties,
+};
+
+static struct hisi_plane_funcs ade_plane_ops = {
+	.atomic_update = ade_plane_atomic_update,
+	.atomic_disable = ade_plane_atomic_disable,
+	.install_properties = ade_install_plane_properties,
+	.get_properties = ade_get_channel_formats,
+};
+
 static int ade_dts_parse(struct platform_device *pdev,
 			 struct ade_hardware_context *ctx)
 {
@@ -129,19 +1206,25 @@ static int ade_bind(struct device *dev, struct device *master, void *data)
 		hplane = &ade->hplane[i];
 		hplane->ch = i;
 		hplane->ctx = ctx;
+		hplane->ops = &ade_plane_ops;
 		type = i == PRIMARY_CH ? DRM_PLANE_TYPE_PRIMARY :
 			DRM_PLANE_TYPE_OVERLAY;
 
 		ret = hisi_drm_plane_init(drm_dev, hplane, type);
-		if (ret)
+		if (ret) {
+			DRM_ERROR("failed to hisi drm plane init\n");
 			return ret;
+		}
 	}
 
 	/* crtc init */
+	hcrtc->ops = &ade_crtc_ops;
 	hcrtc->ctx = ctx;
 	ret = hisi_drm_crtc_init(drm_dev, hcrtc, &ade->hplane[PRIMARY_CH].base);
-	if (ret)
+	if (ret) {
+		DRM_ERROR("failed to hisi drm crtc init\n");
 		return ret;
+	}
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/hisilicon/hisi_ade_reg.h b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
index bdf3c3b..0e388af 100644
--- a/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
+++ b/drivers/gpu/drm/hisilicon/hisi_ade_reg.h
@@ -13,6 +13,113 @@
 #ifndef __HISI_ADE_REG_H__
 #define __HISI_ADE_REG_H__
 
+/********** ADE Register Offset ***********/
+#define ADE_CTRL                (0x4)
+#define ADE_CTRL1               (0x8C)
+#define ADE_DISP_SRC_CFG        (0x18)
+#define ADE_OVLY1_TRANS_CFG     (0x2C)
+#define ADE_EN                  (0x100)
+/* 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_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_EN(x)             (0x1020 + (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)
+/* scale regs */
+#define ADE_SCL_CTRL(x)         (0x3000 + (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)
+/* ctran regs */
+#define ADE_CTRAN5_TRANS_CFG    (0x40)
+#define ADE_CTRAN_DIS(x)        (0x5004 + (x) * 0x100)
+#define ADE_CTRAN_IMAGE_SIZE(x) (0x503C + (x) * 0x100)
+/* overlay regs */
+#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_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)
+
+/*set ADE flag param define */
+#define	ADE_DISABLE		(0)
+#define	ADE_ENABLE		(1)
+#define	ADE_RGB			(0)
+#define	ADE_BGR			(1)
+
+/* ADE out format param */
+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_BGR_565,
+	ADE_RGB_565,
+	ADE_XBGR_8888,
+	ADE_XRGB_8888,
+	ADE_ABGR_8888,
+	ADE_ARGB_8888,
+	ADE_BGRA_8888,
+	ADE_RGBA_8888,
+	ADE_BGR_888,
+	ADE_RGB_888,
+	ADE_YUYV = 16,
+	ADE_YVYU,
+	ADE_UYVY,
+	ADE_VYUY,
+	ADE_YUV444,
+	ADE_NV12,
+	ADE_NV21,
+	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_channel {
 	ADE_CH1 = 0,	/* channel 1 for primary plane */
 	ADE_CH2,
@@ -24,4 +131,78 @@ enum ade_channel {
 	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 */
+};
+
+/********** LDI Register 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_MSK_INT		(0x7428)
+#define LDI_INT_CLR		(0x742C)
+#define LDI_WORK_MODE		(0x7430)
+#define LDI_DE_SPACE_LOW	(0x7438)
+#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)
+
+/* set LDI param define */
+#define LDI_TEST                (0)
+#define LDI_WORK                (1)
+#define	LDI_ISR_FRAME_END_INT   (0x02)
+#define	LDI_ISR_UNDER_FLOW_INT  (0x04)
+
+/********** 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);
+}
+
 #endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
index ad13614..feeadc4 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
@@ -19,35 +19,82 @@
 
 static void  hisi_drm_crtc_enable(struct drm_crtc *crtc)
 {
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+
+	if (hcrtc->enable)
+		return;
+
+	if (ops->enable)
+		ops->enable(hcrtc);
+	drm_crtc_vblank_on(crtc);
+
+	hcrtc->enable = true;
 }
 
 static void hisi_drm_crtc_disable(struct drm_crtc *crtc)
 {
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+
+	if (!hcrtc->enable)
+		return;
+
+	drm_crtc_vblank_off(crtc);
+	if (ops->disable)
+		ops->disable(hcrtc);
+
+	hcrtc->enable = false;
 }
 
 static void hisi_drm_crtc_mode_prepare(struct drm_crtc *crtc)
 {
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+
+	if (ops->mode_prepare)
+		ops->mode_prepare(hcrtc);
 }
 
 static bool hisi_drm_crtc_mode_fixup(struct drm_crtc *crtc,
 				     const struct drm_display_mode *mode,
 				     struct drm_display_mode *adj_mode)
 {
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
 	bool ret = true;
 
+	if (ops->mode_fixup)
+		ret = ops->mode_fixup(hcrtc, mode, adj_mode);
+
 	return ret;
 }
 
 static void hisi_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
 {
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+
+	if (ops->mode_set_nofb)
+		ops->mode_set_nofb(hcrtc);
 }
 
 static void hisi_crtc_atomic_begin(struct drm_crtc *crtc)
 {
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+
+	if (ops->atomic_begin)
+		ops->atomic_begin(hcrtc);
 }
 
 static void hisi_crtc_atomic_flush(struct drm_crtc *crtc)
 {
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+
+	if (ops->atomic_flush)
+		ops->atomic_flush(hcrtc);
 }
 
 static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
index 989cb1f..6521ed8 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
@@ -13,6 +13,7 @@
 #ifndef __HISI_DRM_CRTC_H__
 #define __HISI_DRM_CRTC_H__
 
+#define to_hisi_crtc(crtc)  container_of(crtc, struct hisi_crtc, base)
 #define to_hisi_crtc_state(state) \
 		container_of(state, struct hisi_crtc_state, base)
 
@@ -27,9 +28,20 @@ struct hisi_crtc {
 	struct drm_crtc base;
 	void *ops;
 	void *ctx;
+	bool enable;
 };
 
 struct hisi_crtc_ops {
+	void (*disable)(struct hisi_crtc *hcrtc);
+	void (*enable)(struct hisi_crtc *hcrtc);
+	void (*mode_prepare)(struct hisi_crtc *hcrtc);
+	bool (*mode_fixup)(struct hisi_crtc *hcrtc,
+			   const struct drm_display_mode *mode,
+			   struct drm_display_mode *adj_mode);
+	void (*mode_set_nofb)(struct hisi_crtc *hcrtc);
+	void (*atomic_begin)(struct hisi_crtc *hcrtc);
+	void (*atomic_flush)(struct hisi_crtc *hcrtc);
+	void (*destroy)(struct hisi_crtc *hcrtc);
 	int (*install_properties)(struct drm_device *dev,
 				  struct hisi_crtc *hcrtc);
 };
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fb.c b/drivers/gpu/drm/hisilicon/hisi_drm_fb.c
index 5dace8b..9221009 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_fb.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fb.c
@@ -10,8 +10,8 @@
  *
  */
 
-#include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_gem_cma_helper.h>
 
 #include "hisi_drm_fb.h"
 
@@ -154,3 +154,22 @@ err_gem_object_unreference:
 	return ERR_PTR(ret);
 }
 
+/**
+ * hisi_drm_fb_get_gem_obj() - Get CMA GEM object for framebuffer
+ * @fb: The framebuffer
+ * @plane: Which plane
+ *
+ * Return the CMA GEM object for given framebuffer.
+ *
+ * This function will usually be called from the CRTC callback functions.
+ */
+struct drm_gem_cma_object *hisi_drm_fb_get_gem_obj(struct drm_framebuffer *fb,
+						   unsigned int plane)
+{
+	struct hisi_drm_fb *hisi_fb = to_hisi_drm_fb(fb);
+
+	if (plane >= 4)
+		return NULL;
+
+	return hisi_fb->obj[plane];
+}
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fb.h b/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
index 1db1289..4bd168e 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
@@ -22,5 +22,7 @@ struct hisi_drm_fb {
 struct drm_framebuffer *hisi_drm_fb_create(struct drm_device *dev,
 					   struct drm_file *file_priv,
 					   struct drm_mode_fb_cmd2 *mode_cmd);
+struct drm_gem_cma_object *
+hisi_drm_fb_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane);
 
 #endif /* __HISI_DRM_FB_H__ */
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_plane.c b/drivers/gpu/drm/hisilicon/hisi_drm_plane.c
index af040b6..df3edab 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_plane.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_plane.c
@@ -24,11 +24,28 @@
 static void hisi_plane_atomic_disable(struct drm_plane *plane,
 				      struct drm_plane_state *old_state)
 {
+	struct hisi_plane *hplane = to_hisi_plane(plane);
+	struct hisi_plane_funcs *ops = hplane->ops;
+
+	if (!old_state->crtc)
+		return;
+
+	if (ops->atomic_disable)
+		ops->atomic_disable(hplane, old_state);
 }
 
 static void hisi_plane_atomic_update(struct drm_plane *plane,
 				     struct drm_plane_state *old_state)
 {
+	struct hisi_plane *hplane = to_hisi_plane(plane);
+	struct hisi_plane_funcs *ops = hplane->ops;
+	struct drm_plane_state	*hstate	= plane->state;
+
+	if (!hstate->crtc)
+		return;
+
+	if (ops->atomic_update)
+		ops->atomic_update(hplane, old_state);
 }
 
 int hisi_plane_atomic_check(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_plane.h b/drivers/gpu/drm/hisilicon/hisi_drm_plane.h
index 70ee845..212514c 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_plane.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_plane.h
@@ -35,6 +35,10 @@ struct hisi_plane_funcs {
 	u32 (*get_properties)(u8 ch, const u32 **formats);
 	int (*install_properties)(struct drm_device *dev,
 				  struct hisi_plane *hplane);
+	void (*atomic_update)(struct hisi_plane *hplane,
+			      struct drm_plane_state *old_state);
+	void (*atomic_disable)(struct hisi_plane *hplane,
+			       struct drm_plane_state *old_state);
 };
 
 int hisi_drm_plane_init(struct drm_device *dev, struct hisi_plane *hplane,
-- 
1.9.1



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

* [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
                   ` (3 preceding siblings ...)
  2015-09-15  9:37 ` [PATCH RFC 4/8] drm: hisilicon: fill interface function of plane\crtc part Xinwei Kong
@ 2015-09-15  9:37 ` Xinwei Kong
  2015-09-17 11:39   ` Archit Taneja
  2015-09-15  9:37 ` [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev Xinwei Kong
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

This patch enables the adv7533 module which is connecting hisilicon SOC
by dsi module. while using DSI module and adv7533 module to implement the
encoder/connector interface of DRM\KMS.

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>
Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
Signed-off-by: Yu Gong <gongyu@hisilicon.com>
---
 drivers/gpu/drm/hisilicon/Kconfig              |  10 +
 drivers/gpu/drm/hisilicon/hisi_drm_connector.c |  34 ++
 drivers/gpu/drm/hisilicon/hisi_drm_connector.h |   8 +
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c       | 670 +++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_encoder.c   |  52 ++
 drivers/gpu/drm/hisilicon/hisi_drm_encoder.h   |  19 +
 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h       |  91 ++++
 7 files changed, 884 insertions(+)
 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 60b42e4..105dbcb 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -7,3 +7,13 @@ config DRM_HISI
 	  Choose this option if you have a hisilicon terminal chipset.
 	  If M is selected the module will be called hisi-drm.
 
+if DRM_HISI
+
+config DRM_HISI_HAS_SLAVE_ENCODER
+	bool "Support slave encoder output"
+	default y
+	help
+	  Support slave encoder output device such as DSI interface connecting
+	  HDMI converter by i2c.
+
+endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_connector.c b/drivers/gpu/drm/hisilicon/hisi_drm_connector.c
index 62efdc7..57ab2e8 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_connector.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_connector.c
@@ -23,8 +23,21 @@
 int hisi_drm_connector_mode_valid(struct drm_connector *connector,
 				  struct drm_display_mode *mode)
 {
+	struct hisi_connector *hconnector = to_hisi_connector(connector);
+	struct drm_encoder *encoder = hconnector->encoder;
+	struct hisi_connector_funcs *ops = hconnector->ops;
+	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
 	int ret = MODE_OK;
 
+	if (ops->modes_valid)
+		ops->modes_valid(connector);
+
+	if (sfuncs && sfuncs->mode_valid) {
+		ret = sfuncs->mode_valid(encoder, mode);
+		if (ret != MODE_OK)
+			return ret;
+	}
+
 	return ret;
 }
 
@@ -39,8 +52,19 @@ hisi_drm_best_encoder(struct drm_connector *connector)
 
 int hisi_drm_get_modes(struct drm_connector *connector)
 {
+	struct hisi_connector *hconnector = to_hisi_connector(connector);
+	struct hisi_connector_funcs *ops = hconnector->ops;
+	struct drm_encoder *encoder = hconnector->encoder;
+	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
 	int count = 0;
 
+	if (ops->get_modes) {
+		count += ops->get_modes(connector);
+	} else {
+		if (sfuncs && sfuncs->get_modes)
+			count += sfuncs->get_modes(encoder, connector);
+	}
+
 	return count;
 }
 
@@ -59,8 +83,18 @@ void hisi_drm_connector_destroy(struct drm_connector *connector)
 enum drm_connector_status
 hisi_drm_detect(struct drm_connector *connector, bool force)
 {
+	struct hisi_connector *hconnector = to_hisi_connector(connector);
+	struct drm_encoder *encoder = hconnector->encoder;
+	struct hisi_connector_funcs *ops = hconnector->ops;
+	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
 	enum drm_connector_status status = connector_status_unknown;
 
+	if (ops->detect)
+		ops->detect(connector);
+
+	if (sfuncs && sfuncs->detect)
+		status = sfuncs->detect(encoder, connector);
+
 	return status;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_connector.h b/drivers/gpu/drm/hisilicon/hisi_drm_connector.h
index 114391c..a8b8409 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_connector.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_connector.h
@@ -13,9 +13,17 @@
 #ifndef __HISI_DRM_CONNECTOR_H__
 #define __HISI_DRM_CONNECTOR_H__
 
+struct hisi_connector_funcs {
+	enum drm_connector_status
+		(*detect) (struct drm_connector *connector);
+	int (*get_modes)(struct drm_connector *connector);
+	int (*modes_valid)(struct drm_connector *connector);
+};
+
 struct hisi_connector {
 	struct drm_connector connector;
 	struct drm_encoder *encoder;
+	void *ops;
 };
 
 void hisi_drm_connector_init(struct drm_device *dev,
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index 046fd8e..8509ced 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -12,18 +12,72 @@
 
 #include <linux/clk.h>
 #include <linux/component.h>
+#include <video/videomode.h>
 
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_encoder_slave.h>
 
 #include "hisi_drm_encoder.h"
 #include "hisi_drm_connector.h"
+#include "hisi_dsi_reg.h"
 
+#define encoder_to_dsi(encoder) \
+	container_of(encoder, struct hisi_dsi, hisi_encoder.base.base)
+
+#define MAX_TX_ESC_CLK		   (10)
 #define DSI_24BITS_1               (5)
+#define DSI_NON_BURST_SYNC_PULSES  (0)
+#define DSI_BURST_MODE    DSI_NON_BURST_SYNC_PULSES
+
+#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)dsi->vm.pixelclock) / \
+	      phy->lane_byte_clk_kHz)))
+
+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;
+	u32 burst_mode;
+};
 
 struct hisi_dsi {
 	struct hisi_encoder hisi_encoder;
 	struct hisi_connector hisi_connector;
+	struct mipi_phy_register phy;
+	struct videomode vm;
 
 	u32 lanes;
 	u32 format;
@@ -35,6 +89,10 @@ struct hisi_dsi {
 
 struct hisi_dsi_context {
 	struct hisi_dsi dsi;
+#ifdef CONFIG_DRM_HISI_HAS_SLAVE_ENCODER
+	struct i2c_client *client;
+	struct drm_i2c_encoder_driver *drm_i2c_driver;
+#endif
 	struct clk *dsi_cfg_clk;
 	struct drm_device *dev;
 
@@ -42,6 +100,578 @@ struct hisi_dsi_context {
 	int nominal_pixel_clk_kHz;
 };
 
+struct dsi_phy_seq_info {
+	u32 min_range_kHz;
+	u32 max_range_kHz;
+	u32 pll_vco_750M;
+	u32 hstx_ckg_sel;
+};
+
+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 }
+};
+
+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;
+
+	do {
+		f_kHz = *phy_freq_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;
+
+		(*phy_freq_kHz) += 10;
+
+	} while (1);
+
+	*phy_freq_kHz = f_kHz;
+	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++;
+
+	phy->burst_mode = DSI_BURST_MODE;
+}
+
+int dsi_mipi_init(struct hisi_dsi *dsi)
+{
+	struct hisi_dsi_context *ctx = dsi->ctx;
+	struct mipi_phy_register *phy = &dsi->phy;
+	void __iomem *base = ctx->base;
+
+	u32 i = 0;
+	u32 hline_time = 0;
+	u32 hsa_time = 0;
+	u32 hbp_time = 0;
+	u32 pixel_clk_kHz;
+	u32 delay_count = 0;
+	int refresh_nom, refresh_real;
+	int htot, vtot, blc_hactive;
+	int tmp, tmp1, val;
+	bool is_ready = false;
+
+	/* reset Core */
+	writel(PWR_UP_OFF, base + PWR_UP);
+
+	/* set lanes value */
+	val = (dsi->lanes - 1);
+	val |= PHY_STOP_WAIT_TIME << 8;
+	writel(val, base + PHY_IF_CFG);
+
+	/* set phy clk division */
+	writel(phy->clk_division, base + CLKMGR_CFG);
+
+	/* clean up phy set param */
+	writel(0x00, base + PHY_RSTZ);
+	writel(0x00, base + PHY_TST_CTRL0);
+	writel(0x01, base + PHY_TST_CTRL0);
+	writel(0x00, base + PHY_TST_CTRL0);
+
+	/* clock lane Timing control - TLPX */
+	dsi_phy_tst_set(base, CLK_LPX_ADDR, phy->clk_t_lpx);
+
+	/* clock lane Timing control - THS-PREPARE */
+	dsi_phy_tst_set(base, CLK_HS_PRE_ADDR, phy->clk_t_hs_prepare);
+
+	/* clock lane Timing control - THS-ZERO */
+	dsi_phy_tst_set(base, CLK_HS_ZERO_ADDR, phy->clk_t_hs_zero);
+
+	/* clock lane Timing control - THS-TRAIL */
+	dsi_phy_tst_set(base, CLK_HS_TRIAL_ADDR, phy->clk_t_hs_trial);
+
+	/* clock lane Timing control - TWAKEUP */
+	dsi_phy_tst_set(base, CLK_WAKEUP_ADDR, phy->clk_t_wakeup);
+
+	/* data lane */
+	for (i = 0; i < dsi->lanes; i++) {
+		/* Timing control - TLPX*/
+		dsi_phy_tst_set(base, DATA_LPX_ADDR + (i << 4),
+				phy->data_t_lpx);
+
+		/* Timing control - THS-PREPARE */
+		dsi_phy_tst_set(base, DATA_HS_PRE_ADDR + (i << 4),
+				phy->data_t_hs_prepare);
+
+		/* Timing control - THS-ZERO */
+		dsi_phy_tst_set(base, DATA_HS_ZERO_ADDR + (i << 4),
+				phy->data_t_hs_zero);
+
+		/* Timing control - THS-TRAIL */
+		dsi_phy_tst_set(base, DATA_HS_TRIAL_ADDR + (i << 4),
+				phy->data_t_hs_trial);
+
+		/* Timing control - TTA-GO */
+		dsi_phy_tst_set(base, DATA_TA_GO_ADDR + (i << 4),
+				phy->data_t_ta_go);
+
+		/* Timing control - TTA-GET */
+		dsi_phy_tst_set(base, DATA_TA_GET_ADDR + (i << 4),
+				phy->data_t_ta_get);
+
+		/*  Timing control - TWAKEUP */
+		dsi_phy_tst_set(base, DATA_WAKEUP_ADDR + (i << 4),
+				phy->data_t_wakeup);
+	}
+
+	/* physical configuration I  */
+	dsi_phy_tst_set(base, HSTX_CKG_SEL_ADDR, 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, PLL_FBD_DPN_ADDR, val);
+
+	/* physical configuration pll II  */
+	dsi_phy_tst_set(base, PLL_FBD_P_ADDR, phy->pll_fbd_p);
+
+	/* physical configuration pll III  */
+	dsi_phy_tst_set(base, PLL_FBD_S_ADDR, phy->pll_fbd_s);
+
+	/*physical configuration pll IV*/
+	val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p;
+	dsi_phy_tst_set(base, PLL_PRA_DP_ADDR, 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, PLL_LPF_VOF_ADDR, val);
+
+	writel(0x04, base + PHY_RSTZ);
+	udelay(1);
+
+	writel(0x05, base + PHY_RSTZ);
+	udelay(1);
+
+	writel(0x07, base + PHY_RSTZ);
+	usleep_range(1000, 1500);
+
+	while (1) {
+		val = readl(base +  PHY_STATUS);
+		if ((0x01 & 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 is not ready.\n");
+
+	while (1) {
+		val = readl(base + PHY_STATUS);
+		if ((BIT(2) & val) || delay_count > 100) {
+			is_ready = (delay_count < 100) ? true : false;
+			break;
+		}
+
+		udelay(1);
+		++delay_count;
+	}
+
+	if (!is_ready)
+		DRM_INFO("phystopstateclklane is not ready.\n");
+
+	/* DSI color mode setting */
+	writel(0, base + DPI_VCID);
+	writel(dsi->color_mode, base + DPI_COLOR_CODING);
+
+	/* DSI format and pol setting */
+	val = dsi->date_enable_pol;
+	val |= (dsi->vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ? 0 : 1) << 0x2;
+	val |= (dsi->vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ? 0 : 1) << 0x1;
+	writel(val, base +  DPI_CFG_POL);
+
+	if (dsi->format == MIPI_DSI_FMT_RGB666)
+		writel(dsi->color_mode | BIT(9), base + DPI_COLOR_CODING);
+
+	/*
+	 * 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.
+	 */
+
+	htot = dsi->vm.hactive + dsi->vm.hsync_len +
+		  dsi->vm.hfront_porch + dsi->vm.hback_porch;
+	vtot = dsi->vm.vactive + dsi->vm.vsync_len +
+		  dsi->vm.vfront_porch + dsi->vm.vback_porch;
+
+	pixel_clk_kHz = dsi->vm.pixelclock;
+
+	hsa_time = (dsi->vm.hsync_len * phy->lane_byte_clk_kHz) /
+		   pixel_clk_kHz;
+	hbp_time = (dsi->vm.hback_porch * phy->lane_byte_clk_kHz) /
+		   pixel_clk_kHz;
+	hline_time  = (((u64)htot * (u64)phy->lane_byte_clk_kHz)) /
+		      pixel_clk_kHz;
+	blc_hactive  = (((u64)dsi->vm.hactive *
+			(u64)phy->lane_byte_clk_kHz)) / pixel_clk_kHz;
+
+	if ((R(hline_time) / 1000) > htot)
+		hline_time--;
+
+	if ((R(hline_time) / 1000) < htot)
+		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);
+
+	if (dsi->vm.vsync_len > 15)
+		dsi->vm.vsync_len = 15;
+
+	writel(dsi->vm.vsync_len, base + VID_VSA_LINES);
+	writel(dsi->vm.vback_porch, base + VID_VBP_LINES);
+	writel(dsi->vm.vfront_porch, base + VID_VFP_LINES);
+	writel(dsi->vm.vactive, base + VID_VACTIVE_LINES);
+	writel(dsi->vm.hactive, base + VID_PKT_SIZE);
+
+	refresh_nom = ((u64)ctx->nominal_pixel_clk_kHz * 1000000) /
+		      (htot * vtot);
+
+	tmp = 1000000000 / dsi->vm.pixelclock;
+	tmp1 = 1000000000 / phy->lane_byte_clk_kHz;
+
+	refresh_real = ((u64)dsi->vm.pixelclock * (u64)1000000000) /
+		      ((u64)R(hline_time) * (u64)vtot);
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+		/*
+		 * we disable this since it affects downstream
+		 * DSI -> HDMI converter output
+		 */
+		writel(0x00, base + VID_MODE_CFG);
+
+		/*VSA/VBP/VFP max transfer byte in LP mode*/
+		writel(0x00, base + DPI_LP_CMD_TIM);
+		/* enable LP command transfer */
+		writel(0x00, base + VID_MODE_CFG);
+		/* config max read time */
+		writel(PHY_MAX_TIME, base + PHY_TMR_CFG);
+	}
+
+	/* Configure core's phy parameters */
+	writel(0xFFF, base + BTA_TO_CNT);
+
+	val = 0xFF;
+	val |= (phy->lp2hs_time) << 16;
+	val |= (phy->hs2lp_time) << 24;
+	writel(val, base + PHY_TMR_CFG);
+
+	val = phy->clklp2hs_time;
+	val |= (phy->clkhs2lp_time) << 16;
+	writel(val, base + PHY_TMR_LPCLK_CFG);
+
+	/* setting burst mode */
+	val = phy->clk_to_data_delay;
+	val |= (phy->data_to_clk_delay) << 8;
+	writel(val, base + NO_CONTINUE);
+	writel(0x00, base + VID_MODE_CFG);
+	writel(phy->burst_mode, base + VID_MODE_CFG);
+	writel(0x0, base + LPCLK_CTRL);
+
+	/* for dsi read */
+	writel(0x0, base + PCKHDL_CFG);
+
+	/* Enable EOTP TX; Enable EDPI */
+	if (dsi->mode_flags == MIPI_DSI_MODE_VIDEO)
+		writel(dsi->vm.hactive, base + EDPI_CMD_SIZE);
+
+	/* DSI and D-PHY Initialization */
+	writel(VIDEO_MODE, base + MODE_CFG);
+	writel(0x1, base + LPCLK_CTRL);
+
+	writel(PWR_UP_ON, base + PWR_UP);
+
+	return 0;
+}
+
+static void dsi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct hisi_dsi_context *ctx = dsi->ctx;
+	void __iomem *base = ctx->base;
+
+	writel(PWR_UP_OFF, base + PWR_UP);
+	writel(0x00, base + LPCLK_CTRL);
+	writel(0x00, base + PHY_RSTZ);
+	clk_disable_unprepare(ctx->dsi_cfg_clk);
+}
+
+static void dsi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct hisi_dsi_context *ctx = dsi->ctx;
+	int ret;
+
+	/* 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;
+	}
+
+	ret = dsi_mipi_init(dsi);
+	if (ret) {
+		DRM_ERROR("failed to init mipi: %d!\n", ret);
+		return;
+	}
+}
+
+void dsi_encoder_mode_set(struct drm_encoder *encoder,
+			  struct drm_display_mode *mode,
+			  struct drm_display_mode *adjusted_mode)
+{
+	struct hisi_dsi *dsi = encoder_to_dsi(encoder);
+	struct hisi_dsi_context *ctx = dsi->ctx;
+	struct videomode *vm = &dsi->vm;
+	u32 dphy_freq_kHz;
+
+	vm->flags = 0;
+	vm->hactive = mode->hdisplay;
+	vm->vactive = mode->vdisplay;
+	vm->vfront_porch = mode->vsync_start - mode->vdisplay;
+	vm->vback_porch = mode->vtotal - mode->vsync_end;
+	vm->vsync_len = mode->vsync_end - mode->vsync_start;
+	vm->hfront_porch = mode->hsync_start - mode->hdisplay;
+	vm->hback_porch = mode->htotal - mode->hsync_end;
+	vm->hsync_len = mode->hsync_end - mode->hsync_start;
+
+	vm->pixelclock = adjusted_mode->clock;
+	ctx->nominal_pixel_clk_kHz = mode->clock;
+	dsi->lanes = 3 + !!(vm->pixelclock >= 115000);
+	dphy_freq_kHz = vm->pixelclock * 24 / dsi->lanes;
+
+	/* avoid a less-compatible DSI rate with 1.2GHz px PLL */
+	if (dphy_freq_kHz == 600000)
+		dphy_freq_kHz = 640000;
+
+	set_dsi_phy_rate_equal_or_faster(&dphy_freq_kHz, &dsi->phy);
+
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+	else if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+		vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+	else if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+		vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
+}
+
+static struct drm_display_mode mode_720p = {
+	.name		= "1280x720",
+	.vrefresh	= 60,
+	.clock		= 74250,
+	.hdisplay	= 1280,
+	.hsync_start	= 1390,
+	.hsync_end	= 1430,
+	.htotal		= 1650,
+	.vdisplay	= 720,
+	.vsync_start	= 725,
+	.vsync_end	= 730,
+	.vtotal		= 750,
+	.type		= DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER,
+	.flags		= DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+	.width_mm	= 735,
+	.height_mm	= 420,
+};
+
+/* 800x600@60 works well, so add to defaut modes */
+static struct drm_display_mode mode_800x600 = {
+	.name		= "800x600",
+	.vrefresh	= 60,
+	.clock		= 40000,
+	.hdisplay	= 800,
+	.hsync_start	= 840,
+	.hsync_end	= 968,
+	.htotal		= 1056,
+	.vdisplay	= 600,
+	.vsync_start	= 601,
+	.vsync_end	= 605,
+	.vtotal		= 628,
+	.type		= DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER,
+	.flags		= DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
+	.width_mm	= 735,
+	.height_mm	= 420,
+};
+
+static int dsi_connector_get_modes(struct drm_connector *connector)
+{
+	struct drm_display_mode *mode;
+
+	/* 1280x720@60: 720P */
+	mode = drm_mode_duplicate(connector->dev, &mode_720p);
+	if (!mode)
+		DRM_ERROR("failed to create a new display mode\n");
+
+	drm_mode_probed_add(connector, mode);
+
+	/* 800x600@60 */
+	mode = drm_mode_duplicate(connector->dev, &mode_800x600);
+	if (!mode)
+		DRM_ERROR("failed to create a new display mode\n");
+	drm_mode_probed_add(connector, mode);
+
+	return 2;
+}
+
+struct hisi_connector_funcs hisi_dsi_connector_ops = {
+	.get_modes = dsi_connector_get_modes,
+};
+
+struct hisi_encoder_funcs hisi_dsi_encoder_ops = {
+	.mode_set = dsi_encoder_mode_set,
+	.enable = dsi_encoder_enable,
+	.disable = dsi_encoder_disable,
+};
+
 static int hisi_dsi_bind(struct device *dev, struct device *master,
 			 void *data)
 {
@@ -52,8 +682,23 @@ static int hisi_dsi_bind(struct device *dev, struct device *master,
 
 	hisi_drm_encoder_init(ctx->dev, &ctx->dsi.hisi_encoder.base.base);
 
+#ifdef CONFIG_DRM_HISI_HAS_SLAVE_ENCODER
+	ret = ctx->drm_i2c_driver->encoder_init(ctx->client, ctx->dev,
+						&ctx->dsi.hisi_encoder.base);
+	if (ret) {
+		DRM_ERROR("fail to init drm i2c encoder\n");
+		return ret;
+	}
+
+	if (!ctx->dsi.hisi_encoder.base.slave_funcs) {
+		DRM_ERROR("failed check encoder function\n");
+		return -ENODEV;
+	}
+#endif
+
 	hisi_drm_connector_init(ctx->dev, &ctx->dsi.hisi_encoder.base.base,
 				&ctx->dsi.hisi_connector.connector);
+
 	return ret;
 }
 
@@ -102,6 +747,27 @@ static int hisi_dsi_probe(struct platform_device *pdev)
 		return -EINVAL;
 	}
 
+#ifdef CONFIG_DRM_HISI_HAS_SLAVE_ENCODER
+	ctx->client = of_find_i2c_device_by_node(slave_node);
+	of_node_put(slave_node);
+	if (!ctx->client) {
+		DRM_ERROR("failed to find slave encoder i2c client\n");
+		return -EPROBE_DEFER;
+	}
+
+	if (!ctx->client->dev.driver) {
+		DRM_ERROR("%s: NULL client driver\n", __func__);
+		return -EPROBE_DEFER;
+	}
+
+	ctx->drm_i2c_driver = to_drm_i2c_encoder_driver(
+		to_i2c_driver(ctx->client->dev.driver));
+	if (IS_ERR(ctx->drm_i2c_driver)) {
+		DRM_ERROR("failed to initialize encoder driver");
+		return -EPROBE_DEFER;
+	}
+#endif
+
 	dsi = &ctx->dsi;
 	dsi->ctx = ctx;
 	dsi->lanes = 3;
@@ -110,6 +776,10 @@ static int hisi_dsi_probe(struct platform_device *pdev)
 	dsi->format = MIPI_DSI_FMT_RGB888;
 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
 
+	dsi->hisi_encoder.ops = &hisi_dsi_encoder_ops;
+	dsi->hisi_connector.encoder = &dsi->hisi_encoder.base.base;
+	dsi->hisi_connector.ops = &hisi_dsi_connector_ops;
+
 	return component_add(&pdev->dev, &hisi_dsi_ops);
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
index 89fc73d..acd73d8 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
@@ -15,18 +15,49 @@
 
 #include "hisi_drm_encoder.h"
 
+#define to_hisi_encoder(encoder) \
+	container_of(encoder, struct hisi_encoder, base.base)
+
 void hisi_drm_encoder_disable(struct drm_encoder *encoder)
 {
+	struct hisi_encoder *hencoder = to_hisi_encoder(encoder);
+	struct hisi_encoder_funcs *ops = hencoder->ops;
+	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
+
+	if (ops->enable)
+		ops->disable(encoder);
+
+	if (sfuncs && sfuncs->dpms)
+		sfuncs->dpms(encoder, DRM_MODE_DPMS_OFF);
 }
 
 void hisi_drm_encoder_enable(struct drm_encoder *encoder)
 {
+	struct hisi_encoder *hencoder = to_hisi_encoder(encoder);
+	struct hisi_encoder_funcs *ops = hencoder->ops;
+	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
+
+	if (ops->enable)
+		ops->enable(encoder);
+
+	if (sfuncs && sfuncs->dpms)
+		sfuncs->dpms(encoder, DRM_MODE_DPMS_ON);
 }
 
 void hisi_drm_encoder_mode_set(struct drm_encoder *encoder,
 			       struct drm_display_mode *mode,
 			       struct drm_display_mode *adjusted_mode)
 {
+	struct hisi_encoder *hencoder = to_hisi_encoder(encoder);
+	struct hisi_encoder_funcs *ops = hencoder->ops;
+	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
+
+	if (ops->mode_set)
+		ops->mode_set(encoder, mode, adjusted_mode);
+
+	if (sfuncs && sfuncs->mode_set)
+		sfuncs->mode_set(encoder, mode, adjusted_mode);
+
 }
 
 bool
@@ -34,13 +65,34 @@ hisi_drm_encoder_mode_fixup(struct drm_encoder *encoder,
 			    const struct drm_display_mode *mode,
 			    struct drm_display_mode *adjusted_mode)
 {
+	struct hisi_encoder *hencoder = to_hisi_encoder(encoder);
+	struct hisi_encoder_funcs *ops = hencoder->ops;
+	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
 	bool ret = true;
 
+	if (ops->mode_fixup)
+		ops->mode_fixup(encoder, mode, adjusted_mode);
+
+	if (sfuncs && sfuncs->mode_fixup)
+		ret = sfuncs->mode_fixup(encoder, mode, adjusted_mode);
+
 	return ret;
 }
 
 void hisi_drm_encoder_destroy(struct drm_encoder *encoder)
 {
+	struct hisi_encoder *hencoder = to_hisi_encoder(encoder);
+	struct hisi_encoder_funcs *ops = hencoder->ops;
+	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
+
+	if (ops->destroy)
+		ops->destroy(encoder);
+
+	/*release*/
+	if (sfuncs && sfuncs->destroy)
+		sfuncs->destroy(encoder);
+
+	drm_encoder_cleanup(encoder);
 }
 
 static struct drm_encoder_helper_funcs hisi_encoder_helper_funcs = {
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_encoder.h b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.h
index 31c04e4..06e4e22 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_encoder.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.h
@@ -13,10 +13,29 @@
 #ifndef __HISI_DRM_ENCODER_H__
 #define __HISI_DRM_ENCODER_H__
 
+struct hisi_encoder_funcs {
+	void (*destroy)(struct drm_encoder *encoder);
+	bool (*mode_fixup)(struct drm_encoder *encoder,
+			   const struct drm_display_mode *mode,
+			   struct drm_display_mode *adjusted_mode);
+	void (*mode_set)(struct drm_encoder *encoder,
+			 struct drm_display_mode *mode,
+			 struct drm_display_mode *adjusted_mode);
+	void (*enable)(struct drm_encoder *encoder);
+	void (*disable)(struct drm_encoder *encoder);
+};
+
 struct hisi_encoder {
 	struct drm_encoder_slave base;
+	void *ops;
 };
 
+static inline struct drm_encoder_slave_funcs *
+		get_slave_funcs(struct drm_encoder *enc)
+{
+	return to_encoder_slave(enc)->slave_funcs;
+}
+
 void hisi_drm_encoder_init(struct drm_device *dev, struct drm_encoder *encoder);
 
 #endif
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..1ab949f
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
@@ -0,0 +1,91 @@
+/*
+ *  Hisilicon Terminal SoCs drm driver
+ *
+ *  Copyright (c) 2014-2015 Hisilicon Limited.
+ *  Author:
+ *
+ *  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__
+
+#define  PWR_UP_ON               (1)
+#define  PWR_UP_OFF              (0)
+#define  COMMAND_MODE            (1)
+#define  VIDEO_MODE              (0)
+#define  PHY_MAX_TIME            (0xFF)
+
+#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  NO_CONTINUE             (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)
+#define CLK_LPX_ADDR		(0x10010)
+#define CLK_HS_PRE_ADDR		(0x10011)
+#define CLK_HS_ZERO_ADDR	(0x10012)
+#define CLK_HS_TRIAL_ADDR	(0x10013)
+#define CLK_WAKEUP_ADDR		(0x10014)
+#define DATA_LPX_ADDR		(0x10020)
+#define DATA_HS_PRE_ADDR        (0x10021)
+#define DATA_HS_ZERO_ADDR       (0x10022)
+#define DATA_HS_TRIAL_ADDR      (0x10023)
+#define DATA_TA_GO_ADDR         (0x10024)
+#define DATA_TA_GET_ADDR        (0x10025)
+#define DATA_WAKEUP_ADDR        (0x10026)
+#define HSTX_CKG_SEL_ADDR	(0x10060)
+#define PLL_FBD_DPN_ADDR	(0x10063)
+#define PLL_FBD_P_ADDR		(0x10064)
+#define PLL_FBD_S_ADDR		(0x10065)
+#define PLL_PRA_DP_ADDR		(0x10066)
+#define PLL_LPF_VOF_ADDR	(0x10067)
+
+static void dsi_phy_tst_set(void __iomem *base, u32 reg_addr,
+			    u32 reg_data)
+{
+	writel(reg_addr, 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(reg_data, 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] 22+ messages in thread

* [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
                   ` (4 preceding siblings ...)
  2015-09-15  9:37 ` [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part Xinwei Kong
@ 2015-09-15  9:37 ` Xinwei Kong
  2015-09-15 18:25   ` Rob Herring
  2015-09-15  9:37 ` [PATCH RFC 7/8] drm: hisilicon: Add support for vblank Xinwei Kong
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

If you config DRM_HISI_FBDEV optional, this patch will only support fbdev
mode while also supporting double buffer.

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>
Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
Signed-off-by: Yu Gong <gongyu@hisilicon.com>
---
 drivers/gpu/drm/hisilicon/Kconfig              |  13 +
 drivers/gpu/drm/hisilicon/Makefile             |   3 +-
 drivers/gpu/drm/hisilicon/hisi_drm_connector.c |   4 +
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c       |   9 +
 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c       |  15 +
 drivers/gpu/drm/hisilicon/hisi_drm_fb.h        |   5 +
 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c     | 395 +++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h     |  24 ++
 8 files changed, 467 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c
 create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h

diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
index 105dbcb..ddf43d5 100644
--- a/drivers/gpu/drm/hisilicon/Kconfig
+++ b/drivers/gpu/drm/hisilicon/Kconfig
@@ -16,4 +16,17 @@ config DRM_HISI_HAS_SLAVE_ENCODER
 	  Support slave encoder output device such as DSI interface connecting
 	  HDMI converter by i2c.
 
+config DRM_HISI_FBDEV
+	bool "Enable legacy fbdev support"
+	select DRM_KMS_FB_HELPER
+	select FB_SYS_FILLRECT
+	select FB_SYS_COPYAREA
+	select FB_SYS_IMAGEBLIT
+	select FB_SYS_FOPS
+	default y
+	help
+	  Choose this option if you have a need for the legacy fbdev support.
+	  Note that this support also provides the Linux console on top of
+	  the hisi modesetting driver.
+
 endif
diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
index aa522f8..1877d36 100644
--- a/drivers/gpu/drm/hisilicon/Makefile
+++ b/drivers/gpu/drm/hisilicon/Makefile
@@ -5,7 +5,8 @@ hisi-drm-y := hisi_drm_drv.o \
 	      hisi_drm_crtc.o \
 	      hisi_drm_encoder.o \
 	      hisi_drm_connector.o \
-	      hisi_drm_fb.o \
+	      hisi_drm_fb.o
 
 obj-$(CONFIG_DRM_HISI)	+= hisi-drm.o
+obj-$(CONFIG_DRM_HISI_FBDEV) += hisi_drm_fbdev.o
 
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_connector.c b/drivers/gpu/drm/hisilicon/hisi_drm_connector.c
index 57ab2e8..2359ed8 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_connector.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_connector.c
@@ -120,5 +120,9 @@ void hisi_drm_connector_init(struct drm_device *dev,
 	drm_connector_register(connector);
 	drm_mode_connector_attach_encoder(connector, encoder);
 
+#ifndef CONFIG_DRM_HISI_FBDEV
+	drm_reinit_primary_mode_group(dev);
+#endif
+
 	drm_mode_config_reset(dev);
 }
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index 0983ad7..53f2521 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -17,6 +17,7 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 
+#include "hisi_drm_drv.h"
 #include "hisi_drm_fb.h"
 
 #define DRIVER_NAME	"hisi-drm"
@@ -49,11 +50,19 @@ 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;
 
 	/* debug setting
 	drm_debug = DRM_UT_DRIVER|DRM_UT_KMS; */
 
+	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	dev->dev_private = priv;
+	dev_set_drvdata(dev->dev, dev);
+
 	/* dev->mode_config initialization */
 	drm_mode_config_init(dev);
 	hisi_drm_mode_config_init(dev);
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
index 8509ced..8329734 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
@@ -16,10 +16,14 @@
 
 #include <drm/drm_mipi_dsi.h>
 #include <drm/drm_encoder_slave.h>
+#include <drm/drm_fb_helper.h>
 
 #include "hisi_drm_encoder.h"
 #include "hisi_drm_connector.h"
 #include "hisi_dsi_reg.h"
+#ifdef CONFIG_DRM_HISI_FBDEV
+#include "hisi_drm_fbdev.h"
+#endif
 
 #define encoder_to_dsi(encoder) \
 	container_of(encoder, struct hisi_dsi, hisi_encoder.base.base)
@@ -699,6 +703,15 @@ static int hisi_dsi_bind(struct device *dev, struct device *master,
 	hisi_drm_connector_init(ctx->dev, &ctx->dsi.hisi_encoder.base.base,
 				&ctx->dsi.hisi_connector.connector);
 
+#ifdef CONFIG_DRM_HISI_FBDEV
+	/* fbdev initialization should be put at last position */
+	ret = hisi_drm_fbdev_init(ctx->dev);
+	if (ret) {
+		DRM_ERROR("failed to initialize fbdev\n");
+		return ret;
+	}
+#endif
+
 	return ret;
 }
 
@@ -780,6 +793,8 @@ static int hisi_dsi_probe(struct platform_device *pdev)
 	dsi->hisi_connector.encoder = &dsi->hisi_encoder.base.base;
 	dsi->hisi_connector.ops = &hisi_dsi_connector_ops;
 
+	platform_set_drvdata(pdev, ctx);
+
 	return component_add(&pdev->dev, &hisi_dsi_ops);
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fb.h b/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
index 4bd168e..652a0a9 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fb.h
@@ -24,5 +24,10 @@ struct drm_framebuffer *hisi_drm_fb_create(struct drm_device *dev,
 					   struct drm_mode_fb_cmd2 *mode_cmd);
 struct drm_gem_cma_object *
 hisi_drm_fb_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane);
+void hisi_drm_fb_destroy(struct drm_framebuffer *fb);
+struct hisi_drm_fb *
+hisi_drm_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd,
+		  struct drm_gem_cma_object **obj, unsigned int num_planes,
+		  bool is_fbdev_fb);
 
 #endif /* __HISI_DRM_FB_H__ */
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c b/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c
new file mode 100644
index 0000000..7d32b87
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c
@@ -0,0 +1,395 @@
+/*
+ * Hisilicon Terminal SoCs drm fbdev driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author: z.liuxinliang@huawei.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 <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "hisi_drm_fb.h"
+#include "hisi_drm_fbdev.h"
+#include "hisi_drm_drv.h"
+
+#define PREFERRED_BPP		32
+#define HISI_NUM_FRAMEBUFFERS   2
+
+static inline
+struct hisi_drm_fbdev *to_hisi_drm_fbdev(struct drm_fb_helper *helper)
+{
+	return container_of(helper, struct hisi_drm_fbdev, fb_helper);
+}
+
+static int hisi_drm_fb_helper_check_var(struct fb_var_screeninfo *var,
+					struct fb_info *info)
+{
+	struct drm_fb_helper *fb_helper = info->par;
+	struct drm_framebuffer *fb = fb_helper->fb;
+	int depth;
+
+	if (var->pixclock != 0 || in_dbg_master())
+		return -EINVAL;
+
+	/* Need to resize the fb object !!! */
+	if (var->bits_per_pixel > fb->bits_per_pixel ||
+	    var->xres > fb->width || var->yres > fb->height ||
+	    var->xres_virtual > fb->width || var->yres_virtual > fb->height) {
+		DRM_ERROR("fb userspace request is greater than current fb");
+		return -EINVAL;
+	}
+
+	switch (var->bits_per_pixel) {
+	case 16:
+		depth = (var->green.length == 6) ? 16 : 15;
+		break;
+	case 32:
+		depth = (var->transp.length > 0) ? 32 : 24;
+		break;
+	default:
+		depth = var->bits_per_pixel;
+		break;
+	}
+
+	switch (depth) {
+	case 8:
+		var->red.offset = 0;
+		var->green.offset = 0;
+		var->blue.offset = 0;
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		var->transp.length = 0;
+		var->transp.offset = 0;
+		break;
+	case 15:
+		var->red.offset = 10;
+		var->green.offset = 5;
+		var->blue.offset = 0;
+		var->red.length = 5;
+		var->green.length = 5;
+		var->blue.length = 5;
+		var->transp.length = 1;
+		var->transp.offset = 15;
+		break;
+	case 16:
+		var->red.offset = 11;
+		var->green.offset = 5;
+		var->blue.offset = 0;
+		var->red.length = 5;
+		var->green.length = 6;
+		var->blue.length = 5;
+		var->transp.length = 0;
+		var->transp.offset = 0;
+		break;
+	case 24:
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		var->transp.length = 0;
+		var->transp.offset = 0;
+		break;
+	case 32: /* RGBA8888 */
+		var->red.offset = 0;
+		var->green.offset = 8;
+		var->blue.offset = 16;
+		var->red.length = 8;
+		var->green.length = 8;
+		var->blue.length = 8;
+		var->transp.length = 8;
+		var->transp.offset = 24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void hisi_drm_fb_helper_fill_var(struct fb_info *info,
+					struct drm_fb_helper *fb_helper,
+					u32 fb_width, u32 fb_height)
+{
+	struct drm_framebuffer *fb = fb_helper->fb;
+
+	info->pseudo_palette = fb_helper->pseudo_palette;
+	info->var.xres_virtual = fb->width;
+	info->var.yres_virtual = fb->height;
+	info->var.bits_per_pixel = fb->bits_per_pixel;
+	info->var.accel_flags = FB_ACCELF_TEXT;
+	info->var.xoffset = 0;
+	info->var.yoffset = 0;
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->var.height = -1;
+	info->var.width = -1;
+
+	switch (fb->depth) {
+	case 8:
+		info->var.red.offset = 0;
+		info->var.green.offset = 0;
+		info->var.blue.offset = 0;
+		info->var.red.length = 8; /* 8bit DAC */
+		info->var.green.length = 8;
+		info->var.blue.length = 8;
+		info->var.transp.offset = 0;
+		info->var.transp.length = 0;
+		break;
+	case 15:
+		info->var.red.offset = 10;
+		info->var.green.offset = 5;
+		info->var.blue.offset = 0;
+		info->var.red.length = 5;
+		info->var.green.length = 5;
+		info->var.blue.length = 5;
+		info->var.transp.offset = 15;
+		info->var.transp.length = 1;
+		break;
+	case 16:
+		info->var.red.offset = 11;
+		info->var.green.offset = 5;
+		info->var.blue.offset = 0;
+		info->var.red.length = 5;
+		info->var.green.length = 6;
+		info->var.blue.length = 5;
+		info->var.transp.offset = 0;
+		break;
+	case 24:
+		info->var.red.offset = 16;
+		info->var.green.offset = 8;
+		info->var.blue.offset = 0;
+		info->var.red.length = 8;
+		info->var.green.length = 8;
+		info->var.blue.length = 8;
+		info->var.transp.offset = 0;
+		info->var.transp.length = 0;
+		break;
+	case 32: /* RGBA8888 */
+		info->var.red.offset = 0;
+		info->var.green.offset = 8;
+		info->var.blue.offset = 16;
+		info->var.red.length = 8;
+		info->var.green.length = 8;
+		info->var.blue.length = 8;
+		info->var.transp.length = 8;
+		info->var.transp.offset = 24;
+		break;
+	default:
+		break;
+	}
+
+	info->var.xres = fb_width;
+	info->var.yres = fb_height;
+}
+
+static struct fb_ops hisi_drm_fbdev_ops = {
+	.owner		= THIS_MODULE,
+	.fb_fillrect	= sys_fillrect,
+	.fb_copyarea	= sys_copyarea,
+	.fb_imageblit	= sys_imageblit,
+	.fb_check_var	= hisi_drm_fb_helper_check_var,
+	.fb_set_par	= drm_fb_helper_set_par,
+	.fb_blank	= drm_fb_helper_blank,
+	.fb_pan_display	= drm_fb_helper_pan_display,
+	.fb_setcmap	= drm_fb_helper_setcmap,
+};
+
+static int hisi_drm_fbdev_probe(struct drm_fb_helper *helper,
+				struct drm_fb_helper_surface_size *sizes)
+{
+	struct hisi_drm_fbdev *fbdev = to_hisi_drm_fbdev(helper);
+	struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+	struct drm_device *dev = helper->dev;
+	struct drm_gem_cma_object *obj;
+	struct drm_framebuffer *fb;
+	unsigned int bytes_per_pixel;
+	unsigned long offset;
+	struct fb_info *fbi;
+	size_t size;
+	int ret;
+
+	/* TODO: Need to use ion heaps to create frame buffer?? */
+	bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8);
+	sizes->surface_depth = PREFERRED_BPP;
+
+	mode_cmd.width = sizes->surface_width;
+	mode_cmd.height = sizes->surface_height * HISI_NUM_FRAMEBUFFERS;
+	mode_cmd.pitches[0] = sizes->surface_width * bytes_per_pixel;
+	mode_cmd.pixel_format = DRM_FORMAT_ARGB8888;
+
+	size = roundup(mode_cmd.pitches[0] * mode_cmd.height, PAGE_SIZE);
+	obj = drm_gem_cma_create(dev, size);
+	if (IS_ERR(obj))
+		return -ENOMEM;
+
+	fbi = framebuffer_alloc(0, dev->dev);
+	if (!fbi) {
+		dev_err(dev->dev, "Failed to allocate framebuffer info.\n");
+		ret = -ENOMEM;
+		goto err_drm_gem_cma_free_object;
+	}
+
+	fbdev->fb = hisi_drm_fb_alloc(dev, &mode_cmd, &obj, 1, true);
+	if (IS_ERR(fbdev->fb)) {
+		dev_err(dev->dev, "Failed to allocate DRM framebuffer.\n");
+		ret = PTR_ERR(fbdev->fb);
+		goto err_framebuffer_release;
+	}
+
+	fb = &fbdev->fb->fb;
+	helper->fb = fb;
+	helper->fbdev = fbi;
+
+	fbi->par = helper;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->fbops = &hisi_drm_fbdev_ops;
+
+	ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+	if (ret) {
+		dev_err(dev->dev, "Failed to allocate color map.\n");
+		goto err_hisi_drm_fb_destroy;
+	}
+
+	drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
+	hisi_drm_fb_helper_fill_var(fbi, helper, fb->width,
+				    fb->height / HISI_NUM_FRAMEBUFFERS);
+
+	offset = fbi->var.xoffset * bytes_per_pixel;
+	offset += fbi->var.yoffset * fb->pitches[0];
+
+	dev->mode_config.fb_base = (resource_size_t)obj->paddr;
+	fbi->screen_base = obj->vaddr + offset;
+	fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
+	fbi->screen_size = size;
+	fbi->fix.smem_len = size;
+
+	return 0;
+
+err_hisi_drm_fb_destroy:
+	drm_framebuffer_unregister_private(fb);
+	hisi_drm_fb_destroy(fb);
+err_framebuffer_release:
+	framebuffer_release(fbi);
+err_drm_gem_cma_free_object:
+	drm_gem_cma_free_object(&obj->base);
+
+	return ret;
+}
+
+static const struct drm_fb_helper_funcs hisi_fb_helper_funcs = {
+	.fb_probe = hisi_drm_fbdev_probe,
+};
+
+static struct hisi_drm_fbdev *hisi_drm_fbdev_create(struct drm_device *dev,
+						    unsigned int preferred_bpp,
+						    unsigned int num_crtc,
+						    unsigned int max_con_count)
+{
+	struct hisi_drm_fbdev *fbdev;
+	struct drm_fb_helper *helper;
+	int ret;
+
+	fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
+	if (!fbdev)
+		return ERR_PTR(-ENOMEM);
+
+	helper = &fbdev->fb_helper;
+
+	drm_fb_helper_prepare(dev, helper, &hisi_fb_helper_funcs);
+
+	ret = drm_fb_helper_init(dev, helper, num_crtc, max_con_count);
+	if (ret < 0) {
+		dev_err(dev->dev, "Failed to initialize drm fb helper.\n");
+		goto err_free;
+	}
+
+	ret = drm_fb_helper_single_add_all_connectors(helper);
+	if (ret < 0) {
+		dev_err(dev->dev, "Failed to add connectors.\n");
+		goto err_drm_fb_helper_fini;
+	}
+
+	/* disable all the possible outputs/crtcs before entering KMS mode */
+	drm_helper_disable_unused_functions(dev);
+
+	ret = drm_fb_helper_initial_config(helper, preferred_bpp);
+	if (ret < 0) {
+		dev_err(dev->dev, "Failed to set initial hw configuration.\n");
+		goto err_drm_fb_helper_fini;
+	}
+
+	return fbdev;
+
+err_drm_fb_helper_fini:
+	drm_fb_helper_fini(helper);
+err_free:
+	kfree(fbdev);
+
+	return ERR_PTR(ret);
+}
+
+static void hisi_drm_fbdev_fini(struct hisi_drm_fbdev *fbdev)
+{
+	if (fbdev->fb_helper.fbdev) {
+		struct fb_info *info;
+		int ret;
+
+		info = fbdev->fb_helper.fbdev;
+		ret = unregister_framebuffer(info);
+		if (ret < 0)
+			DRM_DEBUG_KMS("failed to unregister framebuffe\n");
+
+		if (info->cmap.len)
+			fb_dealloc_cmap(&info->cmap);
+
+		framebuffer_release(info);
+	}
+
+	if (fbdev->fb) {
+		drm_framebuffer_unregister_private(&fbdev->fb->fb);
+		hisi_drm_fb_destroy(&fbdev->fb->fb);
+	}
+
+	drm_fb_helper_fini(&fbdev->fb_helper);
+	kfree(fbdev);
+}
+
+/**
+ * hisi_drm_fbdev_init - create and init hisi_drm_fbdev
+ * @dev: The drm_device struct
+ */
+int hisi_drm_fbdev_init(struct drm_device *dev)
+{
+	struct hisi_drm_private *private = dev->dev_private;
+
+	private->fbdev = hisi_drm_fbdev_create(dev, PREFERRED_BPP,
+			dev->mode_config.num_crtc,
+			dev->mode_config.num_connector);
+	if (IS_ERR(private->fbdev))
+		return PTR_ERR(private->fbdev);
+
+	return 0;
+}
+
+/*
+ * hisi_drm_fbdev_exit - Free hisi_drm_fbdev struct
+ * @dev: The drm_device struct
+ */
+void hisi_drm_fbdev_exit(struct drm_device *dev)
+{
+	struct hisi_drm_private *private = dev->dev_private;
+
+	if (private->fbdev) {
+		hisi_drm_fbdev_fini(private->fbdev);
+		private->fbdev = NULL;
+	}
+}
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h b/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h
new file mode 100644
index 0000000..f6a8a68
--- /dev/null
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h
@@ -0,0 +1,24 @@
+/*
+ * Hisilicon Terminal SoCs drm driver
+ *
+ * Copyright (c) 2014-2015 Hisilicon Limited.
+ * Author:
+ *
+ * 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_FBDEV_H__
+#define __HISI_DRM_FBDEV_H__
+
+struct hisi_drm_fbdev {
+	struct drm_fb_helper	fb_helper;
+	struct hisi_drm_fb	*fb;
+};
+
+int hisi_drm_fbdev_init(struct drm_device *dev);
+void hisi_drm_fbdev_exit(struct drm_device *dev);
+
+#endif /* __HISI_DRM_FBDEV_H__ */
-- 
1.9.1



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

* [PATCH RFC 7/8] drm: hisilicon: Add support for vblank
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
                   ` (5 preceding siblings ...)
  2015-09-15  9:37 ` [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev Xinwei Kong
@ 2015-09-15  9:37 ` Xinwei Kong
  2015-09-15  9:37 ` [PATCH RFC 8/8] dts: hisilicon: Add drm driver device dts config for HiKey board Xinwei Kong
  2015-09-16 15:23 ` [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Daniel Stone
  8 siblings, 0 replies; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

This patch adds ldi interrupt to handle vblank.

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>
Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
Signed-off-by: Yu Gong <gongyu@hisilicon.com>
---
 drivers/gpu/drm/hisilicon/hisi_ade.c      | 71 +++++++++++++++++++++++-
 drivers/gpu/drm/hisilicon/hisi_drm_crtc.c | 89 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/hisilicon/hisi_drm_crtc.h |  7 +++
 drivers/gpu/drm/hisilicon/hisi_drm_drv.c  |  5 ++
 4 files changed, 170 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/hisilicon/hisi_ade.c b/drivers/gpu/drm/hisilicon/hisi_ade.c
index 2ea3f8f..44480c2 100644
--- a/drivers/gpu/drm/hisilicon/hisi_ade.c
+++ b/drivers/gpu/drm/hisilicon/hisi_ade.c
@@ -156,11 +156,12 @@ static void ade_display_commit(struct ade_crtc *acrtc)
 	/* set reset mode:soft or hw, and reload modules */
 	ade_set_reset_and_reload(acrtc);
 
-	/* enable ade */
+	/* ade enabled */
 	wmb();
 	writel(ADE_ENABLE, base + ADE_EN);
 
-	wmb(); /* memory barrier */
+	/* ldi enabled after ade */
+	wmb();
 	val = ADE_ENABLE;
 	val |= readl(base + LDI_CTRL);
 	writel(val, base + LDI_CTRL);
@@ -596,6 +597,63 @@ int ade_install_plane_properties(struct drm_device *dev,
 	return 0;
 }
 
+int ade_enable_vblank(struct hisi_crtc *hcrtc)
+{
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 intr_en;
+	int ret;
+
+	if (!ctx->power_on) {
+		ret = ade_power_up(ctx);
+		if (ret) {
+			DRM_ERROR("%s: failed to power up ade\n", __func__);
+			return ret;
+		}
+	}
+
+	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 hisi_crtc *hcrtc)
+{
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+	void __iomem *base = ctx->base;
+	u32 intr_en;
+
+	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);
+}
+
+irqreturn_t ade_irq_handler(int irq, struct hisi_crtc *hcrtc)
+{
+	struct ade_hardware_context *ctx = hcrtc->ctx;
+	struct drm_crtc *crtc = &hcrtc->base;
+	struct drm_device *dev = crtc->dev;
+	void __iomem *base = ctx->base;
+	u32 status;
+
+	status = readl(base + LDI_MSK_INT);
+
+	/* 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;
+}
+
 /* convert from fourcc format to ade format */
 static u32 ade_get_format(u32 pixel_format)
 {
@@ -1112,6 +1170,9 @@ static struct hisi_crtc_ops ade_crtc_ops = {
 	.mode_set_nofb = ade_crtc_mode_set_nofb,
 	.atomic_begin = ade_crtc_atomic_begin,
 	.atomic_flush = ade_crtc_atomic_flush,
+	.irq_handler = ade_irq_handler,
+	.enable_vblank = ade_enable_vblank,
+	.disable_vblank = ade_disable_vblank,
 	.install_properties = ade_install_crtc_properties,
 };
 
@@ -1226,6 +1287,12 @@ static int ade_bind(struct device *dev, struct device *master, void *data)
 		return ret;
 	}
 
+	/* ldi irq install */
+	ret = hisi_drm_crtc_irq_install(drm_dev, ctx->irq, DRIVER_IRQ_SHARED,
+					hcrtc);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
index feeadc4..db64c2a 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.c
@@ -17,6 +17,95 @@
 #include "hisi_drm_drv.h"
 #include "hisi_drm_crtc.h"
 
+/*
+ * drm_get_crtc_from_index - find a registered CRTC from the index
+ * @dev: DRM device
+ * @index: index of a registered CRTC
+ *
+ * Given a index, return the registered CRTC within a DRM
+ * device's list of CRTCs.
+ */
+struct drm_crtc *hisi_drm_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++;
+	}
+
+	BUG();
+}
+
+int hisi_drm_crtc_enable_vblank(struct drm_device *dev, int c)
+{
+	struct drm_crtc *crtc = hisi_drm_get_crtc_from_index(dev, c);
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+	int ret = 0;
+
+	if (ops->enable_vblank)
+		ret = ops->enable_vblank(hcrtc);
+
+	return ret;
+}
+
+void hisi_drm_crtc_disable_vblank(struct drm_device *dev, int c)
+{
+	struct drm_crtc *crtc = hisi_drm_get_crtc_from_index(dev, c);
+	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+
+	if (ops->disable_vblank)
+		ops->disable_vblank(hcrtc);
+}
+
+irqreturn_t hisi_drm_crtc_irq_handler(int irq, void *arg)
+{
+	struct hisi_crtc *hcrtc = (struct hisi_crtc *)arg;
+	struct hisi_crtc_ops *ops = hcrtc->ops;
+	irqreturn_t ret = IRQ_HANDLED;
+
+	if (ops->irq_handler)
+		ret = ops->irq_handler(irq, hcrtc);
+
+	return ret;
+}
+
+int hisi_drm_crtc_irq_install(struct drm_device *dev, int irq,
+			      unsigned long flags, void *data)
+{
+	int ret;
+
+	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
+		return -EINVAL;
+
+	if (irq == 0)
+		return -EINVAL;
+
+	/* Driver must have been initialized */
+	if (!dev->dev_private)
+		return -EINVAL;
+
+	if (dev->irq_enabled)
+		return -EBUSY;
+	dev->irq_enabled = true;
+
+	ret = request_irq(irq, hisi_drm_crtc_irq_handler,
+			  flags, dev->driver->name, data);
+
+	if (ret < 0) {
+		dev->irq_enabled = false;
+		return ret;
+	}
+
+	return 0;
+}
+
 static void  hisi_drm_crtc_enable(struct drm_crtc *crtc)
 {
 	struct hisi_crtc *hcrtc = to_hisi_crtc(crtc);
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
index 6521ed8..f29fe76 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_crtc.h
@@ -42,6 +42,9 @@ struct hisi_crtc_ops {
 	void (*atomic_begin)(struct hisi_crtc *hcrtc);
 	void (*atomic_flush)(struct hisi_crtc *hcrtc);
 	void (*destroy)(struct hisi_crtc *hcrtc);
+	int  (*enable_vblank)(struct hisi_crtc *hcrtc);
+	void (*disable_vblank)(struct hisi_crtc *hcrtc);
+	irqreturn_t (*irq_handler)(int irq, struct hisi_crtc *hcrtc);
 	int (*install_properties)(struct drm_device *dev,
 				  struct hisi_crtc *hcrtc);
 };
@@ -53,5 +56,9 @@ struct hisi_crtc_state {
 
 int hisi_drm_crtc_init(struct drm_device *dev, struct hisi_crtc *crtc,
 		       struct drm_plane *plane);
+int hisi_drm_crtc_enable_vblank(struct drm_device *dev, int c);
+void hisi_drm_crtc_disable_vblank(struct drm_device *dev, int c);
+int hisi_drm_crtc_irq_install(struct drm_device *dev, int irq,
+			      unsigned long flags, void *data);
 
 #endif
diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
index 53f2521..4ff2693 100644
--- a/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hisi_drm_drv.c
@@ -18,6 +18,7 @@
 #include <drm/drm_gem_cma_helper.h>
 
 #include "hisi_drm_drv.h"
+#include "hisi_drm_crtc.h"
 #include "hisi_drm_fb.h"
 
 #define DRIVER_NAME	"hisi-drm"
@@ -130,6 +131,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		= hisi_drm_crtc_enable_vblank,
+	.disable_vblank		= hisi_drm_crtc_disable_vblank,
+
 	.name			= "hisi",
 	.desc			= "Hisilicon Terminal SoCs DRM Driver",
 	.date			= "20150830",
-- 
1.9.1



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

* [PATCH RFC 8/8] dts: hisilicon: Add drm driver device dts config for HiKey board
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
                   ` (6 preceding siblings ...)
  2015-09-15  9:37 ` [PATCH RFC 7/8] drm: hisilicon: Add support for vblank Xinwei Kong
@ 2015-09-15  9:37 ` Xinwei Kong
  2015-09-16 15:23 ` [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Daniel Stone
  8 siblings, 0 replies; 22+ messages in thread
From: Xinwei Kong @ 2015-09-15  9:37 UTC (permalink / raw)
  To: airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, kong.kongxinwei

This patch adds drm dts node for HiKey board using 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>
Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
Signed-off-by: Yu Gong <gongyu@hisilicon.com>
---
 arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 34 +++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
index 3f03380..9ce8c62 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -4,6 +4,7 @@
  * Copyright (C) 2015, Hisilicon Ltd.
  */
 
+#include <dt-bindings/clock/hi6220-clock.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
@@ -167,5 +168,38 @@
 			clocks = <&ao_ctrl 36>, <&ao_ctrl 36>;
 			clock-names = "uartclk", "apb_pclk";
 		};
+
+		display-subsystem {
+			compatible = "hisilicon,display-subsystem";
+			#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>;
+				/*clock name*/
+				clock-names  = "clk_ade_core",
+					       "aclk_codec_jpeg_src",
+					       "clk_ade_pix";
+			};
+
+			dsi {
+				compatible = "hisilicon,hi6220-dsi";
+				reg = <0x0 0xf4107800 0x0 0x100>;
+				clocks = <&media_ctrl  HI6220_DSI_PCLK>;
+				clock-names = "pclk_dsi";
+				encoder-slave = <&adv7533>;
+			};
+		};
 	};
 };
-- 
1.9.1



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

* Re: [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver
  2015-09-15  9:37 ` [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver Xinwei Kong
@ 2015-09-15 18:11   ` Rob Herring
  2015-09-16  8:34     ` Xinwei Kong
  0 siblings, 1 reply; 22+ messages in thread
From: Rob Herring @ 2015-09-15 18:11 UTC (permalink / raw)
  To: Xinwei Kong, airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun

On 09/15/2015 04:37 AM, Xinwei Kong wrote:
> This adds documentation of device tree bindings for the
> Graphics Processing Unit of 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>
> Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
> Signed-off-by: Yu Gong <gongyu@hisilicon.com>
> ---
>  .../devicetree/bindings/gpu/hisilicon,hi6220.txt   | 69 ++++++++++++++++++++++
>  1 file changed, 69 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
> 
> diff --git a/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
> new file mode 100644
> index 0000000..173ac63
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
> @@ -0,0 +1,69 @@
> + * Hisilicon hi6220 Graphics Processing Unit for HiKey board
> +
> + ** display-subsystem: Master device for binding DRM sub-components

DRM is a Linuxism that doesn't belong in the binding.

> +    This master device is parent node and it will be responsible to bind all
> +    sub-components devices node.

Are these nodes a single block in the h/w? If not, you should describe
the connection of sub-nodes with of-graph instead.

> +    - Required properties :
> +      - compatible: "hisilicon,display-subsystem".
> +      - #address-cells, #size-cells: Must be present if the device has sub-nodes.
> +      - ranges: to allow probing of subdevices.
> +      - dma-coherent: Present if dma operations are coherent.
> +
> + ** ade: Graphic overlay, Graphic post-processing, display timing control.
> +    This device is child node of display-subsystem
> +    - Required properties :
> +      - compatible: "hisilicon,hi6220-ade".
> +      - reg: physical base address of the ADE register and length of memory
> +	region.
> +      - reg-names: Should contain the reg names "ade_base" and "media_base".
> +      - interrupt: The interrupt number to the cpu. Defines the interrupt
> +        by ADE.
> +      - clocks: The clocks needed by the ADE module.
> +      - clock-names: the name of the clocks.
> +
> + ** dsi: support mipi dsi interface
> +    This device is child node of display-subsystem
> +    - Required properties :
> +      - compatible: "hisilicon,hi6220-dsi".
> +      - reg: physical base address of the DSI register and length of memory
> +	region.
> +      - clocks: The clocks needed by the DSI module.
> +      - clock-names: the name of the clocks.
> +      -	encoder-slave: phandles to a 'encoder-slave' subnode which DSI connect
> +        ADV7533 in order to support hdmi display.

What the ADV7533 binding looks like is still being discussed.
"encoder-slave" is certainly DRM specific and not how it should be done.
Most likely, this needs to use the of-graph ports.

Also, the ADV7533 connection is specific to HiKey. This binding should
just generically describe how any bridge or panel is connected.

Rob

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

* Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev
  2015-09-15  9:37 ` [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev Xinwei Kong
@ 2015-09-15 18:25   ` Rob Herring
  2015-09-16  3:32     ` Xinwei Kong
       [not found]     ` <CAGd==05f+XVg4ZSDihftjB2wcOGkAou=AxXYXB+1=ckM2J6EBQ@mail.gmail.com>
  0 siblings, 2 replies; 22+ messages in thread
From: Rob Herring @ 2015-09-15 18:25 UTC (permalink / raw)
  To: Xinwei Kong, airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun

On 09/15/2015 04:37 AM, Xinwei Kong wrote:
> If you config DRM_HISI_FBDEV optional, this patch will only support fbdev
> mode while also supporting double buffer.

This is a lot of duplicated code from CMA fbdev. Is double buffering the
only reason why CMA fbdev can't be used or are there some other
constraints? Double buffering in fbdev has always been a hack, so I'm
guessing that is not a feature that should be added here.

Rob

> 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>
> Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
> Signed-off-by: Yu Gong <gongyu@hisilicon.com>
> ---
>  drivers/gpu/drm/hisilicon/Kconfig              |  13 +
>  drivers/gpu/drm/hisilicon/Makefile             |   3 +-
>  drivers/gpu/drm/hisilicon/hisi_drm_connector.c |   4 +
>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c       |   9 +
>  drivers/gpu/drm/hisilicon/hisi_drm_dsi.c       |  15 +
>  drivers/gpu/drm/hisilicon/hisi_drm_fb.h        |   5 +
>  drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c     | 395 +++++++++++++++++++++++++
>  drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h     |  24 ++
>  8 files changed, 467 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c
>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h


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

* Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev
  2015-09-15 18:25   ` Rob Herring
@ 2015-09-16  3:32     ` Xinwei Kong
       [not found]     ` <CAGd==05f+XVg4ZSDihftjB2wcOGkAou=AxXYXB+1=ckM2J6EBQ@mail.gmail.com>
  1 sibling, 0 replies; 22+ messages in thread
From: Xinwei Kong @ 2015-09-16  3:32 UTC (permalink / raw)
  To: Rob Herring, airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun

hi rob

On 2015/9/16 2:25, Rob Herring wrote:
> On 09/15/2015 04:37 AM, Xinwei Kong wrote:
>> If you config DRM_HISI_FBDEV optional, this patch will only support fbdev
>> mode while also supporting double buffer.
> 
> This is a lot of duplicated code from CMA fbdev. Is double buffering the
> only reason why CMA fbdev can't be used or are there some other
> constraints? Double buffering in fbdev has always been a hack, so I'm
> guessing that is not a feature that should be added here.
> 
I will drop it.

xinwei
> Rob
> 
>> 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>
>> Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
>> Signed-off-by: Yu Gong <gongyu@hisilicon.com>
>> ---
>>  drivers/gpu/drm/hisilicon/Kconfig              |  13 +
>>  drivers/gpu/drm/hisilicon/Makefile             |   3 +-
>>  drivers/gpu/drm/hisilicon/hisi_drm_connector.c |   4 +
>>  drivers/gpu/drm/hisilicon/hisi_drm_drv.c       |   9 +
>>  drivers/gpu/drm/hisilicon/hisi_drm_dsi.c       |  15 +
>>  drivers/gpu/drm/hisilicon/hisi_drm_fb.h        |   5 +
>>  drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c     | 395 +++++++++++++++++++++++++
>>  drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h     |  24 ++
>>  8 files changed, 467 insertions(+), 1 deletion(-)
>>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c
>>  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h
> 
> 
> .
> 


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

* Re: [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver
  2015-09-15 18:11   ` Rob Herring
@ 2015-09-16  8:34     ` Xinwei Kong
  2015-09-16  9:10       ` Archit Taneja
  0 siblings, 1 reply; 22+ messages in thread
From: Xinwei Kong @ 2015-09-16  8:34 UTC (permalink / raw)
  To: architt, lars, treding
  Cc: Rob Herring, airlied, corbet, catalin.marinas, will.deacon,
	dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, linux-arm-msm,
	laurent.pinchart, Andy Green, srinivas.kandagatla

hi architt

On 2015/9/16 2:11, Rob Herring wrote:
> On 09/15/2015 04:37 AM, Xinwei Kong wrote:
>> This adds documentation of device tree bindings for the
>> Graphics Processing Unit of 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>
>> Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
>> Signed-off-by: Yu Gong <gongyu@hisilicon.com>
>> ---
>>  .../devicetree/bindings/gpu/hisilicon,hi6220.txt   | 69 ++++++++++++++++++++++
>>  1 file changed, 69 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>>
>> diff --git a/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>> new file mode 100644
>> index 0000000..173ac63
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>> @@ -0,0 +1,69 @@
>> + * Hisilicon hi6220 Graphics Processing Unit for HiKey board
>> +
>> + ** display-subsystem: Master device for binding DRM sub-components
> 
> DRM is a Linuxism that doesn't belong in the binding.
> 
>> +    This master device is parent node and it will be responsible to bind all
>> +    sub-components devices node.
> 
> Are these nodes a single block in the h/w? If not, you should describe
> the connection of sub-nodes with of-graph instead.
> 
>> +    - Required properties :
>> +      - compatible: "hisilicon,display-subsystem".
>> +      - #address-cells, #size-cells: Must be present if the device has sub-nodes.
>> +      - ranges: to allow probing of subdevices.
>> +      - dma-coherent: Present if dma operations are coherent.
>> +
>> + ** ade: Graphic overlay, Graphic post-processing, display timing control.
>> +    This device is child node of display-subsystem
>> +    - Required properties :
>> +      - compatible: "hisilicon,hi6220-ade".
>> +      - reg: physical base address of the ADE register and length of memory
>> +	region.
>> +      - reg-names: Should contain the reg names "ade_base" and "media_base".
>> +      - interrupt: The interrupt number to the cpu. Defines the interrupt
>> +        by ADE.
>> +      - clocks: The clocks needed by the ADE module.
>> +      - clock-names: the name of the clocks.
>> +
>> + ** dsi: support mipi dsi interface
>> +    This device is child node of display-subsystem
>> +    - Required properties :
>> +      - compatible: "hisilicon,hi6220-dsi".
>> +      - reg: physical base address of the DSI register and length of memory
>> +	region.
>> +      - clocks: The clocks needed by the DSI module.
>> +      - clock-names: the name of the clocks.
>> +      -	encoder-slave: phandles to a 'encoder-slave' subnode which DSI connect
>> +        ADV7533 in order to support hdmi display.
> 
> What the ADV7533 binding looks like is still being discussed.
> "encoder-slave" is certainly DRM specific and not how it should be done.
> Most likely, this needs to use the of-graph ports.
> 
I dont how to implement the encoder bridge stuff in upstream,
you think that I will how to handle this part?

Thank you
xinwei

> Also, the ADV7533 connection is specific to HiKey. This binding should
> just generically describe how any bridge or panel is connected.
> 
> Rob
> 
> .
> 


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

* Re: [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver
  2015-09-16  8:34     ` Xinwei Kong
@ 2015-09-16  9:10       ` Archit Taneja
  2015-09-17 12:14         ` Xinwei Kong
  0 siblings, 1 reply; 22+ messages in thread
From: Archit Taneja @ 2015-09-16  9:10 UTC (permalink / raw)
  To: Xinwei Kong, lars, treding
  Cc: Rob Herring, airlied, corbet, catalin.marinas, will.deacon,
	dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, linux-arm-msm,
	laurent.pinchart, srinivas.kandagatla

Hi,

On 09/16/2015 02:04 PM, Xinwei Kong wrote:
> hi architt
>
> On 2015/9/16 2:11, Rob Herring wrote:
>> On 09/15/2015 04:37 AM, Xinwei Kong wrote:
>>> This adds documentation of device tree bindings for the
>>> Graphics Processing Unit of 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>
>>> Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
>>> Signed-off-by: Yu Gong <gongyu@hisilicon.com>
>>> ---
>>>   .../devicetree/bindings/gpu/hisilicon,hi6220.txt   | 69 ++++++++++++++++++++++
>>>   1 file changed, 69 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>>> new file mode 100644
>>> index 0000000..173ac63
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>>> @@ -0,0 +1,69 @@
>>> + * Hisilicon hi6220 Graphics Processing Unit for HiKey board
>>> +
>>> + ** display-subsystem: Master device for binding DRM sub-components
>>
>> DRM is a Linuxism that doesn't belong in the binding.
>>
>>> +    This master device is parent node and it will be responsible to bind all
>>> +    sub-components devices node.
>>
>> Are these nodes a single block in the h/w? If not, you should describe
>> the connection of sub-nodes with of-graph instead.
>>
>>> +    - Required properties :
>>> +      - compatible: "hisilicon,display-subsystem".
>>> +      - #address-cells, #size-cells: Must be present if the device has sub-nodes.
>>> +      - ranges: to allow probing of subdevices.
>>> +      - dma-coherent: Present if dma operations are coherent.
>>> +
>>> + ** ade: Graphic overlay, Graphic post-processing, display timing control.
>>> +    This device is child node of display-subsystem
>>> +    - Required properties :
>>> +      - compatible: "hisilicon,hi6220-ade".
>>> +      - reg: physical base address of the ADE register and length of memory
>>> +	region.
>>> +      - reg-names: Should contain the reg names "ade_base" and "media_base".
>>> +      - interrupt: The interrupt number to the cpu. Defines the interrupt
>>> +        by ADE.
>>> +      - clocks: The clocks needed by the ADE module.
>>> +      - clock-names: the name of the clocks.
>>> +
>>> + ** dsi: support mipi dsi interface
>>> +    This device is child node of display-subsystem
>>> +    - Required properties :
>>> +      - compatible: "hisilicon,hi6220-dsi".
>>> +      - reg: physical base address of the DSI register and length of memory
>>> +	region.
>>> +      - clocks: The clocks needed by the DSI module.
>>> +      - clock-names: the name of the clocks.
>>> +      -	encoder-slave: phandles to a 'encoder-slave' subnode which DSI connect
>>> +        ADV7533 in order to support hdmi display.
>>
>> What the ADV7533 binding looks like is still being discussed.
>> "encoder-slave" is certainly DRM specific and not how it should be done.
>> Most likely, this needs to use the of-graph ports.
>>
> I dont how to implement the encoder bridge stuff in upstream,
> you think that I will how to handle this part?

You can use of-graph ports to link the dsi output with the adv7533
bridge.

An example of the binding looks like:

Documentation/devicetree/bindings/drm/msm/dsi.txt

The implementation of this on the dsi host side of drm/msm
can be found in dsi_host_parse_dt, in:

drivers/gpu/drm/msm/dsi/dsi_host.c

You can get to know more about of-graph parsing here:

Documentation/devicetree/bindings/graph.txt

I'd started going through the drm/hisil patches. I'll
share more comments there.

Thanks,
Archit

>
> Thank you
> xinwei
>
>> Also, the ADV7533 connection is specific to HiKey. This binding should
>> just generically describe how any bridge or panel is connected.
>>
>> Rob
>>
>> .
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC
  2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
                   ` (7 preceding siblings ...)
  2015-09-15  9:37 ` [PATCH RFC 8/8] dts: hisilicon: Add drm driver device dts config for HiKey board Xinwei Kong
@ 2015-09-16 15:23 ` Daniel Stone
  2015-09-16 20:16   ` Daniel Vetter
  2015-09-18 10:32   ` Xinwei Kong
  8 siblings, 2 replies; 22+ messages in thread
From: Daniel Stone @ 2015-09-16 15:23 UTC (permalink / raw)
  To: Xinwei Kong
  Cc: David Airlie, Catalin Marinas, Will Deacon, dri-devel,
	haojian.zhuang, james.yanglong, yinshengbao, xuyiping, xuwei5,
	qijiwen, puck.chen, yanhaifeng, fangdechun, andy.green, gongyu,
	Linux Kernel Mailing List, ml.yang, liguozhu

Hi Xinwei,
Thanks for this contribution! We look forward to seeing support for
these devices.

This isn't an exhaustive review, but two very high-level comments
which should result in a lot of changes ...

On 15 September 2015 at 10:37, Xinwei Kong
<kong.kongxinwei@hisilicon.com> wrote:
> 1. 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 or pipes, 3 overlay and a LDI.
>   - A channel/pipe looks like: DMA-->clip-->scale-->ctrans/csc.
>   - Overlay is response to compose planes which come from 7 channels and
>   pass composed image to LDI.

This terminology is backwards from what we usually use in DRM, where
an overlay is a special case of DRM planes, and pipes are DRM CRTCs.

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

So this is basically just an implementation detail of DSI?

> 2. Software Detail
>   About the software organization and implementation detail:
> We have a main drm platform driver (hisi_drm_drv.c), ade platform driver
> (hisi_ade.c) and a dsi platform driver (hisi_drm_dsi.c). Ade driver
> implements the plane and crtc driver interfaces and dsi implements the
> encoder and connector driver interfaces. We take advantage of component
> framework to initialize each driver.
>   In order to support multi coming Hisilicon's SoCs, we plan to separate
> common driver code and SoC specific implemented code as possiple as we can.
> We abstract an ops for each component(crtc, plane, encoder and connector)
> to reuse the common interface implementation logic (FIXME: Not sure if we
> can achieve this target and if it is good or not). Thus, we put these
> common driver code into hisi_drm_drv/crtc/plane/encoder/connector.c files.

Please do not do this; in general, the abstraction layers cause more
problems than they create. We have only just finished removing all the
abstraction layers from drivers/gpu/drm/exynos/, which started off
with exactly the same idea, but only created problems. The issue is
that every time the DRM core interface changes, you have to make the
exact same changes in your copies of the interface. In general, there
seems to be no benefit to having these here: you can just assign the
DRM functions directly according to generation. See current Exynos for
an example of this.

The biggest issue though, is that this driver should become an atomic
modesetting driver. Atomic modesetting, rather than sending small
individual commands (enable CRTC, change plane position, etc) is based
on validating and passing around complete sets of hardware state.
Daniel Vetter's blog has an article on how to convert your driver:
http://blog.ffwll.ch/2014/11/atomic-modeset-support-for-kms-drivers.html

In addition, there are some drivers converted already that you can
look at: tegra (very simple), exynos (reasonably simple), fsl-dcu
(moderate), msm (quite complex), i915 (incredibly complex), rcar-du
(???).

Once your driver is converted to atomic and the abstraction layers
removed, then it will be much easier to review the submission in
detail.

Thanks very much!

Cheers,
Daniel

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

* Re: [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC
  2015-09-16 15:23 ` [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Daniel Stone
@ 2015-09-16 20:16   ` Daniel Vetter
       [not found]     ` <CAGd==05NKAjH=hD=bqKNh052ff=osJ4WxwOdDb3xoC1Mgy6Jdg@mail.gmail.com>
  2015-09-18 10:32   ` Xinwei Kong
  1 sibling, 1 reply; 22+ messages in thread
From: Daniel Vetter @ 2015-09-16 20:16 UTC (permalink / raw)
  To: Daniel Stone
  Cc: Xinwei Kong, yinshengbao, xuyiping, Catalin Marinas, Will Deacon,
	yanhaifeng, dri-devel, Linux Kernel Mailing List, andy.green,
	haojian.zhuang, fangdechun, puck.chen, ml.yang, gongyu, xuwei5,
	liguozhu, qijiwen, james.yanglong

On Wed, Sep 16, 2015 at 04:23:35PM +0100, Daniel Stone wrote:
> The biggest issue though, is that this driver should become an atomic
> modesetting driver. Atomic modesetting, rather than sending small
> individual commands (enable CRTC, change plane position, etc) is based
> on validating and passing around complete sets of hardware state.
> Daniel Vetter's blog has an article on how to convert your driver:
> http://blog.ffwll.ch/2014/11/atomic-modeset-support-for-kms-drivers.html

Yeah, any new driver should really be built on top of atomic - it's a lot
more flexible than the old thing and it's also what you want long-term.

I've also just done a presenation about atomic for drivers:

http://people.freedesktop.org/~danvet/presentations/xdc-2015.pdf

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

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

* Re: [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc
  2015-09-15  9:37 ` [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc Xinwei Kong
@ 2015-09-17 11:13   ` Archit Taneja
  0 siblings, 0 replies; 22+ messages in thread
From: Archit Taneja @ 2015-09-17 11:13 UTC (permalink / raw)
  To: Xinwei Kong, airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun

Hi,

On 9/15/2015 3:07 PM, Xinwei Kong wrote:
> This patch creates this driver itself and register all the sub-components
> which is from DTS inode, this driver uses components framework mechanism
> to bind all the sub-components.
>
> This patch also introduces a memory manager for hisilison drm. As cma
> framebuffer helpers can no more be used.
>
> 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>
> Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
> Signed-off-by: Yu Gong <gongyu@hisilicon.com>
> ---
>   arch/arm64/configs/defconfig             |   5 +
>   drivers/gpu/drm/Kconfig                  |   2 +
>   drivers/gpu/drm/Makefile                 |   1 +
>   drivers/gpu/drm/hisilicon/Kconfig        |   9 ++
>   drivers/gpu/drm/hisilicon/Makefile       |   7 ++
>   drivers/gpu/drm/hisilicon/hisi_ade.c     | 166 +++++++++++++++++++++++++
>   drivers/gpu/drm/hisilicon/hisi_drm_drv.c | 206 +++++++++++++++++++++++++++++++
>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c | 131 ++++++++++++++++++++
>   drivers/gpu/drm/hisilicon/hisi_drm_fb.c  | 156 +++++++++++++++++++++++
>   drivers/gpu/drm/hisilicon/hisi_drm_fb.h  |  26 ++++
>   10 files changed, 709 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_ade.c
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_drv.c
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fb.c
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fb.h
>

<snip>

> 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..a8dbaad
> --- /dev/null
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_dsi.c
> @@ -0,0 +1,131 @@
> +/*
> + * Hisilicon Terminal SoCs drm driver
> + *
> + * Copyright (c) 2014-2015 Hisilicon Limited.
> + * Author: Xinwei Kong <kong.kongxinwei@hisilicon.com> for hisilicon
> + *
> + * 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 <drm/drm_mipi_dsi.h>
> +#include <drm/drm_encoder_slave.h>
> +
> +#define DSI_24BITS_1               (5)
> +
> +struct hisi_dsi {
> +	u32 lanes;
> +	u32 format;
> +	u32 date_enable_pol;
> +	u32 mode_flags;
> +	u8 color_mode;
> +	void *ctx;
> +};
> +
> +struct hisi_dsi_context {
> +	struct hisi_dsi dsi;
> +	struct clk *dsi_cfg_clk;
> +	struct drm_device *dev;
> +
> +	void __iomem *base;
> +	int nominal_pixel_clk_kHz;
> +};
> +
> +static int hisi_dsi_bind(struct device *dev, struct device *master,
> +			 void *data)
> +{
> +	int ret = 0;
> +
> +	return ret;
> +}
> +
> +static void hisi_dsi_unbind(struct device *dev, struct device *master,
> +			    void *data)
> +{
> +	/* do nothing */
> +}
> +
> +static const struct component_ops hisi_dsi_ops = {
> +	.bind	= hisi_dsi_bind,
> +	.unbind	= hisi_dsi_unbind,
> +};
> +
> +static int hisi_dsi_probe(struct platform_device *pdev)
> +{
> +	struct hisi_dsi_context *ctx;
> +	struct hisi_dsi *dsi;
> +	struct resource *res;
> +	struct device_node *slave_node;
> +	struct device_node *np = pdev->dev.of_node;
> +	int ret;
> +
> +	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx) {
> +		DRM_ERROR("failed to allocate hisi dsi context.\n");
> +		ret = -ENOMEM;
> +	}
> +
> +	ctx->dsi_cfg_clk = devm_clk_get(&pdev->dev, "pclk_dsi");
> +	if (IS_ERR(ctx->dsi_cfg_clk)) {
> +		DRM_ERROR("failed to parse the dsi config clock\n");
> +		ret = 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");
> +		ret = PTR_ERR(ctx->base);
> +	}
> +
> +	slave_node = of_parse_phandle(np, "encoder-slave", 0);
> +	if (!slave_node) {
> +		DRM_ERROR("failed to parse the slave encoder node\n");
> +		return -EINVAL;
> +	}
> +
> +	dsi = &ctx->dsi;
> +	dsi->ctx = ctx;
> +	dsi->lanes = 3;
> +	dsi->date_enable_pol = 0;
> +	dsi->color_mode = DSI_24BITS_1;
> +	dsi->format = MIPI_DSI_FMT_RGB888;
> +	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
> +
> +	return component_add(&pdev->dev, &hisi_dsi_ops);
> +}
> +

The DSI driver should register the dsi host via 
mipi_dsi_host_register(). That's the standard way of establishing a
connection between a host and dsi peripherals.

The dsi_context approach isn't something that will work very well.
With this approach, you're forced to set DSI parameters like number of
lanes, format, mode flags etc in the host driver, rather than receiving
them from the connected device.

Archit

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part
  2015-09-15  9:37 ` [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part Xinwei Kong
@ 2015-09-17 11:39   ` Archit Taneja
  0 siblings, 0 replies; 22+ messages in thread
From: Archit Taneja @ 2015-09-17 11:39 UTC (permalink / raw)
  To: Xinwei Kong, airlied, corbet, catalin.marinas, will.deacon
  Cc: dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun



On 9/15/2015 3:07 PM, Xinwei Kong wrote:
> This patch enables the adv7533 module which is connecting hisilicon SOC
> by dsi module. while using DSI module and adv7533 module to implement the
> encoder/connector interface of DRM\KMS.
>
> 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>
> Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
> Signed-off-by: Yu Gong <gongyu@hisilicon.com>
> ---
>   drivers/gpu/drm/hisilicon/Kconfig              |  10 +
>   drivers/gpu/drm/hisilicon/hisi_drm_connector.c |  34 ++
>   drivers/gpu/drm/hisilicon/hisi_drm_connector.h |   8 +
>   drivers/gpu/drm/hisilicon/hisi_drm_dsi.c       | 670 +++++++++++++++++++++++++
>   drivers/gpu/drm/hisilicon/hisi_drm_encoder.c   |  52 ++
>   drivers/gpu/drm/hisilicon/hisi_drm_encoder.h   |  19 +
>   drivers/gpu/drm/hisilicon/hisi_dsi_reg.h       |  91 ++++
>   7 files changed, 884 insertions(+)
>   create mode 100644 drivers/gpu/drm/hisilicon/hisi_dsi_reg.h
>

<snip>

> +struct hisi_connector_funcs hisi_dsi_connector_ops = {
> +	.get_modes = dsi_connector_get_modes,
> +};
> +
> +struct hisi_encoder_funcs hisi_dsi_encoder_ops = {
> +	.mode_set = dsi_encoder_mode_set,
> +	.enable = dsi_encoder_enable,
> +	.disable = dsi_encoder_disable,
> +};
> +
>   static int hisi_dsi_bind(struct device *dev, struct device *master,
>   			 void *data)
>   {
> @@ -52,8 +682,23 @@ static int hisi_dsi_bind(struct device *dev, struct device *master,
>
>   	hisi_drm_encoder_init(ctx->dev, &ctx->dsi.hisi_encoder.base.base);
>
> +#ifdef CONFIG_DRM_HISI_HAS_SLAVE_ENCODER
> +	ret = ctx->drm_i2c_driver->encoder_init(ctx->client, ctx->dev,
> +						&ctx->dsi.hisi_encoder.base);
> +	if (ret) {
> +		DRM_ERROR("fail to init drm i2c encoder\n");
> +		return ret;
> +	}
> +
> +	if (!ctx->dsi.hisi_encoder.base.slave_funcs) {
> +		DRM_ERROR("failed check encoder function\n");
> +		return -ENODEV;
> +	}
> +#endif

A slave encoder isn't supposed to be used this way. A slave encoder is
supposed to register itself to drm as an encoder object. A slave
encoder connects directly to a crtc, and operate like a normal encoder.
In other words, a slave encoder isn't something that attaches to a
'master' encoder as the driver does here. 'Slave encoder' here means
that the encoder is a part of a different bus (like i2c etc).

Currently, the driver is directly calling slave encoder ops in 
hisi_drm_encoder.c.


> +
>   	hisi_drm_connector_init(ctx->dev, &ctx->dsi.hisi_encoder.base.base,
>   				&ctx->dsi.hisi_connector.connector);
> +
>   	return ret;
>   }
>
> @@ -102,6 +747,27 @@ static int hisi_dsi_probe(struct platform_device *pdev)
>   		return -EINVAL;
>   	}
>
> +#ifdef CONFIG_DRM_HISI_HAS_SLAVE_ENCODER
> +	ctx->client = of_find_i2c_device_by_node(slave_node);
> +	of_node_put(slave_node);
> +	if (!ctx->client) {
> +		DRM_ERROR("failed to find slave encoder i2c client\n");
> +		return -EPROBE_DEFER;
> +	}
> +
> +	if (!ctx->client->dev.driver) {
> +		DRM_ERROR("%s: NULL client driver\n", __func__);
> +		return -EPROBE_DEFER;
> +	}
> +
> +	ctx->drm_i2c_driver = to_drm_i2c_encoder_driver(
> +		to_i2c_driver(ctx->client->dev.driver));
> +	if (IS_ERR(ctx->drm_i2c_driver)) {
> +		DRM_ERROR("failed to initialize encoder driver");
> +		return -EPROBE_DEFER;
> +	}
> +#endif
> +
>   	dsi = &ctx->dsi;
>   	dsi->ctx = ctx;
>   	dsi->lanes = 3;
> @@ -110,6 +776,10 @@ static int hisi_dsi_probe(struct platform_device *pdev)
>   	dsi->format = MIPI_DSI_FMT_RGB888;
>   	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
>
> +	dsi->hisi_encoder.ops = &hisi_dsi_encoder_ops;
> +	dsi->hisi_connector.encoder = &dsi->hisi_encoder.base.base;
> +	dsi->hisi_connector.ops = &hisi_dsi_connector_ops;
> +
>   	return component_add(&pdev->dev, &hisi_dsi_ops);
>   }
>
> diff --git a/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
> index 89fc73d..acd73d8 100644
> --- a/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
> +++ b/drivers/gpu/drm/hisilicon/hisi_drm_encoder.c
> @@ -15,18 +15,49 @@
>
>   #include "hisi_drm_encoder.h"
>
> +#define to_hisi_encoder(encoder) \
> +	container_of(encoder, struct hisi_encoder, base.base)
> +
>   void hisi_drm_encoder_disable(struct drm_encoder *encoder)
>   {
> +	struct hisi_encoder *hencoder = to_hisi_encoder(encoder);
> +	struct hisi_encoder_funcs *ops = hencoder->ops;
> +	struct drm_encoder_slave_funcs *sfuncs = get_slave_funcs(encoder);
> +
> +	if (ops->enable)
> +		ops->disable(encoder);
> +
> +	if (sfuncs && sfuncs->dpms)
> +		sfuncs->dpms(encoder, DRM_MODE_DPMS_OFF);
>   }
>

The encoder should represent only the DSI encoder hardware here. It
shouldn't be calling slave encoder ops.

What you want is to have the encoder connect to a bridge. Something
like:

crtc(ade)->encoder(dsi)->bridge(adv7533)->connector

Archit

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

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

* Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev
       [not found]     ` <CAGd==05f+XVg4ZSDihftjB2wcOGkAou=AxXYXB+1=ckM2J6EBQ@mail.gmail.com>
@ 2015-09-17 11:52       ` Rob Clark
  0 siblings, 0 replies; 22+ messages in thread
From: Rob Clark @ 2015-09-17 11:52 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: Rob Herring, linux-doc, Catalin Marinas, Will Deacon, linuxarm,
	dri-devel, Haojian Zhuang, Benjamin Gaignard, Yanglong (James),
	Yinshengbao, xuyiping, Jonathan Corbet, Min Yi, xuwei5, Wang Fei,
	qijiwen, devicetree, bintian.wang, puck.chen, Yanhaifeng,
	Dechun Fang, linux-arm-kernel, Andy Green, gongyu,
	Linux Kernel Mailing List, Yangminglei, Liguozhu (Kenneth)

On Wed, Sep 16, 2015 at 5:48 AM, Xinliang Liu <xinliang.liu@linaro.org> wrote:
>
>
> On 16 September 2015 at 02:25, Rob Herring <robh@kernel.org> wrote:
> Hi Rob, thanks a lot for reply:-)
>
>> On 09/15/2015 04:37 AM, Xinwei Kong wrote:
>> > If you config DRM_HISI_FBDEV optional, this patch will only support
>> > fbdev
>> > mode while also supporting double buffer.
>>
>> This is a lot of duplicated code from CMA fbdev. Is double buffering the
>> only reason why CMA fbdev can't be used or are there some other
>> constraints?
>
> Yes, double buffering is the main reason we rewrite our own fbdev.
> CMA fbdev only create one buffer. But we need at least  double buffer for
> running Android with fbdev.
>
>> Double buffering in fbdev has always been a hack, so I'm
>> guessing that is not a feature that should be added here.
>>
> If so, I think it is hard to be accepted for my cma fbdev patch to support
> multi buffer.
> This early week, I have sent a cma fbdev patch for supporting this. The
> subject is
> "[PATCH] drm/cma-helper: Add multi buffer support for cma fbdev".
> We do have a strong will to support this feature. I described the reason in
> the patch. Please take a look for me. Thank you very much.

fwiw, drm_gralloc has support for kms.  Currently it is expected to be
paired w/ a mesa gpu driver, which might not work for everyone, but I
suppose the display part of it could be extracted out for a
gralloc.kms.so for pure sw rendering.. that might be a better
approach.

http://git.android-x86.org/?p=platform/hardware/drm_gralloc.git

BR,
-R

> -Xinliang
>
>> Rob
>>
>> > 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>
>> > Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
>> > Signed-off-by: Yu Gong <gongyu@hisilicon.com>
>> > ---
>> >  drivers/gpu/drm/hisilicon/Kconfig              |  13 +
>> >  drivers/gpu/drm/hisilicon/Makefile             |   3 +-
>> >  drivers/gpu/drm/hisilicon/hisi_drm_connector.c |   4 +
>> >  drivers/gpu/drm/hisilicon/hisi_drm_drv.c       |   9 +
>> >  drivers/gpu/drm/hisilicon/hisi_drm_dsi.c       |  15 +
>> >  drivers/gpu/drm/hisilicon/hisi_drm_fb.h        |   5 +
>> >  drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c     | 395
>> > +++++++++++++++++++++++++
>> >  drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h     |  24 ++
>> >  8 files changed, 467 insertions(+), 1 deletion(-)
>> >  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.c
>> >  create mode 100644 drivers/gpu/drm/hisilicon/hisi_drm_fbdev.h
>>
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

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

* Re: [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver
  2015-09-16  9:10       ` Archit Taneja
@ 2015-09-17 12:14         ` Xinwei Kong
  0 siblings, 0 replies; 22+ messages in thread
From: Xinwei Kong @ 2015-09-17 12:14 UTC (permalink / raw)
  To: Archit Taneja, lars, treding
  Cc: Rob Herring, airlied, corbet, catalin.marinas, will.deacon,
	dri-devel, linux-doc, linux-arm-kernel, linuxarm, devicetree,
	linux-kernel, xinliang.liu, andy.green, qijiwen, gongyu,
	haojian.zhuang, liguozhu, xuwei5, yinshengbao, yanhaifeng,
	ml.yang, yimin, w.f, puck.chen, bintian.wang, benjamin.gaignard,
	xuyiping, james.yanglong, fangdechun, linux-arm-msm,
	laurent.pinchart, srinivas.kandagatla

hi architt

On 2015/9/16 17:10, Archit Taneja wrote:
> Hi,
> 
> On 09/16/2015 02:04 PM, Xinwei Kong wrote:
>> hi architt
>>
>> On 2015/9/16 2:11, Rob Herring wrote:
>>> On 09/15/2015 04:37 AM, Xinwei Kong wrote:
>>>> This adds documentation of device tree bindings for the
>>>> Graphics Processing Unit of 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>
>>>> Signed-off-by: Jiwen Qi <qijiwen@hisilicon.com>
>>>> Signed-off-by: Yu Gong <gongyu@hisilicon.com>
>>>> ---
>>>>   .../devicetree/bindings/gpu/hisilicon,hi6220.txt   | 69 ++++++++++++++++++++++
>>>>   1 file changed, 69 insertions(+)
>>>>   create mode 100644 Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>>>> new file mode 100644
>>>> index 0000000..173ac63
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/gpu/hisilicon,hi6220.txt
>>>> @@ -0,0 +1,69 @@
>>>> + * Hisilicon hi6220 Graphics Processing Unit for HiKey board
>>>> +
>>>> + ** display-subsystem: Master device for binding DRM sub-components
>>>
>>> DRM is a Linuxism that doesn't belong in the binding.
>>>
>>>> +    This master device is parent node and it will be responsible to bind all
>>>> +    sub-components devices node.
>>>
>>> Are these nodes a single block in the h/w? If not, you should describe
>>> the connection of sub-nodes with of-graph instead.
>>>
>>>> +    - Required properties :
>>>> +      - compatible: "hisilicon,display-subsystem".
>>>> +      - #address-cells, #size-cells: Must be present if the device has sub-nodes.
>>>> +      - ranges: to allow probing of subdevices.
>>>> +      - dma-coherent: Present if dma operations are coherent.
>>>> +
>>>> + ** ade: Graphic overlay, Graphic post-processing, display timing control.
>>>> +    This device is child node of display-subsystem
>>>> +    - Required properties :
>>>> +      - compatible: "hisilicon,hi6220-ade".
>>>> +      - reg: physical base address of the ADE register and length of memory
>>>> +    region.
>>>> +      - reg-names: Should contain the reg names "ade_base" and "media_base".
>>>> +      - interrupt: The interrupt number to the cpu. Defines the interrupt
>>>> +        by ADE.
>>>> +      - clocks: The clocks needed by the ADE module.
>>>> +      - clock-names: the name of the clocks.
>>>> +
>>>> + ** dsi: support mipi dsi interface
>>>> +    This device is child node of display-subsystem
>>>> +    - Required properties :
>>>> +      - compatible: "hisilicon,hi6220-dsi".
>>>> +      - reg: physical base address of the DSI register and length of memory
>>>> +    region.
>>>> +      - clocks: The clocks needed by the DSI module.
>>>> +      - clock-names: the name of the clocks.
>>>> +      -    encoder-slave: phandles to a 'encoder-slave' subnode which DSI connect
>>>> +        ADV7533 in order to support hdmi display.
>>>
>>> What the ADV7533 binding looks like is still being discussed.
>>> "encoder-slave" is certainly DRM specific and not how it should be done.
>>> Most likely, this needs to use the of-graph ports.
>>>
>> I dont how to implement the encoder bridge stuff in upstream,
>> you think that I will how to handle this part?
> 
> You can use of-graph ports to link the dsi output with the adv7533
> bridge.
> 
> An example of the binding looks like:
> 
> Documentation/devicetree/bindings/drm/msm/dsi.txt
> 
> The implementation of this on the dsi host side of drm/msm
> can be found in dsi_host_parse_dt, in:
> 
> drivers/gpu/drm/msm/dsi/dsi_host.c
> 
> You can get to know more about of-graph parsing here:
> 
> Documentation/devicetree/bindings/graph.txt
> 
I study your patch about of-graph parsing, I know that how to parse this
dts endpoint node. Then i dont kow how to use this device_node (which is
get by "of_graph_get_remote_port_parent" function.) to hook adv7533 operation.

can you give me some help to how to use the adv7533 interface by device_node or
other way to use adv7533?

> I'd started going through the drm/hisil patches. I'll
> share more comments there.
> 
> Thanks,
> Archit
> 
>>
>> Thank you
>> xinwei
>>
>>> Also, the ADV7533 connection is specific to HiKey. This binding should
>>> just generically describe how any bridge or panel is connected.
>>>
>>> Rob
>>>
>>> .
>>>
>>
>> -- 
>> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
> 


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

* Re: [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC
  2015-09-16 15:23 ` [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Daniel Stone
  2015-09-16 20:16   ` Daniel Vetter
@ 2015-09-18 10:32   ` Xinwei Kong
  1 sibling, 0 replies; 22+ messages in thread
From: Xinwei Kong @ 2015-09-18 10:32 UTC (permalink / raw)
  To: Daniel Stone
  Cc: David Airlie, Catalin Marinas, Will Deacon, dri-devel,
	haojian.zhuang, james.yanglong, yinshengbao, xuyiping, xuwei5,
	qijiwen, puck.chen, yanhaifeng, fangdechun, andy.green, gongyu,
	Linux Kernel Mailing List, ml.yang, liguozhu

hi Daniel Stone:

On 2015/9/16 23:23, Daniel Stone wrote:
> Hi Xinwei,
> Thanks for this contribution! We look forward to seeing support for
> these devices.
> 
> This isn't an exhaustive review, but two very high-level comments
> which should result in a lot of changes ...
> 
> On 15 September 2015 at 10:37, Xinwei Kong
> <kong.kongxinwei@hisilicon.com> wrote:
>> 1. 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 or pipes, 3 overlay and a LDI.
>>   - A channel/pipe looks like: DMA-->clip-->scale-->ctrans/csc.
>>   - Overlay is response to compose planes which come from 7 channels and
>>   pass composed image to LDI.
> 
> This terminology is backwards from what we usually use in DRM, where
> an overlay is a special case of DRM planes, and pipes are DRM CRTCs.
> 
>>   - 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.
> 
> So this is basically just an implementation detail of DSI?
> 
>> 2. Software Detail
>>   About the software organization and implementation detail:
>> We have a main drm platform driver (hisi_drm_drv.c), ade platform driver
>> (hisi_ade.c) and a dsi platform driver (hisi_drm_dsi.c). Ade driver
>> implements the plane and crtc driver interfaces and dsi implements the
>> encoder and connector driver interfaces. We take advantage of component
>> framework to initialize each driver.
>>   In order to support multi coming Hisilicon's SoCs, we plan to separate
>> common driver code and SoC specific implemented code as possiple as we can.
>> We abstract an ops for each component(crtc, plane, encoder and connector)
>> to reuse the common interface implementation logic (FIXME: Not sure if we
>> can achieve this target and if it is good or not). Thus, we put these
>> common driver code into hisi_drm_drv/crtc/plane/encoder/connector.c files.
> 
> Please do not do this; in general, the abstraction layers cause more
> problems than they create. We have only just finished removing all the
> abstraction layers from drivers/gpu/drm/exynos/, which started off
> with exactly the same idea, but only created problems. The issue is
> that every time the DRM core interface changes, you have to make the
> exact same changes in your copies of the interface. In general, there
> seems to be no benefit to having these here: you can just assign the
> DRM functions directly according to generation. See current Exynos for
> an example of this.
> 
I understand that you want to let us remove the hisi_drm_crtc/plane/
encoder/connector.c files in my driver.

When we plan to use abstraction layers, our purpose is that our commmon
drm interface will be used in diff hisilicon soc platform such as mobile
series、TV series soc , if this common interface don't use in diff soc
or not take advantage of following DRM core interface changes, we will fix it.

but if I will port hisi_drm_crtc/plane/.c file code into hisi_ade.c file
and port hisi_drm_encoder/connector.c into hisi_drm_dsi.c file,
when we add some other soc platform, we will be similar to create hardware
ip *.c file, if DRM core interface will changes , we will change all refering
ip.c file.

I wish that you can give me some guides for this abstraction layers.

Thank you
xinwei


> The biggest issue though, is that this driver should become an atomic
> modesetting driver. Atomic modesetting, rather than sending small
> individual commands (enable CRTC, change plane position, etc) is based
> on validating and passing around complete sets of hardware state.
> Daniel Vetter's blog has an article on how to convert your driver:
> http://blog.ffwll.ch/2014/11/atomic-modeset-support-for-kms-drivers.html
> 
> In addition, there are some drivers converted already that you can
> look at: tegra (very simple), exynos (reasonably simple), fsl-dcu
> (moderate), msm (quite complex), i915 (incredibly complex), rcar-du
> (???).
> 
> Once your driver is converted to atomic and the abstraction layers
> removed, then it will be much easier to review the submission in
> detail.
> 
> Thanks very much!
> 
> Cheers,
> Daniel
> 
> .
> 


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

* Re: [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC
       [not found]     ` <CAGd==05NKAjH=hD=bqKNh052ff=osJ4WxwOdDb3xoC1Mgy6Jdg@mail.gmail.com>
@ 2015-09-22  8:49       ` Daniel Vetter
  0 siblings, 0 replies; 22+ messages in thread
From: Daniel Vetter @ 2015-09-22  8:49 UTC (permalink / raw)
  To: Xinliang Liu
  Cc: Daniel Stone, Xinwei Kong, Yinshengbao, Yiping Xu,
	Catalin Marinas, Will Deacon, Yanhaifeng, dri-devel,
	Linux Kernel Mailing List, Andy Green, Haojian Zhuang,
	Dechun Fang, puck.chen, Yangminglei, gongyu, xuwei5,
	Liguozhu (Kenneth), qijiwen, Yanglong (James)

On Thu, Sep 17, 2015 at 05:51:28PM +0800, Xinliang Liu wrote:
> On 17 September 2015 at 04:16, Daniel Vetter <daniel@ffwll.ch> wrote:
> 
> > On Wed, Sep 16, 2015 at 04:23:35PM +0100, Daniel Stone wrote:
> > > The biggest issue though, is that this driver should become an atomic
> > > modesetting driver. Atomic modesetting, rather than sending small
> > > individual commands (enable CRTC, change plane position, etc) is based
> > > on validating and passing around complete sets of hardware state.
> > > Daniel Vetter's blog has an article on how to convert your driver:
> > > http://blog.ffwll.ch/2014/11/atomic-modeset-support-for-kms-drivers.html
> >
> > Yeah, any new driver should really be built on top of atomic - it's a lot
> > more flexible than the old thing and it's also what you want long-term.
> >
> > I've also just done a presenation about atomic for drivers:
> >
> > http://people.freedesktop.org/~danvet/presentations/xdc-2015.pdf
> 
> 
> Hi Daniel,
> This is a good presentation. It gives us very detail and good suggection on
> implementation.
> Thank you for sharing this.
> 
> We have a open source KMS hwc:
> wiki:
> https://wiki.linaro.org/BenjaminGaignard/HWComposer_DRM?highlight=%28hwcomposer%2
> source code: git://git.linaro.org/people/benjamin.gaignard/hwcomposer.git
> Now only STI and Hikey boards are tested on it. And atomic mode setting is
> not support now.
> I think we should add support for atomic mode setting next.
> 
> One difficulty I am facing is that one setting should be made sure is ok in
> the prepare function of hwc.
> If not, the set function of hwc may be fail and display will not properly.
> I don't know atomic mode setting how to handle this situation. And it seems
> that in the prepare function,
> it should check the hardware's capabilities, such as clip, scale, rotation,
> blending and so on.

Specifically to support things like hwc's ->prepare callback atomic
supports a TEST_ONLY mode. Hence in your the prepare code build up the
atomic state, but set the TEST_ONLY flag when calling the ioctl. When the
kernel is happy you can store it somewhere and tell surface flinger the
configuration so it can render the remaining buffers with GL. The idea is
that generic userspace does use TEST_ONLY mode iterative to build up the
maximal configuration of hw planes that a given kms driver supports,
leaving no hw-specific code in userspace. For optimized hwc drivers
running on atomic you then just need to tune the selection, but detailed
constraint checking would still be done by the kernel.

The weston patches from Daniel Stone have a similar design, would be worth
checking those out.

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

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

end of thread, other threads:[~2015-09-22  8:46 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-15  9:37 [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong
2015-09-15  9:37 ` [PATCH RFC 1/8] dt-bindings: Document the hi6220 bindings for DRM driver Xinwei Kong
2015-09-15 18:11   ` Rob Herring
2015-09-16  8:34     ` Xinwei Kong
2015-09-16  9:10       ` Archit Taneja
2015-09-17 12:14         ` Xinwei Kong
2015-09-15  9:37 ` [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc Xinwei Kong
2015-09-17 11:13   ` Archit Taneja
2015-09-15  9:37 ` [PATCH RFC 3/8] drm: hisilicon: Add the link to DRM/KMS interface Xinwei Kong
2015-09-15  9:37 ` [PATCH RFC 4/8] drm: hisilicon: fill interface function of plane\crtc part Xinwei Kong
2015-09-15  9:37 ` [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part Xinwei Kong
2015-09-17 11:39   ` Archit Taneja
2015-09-15  9:37 ` [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev Xinwei Kong
2015-09-15 18:25   ` Rob Herring
2015-09-16  3:32     ` Xinwei Kong
     [not found]     ` <CAGd==05f+XVg4ZSDihftjB2wcOGkAou=AxXYXB+1=ckM2J6EBQ@mail.gmail.com>
2015-09-17 11:52       ` Rob Clark
2015-09-15  9:37 ` [PATCH RFC 7/8] drm: hisilicon: Add support for vblank Xinwei Kong
2015-09-15  9:37 ` [PATCH RFC 8/8] dts: hisilicon: Add drm driver device dts config for HiKey board Xinwei Kong
2015-09-16 15:23 ` [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Daniel Stone
2015-09-16 20:16   ` Daniel Vetter
     [not found]     ` <CAGd==05NKAjH=hD=bqKNh052ff=osJ4WxwOdDb3xoC1Mgy6Jdg@mail.gmail.com>
2015-09-22  8:49       ` Daniel Vetter
2015-09-18 10:32   ` Xinwei Kong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).