Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1224930 > unrolled thread

[PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC

Started byXinwei Kong <kong.kongxinwei@hisilicon.com>
First post2015-09-15 11:50 +0200
Last post2015-09-18 12:50 +0200
Articles 14 — 6 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong <kong.kongxinwei@hisilicon.com> - 2015-09-15 11:50 +0200
    [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev Xinwei Kong <kong.kongxinwei@hisilicon.com> - 2015-09-15 11:50 +0200
      Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev Rob Herring <robh@kernel.org> - 2015-09-15 20:30 +0200
        Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev Xinwei Kong <kong.kongxinwei@hisilicon.com> - 2015-09-16 05:50 +0200
        Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev Rob Clark <robdclark@gmail.com> - 2015-09-17 14:00 +0200
    [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part Xinwei Kong <kong.kongxinwei@hisilicon.com> - 2015-09-15 11:50 +0200
      Re: [PATCH RFC 5/8] drm: hisilicon: fill interface function of  encoder\connector part Archit Taneja <architt@codeaurora.org> - 2015-09-17 13:50 +0200
    [PATCH RFC 3/8] drm: hisilicon: Add the link to DRM/KMS interface Xinwei Kong <kong.kongxinwei@hisilicon.com> - 2015-09-15 11:50 +0200
    [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc Xinwei Kong <kong.kongxinwei@hisilicon.com> - 2015-09-15 11:50 +0200
      Re: [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon  Soc Archit Taneja <architt@codeaurora.org> - 2015-09-17 13:20 +0200
    Re: [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Daniel Stone <daniel@fooishbar.org> - 2015-09-16 17:30 +0200
      Re: [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Daniel Vetter <daniel@ffwll.ch> - 2015-09-16 22:20 +0200
        Re: [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Daniel Vetter <daniel@ffwll.ch> - 2015-09-22 10:50 +0200
      Re: [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC Xinwei Kong <kong.kongxinwei@hisilicon.com> - 2015-09-18 12:50 +0200

#1224930 — [PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC

FromXinwei Kong <kong.kongxinwei@hisilicon.com>
Date2015-09-15 11:50 +0200
Subject[PATCH RFC 0/8] Add New DRM Driver for Hisilicon's Hi6220 SoC
Message-ID<q8USv-QT-55@gated-at.bofh.it>
  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


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

[toc] | [next] | [standalone]


#1224933 — [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev

FromXinwei Kong <kong.kongxinwei@hisilicon.com>
Date2015-09-15 11:50 +0200
Subject[PATCH RFC 6/8] drm: hisilicon: Add support for fbdev
Message-ID<q8V2a-12p-35@gated-at.bofh.it>
In reply to#1224930
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


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

[toc] | [prev] | [next] | [standalone]


#1225492 — Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev

FromRob Herring <robh@kernel.org>
Date2015-09-15 20:30 +0200
SubjectRe: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev
Message-ID<q939n-4nZ-1@gated-at.bofh.it>
In reply to#1224933
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

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

[toc] | [prev] | [next] | [standalone]


#1225700 — Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev

FromXinwei Kong <kong.kongxinwei@hisilicon.com>
Date2015-09-16 05:50 +0200
SubjectRe: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev
Message-ID<q9bTj-Zt-3@gated-at.bofh.it>
In reply to#1225492
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
> 
> 
> .
> 

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

[toc] | [prev] | [next] | [standalone]


#1226950 — Re: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev

FromRob Clark <robdclark@gmail.com>
Date2015-09-17 14:00 +0200
SubjectRe: [PATCH RFC 6/8] drm: hisilicon: Add support for fbdev
Message-ID<q9G14-2Dx-15@gated-at.bofh.it>
In reply to#1225492
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
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1224939 — [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part

FromXinwei Kong <kong.kongxinwei@hisilicon.com>
Date2015-09-15 11:50 +0200
Subject[PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part
Message-ID<q8V2b-12p-51@gated-at.bofh.it>
In reply to#1224930
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


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

[toc] | [prev] | [next] | [standalone]


#1226939 — Re: [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part

FromArchit Taneja <architt@codeaurora.org>
Date2015-09-17 13:50 +0200
SubjectRe: [PATCH RFC 5/8] drm: hisilicon: fill interface function of encoder\connector part
Message-ID<q9FRp-2rZ-31@gated-at.bofh.it>
In reply to#1224939

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

[toc] | [prev] | [next] | [standalone]


#1224940 — [PATCH RFC 3/8] drm: hisilicon: Add the link to DRM/KMS interface

FromXinwei Kong <kong.kongxinwei@hisilicon.com>
Date2015-09-15 11:50 +0200
Subject[PATCH RFC 3/8] drm: hisilicon: Add the link to DRM/KMS interface
Message-ID<q8V2b-12p-47@gated-at.bofh.it>
In reply to#1224930
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


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

[toc] | [prev] | [next] | [standalone]


#1224941 — [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc

FromXinwei Kong <kong.kongxinwei@hisilicon.com>
Date2015-09-15 11:50 +0200
Subject[PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc
Message-ID<q8V2b-12p-45@gated-at.bofh.it>
In reply to#1224930
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


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

[toc] | [prev] | [next] | [standalone]


#1226923 — Re: [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc

FromArchit Taneja <architt@codeaurora.org>
Date2015-09-17 13:20 +0200
SubjectRe: [PATCH RFC 2/8] drm: hisilicon: Add new DRM driver for hisilicon Soc
Message-ID<q9Fom-1Tl-9@gated-at.bofh.it>
In reply to#1224941
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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1226195

FromDaniel Stone <daniel@fooishbar.org>
Date2015-09-16 17:30 +0200
Message-ID<q9mOJ-8oQ-7@gated-at.bofh.it>
In reply to#1224930
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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1226445

FromDaniel Vetter <daniel@ffwll.ch>
Date2015-09-16 22:20 +0200
Message-ID<q9rlo-6v3-11@gated-at.bofh.it>
In reply to#1226195
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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1229986

FromDaniel Vetter <daniel@ffwll.ch>
Date2015-09-22 10:50 +0200
Message-ID<qbrqW-fr-1@gated-at.bofh.it>
In reply to#1226445
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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1227765

FromXinwei Kong <kong.kongxinwei@hisilicon.com>
Date2015-09-18 12:50 +0200
Message-ID<qa1oS-cV-15@gated-at.bofh.it>
In reply to#1226195
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
> 
> .
> 

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

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web