linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/13] drm/meson: Initial support for HDMI Output
@ 2017-03-21 15:25 Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 01/13] drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable sync for vsync commit Neil Armstrong
                   ` (13 more replies)
  0 siblings, 14 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

The Amlogic GX SoCs implements a Synopsys DesignWare HDMI TX Controller
in combination with a very custom PHY.

This patchset depends on Laurent Pinchart patchset merged in drm-misc-next
and my v4 patchset at [1] to permit PHY control from outside the dw-hdmi driver.

The Synopsys DesignWare HDMI TX Controller is integrated like :
         ___________________________________
        |            HDMI TOP               |<= HPD
        |___________________________________|
        |                  |                |
HDMI-TX-|  Synopsys HDMI   |   HDMI PHY     |=> TMDS
        |    Controller    |________________|
        |___________________________________|<=> DDC

And uses the following paths for Pixels Encoding :
       _____   _____   ____________________
vd1---|     |-|     | | VENC     /---------|----VDAC
vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|\
osd1--|     |-|     | | \                  | X--HDMI-TX
osd2--|_____|-|_____| |  |\-ENCP--ENCP_DVI-|/
                      |  |                 |
                      |  \--ENCL-----------|----LVDS
                      |____________________|

The ENCI and ENCP encoders pre-formats the data for the ENCI-DVI and
ENCP-DVI encoders. Those DVI encoders will format the pixels for the
Synopsys DesignWare HDMI TX Controller.

In order to support display modes, the ENCI and ENCP encoders needs very
specific parameters for *each* display modes, so usage of the CEA VIC
identifier is necessary. But the DVI timings are generated from the
drm_mode structure in a generic way.

To simplify the first push, only the main CEA modes are supported up to
1920x1080p60. Supporting the 480i and 576i needs tweaking in the dw-hdmi
in order to support the Clock Doubling necessary for these modes.

Support for more traditional modes like the EDID fallback modes is planned
but will need tome additionnal handling along the CEA modes.
Support for 4k2k modes needs to be able to get the EDID HDMI modes, but
for now only the HDMI 1.4 modes are currently available in the drm_edid
implementation.

This patchset does :
 - Fixes the CRTC handling
 - Fixes the registers definitions
 - Adds support for device components registration along of-graph
 - Adds support for HDMI clocks
 - Adds support for HDMI VENC video modes
 - Adds support for the Custom HDMI PHY using callbacks added in [1] and [2]
 - Adds CMA node to reserve enougth memory for 1080p display
 - Adds the HDMI controller et connector modes on selected boards
 - Adds a proper dt-bindings for the HDMI controller et connector
 - Add RST documentation for Meson DRM driver
 - Updates the MAINTAINERS file to track the new files

Changes since v1 patchset at [2] :
 - Add the meson drm documentation from [3] to this patchset
 - Update with new bus formats and HPD callbacks
 - Drop all the of_machine_is_compatible

[1] http://lkml.kernel.org/r/1490109161-20529-1-git-send-email-narmstrong@baylibre.com
[2] http://lkml.kernel.org/r/1488469207-523-1-git-send-email-narmstrong@baylibre.com
[3] http://lkml.kernel.org/r/1488536068-9407-1-git-send-email-narmstrong@baylibre.com

Neil Armstrong (13):
  drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable
    sync for vsync commit
  drm/meson: Add missing HDMI register
  drm/meson: Add support for components
  drm/meson: venc_cvbs: no more return -ENODEV if CVBS is not available
  drm/meson: add support for HDMI clock support
  drm/meson: Add support for HDMI venc modes and settings
  drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY
  ARM64: dts: meson-gx: Add shared CMA dma memory pool
  ARM64: dts: meson-gx: Add support for HDMI output
  dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension
  drm/meson: Convert existing documentation to actual kerneldoc
  drm/meson: Add RST to bring together kerneldoc
  MAINTAINERS: update files for Amlogic DRM Driver

 .../bindings/display/amlogic,meson-dw-hdmi.txt     |  111 ++
 Documentation/gpu/index.rst                        |    1 +
 Documentation/gpu/meson.rst                        |   61 +
 MAINTAINERS                                        |    2 +
 .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi |   39 +
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi          |   40 +
 .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts    |   23 +
 arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi   |   23 +
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        |   12 +
 .../dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts    |   23 +
 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         |   13 +
 .../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts |   23 +
 arch/arm64/boot/dts/amlogic/meson-gxm.dtsi         |    3 +
 drivers/gpu/drm/meson/Kconfig                      |    6 +
 drivers/gpu/drm/meson/Makefile                     |    1 +
 drivers/gpu/drm/meson/meson_canvas.c               |    4 +-
 drivers/gpu/drm/meson/meson_crtc.c                 |   15 +-
 drivers/gpu/drm/meson/meson_drv.c                  |  118 +-
 drivers/gpu/drm/meson/meson_drv.h                  |    3 +
 drivers/gpu/drm/meson/meson_dw_hdmi.c              |  919 ++++++++++++++
 drivers/gpu/drm/meson/meson_dw_hdmi.h              |  146 +++
 drivers/gpu/drm/meson/meson_registers.h            |    1 +
 drivers/gpu/drm/meson/meson_vclk.c                 |  632 +++++++++-
 drivers/gpu/drm/meson/meson_vclk.h                 |    6 +-
 drivers/gpu/drm/meson/meson_venc.c                 | 1254 +++++++++++++++++++-
 drivers/gpu/drm/meson/meson_venc.h                 |    7 +
 drivers/gpu/drm/meson/meson_venc_cvbs.c            |   11 +-
 drivers/gpu/drm/meson/meson_viu.c                  |    6 +-
 drivers/gpu/drm/meson/meson_vpp.c                  |    8 +-
 drivers/gpu/drm/meson/meson_vpp.h                  |    2 +
 30 files changed, 3466 insertions(+), 47 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
 create mode 100644 Documentation/gpu/meson.rst
 create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.c
 create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.h

-- 
1.9.1

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

* [PATCH v2 01/13] drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable sync for vsync commit
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-04-04  8:49   ` Daniel Vetter
  2017-03-21 15:25 ` [PATCH v2 02/13] drm/meson: Add missing HDMI register Neil Armstrong
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

Clean the crtc_enable by using the proper crtc_state instead of the state
of the primary plane state data.

Also fix the dependency to commit the plane changes even if enable is called
after the flush.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_crtc.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
index 0fe49ec..c986eb0 100644
--- a/drivers/gpu/drm/meson/meson_crtc.c
+++ b/drivers/gpu/drm/meson/meson_crtc.c
@@ -82,11 +82,18 @@ static void meson_crtc_disable_vblank(struct drm_crtc *crtc)
 static void meson_crtc_enable(struct drm_crtc *crtc)
 {
 	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
-	struct drm_plane *plane = meson_crtc->priv->primary_plane;
+	struct drm_crtc_state *crtc_state = crtc->state;
 	struct meson_drm *priv = meson_crtc->priv;
 
+	DRM_DEBUG_DRIVER("\n");
+
+	if (!crtc_state) {
+		DRM_ERROR("Invalid crtc_state\n");
+		return;
+	}
+
 	/* Enable VPP Postblend */
-	writel(plane->state->crtc_w,
+	writel(crtc_state->mode.hdisplay,
 	       priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
 
 	writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
@@ -101,6 +108,7 @@ static void meson_crtc_disable(struct drm_crtc *crtc)
 	struct meson_drm *priv = meson_crtc->priv;
 
 	priv->viu.osd1_enabled = false;
+	priv->viu.osd1_commit = false;
 
 	/* Disable VPP Postblend */
 	writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
@@ -137,8 +145,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
 	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
 	struct meson_drm *priv = meson_crtc->priv;
 
-	if (priv->viu.osd1_enabled)
-		priv->viu.osd1_commit = true;
+	priv->viu.osd1_commit = true;
 }
 
 static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
-- 
1.9.1

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

* [PATCH v2 02/13] drm/meson: Add missing HDMI register
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 01/13] drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable sync for vsync commit Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 03/13] drm/meson: Add support for components Neil Armstrong
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

Add missing VPU HDMI register.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_registers.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/meson/meson_registers.h b/drivers/gpu/drm/meson/meson_registers.h
index 6adf9c1..2847381 100644
--- a/drivers/gpu/drm/meson/meson_registers.h
+++ b/drivers/gpu/drm/meson/meson_registers.h
@@ -1319,6 +1319,7 @@
 #define VPU_MISC_CTRL 0x2740
 #define VPU_ISP_GCLK_CTRL0 0x2741
 #define VPU_ISP_GCLK_CTRL1 0x2742
+#define VPU_HDMI_FMT_CTRL 0x2743
 #define VPU_VDIN_ASYNC_HOLD_CTRL 0x2743
 #define VPU_VDISP_ASYNC_HOLD_CTRL 0x2744
 #define VPU_VPUARB2_ASYNC_HOLD_CTRL 0x2745
-- 
1.9.1

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

* [PATCH v2 03/13] drm/meson: Add support for components
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 01/13] drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable sync for vsync commit Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 02/13] drm/meson: Add missing HDMI register Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-04-04  8:59   ` Daniel Vetter
  2017-03-21 15:25 ` [PATCH v2 04/13] drm/meson: venc_cvbs: no more return -ENODEV if CVBS is not available Neil Armstrong
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

This patch adds support for optional components connected through the
Device Tree endpoints scheme.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_drv.c | 113 +++++++++++++++++++++++++++++++++-----
 1 file changed, 99 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index bc562a0..a2e9f56 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -24,6 +24,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
+#include <linux/component.h>
 #include <linux/of_graph.h>
 
 #include <drm/drmP.h>
@@ -150,9 +151,9 @@ static bool meson_vpu_has_available_connectors(struct device *dev)
 	.max_register   = 0x1000,
 };
 
-static int meson_drv_probe(struct platform_device *pdev)
+static int meson_drv_bind(struct device *dev)
 {
-	struct device *dev = &pdev->dev;
+	struct platform_device *pdev = to_platform_device(dev);
 	struct meson_drm *priv;
 	struct drm_device *drm;
 	struct resource *res;
@@ -215,6 +216,15 @@ static int meson_drv_probe(struct platform_device *pdev)
 
 	drm_vblank_init(drm, 1);
 	drm_mode_config_init(drm);
+	drm->mode_config.max_width = 3840;
+	drm->mode_config.max_height = 2160;
+	drm->mode_config.funcs = &meson_mode_config_funcs;
+
+	/* Hardware Initialization */
+
+	meson_venc_init(priv);
+	meson_vpp_init(priv);
+	meson_viu_init(priv);
 
 	/* Encoder Initialization */
 
@@ -222,11 +232,11 @@ static int meson_drv_probe(struct platform_device *pdev)
 	if (ret)
 		goto free_drm;
 
-	/* Hardware Initialization */
-
-	meson_venc_init(priv);
-	meson_vpp_init(priv);
-	meson_viu_init(priv);
+	ret = component_bind_all(drm->dev, drm);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't bind all components\n");
+		goto free_drm;
+	}
 
 	ret = meson_plane_create(priv);
 	if (ret)
@@ -241,9 +251,6 @@ static int meson_drv_probe(struct platform_device *pdev)
 		goto free_drm;
 
 	drm_mode_config_reset(drm);
-	drm->mode_config.max_width = 8192;
-	drm->mode_config.max_height = 8192;
-	drm->mode_config.funcs = &meson_mode_config_funcs;
 
 	priv->fbdev = drm_fbdev_cma_init(drm, 32,
 					 drm->mode_config.num_connector);
@@ -268,9 +275,9 @@ static int meson_drv_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int meson_drv_remove(struct platform_device *pdev)
+static void meson_drv_unbind(struct device *dev)
 {
-	struct drm_device *drm = dev_get_drvdata(&pdev->dev);
+	struct drm_device *drm = dev_get_drvdata(dev);
 	struct meson_drm *priv = drm->dev_private;
 
 	drm_dev_unregister(drm);
@@ -280,9 +287,88 @@ static int meson_drv_remove(struct platform_device *pdev)
 	drm_vblank_cleanup(drm);
 	drm_dev_unref(drm);
 
-	return 0;
 }
 
+static const struct component_master_ops meson_drv_master_ops = {
+	.bind	= meson_drv_bind,
+	.unbind	= meson_drv_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+	DRM_DEBUG_DRIVER("Comparing of node %s with %s\n",
+			 of_node_full_name(dev->of_node),
+			 of_node_full_name(data));
+
+	return dev->of_node == data;
+}
+
+/* Possible connectors nodes to ignore */
+static const struct of_device_id connectors_match[] = {
+	{ .compatible = "composite-video-connector" },
+	{ .compatible = "svideo-connector" },
+	{ .compatible = "hdmi-connector" },
+	{ .compatible = "dvi-connector" },
+	{}
+};
+
+static int meson_probe_remote(struct platform_device *pdev,
+			      struct component_match **match,
+			      struct device_node *parent,
+			      struct device_node *remote)
+{
+	struct device_node *ep, *remote_node;
+	int count = 1;
+
+	/* If node is a connector, return and do not add to match table */
+	if (of_match_node(connectors_match, remote))
+		return 1;
+
+	component_match_add(&pdev->dev, match, compare_of, remote);
+
+	for_each_endpoint_of_node(remote, ep) {
+		remote_node = of_graph_get_remote_port_parent(ep);
+		if (!remote_node ||
+		    remote_node == parent || /* Ignore parent endpoint */
+		    !of_device_is_available(remote_node))
+			continue;
+
+		count += meson_probe_remote(pdev, match, remote, remote_node);
+
+		of_node_put(remote_node);
+	}
+
+	return count;
+}
+
+static int meson_drv_probe(struct platform_device *pdev)
+{
+	struct component_match *match = NULL;
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *ep, *remote;
+	int count = 0;
+
+	for_each_endpoint_of_node(np, ep) {
+		remote = of_graph_get_remote_port_parent(ep);
+		if (!remote || !of_device_is_available(remote))
+			continue;
+
+		count += meson_probe_remote(pdev, &match, np, remote);
+	}
+
+	/* If some endpoints were found, initialize the nodes */
+	if (count) {
+		dev_info(&pdev->dev, "Queued %d outputs on vpu\n", count);
+
+		return component_master_add_with_match(&pdev->dev,
+						       &meson_drv_master_ops,
+						       match);
+	}
+
+	/* If no output endpoints were available, simply bail out */
+	return 0;
+};
+
 static const struct of_device_id dt_match[] = {
 	{ .compatible = "amlogic,meson-gxbb-vpu" },
 	{ .compatible = "amlogic,meson-gxl-vpu" },
@@ -293,7 +379,6 @@ static int meson_drv_remove(struct platform_device *pdev)
 
 static struct platform_driver meson_drm_platform_driver = {
 	.probe      = meson_drv_probe,
-	.remove     = meson_drv_remove,
 	.driver     = {
 		.name	= "meson-drm",
 		.of_match_table = dt_match,
-- 
1.9.1

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

* [PATCH v2 04/13] drm/meson: venc_cvbs: no more return -ENODEV if CVBS is not available
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (2 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 03/13] drm/meson: Add support for components Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 05/13] drm/meson: add support for HDMI clock support Neil Armstrong
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

Since this is managed now by the components code, if CVBS is not available
and HDMI neither, the drm driver won't bind anyway.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_venc_cvbs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
index a2bcc70..a96fcb4 100644
--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
@@ -248,7 +248,7 @@ int meson_venc_cvbs_create(struct meson_drm *priv)
 
 	if (!meson_venc_cvbs_connector_is_available(priv)) {
 		dev_info(drm->dev, "CVBS Output connector not available\n");
-		return -ENODEV;
+		return 0;
 	}
 
 	meson_venc_cvbs = devm_kzalloc(priv->dev, sizeof(*meson_venc_cvbs),
-- 
1.9.1

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

* [PATCH v2 05/13] drm/meson: add support for HDMI clock support
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (3 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 04/13] drm/meson: venc_cvbs: no more return -ENODEV if CVBS is not available Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 06/13] drm/meson: Add support for HDMI venc modes and settings Neil Armstrong
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

This patchs adds support for the supported HDMI modes clocks frequencies.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_vclk.c      | 624 +++++++++++++++++++++++++++++++-
 drivers/gpu/drm/meson/meson_vclk.h      |   6 +-
 drivers/gpu/drm/meson/meson_venc_cvbs.c |   9 +-
 3 files changed, 623 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
index 252cfd4..3731479 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -27,9 +27,26 @@
  * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL.
  * We handle the following encodings :
  * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks
- *
- * What is missing :
  * - HDMI Pixel Clocks generation
+ * What is missing :
+ * - Genenate Pixel clocks for 2K/4K 10bit formats
+ *
+ * Clock generator scheme :
+ *  __________   _________            _____
+ * |          | |         |          |     |--ENCI
+ * | HDMI PLL |-| PLL_DIV |--- VCLK--|     |--ENCL
+ * |__________| |_________| \        | MUX |--ENCP
+ *                           --VCLK2-|     |--VDAC
+ *                                   |_____|--HDMI-TX
+ *
+ * Final clocks can take input for either VCLK or VCLK2, but
+ * VCLK is the preferred path for HDMI clocking and VCLK2 is the
+ * preferred path for CVBS VDAC clocking.
+ *
+ * VCLK and VCLK2 have fixed divided clocks paths for /1, /2, /4, /6 or /12.
+ *
+ * The PLL_DIV can achieve an additional fractional dividing like
+ * 1.5, 3.5, 3.75... to generate special 2K and 4K 10bit clocks.
  */
 
 /* HHI Registers */
@@ -50,11 +67,34 @@
 #define VCLK2_SOFT_RESET	BIT(15)
 #define VCLK2_DIV1_EN		BIT(0)
 #define HHI_VID_CLK_DIV		0x164 /* 0x59 offset in data sheet */
+#define VCLK_DIV_MASK		0xff
+#define VCLK_DIV_EN		BIT(16)
+#define VCLK_DIV_RESET		BIT(17)
+#define CTS_ENCP_SEL_MASK	(0xf << 24)
+#define CTS_ENCP_SEL_SHIFT	24
 #define CTS_ENCI_SEL_MASK	(0xf << 28)
 #define CTS_ENCI_SEL_SHIFT	28
+#define HHI_VID_CLK_CNTL	0x17c /* 0x5f offset in data sheet */
+#define VCLK_EN			BIT(19)
+#define VCLK_SEL_MASK		(0x7 << 16)
+#define VCLK_SEL_SHIFT		16
+#define VCLK_SOFT_RESET		BIT(15)
+#define VCLK_DIV1_EN		BIT(0)
+#define VCLK_DIV2_EN		BIT(1)
+#define VCLK_DIV4_EN		BIT(2)
+#define VCLK_DIV6_EN		BIT(3)
+#define VCLK_DIV12_EN		BIT(4)
 #define HHI_VID_CLK_CNTL2	0x194 /* 0x65 offset in data sheet */
 #define CTS_ENCI_EN		BIT(0)
+#define CTS_ENCP_EN		BIT(2)
 #define CTS_VDAC_EN		BIT(4)
+#define HDMI_TX_PIXEL_EN	BIT(5)
+#define HHI_HDMI_CLK_CNTL	0x1cc /* 0x73 offset in data sheet */
+#define HDMI_TX_PIXEL_SEL_MASK	(0xf << 16)
+#define HDMI_TX_PIXEL_SEL_SHIFT	16
+#define CTS_HDMI_SYS_SEL_MASK	(0x7 << 9)
+#define CTS_HDMI_SYS_DIV_MASK	(0x7f)
+#define CTS_HDMI_SYS_EN		BIT(8)
 
 #define HHI_VDAC_CNTL0		0x2F4 /* 0xbd offset in data sheet */
 #define HHI_VDAC_CNTL1		0x2F8 /* 0xbe offset in data sheet */
@@ -69,6 +109,126 @@
 #define HDMI_PLL_RESET		BIT(28)
 #define HDMI_PLL_LOCK		BIT(31)
 
+/* VID PLL Dividers */
+enum {
+	VID_PLL_DIV_1 = 0,
+	VID_PLL_DIV_2,
+	VID_PLL_DIV_2p5,
+	VID_PLL_DIV_3,
+	VID_PLL_DIV_3p5,
+	VID_PLL_DIV_3p75,
+	VID_PLL_DIV_4,
+	VID_PLL_DIV_5,
+	VID_PLL_DIV_6,
+	VID_PLL_DIV_6p25,
+	VID_PLL_DIV_7,
+	VID_PLL_DIV_7p5,
+	VID_PLL_DIV_12,
+	VID_PLL_DIV_14,
+	VID_PLL_DIV_15,
+};
+
+void meson_vid_pll_set(struct meson_drm *priv, unsigned int div)
+{
+	unsigned int shift_val = 0;
+	unsigned int shift_sel = 0;
+
+	/* Disable vid_pll output clock */
+	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
+	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
+
+	switch (div) {
+	case VID_PLL_DIV_2:
+		shift_val = 0x0aaa;
+		shift_sel = 0;
+		break;
+	case VID_PLL_DIV_2p5:
+		shift_val = 0x5294;
+		shift_sel = 2;
+		break;
+	case VID_PLL_DIV_3:
+		shift_val = 0x0db6;
+		shift_sel = 0;
+		break;
+	case VID_PLL_DIV_3p5:
+		shift_val = 0x36cc;
+		shift_sel = 1;
+		break;
+	case VID_PLL_DIV_3p75:
+		shift_val = 0x6666;
+		shift_sel = 2;
+		break;
+	case VID_PLL_DIV_4:
+		shift_val = 0x0ccc;
+		shift_sel = 0;
+		break;
+	case VID_PLL_DIV_5:
+		shift_val = 0x739c;
+		shift_sel = 2;
+		break;
+	case VID_PLL_DIV_6:
+		shift_val = 0x0e38;
+		shift_sel = 0;
+		break;
+	case VID_PLL_DIV_6p25:
+		shift_val = 0x0000;
+		shift_sel = 3;
+		break;
+	case VID_PLL_DIV_7:
+		shift_val = 0x3c78;
+		shift_sel = 1;
+		break;
+	case VID_PLL_DIV_7p5:
+		shift_val = 0x78f0;
+		shift_sel = 2;
+		break;
+	case VID_PLL_DIV_12:
+		shift_val = 0x0fc0;
+		shift_sel = 0;
+		break;
+	case VID_PLL_DIV_14:
+		shift_val = 0x3f80;
+		shift_sel = 1;
+		break;
+	case VID_PLL_DIV_15:
+		shift_val = 0x7f80;
+		shift_sel = 2;
+		break;
+	}
+
+	if (div == VID_PLL_DIV_1)
+		/* Enable vid_pll bypass to HDMI pll */
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   VID_PLL_BYPASS, VID_PLL_BYPASS);
+	else {
+		/* Disable Bypass */
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   VID_PLL_BYPASS, 0);
+		/* Clear sel */
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   3 << 16, 0);
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   VID_PLL_PRESET, 0);
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   0x7fff, 0);
+
+		/* Setup sel and val */
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   3 << 16, shift_sel << 16);
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   VID_PLL_PRESET, VID_PLL_PRESET);
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   0x7fff, shift_val);
+
+		regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				   VID_PLL_PRESET, 0);
+	}
+
+	/* Enable the vid_pll output clock */
+	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
+				VID_PLL_EN, VID_PLL_EN);
+}
+
 /*
  * Setup VCLK2 for 27MHz, and enable clocks for ENCI and VDAC
  *
@@ -110,15 +270,8 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
 	/* Disable VCLK2 */
 	regmap_update_bits(priv->hhi, HHI_VIID_CLK_CNTL, VCLK2_EN, 0);
 
-	/* Disable vid_pll output clock */
-	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_EN, 0);
-	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV, VID_PLL_PRESET, 0);
-	/* Enable vid_pll bypass to HDMI pll */
-	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-				VID_PLL_BYPASS, VID_PLL_BYPASS);
-	/* Enable the vid_pll output clock */
-	regmap_update_bits(priv->hhi, HHI_VID_PLL_CLK_DIV,
-				VID_PLL_EN, VID_PLL_EN);
+	/* Setup vid_pll to /1 */
+	meson_vid_pll_set(priv, VID_PLL_DIV_1);
 
 	/* Setup the VCLK2 divider value to achieve 27MHz */
 	regmap_update_bits(priv->hhi, HHI_VIID_CLK_DIV,
@@ -159,9 +312,454 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
 				CTS_VDAC_EN, CTS_VDAC_EN);
 }
 
+
+/* PLL	O1 O2 O3 VP DV     EN TX */
+/* 4320 /4 /4 /1 /5 /1  => /2 /2 */
+#define MESON_VCLK_HDMI_ENCI_54000	1
+/* 4320 /4 /4 /1 /5 /1  => /1 /2 */
+#define MESON_VCLK_HDMI_DDR_54000	2
+/* 2970 /4 /1 /1 /5 /1  => /1 /2 */
+#define MESON_VCLK_HDMI_DDR_148500	3
+/* 2970 /2 /2 /2 /5 /1  => /1 /1 */
+#define MESON_VCLK_HDMI_74250		4
+/* 2970 /1 /2 /2 /5 /1  => /1 /1 */
+#define MESON_VCLK_HDMI_148500		5
+/* 2970 /1 /1 /1 /5 /2  => /1 /1 */
+#define MESON_VCLK_HDMI_297000		6
+/* 5940 /1 /1 /2 /5 /1  => /1 /1 */
+#define MESON_VCLK_HDMI_594000		7
+
+struct meson_vclk_params {
+	unsigned int pll_base_freq;
+	unsigned int pll_od1;
+	unsigned int pll_od2;
+	unsigned int pll_od3;
+	unsigned int vid_pll_div;
+	unsigned int vclk_div;
+} params[] = {
+	[MESON_VCLK_HDMI_ENCI_54000] = {
+		.pll_base_freq = 4320000,
+		.pll_od1 = 4,
+		.pll_od2 = 4,
+		.pll_od3 = 1,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 1,
+	},
+	[MESON_VCLK_HDMI_DDR_54000] = {
+		.pll_base_freq = 4320000,
+		.pll_od1 = 4,
+		.pll_od2 = 4,
+		.pll_od3 = 1,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 1,
+	},
+	[MESON_VCLK_HDMI_DDR_148500] = {
+		.pll_base_freq = 2970000,
+		.pll_od1 = 4,
+		.pll_od2 = 1,
+		.pll_od3 = 1,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 1,
+	},
+	[MESON_VCLK_HDMI_74250] = {
+		.pll_base_freq = 2970000,
+		.pll_od1 = 2,
+		.pll_od2 = 2,
+		.pll_od3 = 2,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 1,
+	},
+	[MESON_VCLK_HDMI_148500] = {
+		.pll_base_freq = 2970000,
+		.pll_od1 = 1,
+		.pll_od2 = 2,
+		.pll_od3 = 2,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 1,
+	},
+	[MESON_VCLK_HDMI_297000] = {
+		.pll_base_freq = 2970000,
+		.pll_od1 = 1,
+		.pll_od2 = 1,
+		.pll_od3 = 1,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 2,
+	},
+	[MESON_VCLK_HDMI_594000] = {
+		.pll_base_freq = 5940000,
+		.pll_od1 = 1,
+		.pll_od2 = 1,
+		.pll_od3 = 2,
+		.vid_pll_div = VID_PLL_DIV_5,
+		.vclk_div = 1,
+	},
+};
+
+static inline unsigned int pll_od_to_reg(unsigned int od)
+{
+	switch (od) {
+	case 1:
+		return 0;
+	case 2:
+		return 1;
+	case 4:
+		return 2;
+	case 8:
+		return 3;
+	}
+
+	/* Invalid */
+	return 0;
+}
+
+void meson_hdmi_pll_set(struct meson_drm *priv,
+			unsigned int base,
+			unsigned int od1,
+			unsigned int od2,
+			unsigned int od3)
+{
+	unsigned int val;
+
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
+		switch (base) {
+		case 2970000:
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800023d);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+			/* Enable and unreset */
+			regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+						0x7 << 28, 0x4 << 28);
+
+			/* Poll for lock bit */
+			regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+					val, (val & HDMI_PLL_LOCK), 10, 0);
+
+			/* div_frac */
+			regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+						0xFFFF,  0x4e00);
+			break;
+
+		case 4320000:
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800025a);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x00000000);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x0d5c5091);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+			/* unreset */
+			regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+						BIT(28), 0);
+
+			/* Poll for lock bit */
+			regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+					val, (val & HDMI_PLL_LOCK), 10, 0);
+			break;
+
+		case 5940000:
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x5800027b);
+			regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+						0xFFFF,  0x4c00);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x135c5091);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x801da72c);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x71486980);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x00000e55);
+
+			/* unreset */
+			regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+						BIT(28), 0);
+
+			/* Poll for lock bit */
+			regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL,
+					val, (val & HDMI_PLL_LOCK), 10, 0);
+			break;
+		};
+	} else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+		   meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
+		switch (base) {
+		case 2970000:
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x4000027b);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb300);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+			break;
+
+		case 4320000:
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002b4);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb000);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+			break;
+
+		case 5940000:
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL, 0x400002f7);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL2, 0x800cb200);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL3, 0x860f30c4);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL4, 0x0c8e0000);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL5, 0x001fa729);
+			regmap_write(priv->hhi, HHI_HDMI_PLL_CNTL6, 0x01a31500);
+			break;
+
+		};
+
+		/* Reset PLL */
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+					HDMI_PLL_RESET, HDMI_PLL_RESET);
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL,
+					HDMI_PLL_RESET, 0);
+
+		/* Poll for lock bit */
+		regmap_read_poll_timeout(priv->hhi, HHI_HDMI_PLL_CNTL, val,
+				(val & HDMI_PLL_LOCK), 10, 0);
+	};
+
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+				   3 << 16, pll_od_to_reg(od1) << 16);
+	else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+		 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
+				   3 << 21, pll_od_to_reg(od1) << 21);
+
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+				   3 << 22, pll_od_to_reg(od2) << 22);
+	else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+		 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
+				   3 << 23, pll_od_to_reg(od2) << 23);
+
+	if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu"))
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL2,
+				   3 << 18, pll_od_to_reg(od3) << 18);
+	else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
+		 meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu"))
+		regmap_update_bits(priv->hhi, HHI_HDMI_PLL_CNTL3,
+				   3 << 19, pll_od_to_reg(od3) << 19);
+}
+
 void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
-		      unsigned int freq)
+		      unsigned int vclk_freq, unsigned int venc_freq,
+		      unsigned int dac_freq, bool hdmi_use_enci)
 {
-	if (target == MESON_VCLK_TARGET_CVBS && freq == MESON_VCLK_CVBS)
+	unsigned int freq;
+	unsigned int hdmi_tx_div;
+	unsigned int venc_div;
+
+	if (target == MESON_VCLK_TARGET_CVBS) {
 		meson_venci_cvbs_clock_config(priv);
+		return;
+	}
+
+	hdmi_tx_div = vclk_freq / dac_freq;
+
+	if (hdmi_tx_div == 0) {
+		pr_err("Fatal Error, invalid HDMI-TX freq %d\n",
+				dac_freq);
+		return;
+	}
+
+	venc_div = vclk_freq / venc_freq;
+
+	if (venc_div == 0) {
+		pr_err("Fatal Error, invalid HDMI venc freq %d\n",
+				venc_freq);
+		return;
+	}
+
+	switch (vclk_freq) {
+	case 54000:
+		if (hdmi_use_enci)
+			freq = MESON_VCLK_HDMI_ENCI_54000;
+		else
+			freq = MESON_VCLK_HDMI_DDR_54000;
+		break;
+	case 74250:
+		freq = MESON_VCLK_HDMI_74250;
+		break;
+	case 148500:
+		if (dac_freq != 148500)
+			freq = MESON_VCLK_HDMI_DDR_148500;
+		else
+			freq = MESON_VCLK_HDMI_148500;
+		break;
+	case 297000:
+		freq = MESON_VCLK_HDMI_297000;
+		break;
+	case 594000:
+		freq = MESON_VCLK_HDMI_594000;
+		break;
+	default:
+		pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
+			vclk_freq);
+		return;
+	}
+
+	/* Set HDMI-TX sys clock */
+	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+			   CTS_HDMI_SYS_SEL_MASK, 0);
+	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+			   CTS_HDMI_SYS_DIV_MASK, 0);
+	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+			   CTS_HDMI_SYS_EN, CTS_HDMI_SYS_EN);
+
+	/* Set HDMI PLL rate */
+	meson_hdmi_pll_set(priv, params[freq].pll_base_freq,
+			   params[freq].pll_od1,
+			   params[freq].pll_od2,
+			   params[freq].pll_od3);
+
+	/* Setup vid_pll divider */
+	meson_vid_pll_set(priv, params[freq].vid_pll_div);
+
+	/* Set VCLK div */
+	regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+			   VCLK_SEL_MASK, 0);
+	regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+			   VCLK_DIV_MASK, params[freq].vclk_div - 1);
+
+	/* Set HDMI-TX source */
+	switch (hdmi_tx_div) {
+	case 1:
+		/* enable vclk_div1 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV1_EN, VCLK_DIV1_EN);
+
+		/* select vclk_div1 for HDMI-TX */
+		regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+				   HDMI_TX_PIXEL_SEL_MASK, 0);
+		break;
+	case 2:
+		/* enable vclk_div2 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV2_EN, VCLK_DIV2_EN);
+
+		/* select vclk_div2 for HDMI-TX */
+		regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+			HDMI_TX_PIXEL_SEL_MASK, 1 << HDMI_TX_PIXEL_SEL_SHIFT);
+		break;
+	case 4:
+		/* enable vclk_div4 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV4_EN, VCLK_DIV4_EN);
+
+		/* select vclk_div4 for HDMI-TX */
+		regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+			HDMI_TX_PIXEL_SEL_MASK, 2 << HDMI_TX_PIXEL_SEL_SHIFT);
+		break;
+	case 6:
+		/* enable vclk_div6 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV6_EN, VCLK_DIV6_EN);
+
+		/* select vclk_div6 for HDMI-TX */
+		regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+			HDMI_TX_PIXEL_SEL_MASK, 3 << HDMI_TX_PIXEL_SEL_SHIFT);
+		break;
+	case 12:
+		/* enable vclk_div12 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV12_EN, VCLK_DIV12_EN);
+
+		/* select vclk_div12 for HDMI-TX */
+		regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
+			HDMI_TX_PIXEL_SEL_MASK, 4 << HDMI_TX_PIXEL_SEL_SHIFT);
+		break;
+	}
+	regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+				   HDMI_TX_PIXEL_EN, HDMI_TX_PIXEL_EN);
+
+	/* Set ENCI/ENCP Source */
+	switch (venc_div) {
+	case 1:
+		/* enable vclk_div1 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV1_EN, VCLK_DIV1_EN);
+
+		if (hdmi_use_enci)
+			/* select vclk_div1 for enci */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+					   CTS_ENCI_SEL_MASK, 0);
+		else
+			/* select vclk_div1 for encp */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+					   CTS_ENCP_SEL_MASK, 0);
+		break;
+	case 2:
+		/* enable vclk_div2 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV2_EN, VCLK_DIV2_EN);
+
+		if (hdmi_use_enci)
+			/* select vclk_div2 for enci */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCI_SEL_MASK, 1 << CTS_ENCI_SEL_SHIFT);
+		else
+			/* select vclk_div2 for encp */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCP_SEL_MASK, 1 << CTS_ENCP_SEL_SHIFT);
+		break;
+	case 4:
+		/* enable vclk_div4 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV4_EN, VCLK_DIV4_EN);
+
+		if (hdmi_use_enci)
+			/* select vclk_div4 for enci */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCI_SEL_MASK, 2 << CTS_ENCI_SEL_SHIFT);
+		else
+			/* select vclk_div4 for encp */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCP_SEL_MASK, 2 << CTS_ENCP_SEL_SHIFT);
+		break;
+	case 6:
+		/* enable vclk_div6 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV6_EN, VCLK_DIV6_EN);
+
+		if (hdmi_use_enci)
+			/* select vclk_div6 for enci */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCI_SEL_MASK, 3 << CTS_ENCI_SEL_SHIFT);
+		else
+			/* select vclk_div6 for encp */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCP_SEL_MASK, 3 << CTS_ENCP_SEL_SHIFT);
+		break;
+	case 12:
+		/* enable vclk_div12 gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL,
+				   VCLK_DIV12_EN, VCLK_DIV12_EN);
+
+		if (hdmi_use_enci)
+			/* select vclk_div12 for enci */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCI_SEL_MASK, 4 << CTS_ENCI_SEL_SHIFT);
+		else
+			/* select vclk_div12 for encp */
+			regmap_update_bits(priv->hhi, HHI_VID_CLK_DIV,
+				CTS_ENCP_SEL_MASK, 4 << CTS_ENCP_SEL_SHIFT);
+		break;
+	}
+
+	if (hdmi_use_enci)
+		/* Enable ENCI clock gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+				   CTS_ENCI_EN, CTS_ENCI_EN);
+	else
+		/* Enable ENCP clock gate */
+		regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL2,
+				   CTS_ENCP_EN, CTS_ENCP_EN);
+
+	regmap_update_bits(priv->hhi, HHI_VID_CLK_CNTL, VCLK_EN, VCLK_EN);
 }
+EXPORT_SYMBOL_GPL(meson_vclk_setup);
diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
index ec62735..0401b52 100644
--- a/drivers/gpu/drm/meson/meson_vclk.h
+++ b/drivers/gpu/drm/meson/meson_vclk.h
@@ -23,12 +23,14 @@
 
 enum {
 	MESON_VCLK_TARGET_CVBS = 0,
+	MESON_VCLK_TARGET_HDMI = 1,
 };
 
 /* 27MHz is the CVBS Pixel Clock */
-#define MESON_VCLK_CVBS	27000
+#define MESON_VCLK_CVBS			27000
 
 void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
-		      unsigned int freq);
+		      unsigned int vclk_freq, unsigned int venc_freq,
+		      unsigned int dac_freq, bool hdmi_use_enci);
 
 #endif /* __MESON_VCLK_H */
diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c
index a96fcb4..5d4f19a 100644
--- a/drivers/gpu/drm/meson/meson_venc_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c
@@ -32,6 +32,7 @@
 
 #include "meson_venc_cvbs.h"
 #include "meson_venc.h"
+#include "meson_vclk.h"
 #include "meson_registers.h"
 
 /* HHI VDAC Registers */
@@ -194,14 +195,20 @@ static void meson_venc_cvbs_encoder_mode_set(struct drm_encoder *encoder,
 {
 	struct meson_venc_cvbs *meson_venc_cvbs =
 					encoder_to_meson_venc_cvbs(encoder);
+	struct meson_drm *priv = meson_venc_cvbs->priv;
 	int i;
 
 	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
 		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
 
 		if (drm_mode_equal(mode, &meson_mode->mode)) {
-			meson_venci_cvbs_mode_set(meson_venc_cvbs->priv,
+			meson_venci_cvbs_mode_set(priv,
 						  meson_mode->enci);
+
+			/* Setup 27MHz vclk2 for ENCI and VDAC */
+			meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
+					 MESON_VCLK_CVBS, MESON_VCLK_CVBS,
+					 MESON_VCLK_CVBS, true);
 			break;
 		}
 	}
-- 
1.9.1

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

* [PATCH v2 06/13] drm/meson: Add support for HDMI venc modes and settings
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (4 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 05/13] drm/meson: add support for HDMI clock support Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 07/13] drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY Neil Armstrong
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

This patch adds support for the supported HDMI Venc modes and add the VPP mux
value to switch to ENCP encoder.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_venc.c | 1245 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/meson/meson_venc.h |    7 +
 drivers/gpu/drm/meson/meson_vpp.h  |    2 +
 3 files changed, 1249 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index f7c87017..31dc275 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -30,12 +30,37 @@
  * VENC Handle the pixels encoding to the output formats.
  * We handle the following encodings :
  * - CVBS Encoding via the ENCI encoder and VDAC digital to analog converter
- *
- * What is missing :
  * - TMDS/HDMI Encoding via ENCI_DIV and ENCP
  * - Setup of more clock rates for HDMI modes
+ *
+ * What is missing :
  * - LCD Panel encoding via ENCL
  * - TV Panel encoding via ENCT
+ *
+ * VENC paths :
+ *        _____   _____   ____________________
+ * vd1---|     |-|     | | VENC     /---------|----VDAC
+ * vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|\
+ * osd1--|     |-|     | | \                  | X--HDMI-TX
+ * osd2--|_____|-|_____| |  |\-ENCP--ENCP_DVI-|/
+ *                       |  |                 |
+ *                       |  \--ENCL-----------|----LVDS
+ *                       |____________________|
+ *
+ * The ENCI is designed for PAl or NTSC encoding and can go through the VDAC
+ * directly for CVBS encoding or through the ENCI_DVI encoder for HDMI.
+ * The ENCP is designed for Progressive encoding but can also generate
+ * 1080i interlaced pixels, and was initialy desined to encode pixels for
+ * VDAC to output RGB ou YUV analog outputs.
+ * It's output is only used through the ENCP_DVI encoder for HDMI.
+ * The ENCL LVDS encoder is not implemented.
+ *
+ * The ENCI and ENCP encoders needs specially defined parameters for each
+ * supported mode and thus cannot be determined from standard video timings.
+ *
+ * The ENCI end ENCP DVI encoders are more generic and can generate any timings
+ * from the pixel data generated by ENCI or ENCP, so can use the standard video
+ * timings are source for HW parameters.
  */
 
 /* HHI Registers */
@@ -91,6 +116,1219 @@ struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc = {
 	.analog_sync_adj = 0x9c00,
 };
 
+union meson_hdmi_venc_mode {
+	struct {
+		unsigned int mode_tag;
+		unsigned int hso_begin;
+		unsigned int hso_end;
+		unsigned int vso_even;
+		unsigned int vso_odd;
+		unsigned int macv_max_amp;
+		unsigned int video_prog_mode;
+		unsigned int video_mode;
+		unsigned int sch_adjust;
+		unsigned int yc_delay;
+		unsigned int pixel_start;
+		unsigned int pixel_end;
+		unsigned int top_field_line_start;
+		unsigned int top_field_line_end;
+		unsigned int bottom_field_line_start;
+		unsigned int bottom_field_line_end;
+	} enci;
+	struct {
+		unsigned int dvi_settings;
+		unsigned int video_mode;
+		unsigned int video_mode_adv;
+		unsigned int video_prog_mode;
+		bool video_prog_mode_present;
+		unsigned int video_sync_mode;
+		bool video_sync_mode_present;
+		unsigned int video_yc_dly;
+		bool video_yc_dly_present;
+		unsigned int video_rgb_ctrl;
+		bool video_rgb_ctrl_present;
+		unsigned int video_filt_ctrl;
+		bool video_filt_ctrl_present;
+		unsigned int video_ofld_voav_ofst;
+		bool video_ofld_voav_ofst_present;
+		unsigned int yfp1_htime;
+		unsigned int yfp2_htime;
+		unsigned int max_pxcnt;
+		unsigned int hspuls_begin;
+		unsigned int hspuls_end;
+		unsigned int hspuls_switch;
+		unsigned int vspuls_begin;
+		unsigned int vspuls_end;
+		unsigned int vspuls_bline;
+		unsigned int vspuls_eline;
+		unsigned int eqpuls_begin;
+		bool eqpuls_begin_present;
+		unsigned int eqpuls_end;
+		bool eqpuls_end_present;
+		unsigned int eqpuls_bline;
+		bool eqpuls_bline_present;
+		unsigned int eqpuls_eline;
+		bool eqpuls_eline_present;
+		unsigned int havon_begin;
+		unsigned int havon_end;
+		unsigned int vavon_bline;
+		unsigned int vavon_eline;
+		unsigned int hso_begin;
+		unsigned int hso_end;
+		unsigned int vso_begin;
+		unsigned int vso_end;
+		unsigned int vso_bline;
+		unsigned int vso_eline;
+		bool vso_eline_present;
+		unsigned int sy_val;
+		bool sy_val_present;
+		unsigned int sy2_val;
+		bool sy2_val_present;
+		unsigned int max_lncnt;
+	} encp;
+};
+
+union meson_hdmi_venc_mode meson_hdmi_enci_mode_480i = {
+	.enci = {
+		.hso_begin = 5,
+		.hso_end = 129,
+		.vso_even = 3,
+		.vso_odd = 260,
+		.macv_max_amp = 0x810b,
+		.video_prog_mode = 0xf0,
+		.video_mode = 0x8,
+		.sch_adjust = 0x20,
+		.yc_delay = 0,
+		.pixel_start = 227,
+		.pixel_end = 1667,
+		.top_field_line_start = 18,
+		.top_field_line_end = 258,
+		.bottom_field_line_start = 19,
+		.bottom_field_line_end = 259,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_enci_mode_576i = {
+	.enci = {
+		.hso_begin = 3,
+		.hso_end = 129,
+		.vso_even = 3,
+		.vso_odd = 260,
+		.macv_max_amp = 8107,
+		.video_prog_mode = 0xff,
+		.video_mode = 0x13,
+		.sch_adjust = 0x28,
+		.yc_delay = 0x333,
+		.pixel_start = 251,
+		.pixel_end = 1691,
+		.top_field_line_start = 22,
+		.top_field_line_end = 310,
+		.bottom_field_line_start = 23,
+		.bottom_field_line_end = 311,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_480p = {
+	.encp = {
+		.dvi_settings = 0x21,
+		.video_mode = 0x4000,
+		.video_mode_adv = 0x9,
+		.video_prog_mode = 0,
+		.video_prog_mode_present = true,
+		.video_sync_mode = 7,
+		.video_sync_mode_present = true,
+		/* video_yc_dly */
+		/* video_rgb_ctrl */
+		.video_filt_ctrl = 0x2052,
+		.video_filt_ctrl_present = true,
+		/* video_ofld_voav_ofst */
+		.yfp1_htime = 244,
+		.yfp2_htime = 1630,
+		.max_pxcnt = 1715,
+		.hspuls_begin = 0x22,
+		.hspuls_end = 0xa0,
+		.hspuls_switch = 88,
+		.vspuls_begin = 0,
+		.vspuls_end = 1589,
+		.vspuls_bline = 0,
+		.vspuls_eline = 5,
+		.havon_begin = 249,
+		.havon_end = 1689,
+		.vavon_bline = 42,
+		.vavon_eline = 521,
+		/* eqpuls_begin */
+		/* eqpuls_end */
+		/* eqpuls_bline */
+		/* eqpuls_eline */
+		.hso_begin = 3,
+		.hso_end = 5,
+		.vso_begin = 3,
+		.vso_end = 5,
+		.vso_bline = 0,
+		/* vso_eline */
+		.sy_val	= 8,
+		.sy_val_present = true,
+		.sy2_val = 0x1d8,
+		.sy2_val_present = true,
+		.max_lncnt = 524,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_576p = {
+	.encp = {
+		.dvi_settings = 0x21,
+		.video_mode = 0x4000,
+		.video_mode_adv = 0x9,
+		.video_prog_mode = 0,
+		.video_prog_mode_present = true,
+		.video_sync_mode = 7,
+		.video_sync_mode_present = true,
+		/* video_yc_dly */
+		/* video_rgb_ctrl */
+		.video_filt_ctrl = 0x52,
+		.video_filt_ctrl_present = true,
+		/* video_ofld_voav_ofst */
+		.yfp1_htime = 235,
+		.yfp2_htime = 1674,
+		.max_pxcnt = 1727,
+		.hspuls_begin = 0,
+		.hspuls_end = 0x80,
+		.hspuls_switch = 88,
+		.vspuls_begin = 0,
+		.vspuls_end = 1599,
+		.vspuls_bline = 0,
+		.vspuls_eline = 4,
+		.havon_begin = 235,
+		.havon_end = 1674,
+		.vavon_bline = 44,
+		.vavon_eline = 619,
+		/* eqpuls_begin */
+		/* eqpuls_end */
+		/* eqpuls_bline */
+		/* eqpuls_eline */
+		.hso_begin = 0x80,
+		.hso_end = 0,
+		.vso_begin = 0,
+		.vso_end = 5,
+		.vso_bline = 0,
+		/* vso_eline */
+		.sy_val	= 8,
+		.sy_val_present = true,
+		.sy2_val = 0x1d8,
+		.sy2_val_present = true,
+		.max_lncnt = 624,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p60 = {
+	.encp = {
+		.dvi_settings = 0x2029,
+		.video_mode = 0x4040,
+		.video_mode_adv = 0x19,
+		/* video_prog_mode */
+		/* video_sync_mode */
+		/* video_yc_dly */
+		/* video_rgb_ctrl */
+		/* video_filt_ctrl */
+		/* video_ofld_voav_ofst */
+		.yfp1_htime = 648,
+		.yfp2_htime = 3207,
+		.max_pxcnt = 3299,
+		.hspuls_begin = 80,
+		.hspuls_end = 240,
+		.hspuls_switch = 80,
+		.vspuls_begin = 688,
+		.vspuls_end = 3248,
+		.vspuls_bline = 4,
+		.vspuls_eline = 8,
+		.havon_begin = 648,
+		.havon_end = 3207,
+		.vavon_bline = 29,
+		.vavon_eline = 748,
+		/* eqpuls_begin */
+		/* eqpuls_end */
+		/* eqpuls_bline */
+		/* eqpuls_eline */
+		.hso_begin = 256,
+		.hso_end = 168,
+		.vso_begin = 168,
+		.vso_end = 256,
+		.vso_bline = 0,
+		.vso_eline = 5,
+		.vso_eline_present = true,
+		/* sy_val */
+		/* sy2_val */
+		.max_lncnt = 749,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_720p50 = {
+	.encp = {
+		.dvi_settings = 0x202d,
+		.video_mode = 0x4040,
+		.video_mode_adv = 0x19,
+		.video_prog_mode = 0x100,
+		.video_prog_mode_present = true,
+		.video_sync_mode = 0x407,
+		.video_sync_mode_present = true,
+		.video_yc_dly = 0,
+		.video_yc_dly_present = true,
+		/* video_rgb_ctrl */
+		/* video_filt_ctrl */
+		/* video_ofld_voav_ofst */
+		.yfp1_htime = 648,
+		.yfp2_htime = 3207,
+		.max_pxcnt = 3959,
+		.hspuls_begin = 80,
+		.hspuls_end = 240,
+		.hspuls_switch = 80,
+		.vspuls_begin = 688,
+		.vspuls_end = 3248,
+		.vspuls_bline = 4,
+		.vspuls_eline = 8,
+		.havon_begin = 648,
+		.havon_end = 3207,
+		.vavon_bline = 29,
+		.vavon_eline = 748,
+		/* eqpuls_begin */
+		/* eqpuls_end */
+		/* eqpuls_bline */
+		/* eqpuls_eline */
+		.hso_begin = 128,
+		.hso_end = 208,
+		.vso_begin = 128,
+		.vso_end = 128,
+		.vso_bline = 0,
+		.vso_eline = 5,
+		.vso_eline_present = true,
+		/* sy_val */
+		/* sy2_val */
+		.max_lncnt = 749,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i60 = {
+	.encp = {
+		.dvi_settings = 0x2029,
+		.video_mode = 0x5ffc,
+		.video_mode_adv = 0x19,
+		.video_prog_mode = 0x100,
+		.video_prog_mode_present = true,
+		.video_sync_mode = 0x207,
+		.video_sync_mode_present = true,
+		/* video_yc_dly */
+		/* video_rgb_ctrl */
+		/* video_filt_ctrl */
+		.video_ofld_voav_ofst = 0x11,
+		.video_ofld_voav_ofst_present = true,
+		.yfp1_htime = 516,
+		.yfp2_htime = 4355,
+		.max_pxcnt = 4399,
+		.hspuls_begin = 88,
+		.hspuls_end = 264,
+		.hspuls_switch = 88,
+		.vspuls_begin = 440,
+		.vspuls_end = 2200,
+		.vspuls_bline = 0,
+		.vspuls_eline = 4,
+		.havon_begin = 516,
+		.havon_end = 4355,
+		.vavon_bline = 20,
+		.vavon_eline = 559,
+		.eqpuls_begin = 2288,
+		.eqpuls_begin_present = true,
+		.eqpuls_end = 2464,
+		.eqpuls_end_present = true,
+		.eqpuls_bline = 0,
+		.eqpuls_bline_present = true,
+		.eqpuls_eline = 4,
+		.eqpuls_eline_present = true,
+		.hso_begin = 264,
+		.hso_end = 176,
+		.vso_begin = 88,
+		.vso_end = 88,
+		.vso_bline = 0,
+		.vso_eline = 5,
+		.vso_eline_present = true,
+		/* sy_val */
+		/* sy2_val */
+		.max_lncnt = 1124,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080i50 = {
+	.encp = {
+		.dvi_settings = 0x202d,
+		.video_mode = 0x5ffc,
+		.video_mode_adv = 0x19,
+		.video_prog_mode = 0x100,
+		.video_prog_mode_present = true,
+		.video_sync_mode = 0x7,
+		.video_sync_mode_present = true,
+		/* video_yc_dly */
+		/* video_rgb_ctrl */
+		/* video_filt_ctrl */
+		.video_ofld_voav_ofst = 0x11,
+		.video_ofld_voav_ofst_present = true,
+		.yfp1_htime = 526,
+		.yfp2_htime = 4365,
+		.max_pxcnt = 5279,
+		.hspuls_begin = 88,
+		.hspuls_end = 264,
+		.hspuls_switch = 88,
+		.vspuls_begin = 440,
+		.vspuls_end = 2200,
+		.vspuls_bline = 0,
+		.vspuls_eline = 4,
+		.havon_begin = 526,
+		.havon_end = 4365,
+		.vavon_bline = 20,
+		.vavon_eline = 559,
+		.eqpuls_begin = 2288,
+		.eqpuls_begin_present = true,
+		.eqpuls_end = 2464,
+		.eqpuls_end_present = true,
+		.eqpuls_bline = 0,
+		.eqpuls_bline_present = true,
+		.eqpuls_eline = 4,
+		.eqpuls_eline_present = true,
+		.hso_begin = 142,
+		.hso_end = 230,
+		.vso_begin = 142,
+		.vso_end = 142,
+		.vso_bline = 0,
+		.vso_eline = 5,
+		.vso_eline_present = true,
+		/* sy_val */
+		/* sy2_val */
+		.max_lncnt = 1124,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p24 = {
+	.encp = {
+		.dvi_settings = 0xd,
+		.video_mode = 0x4040,
+		.video_mode_adv = 0x18,
+		.video_prog_mode = 0x100,
+		.video_prog_mode_present = true,
+		.video_sync_mode = 0x7,
+		.video_sync_mode_present = true,
+		.video_yc_dly = 0,
+		.video_yc_dly_present = true,
+		.video_rgb_ctrl = 2,
+		.video_rgb_ctrl_present = true,
+		.video_filt_ctrl = 0x1052,
+		.video_filt_ctrl_present = true,
+		/* video_ofld_voav_ofst */
+		.yfp1_htime = 271,
+		.yfp2_htime = 2190,
+		.max_pxcnt = 2749,
+		.hspuls_begin = 44,
+		.hspuls_end = 132,
+		.hspuls_switch = 44,
+		.vspuls_begin = 220,
+		.vspuls_end = 2140,
+		.vspuls_bline = 0,
+		.vspuls_eline = 4,
+		.havon_begin = 271,
+		.havon_end = 2190,
+		.vavon_bline = 41,
+		.vavon_eline = 1120,
+		/* eqpuls_begin */
+		/* eqpuls_end */
+		.eqpuls_bline = 0,
+		.eqpuls_bline_present = true,
+		.eqpuls_eline = 4,
+		.eqpuls_eline_present = true,
+		.hso_begin = 79,
+		.hso_end = 123,
+		.vso_begin = 79,
+		.vso_end = 79,
+		.vso_bline = 0,
+		.vso_eline = 5,
+		.vso_eline_present = true,
+		/* sy_val */
+		/* sy2_val */
+		.max_lncnt = 1124,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p30 = {
+	.encp = {
+		.dvi_settings = 0x1,
+		.video_mode = 0x4040,
+		.video_mode_adv = 0x18,
+		.video_prog_mode = 0x100,
+		.video_prog_mode_present = true,
+		/* video_sync_mode */
+		/* video_yc_dly */
+		/* video_rgb_ctrl */
+		.video_filt_ctrl = 0x1052,
+		.video_filt_ctrl_present = true,
+		/* video_ofld_voav_ofst */
+		.yfp1_htime = 140,
+		.yfp2_htime = 2060,
+		.max_pxcnt = 2199,
+		.hspuls_begin = 2156,
+		.hspuls_end = 44,
+		.hspuls_switch = 44,
+		.vspuls_begin = 140,
+		.vspuls_end = 2059,
+		.vspuls_bline = 0,
+		.vspuls_eline = 4,
+		.havon_begin = 148,
+		.havon_end = 2067,
+		.vavon_bline = 41,
+		.vavon_eline = 1120,
+		/* eqpuls_begin */
+		/* eqpuls_end */
+		/* eqpuls_bline */
+		/* eqpuls_eline */
+		.hso_begin = 44,
+		.hso_end = 2156,
+		.vso_begin = 2100,
+		.vso_end = 2164,
+		.vso_bline = 0,
+		.vso_eline = 5,
+		.vso_eline_present = true,
+		/* sy_val */
+		/* sy2_val */
+		.max_lncnt = 1124,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p50 = {
+	.encp = {
+		.dvi_settings = 0xd,
+		.video_mode = 0x4040,
+		.video_mode_adv = 0x18,
+		.video_prog_mode = 0x100,
+		.video_prog_mode_present = true,
+		.video_sync_mode = 0x7,
+		.video_sync_mode_present = true,
+		.video_yc_dly = 0,
+		.video_yc_dly_present = true,
+		.video_rgb_ctrl = 2,
+		.video_rgb_ctrl_present = true,
+		/* video_filt_ctrl */
+		/* video_ofld_voav_ofst */
+		.yfp1_htime = 271,
+		.yfp2_htime = 2190,
+		.max_pxcnt = 2639,
+		.hspuls_begin = 44,
+		.hspuls_end = 132,
+		.hspuls_switch = 44,
+		.vspuls_begin = 220,
+		.vspuls_end = 2140,
+		.vspuls_bline = 0,
+		.vspuls_eline = 4,
+		.havon_begin = 271,
+		.havon_end = 2190,
+		.vavon_bline = 41,
+		.vavon_eline = 1120,
+		/* eqpuls_begin */
+		/* eqpuls_end */
+		.eqpuls_bline = 0,
+		.eqpuls_bline_present = true,
+		.eqpuls_eline = 4,
+		.eqpuls_eline_present = true,
+		.hso_begin = 79,
+		.hso_end = 123,
+		.vso_begin = 79,
+		.vso_end = 79,
+		.vso_bline = 0,
+		.vso_eline = 5,
+		.vso_eline_present = true,
+		/* sy_val */
+		/* sy2_val */
+		.max_lncnt = 1124,
+	},
+};
+
+union meson_hdmi_venc_mode meson_hdmi_encp_mode_1080p60 = {
+	.encp = {
+		.dvi_settings = 0x1,
+		.video_mode = 0x4040,
+		.video_mode_adv = 0x18,
+		.video_prog_mode = 0x100,
+		.video_prog_mode_present = true,
+		/* video_sync_mode */
+		/* video_yc_dly */
+		/* video_rgb_ctrl */
+		.video_filt_ctrl = 0x1052,
+		.video_filt_ctrl_present = true,
+		/* video_ofld_voav_ofst */
+		.yfp1_htime = 140,
+		.yfp2_htime = 2060,
+		.max_pxcnt = 2199,
+		.hspuls_begin = 2156,
+		.hspuls_end = 44,
+		.hspuls_switch = 44,
+		.vspuls_begin = 140,
+		.vspuls_end = 2059,
+		.vspuls_bline = 0,
+		.vspuls_eline = 4,
+		.havon_begin = 148,
+		.havon_end = 2067,
+		.vavon_bline = 41,
+		.vavon_eline = 1120,
+		/* eqpuls_begin */
+		/* eqpuls_end */
+		/* eqpuls_bline */
+		/* eqpuls_eline */
+		.hso_begin = 44,
+		.hso_end = 2156,
+		.vso_begin = 2100,
+		.vso_end = 2164,
+		.vso_bline = 0,
+		.vso_eline = 5,
+		.vso_eline_present = true,
+		/* sy_val */
+		/* sy2_val */
+		.max_lncnt = 1124,
+	},
+};
+
+struct meson_hdmi_venc_vic_mode {
+	unsigned int vic;
+	union meson_hdmi_venc_mode *mode;
+} meson_hdmi_venc_vic_modes[] = {
+	{ 6, &meson_hdmi_enci_mode_480i },
+	{ 7, &meson_hdmi_enci_mode_480i },
+	{ 21, &meson_hdmi_enci_mode_576i },
+	{ 22, &meson_hdmi_enci_mode_576i },
+	{ 2, &meson_hdmi_encp_mode_480p },
+	{ 3, &meson_hdmi_encp_mode_480p },
+	{ 17, &meson_hdmi_encp_mode_576p },
+	{ 18, &meson_hdmi_encp_mode_576p },
+	{ 4, &meson_hdmi_encp_mode_720p60 },
+	{ 19, &meson_hdmi_encp_mode_720p50 },
+	{ 5, &meson_hdmi_encp_mode_1080i60 },
+	{ 20, &meson_hdmi_encp_mode_1080i50 },
+	{ 32, &meson_hdmi_encp_mode_1080p24 },
+	{ 34, &meson_hdmi_encp_mode_1080p30 },
+	{ 31, &meson_hdmi_encp_mode_1080p50 },
+	{ 16, &meson_hdmi_encp_mode_1080p60 },
+	{ 0, NULL}, /* sentinel */
+};
+
+static signed int to_signed(unsigned int a)
+{
+	if (a <= 7)
+		return a;
+	else
+		return a - 16;
+}
+
+static unsigned long modulo(unsigned long a, unsigned long b)
+{
+	if (a >= b)
+		return a - b;
+	else
+		return a;
+}
+
+bool meson_venc_hdmi_supported_vic(int vic)
+{
+	struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
+
+	while (vmode->vic && vmode->mode) {
+		if (vmode->vic == vic)
+			return true;
+		vmode++;
+	}
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(meson_venc_hdmi_supported_vic);
+
+static union meson_hdmi_venc_mode *meson_venc_hdmi_get_vic_vmode(int vic)
+{
+	struct meson_hdmi_venc_vic_mode *vmode = meson_hdmi_venc_vic_modes;
+
+	while (vmode->vic && vmode->mode) {
+		if (vmode->vic == vic)
+			return vmode->mode;
+		vmode++;
+	}
+
+	return NULL;
+}
+
+bool meson_venc_hdmi_venc_repeat(int vic)
+{
+	/* Repeat VENC pixels for 480/576i/p, 720p50/60 and 1080p50/60 */
+	if (vic == 6 || vic == 7 || /* 480i */
+	    vic == 21 || vic == 22 || /* 576i */
+	    vic == 17 || vic == 18 || /* 576p */
+	    vic == 2 || vic == 3 || /* 480p */
+	    vic == 4 || /* 720p60 */
+	    vic == 19 || /* 720p50 */
+	    vic == 5 || /* 1080i60 */
+	    vic == 20)	/* 1080i50 */
+		return true;
+
+	return false;
+}
+EXPORT_SYMBOL_GPL(meson_venc_hdmi_venc_repeat);
+
+void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
+			      struct drm_display_mode *mode)
+{
+	union meson_hdmi_venc_mode *vmode = NULL;
+	bool use_enci = false;
+	bool venc_repeat = false;
+	bool hdmi_repeat = false;
+	unsigned int venc_hdmi_latency = 2;
+	unsigned long total_pixels_venc = 0;
+	unsigned long active_pixels_venc = 0;
+	unsigned long front_porch_venc = 0;
+	unsigned long hsync_pixels_venc = 0;
+	unsigned long de_h_begin = 0;
+	unsigned long de_h_end = 0;
+	unsigned long de_v_begin_even = 0;
+	unsigned long de_v_end_even = 0;
+	unsigned long de_v_begin_odd = 0;
+	unsigned long de_v_end_odd = 0;
+	unsigned long hs_begin = 0;
+	unsigned long hs_end = 0;
+	unsigned long vs_adjust = 0;
+	unsigned long vs_bline_evn = 0;
+	unsigned long vs_eline_evn = 0;
+	unsigned long vs_bline_odd = 0;
+	unsigned long vs_eline_odd = 0;
+	unsigned long vso_begin_evn = 0;
+	unsigned long vso_begin_odd = 0;
+	unsigned int eof_lines;
+	unsigned int sof_lines;
+	unsigned int vsync_lines;
+
+	vmode = meson_venc_hdmi_get_vic_vmode(vic);
+	if (!vmode) {
+		dev_err(priv->dev, "%s: Fatal Error, unsupported vic %d\n",
+			__func__, vic);
+		return;
+	}
+
+	/* Use VENCI for 480i and 576i and double HDMI pixels */
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK) {
+		hdmi_repeat = true;
+		use_enci = true;
+		venc_hdmi_latency = 1;
+	}
+
+	/* Repeat VENC pixels for 480/576i/p, 720p50/60 and 1080p50/60 */
+	if (meson_venc_hdmi_venc_repeat(vic))
+		venc_repeat = true;
+
+	eof_lines = mode->vsync_start - mode->vdisplay;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		eof_lines /= 2;
+	sof_lines = mode->vtotal - mode->vsync_end;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		sof_lines /= 2;
+	vsync_lines = mode->vsync_end - mode->vsync_start;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		vsync_lines /= 2;
+
+	total_pixels_venc = mode->htotal;
+	if (hdmi_repeat)
+		total_pixels_venc /= 2;
+	if (venc_repeat)
+		total_pixels_venc *= 2;
+
+	active_pixels_venc = mode->hdisplay;
+	if (hdmi_repeat)
+		active_pixels_venc /= 2;
+	if (venc_repeat)
+		active_pixels_venc *= 2;
+
+	front_porch_venc = (mode->hsync_start - mode->hdisplay);
+	if (hdmi_repeat)
+		front_porch_venc /= 2;
+	if (venc_repeat)
+		front_porch_venc *= 2;
+
+	hsync_pixels_venc = (mode->hsync_end - mode->hsync_start);
+	if (hdmi_repeat)
+		hsync_pixels_venc /= 2;
+	if (venc_repeat)
+		hsync_pixels_venc *= 2;
+
+	/* Disable VDACs */
+	writel_bits_relaxed(0x1f, 0x1f,
+			priv->io_base + _REG(VENC_VDAC_SETTING));
+
+	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
+	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
+
+	if (use_enci) {
+		unsigned int lines_f0;
+		unsigned int lines_f1;
+
+		/* CVBS Filter settings */
+		writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL));
+		writel_relaxed(0x12, priv->io_base + _REG(ENCI_CFILT_CTRL2));
+
+		/* Digital Video Select : Interlace, clk27 clk, external */
+		writel_relaxed(0, priv->io_base + _REG(VENC_DVI_SETTING));
+
+		/* Reset Video Mode */
+		writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_MODE));
+		writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
+
+		/* Horizontal sync signal output */
+		writel_relaxed(vmode->enci.hso_begin,
+				priv->io_base + _REG(ENCI_SYNC_HSO_BEGIN));
+		writel_relaxed(vmode->enci.hso_end,
+				priv->io_base + _REG(ENCI_SYNC_HSO_END));
+
+		/* Vertical Sync lines */
+		writel_relaxed(vmode->enci.vso_even,
+				priv->io_base + _REG(ENCI_SYNC_VSO_EVNLN));
+		writel_relaxed(vmode->enci.vso_odd,
+				priv->io_base + _REG(ENCI_SYNC_VSO_ODDLN));
+
+		/* Macrovision max amplitude change */
+		writel_relaxed(vmode->enci.macv_max_amp,
+				priv->io_base + _REG(ENCI_MACV_MAX_AMP));
+
+		/* Video mode */
+		writel_relaxed(vmode->enci.video_prog_mode,
+				priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
+		writel_relaxed(vmode->enci.video_mode,
+				priv->io_base + _REG(ENCI_VIDEO_MODE));
+
+		/* Advanced Video Mode :
+		 * Demux shifting 0x2
+		 * Blank line end at line17/22
+		 * High bandwidth Luma Filter
+		 * Low bandwidth Chroma Filter
+		 * Bypass luma low pass filter
+		 * No macrovision on CSYNC
+		 */
+		writel_relaxed(0x26, priv->io_base + _REG(ENCI_VIDEO_MODE_ADV));
+
+		writel(vmode->enci.sch_adjust,
+				priv->io_base + _REG(ENCI_VIDEO_SCH));
+
+		/* Sync mode : MASTER Master mode, free run, send HSO/VSO out */
+		writel_relaxed(0x07, priv->io_base + _REG(ENCI_SYNC_MODE));
+
+		if (vmode->enci.yc_delay)
+			writel_relaxed(vmode->enci.yc_delay,
+					priv->io_base + _REG(ENCI_YC_DELAY));
+
+
+		/* UNreset Interlaced TV Encoder */
+		writel_relaxed(0, priv->io_base + _REG(ENCI_DBG_PX_RST));
+
+		/* Enable Vfifo2vd, Y_Cb_Y_Cr select */
+		writel_relaxed(0x4e01, priv->io_base + _REG(ENCI_VFIFO2VD_CTL));
+
+		/* Timings */
+		writel_relaxed(vmode->enci.pixel_start,
+			priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_START));
+		writel_relaxed(vmode->enci.pixel_end,
+			priv->io_base + _REG(ENCI_VFIFO2VD_PIXEL_END));
+
+		writel_relaxed(vmode->enci.top_field_line_start,
+			priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_START));
+		writel_relaxed(vmode->enci.top_field_line_end,
+			priv->io_base + _REG(ENCI_VFIFO2VD_LINE_TOP_END));
+
+		writel_relaxed(vmode->enci.bottom_field_line_start,
+			priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_START));
+		writel_relaxed(vmode->enci.bottom_field_line_end,
+			priv->io_base + _REG(ENCI_VFIFO2VD_LINE_BOT_END));
+
+		/* Select ENCI for VIU */
+		meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCI);
+
+		/* Interlace video enable */
+		writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
+
+		lines_f0 = mode->vtotal >> 1;
+		lines_f1 = lines_f0 + 1;
+
+		de_h_begin = modulo(readl_relaxed(priv->io_base +
+					_REG(ENCI_VFIFO2VD_PIXEL_START))
+					+ venc_hdmi_latency,
+				    total_pixels_venc);
+		de_h_end  = modulo(de_h_begin + active_pixels_venc,
+				   total_pixels_venc);
+
+		writel_relaxed(de_h_begin,
+				priv->io_base + _REG(ENCI_DE_H_BEGIN));
+		writel_relaxed(de_h_end,
+				priv->io_base + _REG(ENCI_DE_H_END));
+
+		de_v_begin_even = readl_relaxed(priv->io_base +
+					_REG(ENCI_VFIFO2VD_LINE_TOP_START));
+		de_v_end_even  = de_v_begin_even + mode->vdisplay;
+		de_v_begin_odd = readl_relaxed(priv->io_base +
+					_REG(ENCI_VFIFO2VD_LINE_BOT_START));
+		de_v_end_odd = de_v_begin_odd + mode->vdisplay;
+
+		writel_relaxed(de_v_begin_even,
+				priv->io_base + _REG(ENCI_DE_V_BEGIN_EVEN));
+		writel_relaxed(de_v_end_even,
+				priv->io_base + _REG(ENCI_DE_V_END_EVEN));
+		writel_relaxed(de_v_begin_odd,
+				priv->io_base + _REG(ENCI_DE_V_BEGIN_ODD));
+		writel_relaxed(de_v_end_odd,
+				priv->io_base + _REG(ENCI_DE_V_END_ODD));
+
+		/* Program Hsync timing */
+		hs_begin = de_h_end + front_porch_venc;
+		if (de_h_end + front_porch_venc >= total_pixels_venc) {
+			hs_begin -= total_pixels_venc;
+			vs_adjust  = 1;
+		} else {
+			hs_begin = de_h_end + front_porch_venc;
+			vs_adjust  = 0;
+		}
+
+		hs_end = modulo(hs_begin + hsync_pixels_venc,
+				total_pixels_venc);
+		writel_relaxed(hs_begin,
+				priv->io_base + _REG(ENCI_DVI_HSO_BEGIN));
+		writel_relaxed(hs_end,
+				priv->io_base + _REG(ENCI_DVI_HSO_END));
+
+		/* Program Vsync timing for even field */
+		if (((de_v_end_odd - 1) + eof_lines + vs_adjust) >= lines_f1) {
+			vs_bline_evn = (de_v_end_odd - 1)
+					+ eof_lines
+					+ vs_adjust
+					- lines_f1;
+			vs_eline_evn = vs_bline_evn + vsync_lines;
+
+			writel_relaxed(vs_bline_evn,
+				priv->io_base + _REG(ENCI_DVI_VSO_BLINE_EVN));
+
+			writel_relaxed(vs_eline_evn,
+				priv->io_base + _REG(ENCI_DVI_VSO_ELINE_EVN));
+
+			writel_relaxed(hs_begin,
+				priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_EVN));
+			writel_relaxed(hs_begin,
+				priv->io_base + _REG(ENCI_DVI_VSO_END_EVN));
+		} else {
+			vs_bline_odd = (de_v_end_odd - 1)
+					+ eof_lines
+					+ vs_adjust;
+
+			writel_relaxed(vs_bline_odd,
+				priv->io_base + _REG(ENCI_DVI_VSO_BLINE_ODD));
+
+			writel_relaxed(hs_begin,
+				priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_ODD));
+
+			if ((vs_bline_odd + vsync_lines) >= lines_f1) {
+				vs_eline_evn = vs_bline_odd
+						+ vsync_lines
+						- lines_f1;
+
+				writel_relaxed(vs_eline_evn, priv->io_base
+						+ _REG(ENCI_DVI_VSO_ELINE_EVN));
+
+				writel_relaxed(hs_begin, priv->io_base
+						+ _REG(ENCI_DVI_VSO_END_EVN));
+			} else {
+				vs_eline_odd = vs_bline_odd
+						+ vsync_lines;
+
+				writel_relaxed(vs_eline_odd, priv->io_base
+						+ _REG(ENCI_DVI_VSO_ELINE_ODD));
+
+				writel_relaxed(hs_begin, priv->io_base
+						+ _REG(ENCI_DVI_VSO_END_ODD));
+			}
+		}
+
+		/* Program Vsync timing for odd field */
+		if (((de_v_end_even - 1) + (eof_lines + 1)) >= lines_f0) {
+			vs_bline_odd = (de_v_end_even - 1)
+					+ (eof_lines + 1)
+					- lines_f0;
+			vs_eline_odd = vs_bline_odd + vsync_lines;
+
+			writel_relaxed(vs_bline_odd,
+				priv->io_base + _REG(ENCI_DVI_VSO_BLINE_ODD));
+
+			writel_relaxed(vs_eline_odd,
+				priv->io_base + _REG(ENCI_DVI_VSO_ELINE_ODD));
+
+			vso_begin_odd  = modulo(hs_begin
+						+ (total_pixels_venc >> 1),
+						total_pixels_venc);
+
+			writel_relaxed(vso_begin_odd,
+				priv->io_base + _REG(ENCI_DVI_VSO_BEGIN_ODD));
+			writel_relaxed(vso_begin_odd,
+				priv->io_base + _REG(ENCI_DVI_VSO_END_ODD));
+		} else {
+			vs_bline_evn = (de_v_end_even - 1)
+					+ (eof_lines + 1);
+
+			writel_relaxed(vs_bline_evn,
+				priv->io_base + _REG(ENCI_DVI_VSO_BLINE_EVN));
+
+			vso_begin_evn  = modulo(hs_begin
+						+ (total_pixels_venc >> 1),
+						total_pixels_venc);
+
+			writel_relaxed(vso_begin_evn, priv->io_base
+					+ _REG(ENCI_DVI_VSO_BEGIN_EVN));
+
+			if (vs_bline_evn + vsync_lines >= lines_f0) {
+				vs_eline_odd = vs_bline_evn
+						+ vsync_lines
+						- lines_f0;
+
+				writel_relaxed(vs_eline_odd, priv->io_base
+						+ _REG(ENCI_DVI_VSO_ELINE_ODD));
+
+				writel_relaxed(vso_begin_evn, priv->io_base
+						+ _REG(ENCI_DVI_VSO_END_ODD));
+			} else {
+				vs_eline_evn = vs_bline_evn + vsync_lines;
+
+				writel_relaxed(vs_eline_evn, priv->io_base
+						+ _REG(ENCI_DVI_VSO_ELINE_EVN));
+
+				writel_relaxed(vso_begin_evn, priv->io_base
+						+ _REG(ENCI_DVI_VSO_END_EVN));
+			}
+		}
+	} else {
+		writel_relaxed(vmode->encp.dvi_settings,
+				priv->io_base + _REG(VENC_DVI_SETTING));
+		writel_relaxed(vmode->encp.video_mode,
+				priv->io_base + _REG(ENCP_VIDEO_MODE));
+		writel_relaxed(vmode->encp.video_mode_adv,
+				priv->io_base + _REG(ENCP_VIDEO_MODE_ADV));
+		if (vmode->encp.video_prog_mode_present)
+			writel_relaxed(vmode->encp.video_prog_mode,
+				priv->io_base + _REG(VENC_VIDEO_PROG_MODE));
+		if (vmode->encp.video_sync_mode_present)
+			writel_relaxed(vmode->encp.video_sync_mode,
+				priv->io_base + _REG(ENCP_VIDEO_SYNC_MODE));
+		if (vmode->encp.video_yc_dly_present)
+			writel_relaxed(vmode->encp.video_yc_dly,
+				priv->io_base + _REG(ENCP_VIDEO_YC_DLY));
+		if (vmode->encp.video_rgb_ctrl_present)
+			writel_relaxed(vmode->encp.video_rgb_ctrl,
+				priv->io_base + _REG(ENCP_VIDEO_RGB_CTRL));
+		if (vmode->encp.video_filt_ctrl_present)
+			writel_relaxed(vmode->encp.video_filt_ctrl,
+				priv->io_base + _REG(ENCP_VIDEO_FILT_CTRL));
+		if (vmode->encp.video_ofld_voav_ofst_present)
+			writel_relaxed(vmode->encp.video_ofld_voav_ofst,
+				priv->io_base
+				+ _REG(ENCP_VIDEO_OFLD_VOAV_OFST));
+		writel_relaxed(vmode->encp.yfp1_htime,
+				priv->io_base + _REG(ENCP_VIDEO_YFP1_HTIME));
+		writel_relaxed(vmode->encp.yfp2_htime,
+				priv->io_base + _REG(ENCP_VIDEO_YFP2_HTIME));
+		writel_relaxed(vmode->encp.max_pxcnt,
+				priv->io_base + _REG(ENCP_VIDEO_MAX_PXCNT));
+		writel_relaxed(vmode->encp.hspuls_begin,
+				priv->io_base + _REG(ENCP_VIDEO_HSPULS_BEGIN));
+		writel_relaxed(vmode->encp.hspuls_end,
+				priv->io_base + _REG(ENCP_VIDEO_HSPULS_END));
+		writel_relaxed(vmode->encp.hspuls_switch,
+				priv->io_base + _REG(ENCP_VIDEO_HSPULS_SWITCH));
+		writel_relaxed(vmode->encp.vspuls_begin,
+				priv->io_base + _REG(ENCP_VIDEO_VSPULS_BEGIN));
+		writel_relaxed(vmode->encp.vspuls_end,
+				priv->io_base + _REG(ENCP_VIDEO_VSPULS_END));
+		writel_relaxed(vmode->encp.vspuls_bline,
+				priv->io_base + _REG(ENCP_VIDEO_VSPULS_BLINE));
+		writel_relaxed(vmode->encp.vspuls_eline,
+				priv->io_base + _REG(ENCP_VIDEO_VSPULS_ELINE));
+		if (vmode->encp.eqpuls_begin_present)
+			writel_relaxed(vmode->encp.eqpuls_begin,
+				priv->io_base + _REG(ENCP_VIDEO_EQPULS_BEGIN));
+		if (vmode->encp.eqpuls_end_present)
+			writel_relaxed(vmode->encp.eqpuls_end,
+				priv->io_base + _REG(ENCP_VIDEO_EQPULS_END));
+		if (vmode->encp.eqpuls_bline_present)
+			writel_relaxed(vmode->encp.eqpuls_bline,
+				priv->io_base + _REG(ENCP_VIDEO_EQPULS_BLINE));
+		if (vmode->encp.eqpuls_eline_present)
+			writel_relaxed(vmode->encp.eqpuls_eline,
+				priv->io_base + _REG(ENCP_VIDEO_EQPULS_ELINE));
+		writel_relaxed(vmode->encp.havon_begin,
+				priv->io_base + _REG(ENCP_VIDEO_HAVON_BEGIN));
+		writel_relaxed(vmode->encp.havon_end,
+				priv->io_base + _REG(ENCP_VIDEO_HAVON_END));
+		writel_relaxed(vmode->encp.vavon_bline,
+				priv->io_base + _REG(ENCP_VIDEO_VAVON_BLINE));
+		writel_relaxed(vmode->encp.vavon_eline,
+				priv->io_base + _REG(ENCP_VIDEO_VAVON_ELINE));
+		writel_relaxed(vmode->encp.hso_begin,
+				priv->io_base + _REG(ENCP_VIDEO_HSO_BEGIN));
+		writel_relaxed(vmode->encp.hso_end,
+				priv->io_base + _REG(ENCP_VIDEO_HSO_END));
+		writel_relaxed(vmode->encp.vso_begin,
+				priv->io_base + _REG(ENCP_VIDEO_VSO_BEGIN));
+		writel_relaxed(vmode->encp.vso_end,
+				priv->io_base + _REG(ENCP_VIDEO_VSO_END));
+		writel_relaxed(vmode->encp.vso_bline,
+				priv->io_base + _REG(ENCP_VIDEO_VSO_BLINE));
+		if (vmode->encp.vso_eline_present)
+			writel_relaxed(vmode->encp.vso_eline,
+				priv->io_base + _REG(ENCP_VIDEO_VSO_ELINE));
+		if (vmode->encp.sy_val_present)
+			writel_relaxed(vmode->encp.sy_val,
+				priv->io_base + _REG(ENCP_VIDEO_SY_VAL));
+		if (vmode->encp.sy2_val_present)
+			writel_relaxed(vmode->encp.sy2_val,
+				priv->io_base + _REG(ENCP_VIDEO_SY2_VAL));
+		writel_relaxed(vmode->encp.max_lncnt,
+				priv->io_base + _REG(ENCP_VIDEO_MAX_LNCNT));
+
+		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
+
+		/* Set DE signal’s polarity is active high */
+		writel_bits_relaxed(BIT(14), BIT(14),
+				    priv->io_base + _REG(ENCP_VIDEO_MODE));
+
+		/* Program DE timing */
+		de_h_begin = modulo(readl_relaxed(priv->io_base +
+					_REG(ENCP_VIDEO_HAVON_BEGIN))
+					+ venc_hdmi_latency,
+				    total_pixels_venc);
+		de_h_end = modulo(de_h_begin + active_pixels_venc,
+				  total_pixels_venc);
+
+		writel_relaxed(de_h_begin,
+				priv->io_base + _REG(ENCP_DE_H_BEGIN));
+		writel_relaxed(de_h_end,
+				priv->io_base + _REG(ENCP_DE_H_END));
+
+		/* Program DE timing for even field */
+		de_v_begin_even = readl_relaxed(priv->io_base
+						+ _REG(ENCP_VIDEO_VAVON_BLINE));
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+			de_v_end_even = de_v_begin_even +
+					(mode->vdisplay / 2);
+		else
+			de_v_end_even = de_v_begin_even + mode->vdisplay;
+
+		writel_relaxed(de_v_begin_even,
+				priv->io_base + _REG(ENCP_DE_V_BEGIN_EVEN));
+		writel_relaxed(de_v_end_even,
+				priv->io_base + _REG(ENCP_DE_V_END_EVEN));
+
+		/* Program DE timing for odd field if needed */
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+			unsigned int ofld_voav_ofst =
+				readl_relaxed(priv->io_base +
+					_REG(ENCP_VIDEO_OFLD_VOAV_OFST));
+			de_v_begin_odd = to_signed((ofld_voav_ofst & 0xf0) >> 4)
+						+ de_v_begin_even
+						+ ((mode->vtotal - 1) / 2);
+			de_v_end_odd = de_v_begin_odd + (mode->vdisplay / 2);
+
+			writel_relaxed(de_v_begin_odd,
+				priv->io_base + _REG(ENCP_DE_V_BEGIN_ODD));
+			writel_relaxed(de_v_end_odd,
+				priv->io_base + _REG(ENCP_DE_V_END_ODD));
+		}
+
+		/* Program Hsync timing */
+		if ((de_h_end + front_porch_venc) >= total_pixels_venc) {
+			hs_begin = de_h_end
+				   + front_porch_venc
+				   - total_pixels_venc;
+			vs_adjust  = 1;
+		} else {
+			hs_begin = de_h_end
+				   + front_porch_venc;
+			vs_adjust  = 0;
+		}
+
+		hs_end = modulo(hs_begin + hsync_pixels_venc,
+				total_pixels_venc);
+
+		writel_relaxed(hs_begin,
+				priv->io_base + _REG(ENCP_DVI_HSO_BEGIN));
+		writel_relaxed(hs_end,
+				priv->io_base + _REG(ENCP_DVI_HSO_END));
+
+		/* Program Vsync timing for even field */
+		if (de_v_begin_even >=
+				(sof_lines + vsync_lines + (1 - vs_adjust)))
+			vs_bline_evn = de_v_begin_even
+					- sof_lines
+					- vsync_lines
+					- (1 - vs_adjust);
+		else
+			vs_bline_evn = mode->vtotal
+					+ de_v_begin_even
+					- sof_lines
+					- vsync_lines
+					- (1 - vs_adjust);
+
+		vs_eline_evn = modulo(vs_bline_evn + vsync_lines,
+					mode->vtotal);
+
+		writel_relaxed(vs_bline_evn,
+				priv->io_base + _REG(ENCP_DVI_VSO_BLINE_EVN));
+		writel_relaxed(vs_eline_evn,
+				priv->io_base + _REG(ENCP_DVI_VSO_ELINE_EVN));
+
+		vso_begin_evn = hs_begin;
+		writel_relaxed(vso_begin_evn,
+				priv->io_base + _REG(ENCP_DVI_VSO_BEGIN_EVN));
+		writel_relaxed(vso_begin_evn,
+				priv->io_base + _REG(ENCP_DVI_VSO_END_EVN));
+
+		/* Program Vsync timing for odd field if needed */
+		if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+			vs_bline_odd = (de_v_begin_odd - 1)
+					- sof_lines
+					- vsync_lines;
+			vs_eline_odd = (de_v_begin_odd - 1)
+					- vsync_lines;
+			vso_begin_odd  = modulo(hs_begin
+						+ (total_pixels_venc >> 1),
+						total_pixels_venc);
+
+			writel_relaxed(vs_bline_odd,
+				priv->io_base + _REG(ENCP_DVI_VSO_BLINE_ODD));
+			writel_relaxed(vs_eline_odd,
+				priv->io_base + _REG(ENCP_DVI_VSO_ELINE_ODD));
+			writel_relaxed(vso_begin_odd,
+				priv->io_base + _REG(ENCP_DVI_VSO_BEGIN_ODD));
+			writel_relaxed(vso_begin_odd,
+				priv->io_base + _REG(ENCP_DVI_VSO_END_ODD));
+		}
+
+		/* Select ENCP for VIU */
+		meson_vpp_setup_mux(priv, MESON_VIU_VPP_MUX_ENCP);
+	}
+
+	writel_relaxed((use_enci ? 1 : 2) |
+		       (mode->flags & DRM_MODE_FLAG_PHSYNC ? 1 << 2 : 0) |
+		       (mode->flags & DRM_MODE_FLAG_PVSYNC ? 1 << 3 : 0) |
+		       4 << 5 |
+		       (venc_repeat ? 1 << 8 : 0) |
+		       (hdmi_repeat ? 1 << 12 : 0),
+		       priv->io_base + _REG(VPU_HDMI_SETTING));
+
+	priv->venc.hdmi_repeat = hdmi_repeat;
+	priv->venc.venc_repeat = venc_repeat;
+	priv->venc.hdmi_use_enci = use_enci;
+
+	priv->venc.current_mode = MESON_VENC_MODE_HDMI;
+}
+EXPORT_SYMBOL_GPL(meson_venc_hdmi_mode_set);
+
 void meson_venci_cvbs_mode_set(struct meson_drm *priv,
 			       struct meson_cvbs_enci_mode *mode)
 {
@@ -223,9 +1461,6 @@ void meson_venci_cvbs_mode_set(struct meson_drm *priv,
 	writel_relaxed(mode->analog_sync_adj,
 			priv->io_base + _REG(ENCI_SYNC_ADJ));
 
-	/* Setup 27MHz vclk2 for ENCI and VDAC */
-	meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS, MESON_VCLK_CVBS);
-
 	priv->venc.current_mode = mode->mode_tag;
 }
 
diff --git a/drivers/gpu/drm/meson/meson_venc.h b/drivers/gpu/drm/meson/meson_venc.h
index 77d4a7d..a1b96e8 100644
--- a/drivers/gpu/drm/meson/meson_venc.h
+++ b/drivers/gpu/drm/meson/meson_venc.h
@@ -30,6 +30,7 @@ enum {
 	MESON_VENC_MODE_NONE = 0,
 	MESON_VENC_MODE_CVBS_PAL,
 	MESON_VENC_MODE_CVBS_NTSC,
+	MESON_VENC_MODE_HDMI,
 };
 
 struct meson_cvbs_enci_mode {
@@ -56,12 +57,18 @@ struct meson_cvbs_enci_mode {
 	unsigned int analog_sync_adj;
 };
 
+/* HDMI Clock parameters */
+bool meson_venc_hdmi_supported_vic(int vic);
+bool meson_venc_hdmi_venc_repeat(int vic);
+
 /* CVBS Timings and Parameters */
 extern struct meson_cvbs_enci_mode meson_cvbs_enci_pal;
 extern struct meson_cvbs_enci_mode meson_cvbs_enci_ntsc;
 
 void meson_venci_cvbs_mode_set(struct meson_drm *priv,
 			       struct meson_cvbs_enci_mode *mode);
+void meson_venc_hdmi_mode_set(struct meson_drm *priv, int vic,
+			      struct drm_display_mode *mode);
 unsigned int meson_venci_get_field(struct meson_drm *priv);
 
 void meson_venc_enable_vsync(struct meson_drm *priv);
diff --git a/drivers/gpu/drm/meson/meson_vpp.h b/drivers/gpu/drm/meson/meson_vpp.h
index ede3b26..815177c 100644
--- a/drivers/gpu/drm/meson/meson_vpp.h
+++ b/drivers/gpu/drm/meson/meson_vpp.h
@@ -23,6 +23,8 @@
 
 /* Mux VIU/VPP to ENCI */
 #define MESON_VIU_VPP_MUX_ENCI	0x5
+/* Mux VIU/VPP to ENCP */
+#define MESON_VIU_VPP_MUX_ENCP	0xA
 
 void meson_vpp_setup_mux(struct meson_drm *priv, unsigned int mux);
 
-- 
1.9.1

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

* [PATCH v2 07/13] drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (5 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 06/13] drm/meson: Add support for HDMI venc modes and settings Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-04-04  8:57   ` Daniel Vetter
  2017-03-21 15:25 ` [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool Neil Armstrong
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

The Amlogic Meson GXBB/GXL/GXM SoCs embeds a Synopsys DesignWare HDMI TX
Controller with a custom Bridge + PHY around the Controller.

This driver makes uses of all the custom PHY plat data callbacks and enables
the compatible HDMI modes to be configured as a drm_encoder instance.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/Kconfig         |   6 +
 drivers/gpu/drm/meson/Makefile        |   1 +
 drivers/gpu/drm/meson/meson_drv.h     |   3 +
 drivers/gpu/drm/meson/meson_dw_hdmi.c | 910 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/meson/meson_dw_hdmi.h | 146 ++++++
 5 files changed, 1066 insertions(+)
 create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.c
 create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.h

diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
index 99719af..3ce51d8 100644
--- a/drivers/gpu/drm/meson/Kconfig
+++ b/drivers/gpu/drm/meson/Kconfig
@@ -7,3 +7,9 @@ config DRM_MESON
 	select DRM_GEM_CMA_HELPER
 	select VIDEOMODE_HELPERS
 	select REGMAP_MMIO
+
+config DRM_MESON_DW_HDMI
+	tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
+	depends on DRM_MESON
+	default y if DRM_MESON
+	select DRM_DW_HDMI
diff --git a/drivers/gpu/drm/meson/Makefile b/drivers/gpu/drm/meson/Makefile
index 92cf845..c5c4cc3 100644
--- a/drivers/gpu/drm/meson/Makefile
+++ b/drivers/gpu/drm/meson/Makefile
@@ -2,3 +2,4 @@ meson-drm-y := meson_drv.o meson_plane.o meson_crtc.o meson_venc_cvbs.o
 meson-drm-y += meson_viu.o meson_vpp.o meson_venc.o meson_vclk.o meson_canvas.o
 
 obj-$(CONFIG_DRM_MESON) += meson-drm.o
+obj-$(CONFIG_DRM_MESON_DW_HDMI) += meson_dw_hdmi.o
diff --git a/drivers/gpu/drm/meson/meson_drv.h b/drivers/gpu/drm/meson/meson_drv.h
index 6195327..5e8b392 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -47,6 +47,9 @@ struct meson_drm {
 
 	struct {
 		unsigned int current_mode;
+		bool hdmi_repeat;
+		bool venc_repeat;
+		bool hdmi_use_enci;
 	} venc;
 };
 
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
new file mode 100644
index 0000000..8851dcb
--- /dev/null
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -0,0 +1,910 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+#include <linux/reset.h>
+#include <linux/clk.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/bridge/dw_hdmi.h>
+
+#include <uapi/linux/media-bus-format.h>
+#include <uapi/linux/videodev2.h>
+
+#include "meson_drv.h"
+#include "meson_venc.h"
+#include "meson_vclk.h"
+#include "meson_dw_hdmi.h"
+#include "meson_registers.h"
+
+#define DRIVER_NAME "meson-dw-hdmi"
+#define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver"
+
+/*
+ * HDMI Output is composed of :
+ * - A Synopsys DesignWare HDMI Controller IP
+ * - A TOP control block controlling the Clocks and PHY
+ * - A custom HDMI PHY in order convert video to TMDS signal
+ *  ___________________________________
+ * |            HDMI TOP               |<= HPD
+ * |___________________________________|
+ * |                  |                |
+ * |  Synopsys HDMI   |   HDMI PHY     |=> TMDS
+ * |    Controller    |________________|
+ * |___________________________________|<=> DDC
+ *
+ * The HDMI TOP block only supports HPD sensing.
+ * The Synopsys HDMI Controller interrupt is routed
+ * through the TOP Block interrupt.
+ * Communication to the TOP Block and the Synopsys
+ * HDMI Controller is done a pair of addr+read/write
+ * registers.
+ * The HDMI PHY is configured by registers in the
+ * HHI register block.
+ *
+ * Pixel data arrives in 4:4:4 format from the VENC
+ * block and the VPU HDMI mux selects either the ENCI
+ * encoder for the 576i or 480i formats or the ENCP
+ * encoder for all the other formats including
+ * interlaced HD formats.
+ * The VENC uses a DVI encoder on top of the ENCI
+ * or ENCP encoders to generate DVI timings for the
+ * HDMI controller.
+ *
+ * GXBB, GXL and GXM embeds the Synopsys DesignWare
+ * HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
+ * audio source interfaces.
+ *
+ * We handle the following features :
+ * - HPD Rise & Fall interrupt
+ * - HDMI Controller Interrupt
+ * - HDMI PHY Init for 480i to 1080p60
+ * - VENC & HDMI Clock setup for 480i to 1080p60
+ * - VENC Mode setup for 480i to 1080p60
+ *
+ * What is missing :
+ * - PHY, Clock and Mode setup for 2k && 4k modes
+ * - SDDC Scrambling mode for HDMI 2.0a
+ * - HDCP Setup
+ * - CEC Management
+ */
+
+/* TOP Block Communication Channel */
+#define HDMITX_TOP_ADDR_REG	0x0
+#define HDMITX_TOP_DATA_REG	0x4
+#define HDMITX_TOP_CTRL_REG	0x8
+
+/* Controller Communication Channel */
+#define HDMITX_DWC_ADDR_REG	0x10
+#define HDMITX_DWC_DATA_REG	0x14
+#define HDMITX_DWC_CTRL_REG	0x18
+
+/* HHI Registers */
+#define HHI_MEM_PD_REG0		0x100 /* 0x40 */
+#define HHI_HDMI_CLK_CNTL	0x1cc /* 0x73 */
+#define HHI_HDMI_PHY_CNTL0	0x3a0 /* 0xe8 */
+#define HHI_HDMI_PHY_CNTL1	0x3a4 /* 0xe9 */
+#define HHI_HDMI_PHY_CNTL2	0x3a8 /* 0xea */
+#define HHI_HDMI_PHY_CNTL3	0x3ac /* 0xeb */
+
+static DEFINE_SPINLOCK(reg_lock);
+
+enum meson_venc_source {
+	MESON_VENC_SOURCE_NONE = 0,
+	MESON_VENC_SOURCE_ENCI = 1,
+	MESON_VENC_SOURCE_ENCP = 2,
+};
+
+struct meson_dw_hdmi {
+	struct drm_encoder encoder;
+	struct dw_hdmi_plat_data dw_plat_data;
+	struct meson_drm *priv;
+	struct device *dev;
+	void __iomem *hdmitx;
+	struct reset_control *hdmitx_apb;
+	struct reset_control *hdmitx_ctrl;
+	struct reset_control *hdmitx_phy;
+	struct clk *hdmi_pclk;
+	struct clk *venci_clk;
+	u32 irq_stat;
+};
+#define encoder_to_meson_dw_hdmi(x) \
+	container_of(x, struct meson_dw_hdmi, encoder)
+
+static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
+					const char *compat)
+{
+	return of_device_is_compatible(dw_hdmi->dev->of_node, compat);
+}
+
+/* PHY (via TOP bridge) and Controller dedicated register interface */
+
+static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
+				     unsigned int addr)
+{
+	unsigned long flags;
+	unsigned int data;
+
+	spin_lock_irqsave(&reg_lock, flags);
+
+	/* ADDR must be written twice */
+	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
+	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
+
+	/* Read needs a second DATA read */
+	data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
+	data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
+
+	spin_unlock_irqrestore(&reg_lock, flags);
+
+	return data;
+}
+
+static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
+				     unsigned int addr, unsigned int data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&reg_lock, flags);
+
+	/* ADDR must be written twice */
+	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
+	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
+
+	/* Write needs single DATA write */
+	writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
+
+	spin_unlock_irqrestore(&reg_lock, flags);
+}
+
+/* Helper to change specific bits in PHY registers */
+static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
+					  unsigned int addr,
+					  unsigned int mask,
+					  unsigned int val)
+{
+	unsigned int data = dw_hdmi_top_read(dw_hdmi, addr);
+
+	data &= ~mask;
+	data |= val;
+
+	dw_hdmi_top_write(dw_hdmi, addr, data);
+}
+
+static unsigned int dw_hdmi_dwc_read(struct meson_dw_hdmi *dw_hdmi,
+				     unsigned int addr)
+{
+	unsigned long flags;
+	unsigned int data;
+
+	spin_lock_irqsave(&reg_lock, flags);
+
+	/* ADDR must be written twice */
+	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
+	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
+
+	/* Read needs a second DATA read */
+	data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
+	data = readl(dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
+
+	spin_unlock_irqrestore(&reg_lock, flags);
+
+	return data;
+}
+
+static inline void dw_hdmi_dwc_write(struct meson_dw_hdmi *dw_hdmi,
+				     unsigned int addr, unsigned int data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&reg_lock, flags);
+
+	/* ADDR must be written twice */
+	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
+	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_DWC_ADDR_REG);
+
+	/* Write needs single DATA write */
+	writel(data, dw_hdmi->hdmitx + HDMITX_DWC_DATA_REG);
+
+	spin_unlock_irqrestore(&reg_lock, flags);
+}
+
+/* Helper to change specific bits in controller registers */
+static inline void dw_hdmi_dwc_write_bits(struct meson_dw_hdmi *dw_hdmi,
+					  unsigned int addr,
+					  unsigned int mask,
+					  unsigned int val)
+{
+	unsigned int data = dw_hdmi_dwc_read(dw_hdmi, addr);
+
+	data &= ~mask;
+	data |= val;
+
+	dw_hdmi_dwc_write(dw_hdmi, addr, data);
+}
+
+/* Bridge */
+
+/* Setup PHY bandwidth modes */
+static void meson_hdmi_phy_setup_mode(struct meson_dw_hdmi *dw_hdmi,
+				      struct drm_display_mode *mode)
+{
+	struct meson_drm *priv = dw_hdmi->priv;
+	unsigned int pixel_clock = mode->clock;
+
+	if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
+	    dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi")) {
+		if (pixel_clock >= 371250) {
+			/* 5.94Gbps, 3.7125Gbps */
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x333d3282);
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2136315b);
+		} else if (pixel_clock >= 297000) {
+			/* 2.97Gbps */
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303382);
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2036315b);
+		} else if (pixel_clock >= 148500) {
+			/* 1.485Gbps */
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33303362);
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2016315b);
+		} else {
+			/* 742.5Mbps, and below */
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33604142);
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x0016315b);
+		}
+	} else if (dw_hdmi_is_compatible(dw_hdmi,
+					 "amlogic,meson-gxbb-dw-hdmi")) {
+		if (pixel_clock >= 371250) {
+			/* 5.94Gbps, 3.7125Gbps */
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33353245);
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2100115b);
+		} else if (pixel_clock >= 297000) {
+			/* 2.97Gbps */
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33634283);
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0xb000115b);
+		} else {
+			/* 1.485Gbps, and below */
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0x33632122);
+			regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL3, 0x2000115b);
+		}
+	}
+}
+
+static inline void dw_hdmi_phy_reset(struct meson_dw_hdmi *dw_hdmi)
+{
+	struct meson_drm *priv = dw_hdmi->priv;
+
+	/* Enable and software reset */
+	regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xf);
+
+	mdelay(2);
+
+	/* Enable and unreset */
+	regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0xe);
+
+	mdelay(2);
+}
+
+static void dw_hdmi_set_vclk(struct meson_dw_hdmi *dw_hdmi,
+			     struct drm_display_mode *mode)
+{
+	struct meson_drm *priv = dw_hdmi->priv;
+	int vic = drm_match_cea_mode(mode);
+	unsigned int vclk_freq;
+	unsigned int venc_freq;
+	unsigned int hdmi_freq;
+
+	vclk_freq = mode->clock;
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		vclk_freq *= 2;
+
+	venc_freq = vclk_freq;
+	hdmi_freq = vclk_freq;
+
+	if (meson_venc_hdmi_venc_repeat(vic))
+		venc_freq *= 2;
+
+	vclk_freq = max(venc_freq, hdmi_freq);
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		venc_freq /= 2;
+
+	DRM_DEBUG_DRIVER("vclk:%d venc=%d hdmi=%d enci=%d\n",
+		vclk_freq, venc_freq, hdmi_freq,
+		priv->venc.hdmi_use_enci);
+
+	meson_vclk_setup(priv, MESON_VCLK_TARGET_HDMI, vclk_freq,
+			 venc_freq, hdmi_freq, priv->venc.hdmi_use_enci);
+}
+
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi, void *data,
+			    struct drm_display_mode *mode)
+{
+	struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
+	struct meson_drm *priv = dw_hdmi->priv;
+	unsigned int wr_clk =
+		readl_relaxed(priv->io_base + _REG(VPU_HDMI_SETTING));
+
+	DRM_DEBUG_DRIVER("%d:\"%s\"\n", mode->base.id, mode->name);
+
+	/* Enable clocks */
+	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
+
+	/* Bring HDMITX MEM output of power down */
+	regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
+
+	/* Bring out of reset */
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_SW_RESET,  0);
+
+	/* Enable internal pixclk, tmds_clk, spdif_clk, i2s_clk, cecclk */
+	dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
+			       0x3, 0x3);
+	dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_CLK_CNTL,
+			       0x3 << 4, 0x3 << 4);
+
+	/* Enable normal output to PHY */
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_BIST_CNTL, BIT(12));
+
+	/* TMDS pattern setup (TOFIX pattern for 4k2k scrambling) */
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_01, 0x001f001f);
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_23, 0x001f001f);
+
+	/* Load TMDS pattern */
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x1);
+	msleep(20);
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_TMDS_CLK_PTTN_CNTL, 0x2);
+
+	/* Setup PHY parameters */
+	meson_hdmi_phy_setup_mode(dw_hdmi, mode);
+
+	/* Setup PHY */
+	regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
+			   0xffff << 16, 0x0390 << 16);
+
+	/* BIT_INVERT */
+	if (dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxl-dw-hdmi") ||
+	    dw_hdmi_is_compatible(dw_hdmi, "amlogic,meson-gxm-dw-hdmi"))
+		regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
+				   BIT(17), 0);
+	else
+		regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1,
+				   BIT(17), BIT(17));
+
+	/* Disable clock, fifo, fifo_wr */
+	regmap_update_bits(priv->hhi, HHI_HDMI_PHY_CNTL1, 0xf, 0);
+
+	msleep(100);
+
+	/* Reset PHY 3 times in a row */
+	dw_hdmi_phy_reset(dw_hdmi);
+	dw_hdmi_phy_reset(dw_hdmi);
+	dw_hdmi_phy_reset(dw_hdmi);
+
+	/* Temporary Disable VENC video stream */
+	if (priv->venc.hdmi_use_enci)
+		writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
+	else
+		writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
+
+	/* Temporary Disable HDMI video stream to HDMI-TX */
+	writel_bits_relaxed(0x3, 0,
+			    priv->io_base + _REG(VPU_HDMI_SETTING));
+	writel_bits_relaxed(0xf << 8, 0,
+			    priv->io_base + _REG(VPU_HDMI_SETTING));
+
+	/* Re-Enable VENC video stream */
+	if (priv->venc.hdmi_use_enci)
+		writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
+	else
+		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
+
+	/* Push back HDMI clock settings */
+	writel_bits_relaxed(0xf << 8, wr_clk & (0xf << 8),
+			    priv->io_base + _REG(VPU_HDMI_SETTING));
+
+	/* Enable and Select HDMI video source for HDMI-TX */
+	if (priv->venc.hdmi_use_enci)
+		writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCI,
+				    priv->io_base + _REG(VPU_HDMI_SETTING));
+	else
+		writel_bits_relaxed(0x3, MESON_VENC_SOURCE_ENCP,
+				    priv->io_base + _REG(VPU_HDMI_SETTING));
+
+	return 0;
+}
+
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi,
+				void *data)
+{
+	struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
+	struct meson_drm *priv = dw_hdmi->priv;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
+}
+
+static enum drm_connector_status dw_hdmi_read_hpd(struct dw_hdmi *hdmi,
+			     void *data)
+{
+	struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
+
+	return !!dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_STAT0) ?
+		connector_status_connected : connector_status_disconnected;
+}
+
+static void dw_hdmi_setup_hpd(struct dw_hdmi *hdmi,
+			      void *data)
+{
+	struct meson_dw_hdmi *dw_hdmi = (struct meson_dw_hdmi *)data;
+
+	/* Setup HPD Filter */
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_HPD_FILTER,
+			  (0xa << 12) | 0xa0);
+
+	/* Clear interrupts */
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
+			  HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
+
+	/* Unmask interrupts */
+	dw_hdmi_top_write_bits(dw_hdmi, HDMITX_TOP_INTR_MASKN,
+			HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL,
+			HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL);
+}
+
+static const struct dw_hdmi_phy_ops meson_dw_hdmi_phy_ops = {
+	.init = dw_hdmi_phy_init,
+	.disable = dw_hdmi_phy_disable,
+	.read_hpd = dw_hdmi_read_hpd,
+	.setup_hpd = dw_hdmi_setup_hpd,
+};
+
+static irqreturn_t dw_hdmi_top_irq(int irq, void *dev_id)
+{
+	struct meson_dw_hdmi *dw_hdmi = dev_id;
+	u32 stat;
+
+	stat = dw_hdmi_top_read(dw_hdmi, HDMITX_TOP_INTR_STAT);
+	dw_hdmi_top_write(dw_hdmi, HDMITX_TOP_INTR_STAT_CLR, stat);
+
+	/* HPD Events, handle in the threaded interrupt handler */
+	if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
+		dw_hdmi->irq_stat = stat;
+		return IRQ_WAKE_THREAD;
+	}
+
+	/* HDMI Controller Interrupt */
+	if (stat & 1)
+		return IRQ_NONE;
+
+	/* TOFIX Handle HDCP Interrupts */
+
+	return IRQ_HANDLED;
+}
+
+/* Threaded interrupt handler to manage HPD events */
+static irqreturn_t dw_hdmi_top_thread_irq(int irq, void *dev_id)
+{
+	struct meson_dw_hdmi *dw_hdmi = dev_id;
+	u32 stat = dw_hdmi->irq_stat;
+
+	/* HPD Events */
+	if (stat & (HDMITX_TOP_INTR_HPD_RISE | HDMITX_TOP_INTR_HPD_FALL)) {
+		bool hpd_connected = false;
+
+		if (stat & HDMITX_TOP_INTR_HPD_RISE)
+			hpd_connected = true;
+
+		dw_hdmi_setup_rx_sense(dw_hdmi->dev, hpd_connected,
+				       hpd_connected);
+
+		drm_helper_hpd_irq_event(dw_hdmi->encoder.dev);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* TOFIX Enable support for non-vic modes */
+static enum drm_mode_status dw_hdmi_mode_valid(struct drm_connector *connector,
+					       struct drm_display_mode *mode)
+{
+	unsigned int vclk_freq;
+	unsigned int venc_freq;
+	unsigned int hdmi_freq;
+	int vic = drm_match_cea_mode(mode);
+
+	DRM_DEBUG_DRIVER("Modeline %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
+		mode->base.id, mode->name, mode->vrefresh, mode->clock,
+		mode->hdisplay, mode->hsync_start,
+		mode->hsync_end, mode->htotal,
+		mode->vdisplay, mode->vsync_start,
+		mode->vsync_end, mode->vtotal, mode->type, mode->flags);
+
+	/* For now, only accept VIC modes */
+	if (!vic)
+		return MODE_BAD;
+
+	/* For now, filter by supported VIC modes */
+	if (!meson_venc_hdmi_supported_vic(vic))
+		return MODE_BAD;
+
+	vclk_freq = mode->clock;
+
+	/* 480i/576i needs global pixel doubling */
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		vclk_freq *= 2;
+
+	venc_freq = vclk_freq;
+	hdmi_freq = vclk_freq;
+
+	/* VENC double pixels for 1080i and 720p modes */
+	if (meson_venc_hdmi_venc_repeat(vic))
+		venc_freq *= 2;
+
+	vclk_freq = max(venc_freq, hdmi_freq);
+
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
+		venc_freq /= 2;
+
+	dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
+		vclk_freq, venc_freq, hdmi_freq);
+
+	/* Finally filter by configurable vclk frequencies */
+	switch (vclk_freq) {
+	case 54000:
+	case 74250:
+	case 148500:
+	case 297000:
+	case 594000:
+		return MODE_OK;
+	}
+
+	return MODE_CLOCK_RANGE;
+}
+
+/* Encoder */
+
+static void meson_venc_hdmi_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+
+static const struct drm_encoder_funcs meson_venc_hdmi_encoder_funcs = {
+	.destroy        = meson_venc_hdmi_encoder_destroy,
+};
+
+static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+					struct drm_crtc_state *crtc_state,
+					struct drm_connector_state *conn_state)
+{
+	return 0;
+}
+
+static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
+	struct meson_drm *priv = dw_hdmi->priv;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	writel_bits_relaxed(0x3, 0,
+			    priv->io_base + _REG(VPU_HDMI_SETTING));
+
+	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
+	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
+}
+
+static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
+{
+	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
+	struct meson_drm *priv = dw_hdmi->priv;
+
+	DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
+
+	if (priv->venc.hdmi_use_enci)
+		writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
+	else
+		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
+}
+
+static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adjusted_mode)
+{
+	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
+	struct meson_drm *priv = dw_hdmi->priv;
+	int vic = drm_match_cea_mode(mode);
+
+	DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
+			 mode->base.id, mode->name, vic);
+
+	/* Should have been filtered */
+	if (!vic)
+		return;
+
+	/* VENC + VENC-DVI Mode setup */
+	meson_venc_hdmi_mode_set(priv, vic, mode);
+
+	/* VCLK Set clock */
+	dw_hdmi_set_vclk(dw_hdmi, mode);
+
+	/* Setup YUV444 to HDMI-TX, no 10bit diphering */
+	writel_relaxed(0, priv->io_base + _REG(VPU_HDMI_FMT_CTRL));
+}
+
+static const struct drm_encoder_helper_funcs
+				meson_venc_hdmi_encoder_helper_funcs = {
+	.atomic_check	= meson_venc_hdmi_encoder_atomic_check,
+	.disable	= meson_venc_hdmi_encoder_disable,
+	.enable		= meson_venc_hdmi_encoder_enable,
+	.mode_set	= meson_venc_hdmi_encoder_mode_set,
+};
+
+/* DW HDMI Regmap */
+
+static int meson_dw_hdmi_reg_read(void *context, unsigned int reg,
+				  unsigned int *result)
+{
+	*result = dw_hdmi_dwc_read(context, reg);
+
+	return 0;
+
+}
+
+static int meson_dw_hdmi_reg_write(void *context, unsigned int reg,
+				   unsigned int val)
+{
+	dw_hdmi_dwc_write(context, reg, val);
+
+	return 0;
+}
+
+static const struct regmap_config meson_dw_hdmi_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 8,
+	.reg_read = meson_dw_hdmi_reg_read,
+	.reg_write = meson_dw_hdmi_reg_write,
+	.max_register = 0x10000,
+};
+
+static bool meson_hdmi_connector_is_available(struct device *dev)
+{
+	struct device_node *ep, *remote;
+
+	/* HDMI Connector is on the second port, first endpoint */
+	ep = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
+	if (!ep)
+		return false;
+
+	/* If the endpoint node exists, consider it enabled */
+	remote = of_graph_get_remote_port(ep);
+	if (remote) {
+		of_node_put(ep);
+		return true;
+	}
+
+	of_node_put(ep);
+	of_node_put(remote);
+
+	return false;
+}
+
+static int meson_dw_hdmi_bind(struct device *dev, struct device *master,
+				void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct meson_dw_hdmi *meson_dw_hdmi;
+	struct drm_device *drm = data;
+	struct meson_drm *priv = drm->dev_private;
+	struct dw_hdmi_plat_data *dw_plat_data;
+	struct drm_encoder *encoder;
+	struct resource *res;
+	int irq;
+	int ret;
+
+	DRM_DEBUG_DRIVER("\n");
+
+	if (!meson_hdmi_connector_is_available(dev)) {
+		dev_info(drm->dev, "HDMI Output connector not available\n");
+		return -ENODEV;
+	}
+
+	meson_dw_hdmi = devm_kzalloc(dev, sizeof(*meson_dw_hdmi),
+				     GFP_KERNEL);
+	if (!meson_dw_hdmi)
+		return -ENOMEM;
+
+	meson_dw_hdmi->priv = priv;
+	meson_dw_hdmi->dev = dev;
+	dw_plat_data = &meson_dw_hdmi->dw_plat_data;
+	encoder = &meson_dw_hdmi->encoder;
+
+	meson_dw_hdmi->hdmitx_apb = devm_reset_control_get_exclusive(dev,
+						"hdmitx_apb");
+	if (IS_ERR(meson_dw_hdmi->hdmitx_apb)) {
+		dev_err(dev, "Failed to get hdmitx_apb reset\n");
+		return PTR_ERR(meson_dw_hdmi->hdmitx_apb);
+	}
+
+	meson_dw_hdmi->hdmitx_ctrl = devm_reset_control_get_exclusive(dev,
+						"hdmitx");
+	if (IS_ERR(meson_dw_hdmi->hdmitx_ctrl)) {
+		dev_err(dev, "Failed to get hdmitx reset\n");
+		return PTR_ERR(meson_dw_hdmi->hdmitx_ctrl);
+	}
+
+	meson_dw_hdmi->hdmitx_phy = devm_reset_control_get_exclusive(dev,
+						"hdmitx_phy");
+	if (IS_ERR(meson_dw_hdmi->hdmitx_phy)) {
+		dev_err(dev, "Failed to get hdmitx_phy reset\n");
+		return PTR_ERR(meson_dw_hdmi->hdmitx_phy);
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	meson_dw_hdmi->hdmitx = devm_ioremap_resource(dev, res);
+	if (IS_ERR(meson_dw_hdmi->hdmitx))
+		return PTR_ERR(meson_dw_hdmi->hdmitx);
+
+	meson_dw_hdmi->hdmi_pclk = devm_clk_get(dev, "isfr");
+	if (IS_ERR(meson_dw_hdmi->hdmi_pclk)) {
+		dev_err(dev, "Unable to get HDMI pclk\n");
+		return PTR_ERR(meson_dw_hdmi->hdmi_pclk);
+	}
+	clk_prepare_enable(meson_dw_hdmi->hdmi_pclk);
+
+	meson_dw_hdmi->venci_clk = devm_clk_get(dev, "venci");
+	if (IS_ERR(meson_dw_hdmi->venci_clk)) {
+		dev_err(dev, "Unable to get venci clk\n");
+		return PTR_ERR(meson_dw_hdmi->venci_clk);
+	}
+	clk_prepare_enable(meson_dw_hdmi->venci_clk);
+
+	dw_plat_data->regm = devm_regmap_init(dev, NULL, meson_dw_hdmi,
+					      &meson_dw_hdmi_regmap_config);
+	if (IS_ERR(dw_plat_data->regm))
+		return PTR_ERR(dw_plat_data->regm);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "Failed to get hdmi top irq\n");
+		return irq;
+	}
+
+	ret = devm_request_threaded_irq(dev, irq, dw_hdmi_top_irq,
+					dw_hdmi_top_thread_irq, IRQF_SHARED,
+					"dw_hdmi_top_irq", meson_dw_hdmi);
+	if (ret) {
+		dev_err(dev, "Failed to request hdmi top irq\n");
+		return ret;
+	}
+
+	/* Encoder */
+
+	drm_encoder_helper_add(encoder, &meson_venc_hdmi_encoder_helper_funcs);
+
+	ret = drm_encoder_init(drm, encoder, &meson_venc_hdmi_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS, "meson_hdmi");
+	if (ret) {
+		dev_err(priv->dev, "Failed to init HDMI encoder\n");
+		return ret;
+	}
+
+	encoder->possible_crtcs = BIT(0);
+
+	DRM_DEBUG_DRIVER("encoder initialized\n");
+
+	/* Enable clocks */
+	regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL, 0xffff, 0x100);
+
+	/* Bring HDMITX MEM output of power down */
+	regmap_update_bits(priv->hhi, HHI_MEM_PD_REG0, 0xff << 8, 0);
+
+	/* Reset HDMITX APB & TX & PHY */
+	reset_control_reset(meson_dw_hdmi->hdmitx_apb);
+	reset_control_reset(meson_dw_hdmi->hdmitx_ctrl);
+	reset_control_reset(meson_dw_hdmi->hdmitx_phy);
+
+	/* Enable APB3 fail on error */
+	writel_bits_relaxed(BIT(15), BIT(15),
+			    meson_dw_hdmi->hdmitx + HDMITX_TOP_CTRL_REG);
+	writel_bits_relaxed(BIT(15), BIT(15),
+			    meson_dw_hdmi->hdmitx + HDMITX_DWC_CTRL_REG);
+
+	/* Bring out of reset */
+	dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_SW_RESET,  0);
+
+	msleep(20);
+
+	dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_CLK_CNTL, 0xff);
+
+	/* Enable HDMI-TX Interrupt */
+	dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_STAT_CLR,
+			  HDMITX_TOP_INTR_CORE);
+
+	dw_hdmi_top_write(meson_dw_hdmi, HDMITX_TOP_INTR_MASKN,
+			  HDMITX_TOP_INTR_CORE);
+
+	/* Bridge / Connector */
+
+	dw_plat_data->mode_valid = dw_hdmi_mode_valid;
+	dw_plat_data->phy_ops = &meson_dw_hdmi_phy_ops;
+	dw_plat_data->phy_name = "meson_dw_hdmi_phy";
+	dw_plat_data->phy_data = meson_dw_hdmi;
+	dw_plat_data->input_bus_format = MEDIA_BUS_FMT_YUV8_1X24;
+	dw_plat_data->input_bus_encoding = V4L2_YCBCR_ENC_709;
+
+	ret = dw_hdmi_bind(pdev, encoder, &meson_dw_hdmi->dw_plat_data);
+	if (ret)
+		return ret;
+
+	DRM_DEBUG_DRIVER("HDMI controller initialized\n");
+
+	return 0;
+}
+
+static void meson_dw_hdmi_unbind(struct device *dev, struct device *master,
+				   void *data)
+{
+	dw_hdmi_unbind(dev);
+}
+
+static const struct component_ops meson_dw_hdmi_ops = {
+	.bind	= meson_dw_hdmi_bind,
+	.unbind	= meson_dw_hdmi_unbind,
+};
+
+static int meson_dw_hdmi_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &meson_dw_hdmi_ops);
+}
+
+static int meson_dw_hdmi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &meson_dw_hdmi_ops);
+
+	return 0;
+}
+
+static const struct of_device_id meson_dw_hdmi_of_table[] = {
+	{ .compatible = "amlogic,meson-gxbb-dw-hdmi" },
+	{ .compatible = "amlogic,meson-gxl-dw-hdmi" },
+	{ .compatible = "amlogic,meson-gxm-dw-hdmi" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, meson_dw_hdmi_of_table);
+
+static struct platform_driver meson_dw_hdmi_platform_driver = {
+	.probe		= meson_dw_hdmi_probe,
+	.remove		= meson_dw_hdmi_remove,
+	.driver		= {
+		.name		= DRIVER_NAME,
+		.of_match_table	= meson_dw_hdmi_of_table,
+	},
+};
+module_platform_driver(meson_dw_hdmi_platform_driver);
+
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.h b/drivers/gpu/drm/meson/meson_dw_hdmi.h
new file mode 100644
index 0000000..0b81183
--- /dev/null
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __MESON_DW_HDMI_H
+#define __MESON_DW_HDMI_H
+
+/*
+ * Bit 7 RW Reserved. Default 1.
+ * Bit 6 RW Reserved. Default 1.
+ * Bit 5 RW Reserved. Default 1.
+ * Bit 4 RW sw_reset_phyif: PHY interface. 1=Apply reset; 0=Release from reset.
+ *     Default 1.
+ * Bit 3 RW sw_reset_intr: interrupt module. 1=Apply reset;
+ *     0=Release from reset.
+ *     Default 1.
+ * Bit 2 RW sw_reset_mem: KSV/REVOC mem. 1=Apply reset; 0=Release from reset.
+ *     Default 1.
+ * Bit 1 RW sw_reset_rnd: random number interface to HDCP. 1=Apply reset;
+ *     0=Release from reset. Default 1.
+ * Bit 0 RW sw_reset_core: connects to IP's ~irstz. 1=Apply reset;
+ *     0=Release from reset. Default 1.
+ */
+#define HDMITX_TOP_SW_RESET                     (0x000)
+
+/*
+ * Bit 12 RW i2s_ws_inv:1=Invert i2s_ws; 0=No invert. Default 0.
+ * Bit 11 RW i2s_clk_inv: 1=Invert i2s_clk; 0=No invert. Default 0.
+ * Bit 10 RW spdif_clk_inv: 1=Invert spdif_clk; 0=No invert. Default 0.
+ * Bit 9 RW tmds_clk_inv: 1=Invert tmds_clk; 0=No invert. Default 0.
+ * Bit 8 RW pixel_clk_inv: 1=Invert pixel_clk; 0=No invert. Default 0.
+ * Bit 4 RW cec_clk_en: 1=enable cec_clk; 0=disable. Default 0.
+ * Bit 3 RW i2s_clk_en: 1=enable i2s_clk; 0=disable. Default 0.
+ * Bit 2 RW spdif_clk_en: 1=enable spdif_clk; 0=disable. Default 0.
+ * Bit 1 RW tmds_clk_en: 1=enable tmds_clk;  0=disable. Default 0.
+ * Bit 0 RW pixel_clk_en: 1=enable pixel_clk; 0=disable. Default 0.
+ */
+#define HDMITX_TOP_CLK_CNTL                     (0x001)
+
+/*
+ * Bit 11: 0 RW hpd_valid_width: filter out width <= M*1024.    Default 0.
+ * Bit 15:12 RW hpd_glitch_width: filter out glitch <= N.       Default 0.
+ */
+#define HDMITX_TOP_HPD_FILTER                   (0x002)
+
+/*
+ * intr_maskn: MASK_N, one bit per interrupt source.
+ *     1=Enable interrupt source; 0=Disable interrupt source. Default 0.
+ * [  4] hdcp22_rndnum_err
+ * [  3] nonce_rfrsh_rise
+ * [  2] hpd_fall_intr
+ * [  1] hpd_rise_intr
+ * [  0] core_intr
+ */
+#define HDMITX_TOP_INTR_MASKN                   (0x003)
+
+/*
+ * Bit 30: 0 RW intr_stat: For each bit, write 1 to manually set the interrupt
+ *     bit, read back the interrupt status.
+ * Bit    31 R  IP interrupt status
+ * Bit     2 RW hpd_fall
+ * Bit     1 RW hpd_rise
+ * Bit     0 RW IP interrupt
+ */
+#define HDMITX_TOP_INTR_STAT                    (0x004)
+
+/*
+ * [4]	  hdcp22_rndnum_err
+ * [3]	  nonce_rfrsh_rise
+ * [2]	  hpd_fall
+ * [1]	  hpd_rise
+ * [0]	  core_intr_rise
+ */
+#define HDMITX_TOP_INTR_STAT_CLR                (0x005)
+
+#define HDMITX_TOP_INTR_CORE		BIT(0)
+#define HDMITX_TOP_INTR_HPD_RISE	BIT(1)
+#define HDMITX_TOP_INTR_HPD_FALL	BIT(2)
+
+/* Bit 14:12 RW tmds_sel: 3'b000=Output zero; 3'b001=Output normal TMDS data;
+ *     3'b010=Output PRBS data; 3'b100=Output shift pattern. Default 0.
+ * Bit 11: 9 RW shift_pttn_repeat: 0=New pattern every clk cycle; 1=New pattern
+ *     every 2 clk cycles; ...; 7=New pattern every 8 clk cycles. Default 0.
+ * Bit 8 RW shift_pttn_en: 1= Enable shift pattern generator; 0=Disable.
+ *     Default 0.
+ * Bit 4: 3 RW prbs_pttn_mode: 0=PRBS11; 1=PRBS15; 2=PRBS7; 3=PRBS31. Default 0.
+ * Bit 2: 1 RW prbs_pttn_width: 0=idle; 1=output 8-bit pattern;
+ *     2=Output 1-bit pattern; 3=output 10-bit pattern. Default 0.
+ * Bit 0 RW prbs_pttn_en: 1=Enable PRBS generator; 0=Disable. Default 0.
+ */
+#define HDMITX_TOP_BIST_CNTL                    (0x006)
+
+/* Bit 29:20 RW shift_pttn_data[59:50]. Default 0. */
+/* Bit 19:10 RW shift_pttn_data[69:60]. Default 0. */
+/* Bit  9: 0 RW shift_pttn_data[79:70]. Default 0. */
+#define HDMITX_TOP_SHIFT_PTTN_012               (0x007)
+
+/* Bit 29:20 RW shift_pttn_data[29:20]. Default 0. */
+/* Bit 19:10 RW shift_pttn_data[39:30]. Default 0. */
+/* Bit  9: 0 RW shift_pttn_data[49:40]. Default 0. */
+#define HDMITX_TOP_SHIFT_PTTN_345               (0x008)
+
+/* Bit 19:10 RW shift_pttn_data[ 9: 0]. Default 0. */
+/* Bit  9: 0 RW shift_pttn_data[19:10]. Default 0. */
+#define HDMITX_TOP_SHIFT_PTTN_67                (0x009)
+
+/* Bit 25:16 RW tmds_clk_pttn[19:10]. Default 0. */
+/* Bit  9: 0 RW tmds_clk_pttn[ 9: 0]. Default 0. */
+#define HDMITX_TOP_TMDS_CLK_PTTN_01             (0x00A)
+
+/* Bit 25:16 RW tmds_clk_pttn[39:30]. Default 0. */
+/* Bit  9: 0 RW tmds_clk_pttn[29:20]. Default 0. */
+#define HDMITX_TOP_TMDS_CLK_PTTN_23             (0x00B)
+
+/* Bit 1 RW shift_tmds_clk_pttn:1=Enable shifting clk pattern,
+ * used when TMDS CLK rate = TMDS character rate /4. Default 0.
+ * Bit 0 R  Reserved. Default 0.
+ * [	1] shift_tmds_clk_pttn
+ * [	0] load_tmds_clk_pttn
+ */
+#define HDMITX_TOP_TMDS_CLK_PTTN_CNTL           (0x00C)
+
+/* Bit 0 RW revocmem_wr_fail: Read back 1 to indicate Host write REVOC MEM
+ * failure, write 1 to clear the failure flag.  Default 0.
+ */
+#define HDMITX_TOP_REVOCMEM_STAT                (0x00D)
+
+/* Bit     0 R  filtered HPD status. */
+#define HDMITX_TOP_STAT0                        (0x00E)
+
+#endif /* __MESON_DW_HDMI_H */
-- 
1.9.1

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

* [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (6 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 07/13] drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-04-04  8:41   ` Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output Neil Armstrong
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree

The HDMI modes needs more CMA memory to be reserved at boot-time.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 5d995f7..94c6f95 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -71,6 +71,14 @@
 			reg = <0x0 0x10000000 0x0 0x200000>;
 			no-map;
 		};
+
+		linux,cma {
+			compatible = "shared-dma-pool";
+			reusable;
+			size = <0x0 0xbc00000>;
+			alignment = <0x0 0x400000>;
+			linux,cma-default;
+		};
 	};
 
 	cpus {
-- 
1.9.1

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

* [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (7 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-04-04  8:10   ` Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 10/13] dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension Neil Armstrong
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree

Add HDMI output and connector nodes.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 39 ++++++++++++++++++++++
 arch/arm64/boot/dts/amlogic/meson-gx.dtsi          | 32 ++++++++++++++++++
 .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts    | 23 +++++++++++++
 arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi   | 23 +++++++++++++
 arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        | 12 +++++++
 .../dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts    | 23 +++++++++++++
 arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         | 13 ++++++++
 .../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 23 +++++++++++++
 arch/arm64/boot/dts/amlogic/meson-gxm.dtsi         |  3 ++
 9 files changed, 191 insertions(+)

diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
index 7a078be..a84e276 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
@@ -98,6 +98,27 @@
 		clocks = <&wifi32k>;
 		clock-names = "ext_clock";
 	};
+
+	cvbs-connector {
+		compatible = "composite-video-connector";
+
+		port {
+			cvbs_connector_in: endpoint {
+				remote-endpoint = <&cvbs_vdac_out>;
+			};
+		};
+	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi_tx_tmds_out>;
+			};
+		};
+	};
 };
 
 /* This UART is brought out to the DB9 connector */
@@ -188,3 +209,21 @@
 &ethmac {
 	status = "okay";
 };
+
+&cvbs_vdac_port {
+	cvbs_vdac_out: endpoint {
+		remote-endpoint = <&cvbs_connector_in>;
+	};
+};
+
+&hdmi_tx {
+	status = "okay";
+	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+	pinctrl-names = "default";
+};
+
+&hdmi_tx_tmds_port {
+	hdmi_tx_tmds_out: endpoint {
+		remote-endpoint = <&hdmi_connector_in>;
+	};
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
index 94c6f95..0dda058 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
@@ -465,6 +465,38 @@
 			cvbs_vdac_port: port@0 {
 				reg = <0>;
 			};
+
+			/* HDMI-TX output port */
+			hdmi_tx_port: port@1 {
+				reg = <1>;
+
+				hdmi_tx_out: endpoint {
+					remote-endpoint = <&hdmi_tx_in>;
+				};
+			};
+		};
+
+		hdmi_tx: hdmi-tx@c883a000 {
+			compatible = "amlogic,meson-gx-dw-hdmi";
+			reg = <0x0 0xc883a000 0x0 0x1c>;
+			interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+
+			/* VPU VENC Input */
+			hdmi_tx_venc_port: port@0 {
+				reg = <0>;
+
+				hdmi_tx_in: endpoint {
+					remote-endpoint = <&hdmi_tx_out>;
+				};
+			};
+
+			/* TMDS Output */
+			hdmi_tx_tmds_port: port@1 {
+				reg = <1>;
+			};
 		};
 	};
 };
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
index 4cbd626..a2c999f 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
@@ -152,6 +152,17 @@
 			};
 		};
 	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi_tx_tmds_out>;
+			};
+		};
+	};
 };
 
 &uart_AO {
@@ -245,3 +256,15 @@
 		remote-endpoint = <&cvbs_connector_in>;
 	};
 };
+
+&hdmi_tx {
+	status = "okay";
+	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+	pinctrl-names = "default";
+};
+
+&hdmi_tx_tmds_port {
+	hdmi_tx_tmds_out: endpoint {
+		remote-endpoint = <&hdmi_connector_in>;
+	};
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
index 4a96e0f..1c96fc8 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
@@ -135,6 +135,17 @@
 			};
 		};
 	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi_tx_tmds_out>;
+			};
+		};
+	};
 };
 
 /* This UART is brought out to the DB9 connector */
@@ -250,3 +261,15 @@
 		remote-endpoint = <&cvbs_connector_in>;
 	};
 };
+
+&hdmi_tx {
+	status = "okay";
+	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+	pinctrl-names = "default";
+};
+
+&hdmi_tx_tmds_port {
+	hdmi_tx_tmds_out: endpoint {
+		remote-endpoint = <&hdmi_connector_in>;
+	};
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
index 04b3324..9716e65 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
@@ -524,3 +524,15 @@
 &vpu {
 	compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu";
 };
+
+&hdmi_tx {
+	compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
+	resets = <&reset RESET_HDMITX_CAPB3>,
+		 <&reset RESET_HDMI_SYSTEM_RESET>,
+		 <&reset RESET_HDMI_TX>;
+	reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
+	clocks = <&clkc CLKID_HDMI_PCLK>,
+		 <&clkc CLKID_CLK81>,
+		 <&clkc CLKID_GCLK_VENCI_INT0>;
+	clock-names = "isfr", "iahb", "venci";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
index cea4a3e..8873c05 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
@@ -127,6 +127,17 @@
 			};
 		};
 	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi_tx_tmds_out>;
+			};
+		};
+	};
 };
 
 &uart_AO {
@@ -219,3 +230,15 @@
 		remote-endpoint = <&cvbs_connector_in>;
 	};
 };
+
+&hdmi_tx {
+	status = "okay";
+	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+	pinctrl-names = "default";
+};
+
+&hdmi_tx_tmds_port {
+	hdmi_tx_tmds_out: endpoint {
+		remote-endpoint = <&hdmi_connector_in>;
+	};
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
index fe11b5f..9dcac25 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
@@ -44,6 +44,7 @@
 #include "meson-gx.dtsi"
 #include <dt-bindings/clock/gxbb-clkc.h>
 #include <dt-bindings/gpio/meson-gxl-gpio.h>
+#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
 
 / {
 	compatible = "amlogic,meson-gxl";
@@ -381,3 +382,15 @@
 &vpu {
 	compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu";
 };
+
+&hdmi_tx {
+	compatible = "amlogic,meson-gxl-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
+	resets = <&reset RESET_HDMITX_CAPB3>,
+		 <&reset RESET_HDMI_SYSTEM_RESET>,
+		 <&reset RESET_HDMI_TX>;
+	reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
+	clocks = <&clkc CLKID_HDMI_PCLK>,
+		 <&clkc CLKID_CLK81>,
+		 <&clkc CLKID_GCLK_VENCI_INT0>;
+	clock-names = "isfr", "iahb", "venci";
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
index 5a337d3..0e68c62e 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
@@ -100,6 +100,17 @@
 			};
 		};
 	};
+
+	hdmi-connector {
+		compatible = "hdmi-connector";
+		type = "a";
+
+		port {
+			hdmi_connector_in: endpoint {
+				remote-endpoint = <&hdmi_tx_tmds_out>;
+			};
+		};
+	};
 };
 
 /* This UART is brought out to the DB9 connector */
@@ -183,3 +194,15 @@
 		remote-endpoint = <&cvbs_connector_in>;
 	};
 };
+
+&hdmi_tx {
+	status = "okay";
+	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
+	pinctrl-names = "default";
+};
+
+&hdmi_tx_tmds_port {
+	hdmi_tx_tmds_out: endpoint {
+		remote-endpoint = <&hdmi_connector_in>;
+	};
+};
diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
index ddea730..fe451cc 100644
--- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
+++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
@@ -130,3 +130,6 @@
 	compatible = "amlogic,meson-gxm-vpu", "amlogic,meson-gx-vpu";
 };
 
+&hdmi_tx {
+	compatible = "amlogic,meson-gxm-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
+};
-- 
1.9.1

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

* [PATCH v2 10/13] dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (8 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 11/13] drm/meson: Convert existing documentation to actual kerneldoc Neil Armstrong
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree

This binding describes the Amlogic Meson specific extension to the
Synopsys Designware HDMI Controller.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 .../bindings/display/amlogic,meson-dw-hdmi.txt     | 111 +++++++++++++++++++++
 1 file changed, 111 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt

diff --git a/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
new file mode 100644
index 0000000..7f040ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
@@ -0,0 +1,111 @@
+Amlogic specific extensions to the Synopsys Designware HDMI Controller
+======================================================================
+
+The Amlogic Meson Synopsys Designware Integration is composed of :
+- A Synopsys DesignWare HDMI Controller IP
+- A TOP control block controlling the Clocks and PHY
+- A custom HDMI PHY in order to convert video to TMDS signal
+ ___________________________________
+|            HDMI TOP               |<= HPD
+|___________________________________|
+|                  |                |
+|  Synopsys HDMI   |   HDMI PHY     |=> TMDS
+|    Controller    |________________|
+|___________________________________|<=> DDC
+
+The HDMI TOP block only supports HPD sensing.
+The Synopsys HDMI Controller interrupt is routed through the
+TOP Block interrupt.
+Communication to the TOP Block and the Synopsys HDMI Controller is done
+via a pair of dedicated addr+read/write registers.
+The HDMI PHY is configured by registers in the HHI register block.
+
+Pixel data arrives in 4:4:4 format from the VENC block and the VPU HDMI mux
+selects either the ENCI encoder for the 576i or 480i formats or the ENCP
+encoder for all the other formats including interlaced HD formats.
+
+The VENC uses a DVI encoder on top of the ENCI or ENCP encoders to generate
+DVI timings for the HDMI controller.
+
+Amlogic Meson GXBB, GXL and GXM SoCs families embeds the Synopsys DesignWare
+HDMI TX IP version 2.01a with HDCP and I2C & S/PDIF
+audio source interfaces.
+
+Required properties:
+- compatible: value should be different for each SoC family as :
+	- GXBB (S905) : "amlogic,meson-gxbb-dw-hdmi"
+	- GXL (S905X, S905D) : "amlogic,meson-gxl-dw-hdmi"
+	- GXM (S912) : "amlogic,meson-gxm-dw-hdmi"
+	followed by the common "amlogic,meson-gx-dw-hdmi"
+- reg: Physical base address and length of the controller's registers.
+- interrupts: The HDMI interrupt number
+- clocks, clock-names : must have the phandles to the HDMI iahb and isfr clocks,
+  and the Amlogic Meson venci clocks as described in
+  Documentation/devicetree/bindings/clock/clock-bindings.txt,
+  the clocks are soc specific, the clock-names should be "iahb", "isfr", "venci"
+- resets, resets-names: must have the phandles to the HDMI apb, glue and phy
+  resets as described in :
+  Documentation/devicetree/bindings/reset/reset.txt,
+  the reset-names should be "hdmitx_apb", "hdmitx", "hdmitx_phy"
+
+Required nodes:
+
+The connections to the HDMI ports are modeled using the OF graph
+bindings specified in Documentation/devicetree/bindings/graph.txt.
+
+The following table lists for each supported model the port number
+corresponding to each HDMI output and input.
+
+		Port 0		Port 1
+-----------------------------------------
+ S905 (GXBB)	VENC Input	TMDS Output
+ S905X (GXL)	VENC Input	TMDS Output
+ S905D (GXL)	VENC Input	TMDS Output
+ S912 (GXM)	VENC Input	TMDS Output
+
+Example:
+
+hdmi-connector {
+	compatible = "hdmi-connector";
+	type = "a";
+
+	port {
+		hdmi_connector_in: endpoint {
+			remote-endpoint = <&hdmi_tx_tmds_out>;
+		};
+	};
+};
+
+hdmi_tx: hdmi-tx@c883a000 {
+	compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
+	reg = <0x0 0xc883a000 0x0 0x1c>;
+	interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
+	resets = <&reset RESET_HDMITX_CAPB3>,
+		 <&reset RESET_HDMI_SYSTEM_RESET>,
+		 <&reset RESET_HDMI_TX>;
+	reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
+	clocks = <&clkc CLKID_HDMI_PCLK>,
+		 <&clkc CLKID_CLK81>,
+		 <&clkc CLKID_GCLK_VENCI_INT0>;
+	clock-names = "isfr", "iahb", "venci";
+	#address-cells = <1>;
+	#size-cells = <0>;
+
+	/* VPU VENC Input */
+	hdmi_tx_venc_port: port@0 {
+		reg = <0>;
+
+		hdmi_tx_in: endpoint {
+			remote-endpoint = <&hdmi_tx_out>;
+		};
+	};
+
+	/* TMDS Output */
+	hdmi_tx_tmds_port: port@1 {
+		reg = <1>;
+
+		hdmi_tx_tmds_out: endpoint {
+			remote-endpoint = <&hdmi_connector_in>;
+		};
+	};
+};
-- 
1.9.1

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

* [PATCH v2 11/13] drm/meson: Convert existing documentation to actual kerneldoc
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (9 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 10/13] dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-03-21 15:25 ` [PATCH v2 12/13] drm/meson: Add RST to bring together kerneldoc Neil Armstrong
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 drivers/gpu/drm/meson/meson_canvas.c  |  4 +++-
 drivers/gpu/drm/meson/meson_drv.c     |  5 +++--
 drivers/gpu/drm/meson/meson_dw_hdmi.c | 25 +++++++++++++++++--------
 drivers/gpu/drm/meson/meson_vclk.c    | 22 +++++++++++++++-------
 drivers/gpu/drm/meson/meson_venc.c    | 25 ++++++++++++++++---------
 drivers/gpu/drm/meson/meson_viu.c     |  6 +++++-
 drivers/gpu/drm/meson/meson_vpp.c     |  8 ++++++--
 7 files changed, 65 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_canvas.c b/drivers/gpu/drm/meson/meson_canvas.c
index 4109e36..08f6073 100644
--- a/drivers/gpu/drm/meson/meson_canvas.c
+++ b/drivers/gpu/drm/meson/meson_canvas.c
@@ -24,7 +24,9 @@
 #include "meson_canvas.h"
 #include "meson_registers.h"
 
-/*
+/**
+ * DOC: Canvas
+ *
  * CANVAS is a memory zone where physical memory frames information
  * are stored for the VIU to scanout.
  */
diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
index a2e9f56..75382f5 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -52,13 +52,14 @@
 #define DRIVER_NAME "meson"
 #define DRIVER_DESC "Amlogic Meson DRM driver"
 
-/*
- * Video Processing Unit
+/**
+ * DOC: Video Processing Unit
  *
  * VPU Handles the Global Video Processing, it includes management of the
  * clocks gates, blocks reset lines and power domains.
  *
  * What is missing :
+ *
  * - Full reset of entire video processing HW blocks
  * - Scaling and setup of the VPU clock
  * - Bus clock gates
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index 8851dcb..7b86eb7 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -42,18 +42,25 @@
 #define DRIVER_NAME "meson-dw-hdmi"
 #define DRIVER_DESC "Amlogic Meson HDMI-TX DRM driver"
 
-/*
+/**
+ * DOC: HDMI Output
+ *
  * HDMI Output is composed of :
+ *
  * - A Synopsys DesignWare HDMI Controller IP
  * - A TOP control block controlling the Clocks and PHY
  * - A custom HDMI PHY in order convert video to TMDS signal
- *  ___________________________________
- * |            HDMI TOP               |<= HPD
- * |___________________________________|
- * |                  |                |
- * |  Synopsys HDMI   |   HDMI PHY     |=> TMDS
- * |    Controller    |________________|
- * |___________________________________|<=> DDC
+ *
+ * .. code::
+ *
+ *    ___________________________________
+ *   |            HDMI TOP               |<= HPD
+ *   |___________________________________|
+ *   |                  |                |
+ *   |  Synopsys HDMI   |   HDMI PHY     |=> TMDS
+ *   |    Controller    |________________|
+ *   |___________________________________|<=> DDC
+ *
  *
  * The HDMI TOP block only supports HPD sensing.
  * The Synopsys HDMI Controller interrupt is routed
@@ -78,6 +85,7 @@
  * audio source interfaces.
  *
  * We handle the following features :
+ *
  * - HPD Rise & Fall interrupt
  * - HDMI Controller Interrupt
  * - HDMI PHY Init for 480i to 1080p60
@@ -85,6 +93,7 @@
  * - VENC Mode setup for 480i to 1080p60
  *
  * What is missing :
+ *
  * - PHY, Clock and Mode setup for 2k && 4k modes
  * - SDDC Scrambling mode for HDMI 2.0a
  * - HDCP Setup
diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
index 3731479..4767704 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -23,21 +23,29 @@
 #include "meson_drv.h"
 #include "meson_vclk.h"
 
-/*
+/**
+ * DOC: Video Clocks
+ *
  * VCLK is the "Pixel Clock" frequency generator from a dedicated PLL.
  * We handle the following encodings :
+ *
  * - CVBS 27MHz generator via the VCLK2 to the VENCI and VDAC blocks
  * - HDMI Pixel Clocks generation
+ *
  * What is missing :
+ *
  * - Genenate Pixel clocks for 2K/4K 10bit formats
  *
  * Clock generator scheme :
- *  __________   _________            _____
- * |          | |         |          |     |--ENCI
- * | HDMI PLL |-| PLL_DIV |--- VCLK--|     |--ENCL
- * |__________| |_________| \        | MUX |--ENCP
- *                           --VCLK2-|     |--VDAC
- *                                   |_____|--HDMI-TX
+ *
+ * .. code::
+ *
+ *    __________   _________            _____
+ *   |          | |         |          |     |--ENCI
+ *   | HDMI PLL |-| PLL_DIV |--- VCLK--|     |--ENCL
+ *   |__________| |_________| \        | MUX |--ENCP
+ *                             --VCLK2-|     |--VDAC
+ *                                     |_____|--HDMI-TX
  *
  * Final clocks can take input for either VCLK or VCLK2, but
  * VCLK is the preferred path for HDMI clocking and VCLK2 is the
diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c
index 31dc275..9509017 100644
--- a/drivers/gpu/drm/meson/meson_venc.c
+++ b/drivers/gpu/drm/meson/meson_venc.c
@@ -26,26 +26,33 @@
 #include "meson_vclk.h"
 #include "meson_registers.h"
 
-/*
+/**
+ * DOC: Video Encoder
+ *
  * VENC Handle the pixels encoding to the output formats.
  * We handle the following encodings :
+ *
  * - CVBS Encoding via the ENCI encoder and VDAC digital to analog converter
  * - TMDS/HDMI Encoding via ENCI_DIV and ENCP
  * - Setup of more clock rates for HDMI modes
  *
  * What is missing :
+ *
  * - LCD Panel encoding via ENCL
  * - TV Panel encoding via ENCT
  *
  * VENC paths :
- *        _____   _____   ____________________
- * vd1---|     |-|     | | VENC     /---------|----VDAC
- * vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|\
- * osd1--|     |-|     | | \                  | X--HDMI-TX
- * osd2--|_____|-|_____| |  |\-ENCP--ENCP_DVI-|/
- *                       |  |                 |
- *                       |  \--ENCL-----------|----LVDS
- *                       |____________________|
+ *
+ * .. code::
+ *
+ *          _____   _____   ____________________
+ *   vd1---|     |-|     | | VENC     /---------|----VDAC
+ *   vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|-|
+ *   osd1--|     |-|     | | \                  | X--HDMI-TX
+ *   osd2--|_____|-|_____| |  |\-ENCP--ENCP_DVI-|-|
+ *                         |  |                 |
+ *                         |  \--ENCL-----------|----LVDS
+ *                         |____________________|
  *
  * The ENCI is designed for PAl or NTSC encoding and can go through the VDAC
  * directly for CVBS encoding or through the ENCI_DVI encoder for HDMI.
diff --git a/drivers/gpu/drm/meson/meson_viu.c b/drivers/gpu/drm/meson/meson_viu.c
index a6de8ba..6bcfa52 100644
--- a/drivers/gpu/drm/meson/meson_viu.c
+++ b/drivers/gpu/drm/meson/meson_viu.c
@@ -28,9 +28,12 @@
 #include "meson_canvas.h"
 #include "meson_registers.h"
 
-/*
+/**
+ * DOC: Video Input Unit
+ *
  * VIU Handles the Pixel scanout and the basic Colorspace conversions
  * We handle the following features :
+ *
  * - OSD1 RGB565/RGB888/xRGB8888 scanout
  * - RGB conversion to x/cb/cr
  * - Progressive or Interlace buffer scanout
@@ -38,6 +41,7 @@
  * - HDR OSD matrix for GXL/GXM
  *
  * What is missing :
+ *
  * - BGR888/xBGR8888/BGRx8888/BGRx8888 modes
  * - YUV4:2:2 Y0CbY1Cr scanout
  * - Conversion to YUV 4:4:4 from 4:2:2 input
diff --git a/drivers/gpu/drm/meson/meson_vpp.c b/drivers/gpu/drm/meson/meson_vpp.c
index 671909d..27356f8 100644
--- a/drivers/gpu/drm/meson/meson_vpp.c
+++ b/drivers/gpu/drm/meson/meson_vpp.c
@@ -25,16 +25,20 @@
 #include "meson_vpp.h"
 #include "meson_registers.h"
 
-/*
+/**
+ * DOC: Video Post Processing
+ *
  * VPP Handles all the Post Processing after the Scanout from the VIU
  * We handle the following post processings :
- * - Postblend : Blends the OSD1 only
+ *
+ * - Postblend, Blends the OSD1 only
  *	We exclude OSD2, VS1, VS1 and Preblend output
  * - Vertical OSD Scaler for OSD1 only, we disable vertical scaler and
  *	use it only for interlace scanout
  * - Intermediate FIFO with default Amlogic values
  *
  * What is missing :
+ *
  * - Preblend for video overlay pre-scaling
  * - OSD2 support for cursor framebuffer
  * - Video pre-scaling before postblend
-- 
1.9.1

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

* [PATCH v2 12/13] drm/meson: Add RST to bring together kerneldoc
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (10 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 11/13] drm/meson: Convert existing documentation to actual kerneldoc Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-04-04  9:00   ` Daniel Vetter
  2017-03-21 15:25 ` [PATCH v2 13/13] MAINTAINERS: update files for Amlogic DRM Driver Neil Armstrong
  2017-04-04  9:04 ` [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Daniel Vetter
  13 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 Documentation/gpu/index.rst |  1 +
 Documentation/gpu/meson.rst | 61 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)
 create mode 100644 Documentation/gpu/meson.rst

diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst
index e998ee0..7eceb97 100644
--- a/Documentation/gpu/index.rst
+++ b/Documentation/gpu/index.rst
@@ -11,6 +11,7 @@ Linux GPU Driver Developer's Guide
    drm-kms-helpers
    drm-uapi
    i915
+   meson
    tinydrm
    vc4
    vga-switcheroo
diff --git a/Documentation/gpu/meson.rst b/Documentation/gpu/meson.rst
new file mode 100644
index 0000000..479f6f5
--- /dev/null
+++ b/Documentation/gpu/meson.rst
@@ -0,0 +1,61 @@
+=============================================
+drm/meson AmLogic Meson Video Processing Unit
+=============================================
+
+.. kernel-doc:: drivers/gpu/drm/meson/meson_drv.c
+   :doc: Video Processing Unit
+
+Video Processing Unit
+=====================
+
+The Amlogic Meson Display controller is composed of several components
+that are going to be documented below:
+
+.. code::
+
+  DMC|---------------VPU (Video Processing Unit)----------------|------HHI------|
+     | vd1   _______     _____________    _________________     |               |
+  D  |-------|      |----|            |   |                |    |   HDMI PLL    |
+  D  | vd2   | VIU  |    | Video Post |   | Video Encoders |<---|-----VCLK      |
+  R  |-------|      |----| Processing |   |                |    |               |
+     | osd2  |      |    |            |---| Enci ----------|----|-----VDAC------|
+  R  |-------| CSC  |----| Scalers    |   | Encp ----------|----|----HDMI-TX----|
+  A  | osd1  |      |    | Blenders   |   | Encl ----------|----|---------------|
+  M  |-------|______|----|____________|   |________________|    |               |
+  ___|__________________________________________________________|_______________|
+
+Video Input Unit
+================
+
+.. kernel-doc:: drivers/gpu/drm/meson/meson_viu.c
+   :doc: Video Input Unit
+
+Video Post Processing
+=====================
+
+.. kernel-doc:: drivers/gpu/drm/meson/meson_vpp.c
+   :doc: Video Post Processing
+
+Video Encoder
+=============
+
+.. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c
+   :doc: Video Encoder
+
+Video Canvas Management
+=======================
+
+.. kernel-doc:: drivers/gpu/drm/meson/meson_canvas.c
+   :doc: Canvas
+
+Video Clocks
+============
+
+.. kernel-doc:: drivers/gpu/drm/meson/meson_vclk.c
+   :doc: Video Clocks
+
+HDMI Video Output
+=================
+
+.. kernel-doc:: drivers/gpu/drm/meson/meson_dw_hdmi.c
+   :doc: HDMI Output
-- 
1.9.1

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

* [PATCH v2 13/13] MAINTAINERS: update files for Amlogic DRM Driver
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (11 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 12/13] drm/meson: Add RST to bring together kerneldoc Neil Armstrong
@ 2017-03-21 15:25 ` Neil Armstrong
  2017-04-04  9:01   ` Daniel Vetter
  2017-04-04  9:04 ` [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Daniel Vetter
  13 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-03-21 15:25 UTC (permalink / raw)
  To: airlied
  Cc: Neil Armstrong, dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel

This patch adds the dw-hdmi bindings and RST kerneldoc to maintained files.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e88154f..3df68c73 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4256,6 +4256,8 @@ W:	http://linux-meson.com/
 S:	Supported
 F:	drivers/gpu/drm/meson/
 F:	Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
+F:	Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
+F:	Documentation/gpu/meson.rst
 T:	git git://anongit.freedesktop.org/drm/drm-meson
 T:	git git://anongit.freedesktop.org/drm/drm-misc
 
-- 
1.9.1

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

* Re: [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output
  2017-03-21 15:25 ` [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output Neil Armstrong
@ 2017-04-04  8:10   ` Neil Armstrong
  2017-04-04 11:57     ` Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-04-04  8:10 UTC (permalink / raw)
  To: airlied
  Cc: dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel, devicetree

On 03/21/2017 04:25 PM, Neil Armstrong wrote:
> Add HDMI output and connector nodes.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 39 ++++++++++++++++++++++
>  arch/arm64/boot/dts/amlogic/meson-gx.dtsi          | 32 ++++++++++++++++++
>  .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts    | 23 +++++++++++++
>  arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi   | 23 +++++++++++++
>  arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        | 12 +++++++
>  .../dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts    | 23 +++++++++++++
>  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         | 13 ++++++++
>  .../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts | 23 +++++++++++++
>  arch/arm64/boot/dts/amlogic/meson-gxm.dtsi         |  3 ++
>  9 files changed, 191 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> index 7a078be..a84e276 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi
> @@ -98,6 +98,27 @@
>  		clocks = <&wifi32k>;
>  		clock-names = "ext_clock";
>  	};
> +
> +	cvbs-connector {
> +		compatible = "composite-video-connector";
> +
> +		port {
> +			cvbs_connector_in: endpoint {
> +				remote-endpoint = <&cvbs_vdac_out>;
> +			};
> +		};
> +	};
> +
> +	hdmi-connector {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi_connector_in: endpoint {
> +				remote-endpoint = <&hdmi_tx_tmds_out>;
> +			};
> +		};
> +	};
>  };
>  
>  /* This UART is brought out to the DB9 connector */
> @@ -188,3 +209,21 @@
>  &ethmac {
>  	status = "okay";
>  };
> +
> +&cvbs_vdac_port {
> +	cvbs_vdac_out: endpoint {
> +		remote-endpoint = <&cvbs_connector_in>;
> +	};
> +};
> +
> +&hdmi_tx {
> +	status = "okay";
> +	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> +	pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> +	hdmi_tx_tmds_out: endpoint {
> +		remote-endpoint = <&hdmi_connector_in>;
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> index 94c6f95..0dda058 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> @@ -465,6 +465,38 @@
>  			cvbs_vdac_port: port@0 {
>  				reg = <0>;
>  			};
> +
> +			/* HDMI-TX output port */
> +			hdmi_tx_port: port@1 {
> +				reg = <1>;
> +
> +				hdmi_tx_out: endpoint {
> +					remote-endpoint = <&hdmi_tx_in>;
> +				};
> +			};
> +		};
> +
> +		hdmi_tx: hdmi-tx@c883a000 {
> +			compatible = "amlogic,meson-gx-dw-hdmi";
> +			reg = <0x0 0xc883a000 0x0 0x1c>;
> +			interrupts = <GIC_SPI 57 IRQ_TYPE_EDGE_RISING>;
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			status = "disabled";
> +
> +			/* VPU VENC Input */
> +			hdmi_tx_venc_port: port@0 {
> +				reg = <0>;
> +
> +				hdmi_tx_in: endpoint {
> +					remote-endpoint = <&hdmi_tx_out>;
> +				};
> +			};
> +
> +			/* TMDS Output */
> +			hdmi_tx_tmds_port: port@1 {
> +				reg = <1>;
> +			};
>  		};
>  	};
>  };
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
> index 4cbd626..a2c999f 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts
> @@ -152,6 +152,17 @@
>  			};
>  		};
>  	};
> +
> +	hdmi-connector {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi_connector_in: endpoint {
> +				remote-endpoint = <&hdmi_tx_tmds_out>;
> +			};
> +		};
> +	};
>  };
>  
>  &uart_AO {
> @@ -245,3 +256,15 @@
>  		remote-endpoint = <&cvbs_connector_in>;
>  	};
>  };
> +
> +&hdmi_tx {
> +	status = "okay";
> +	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> +	pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> +	hdmi_tx_tmds_out: endpoint {
> +		remote-endpoint = <&hdmi_connector_in>;
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
> index 4a96e0f..1c96fc8 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi
> @@ -135,6 +135,17 @@
>  			};
>  		};
>  	};
> +
> +	hdmi-connector {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi_connector_in: endpoint {
> +				remote-endpoint = <&hdmi_tx_tmds_out>;
> +			};
> +		};
> +	};
>  };
>  
>  /* This UART is brought out to the DB9 connector */
> @@ -250,3 +261,15 @@
>  		remote-endpoint = <&cvbs_connector_in>;
>  	};
>  };
> +
> +&hdmi_tx {
> +	status = "okay";
> +	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> +	pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> +	hdmi_tx_tmds_out: endpoint {
> +		remote-endpoint = <&hdmi_connector_in>;
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
> index 04b3324..9716e65 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi
> @@ -524,3 +524,15 @@
>  &vpu {
>  	compatible = "amlogic,meson-gxbb-vpu", "amlogic,meson-gx-vpu";
>  };
> +
> +&hdmi_tx {
> +	compatible = "amlogic,meson-gxbb-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
> +	resets = <&reset RESET_HDMITX_CAPB3>,
> +		 <&reset RESET_HDMI_SYSTEM_RESET>,
> +		 <&reset RESET_HDMI_TX>;
> +	reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
> +	clocks = <&clkc CLKID_HDMI_PCLK>,
> +		 <&clkc CLKID_CLK81>,
> +		 <&clkc CLKID_GCLK_VENCI_INT0>;
> +	clock-names = "isfr", "iahb", "venci";
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
> index cea4a3e..8873c05 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts
> @@ -127,6 +127,17 @@
>  			};
>  		};
>  	};
> +
> +	hdmi-connector {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi_connector_in: endpoint {
> +				remote-endpoint = <&hdmi_tx_tmds_out>;
> +			};
> +		};
> +	};
>  };
>  
>  &uart_AO {
> @@ -219,3 +230,15 @@
>  		remote-endpoint = <&cvbs_connector_in>;
>  	};
>  };
> +
> +&hdmi_tx {
> +	status = "okay";
> +	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> +	pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> +	hdmi_tx_tmds_out: endpoint {
> +		remote-endpoint = <&hdmi_connector_in>;
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
> index fe11b5f..9dcac25 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
> @@ -44,6 +44,7 @@
>  #include "meson-gx.dtsi"
>  #include <dt-bindings/clock/gxbb-clkc.h>
>  #include <dt-bindings/gpio/meson-gxl-gpio.h>
> +#include <dt-bindings/reset/amlogic,meson-gxbb-reset.h>
>  
>  / {
>  	compatible = "amlogic,meson-gxl";
> @@ -381,3 +382,15 @@
>  &vpu {
>  	compatible = "amlogic,meson-gxl-vpu", "amlogic,meson-gx-vpu";
>  };
> +
> +&hdmi_tx {
> +	compatible = "amlogic,meson-gxl-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
> +	resets = <&reset RESET_HDMITX_CAPB3>,
> +		 <&reset RESET_HDMI_SYSTEM_RESET>,
> +		 <&reset RESET_HDMI_TX>;
> +	reset-names = "hdmitx_apb", "hdmitx", "hdmitx_phy";
> +	clocks = <&clkc CLKID_HDMI_PCLK>,
> +		 <&clkc CLKID_CLK81>,
> +		 <&clkc CLKID_GCLK_VENCI_INT0>;
> +	clock-names = "isfr", "iahb", "venci";
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
> index 5a337d3..0e68c62e 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts
> @@ -100,6 +100,17 @@
>  			};
>  		};
>  	};
> +
> +	hdmi-connector {
> +		compatible = "hdmi-connector";
> +		type = "a";
> +
> +		port {
> +			hdmi_connector_in: endpoint {
> +				remote-endpoint = <&hdmi_tx_tmds_out>;
> +			};
> +		};
> +	};
>  };
>  
>  /* This UART is brought out to the DB9 connector */
> @@ -183,3 +194,15 @@
>  		remote-endpoint = <&cvbs_connector_in>;
>  	};
>  };
> +
> +&hdmi_tx {
> +	status = "okay";
> +	pinctrl-0 = <&hdmi_hpd_pins>, <&hdmi_i2c_pins>;
> +	pinctrl-names = "default";
> +};
> +
> +&hdmi_tx_tmds_port {
> +	hdmi_tx_tmds_out: endpoint {
> +		remote-endpoint = <&hdmi_connector_in>;
> +	};
> +};
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
> index ddea730..fe451cc 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gxm.dtsi
> @@ -130,3 +130,6 @@
>  	compatible = "amlogic,meson-gxm-vpu", "amlogic,meson-gx-vpu";
>  };
>  
> +&hdmi_tx {
> +	compatible = "amlogic,meson-gxm-dw-hdmi", "amlogic,meson-gx-dw-hdmi";
> +};
> 

Hi Kevin,

Please take this one for the amlogic arm-soc DT tree.

It may need a rebase, please tell me then I'll repost this one rebased on your 4.12/dt64 branch.

Thanks,
Neil

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

* Re: [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool
  2017-03-21 15:25 ` [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool Neil Armstrong
@ 2017-04-04  8:41   ` Neil Armstrong
  2017-04-04 11:57     ` Kevin Hilman
  0 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-04-04  8:41 UTC (permalink / raw)
  To: airlied
  Cc: dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel, devicetree

On 03/21/2017 04:25 PM, Neil Armstrong wrote:
> The HDMI modes needs more CMA memory to be reserved at boot-time.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  arch/arm64/boot/dts/amlogic/meson-gx.dtsi | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> index 5d995f7..94c6f95 100644
> --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
> @@ -71,6 +71,14 @@
>  			reg = <0x0 0x10000000 0x0 0x200000>;
>  			no-map;
>  		};
> +
> +		linux,cma {
> +			compatible = "shared-dma-pool";
> +			reusable;
> +			size = <0x0 0xbc00000>;
> +			alignment = <0x0 0x400000>;
> +			linux,cma-default;
> +		};
>  	};
>  
>  	cpus {
> 

Hi Kevin,

Please take this one for the amlogic arm-soc DT tree.

It may need a rebase, please tell me then I'll repost this one rebased on your 4.12/dt64 branch.

Thanks,
Neil

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

* Re: [PATCH v2 01/13] drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable sync for vsync commit
  2017-03-21 15:25 ` [PATCH v2 01/13] drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable sync for vsync commit Neil Armstrong
@ 2017-04-04  8:49   ` Daniel Vetter
  0 siblings, 0 replies; 31+ messages in thread
From: Daniel Vetter @ 2017-04-04  8:49 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On Tue, Mar 21, 2017 at 04:25:38PM +0100, Neil Armstrong wrote:
> Clean the crtc_enable by using the proper crtc_state instead of the state
> of the primary plane state data.
> 
> Also fix the dependency to commit the plane changes even if enable is called
> after the flush.

Would have done this as 2 patches ... either way ack.
-Daniel

> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/meson/meson_crtc.c | 15 +++++++++++----
>  1 file changed, 11 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_crtc.c b/drivers/gpu/drm/meson/meson_crtc.c
> index 0fe49ec..c986eb0 100644
> --- a/drivers/gpu/drm/meson/meson_crtc.c
> +++ b/drivers/gpu/drm/meson/meson_crtc.c
> @@ -82,11 +82,18 @@ static void meson_crtc_disable_vblank(struct drm_crtc *crtc)
>  static void meson_crtc_enable(struct drm_crtc *crtc)
>  {
>  	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
> -	struct drm_plane *plane = meson_crtc->priv->primary_plane;
> +	struct drm_crtc_state *crtc_state = crtc->state;
>  	struct meson_drm *priv = meson_crtc->priv;
>  
> +	DRM_DEBUG_DRIVER("\n");
> +
> +	if (!crtc_state) {
> +		DRM_ERROR("Invalid crtc_state\n");
> +		return;
> +	}
> +
>  	/* Enable VPP Postblend */
> -	writel(plane->state->crtc_w,
> +	writel(crtc_state->mode.hdisplay,
>  	       priv->io_base + _REG(VPP_POSTBLEND_H_SIZE));
>  
>  	writel_bits_relaxed(VPP_POSTBLEND_ENABLE, VPP_POSTBLEND_ENABLE,
> @@ -101,6 +108,7 @@ static void meson_crtc_disable(struct drm_crtc *crtc)
>  	struct meson_drm *priv = meson_crtc->priv;
>  
>  	priv->viu.osd1_enabled = false;
> +	priv->viu.osd1_commit = false;
>  
>  	/* Disable VPP Postblend */
>  	writel_bits_relaxed(VPP_POSTBLEND_ENABLE, 0,
> @@ -137,8 +145,7 @@ static void meson_crtc_atomic_flush(struct drm_crtc *crtc,
>  	struct meson_crtc *meson_crtc = to_meson_crtc(crtc);
>  	struct meson_drm *priv = meson_crtc->priv;
>  
> -	if (priv->viu.osd1_enabled)
> -		priv->viu.osd1_commit = true;
> +	priv->viu.osd1_commit = true;
>  }
>  
>  static const struct drm_crtc_helper_funcs meson_crtc_helper_funcs = {
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

* Re: [PATCH v2 07/13] drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY
  2017-03-21 15:25 ` [PATCH v2 07/13] drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY Neil Armstrong
@ 2017-04-04  8:57   ` Daniel Vetter
  2017-04-04  9:16     ` Neil Armstrong
  0 siblings, 1 reply; 31+ messages in thread
From: Daniel Vetter @ 2017-04-04  8:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On Tue, Mar 21, 2017 at 04:25:44PM +0100, Neil Armstrong wrote:
> The Amlogic Meson GXBB/GXL/GXM SoCs embeds a Synopsys DesignWare HDMI TX
> Controller with a custom Bridge + PHY around the Controller.
> 
> This driver makes uses of all the custom PHY plat data callbacks and enables
> the compatible HDMI modes to be configured as a drm_encoder instance.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

[snip]

> +static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
> +					struct drm_crtc_state *crtc_state,
> +					struct drm_connector_state *conn_state)
> +{
> +	return 0;
> +}

Given the over-the-top complicated mode encoding you seem to have, this
feels like it's a bit too simply.

> +
> +static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
> +{
> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> +	struct meson_drm *priv = dw_hdmi->priv;
> +
> +	DRM_DEBUG_DRIVER("\n");
> +
> +	writel_bits_relaxed(0x3, 0,
> +			    priv->io_base + _REG(VPU_HDMI_SETTING));
> +
> +	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
> +	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
> +}
> +
> +static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
> +{
> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> +	struct meson_drm *priv = dw_hdmi->priv;
> +
> +	DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
> +
> +	if (priv->venc.hdmi_use_enci)
> +		writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
> +	else
> +		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
> +}
> +
> +static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
> +				   struct drm_display_mode *mode,
> +				   struct drm_display_mode *adjusted_mode)
> +{
> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> +	struct meson_drm *priv = dw_hdmi->priv;
> +	int vic = drm_match_cea_mode(mode);
> +
> +	DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
> +			 mode->base.id, mode->name, vic);
> +
> +	/* Should have been filtered */
> +	if (!vic)
> +		return;
> +
> +	/* VENC + VENC-DVI Mode setup */
> +	meson_venc_hdmi_mode_set(priv, vic, mode);

So this calls a different module which export_symbol_gpls that thing. I
have no idea why arm-soc people love modularized-to-the-function level
drivers, but it feels over the top. amd/nouveau/i915 all smash everything
into one driver, makes life so much easier.

Note: bridge drivers as separate .ko makes sense, but separate .ko for
every single functional unit in your vendor IP imo totally doesn't.

Not going to stop you either :-)
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 03/13] drm/meson: Add support for components
  2017-03-21 15:25 ` [PATCH v2 03/13] drm/meson: Add support for components Neil Armstrong
@ 2017-04-04  8:59   ` Daniel Vetter
  2017-04-04  9:08     ` Neil Armstrong
  0 siblings, 1 reply; 31+ messages in thread
From: Daniel Vetter @ 2017-04-04  8:59 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On Tue, Mar 21, 2017 at 04:25:40PM +0100, Neil Armstrong wrote:
> This patch adds support for optional components connected through the
> Device Tree endpoints scheme.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  drivers/gpu/drm/meson/meson_drv.c | 113 +++++++++++++++++++++++++++++++++-----
>  1 file changed, 99 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
> index bc562a0..a2e9f56 100644
> --- a/drivers/gpu/drm/meson/meson_drv.c
> +++ b/drivers/gpu/drm/meson/meson_drv.c
> @@ -24,6 +24,7 @@
>  #include <linux/module.h>
>  #include <linux/mutex.h>
>  #include <linux/platform_device.h>
> +#include <linux/component.h>
>  #include <linux/of_graph.h>
>  
>  #include <drm/drmP.h>
> @@ -150,9 +151,9 @@ static bool meson_vpu_has_available_connectors(struct device *dev)
>  	.max_register   = 0x1000,
>  };
>  
> -static int meson_drv_probe(struct platform_device *pdev)
> +static int meson_drv_bind(struct device *dev)
>  {
> -	struct device *dev = &pdev->dev;
> +	struct platform_device *pdev = to_platform_device(dev);
>  	struct meson_drm *priv;
>  	struct drm_device *drm;
>  	struct resource *res;
> @@ -215,6 +216,15 @@ static int meson_drv_probe(struct platform_device *pdev)
>  
>  	drm_vblank_init(drm, 1);
>  	drm_mode_config_init(drm);
> +	drm->mode_config.max_width = 3840;
> +	drm->mode_config.max_height = 2160;
> +	drm->mode_config.funcs = &meson_mode_config_funcs;
> +
> +	/* Hardware Initialization */
> +
> +	meson_venc_init(priv);
> +	meson_vpp_init(priv);
> +	meson_viu_init(priv);
>  
>  	/* Encoder Initialization */
>  
> @@ -222,11 +232,11 @@ static int meson_drv_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto free_drm;
>  
> -	/* Hardware Initialization */
> -
> -	meson_venc_init(priv);
> -	meson_vpp_init(priv);
> -	meson_viu_init(priv);
> +	ret = component_bind_all(drm->dev, drm);
> +	if (ret) {
> +		dev_err(drm->dev, "Couldn't bind all components\n");
> +		goto free_drm;
> +	}
>  
>  	ret = meson_plane_create(priv);
>  	if (ret)
> @@ -241,9 +251,6 @@ static int meson_drv_probe(struct platform_device *pdev)
>  		goto free_drm;
>  
>  	drm_mode_config_reset(drm);
> -	drm->mode_config.max_width = 8192;
> -	drm->mode_config.max_height = 8192;
> -	drm->mode_config.funcs = &meson_mode_config_funcs;
>  
>  	priv->fbdev = drm_fbdev_cma_init(drm, 32,
>  					 drm->mode_config.num_connector);
> @@ -268,9 +275,9 @@ static int meson_drv_probe(struct platform_device *pdev)
>  	return ret;
>  }
>  
> -static int meson_drv_remove(struct platform_device *pdev)
> +static void meson_drv_unbind(struct device *dev)
>  {
> -	struct drm_device *drm = dev_get_drvdata(&pdev->dev);
> +	struct drm_device *drm = dev_get_drvdata(dev);
>  	struct meson_drm *priv = drm->dev_private;
>  
>  	drm_dev_unregister(drm);
> @@ -280,9 +287,88 @@ static int meson_drv_remove(struct platform_device *pdev)
>  	drm_vblank_cleanup(drm);
>  	drm_dev_unref(drm);
>  
> -	return 0;
>  }
>  
> +static const struct component_master_ops meson_drv_master_ops = {
> +	.bind	= meson_drv_bind,
> +	.unbind	= meson_drv_unbind,
> +};
> +
> +static int compare_of(struct device *dev, void *data)
> +{
> +	DRM_DEBUG_DRIVER("Comparing of node %s with %s\n",
> +			 of_node_full_name(dev->of_node),
> +			 of_node_full_name(data));
> +
> +	return dev->of_node == data;
> +}
> +
> +/* Possible connectors nodes to ignore */
> +static const struct of_device_id connectors_match[] = {
> +	{ .compatible = "composite-video-connector" },
> +	{ .compatible = "svideo-connector" },
> +	{ .compatible = "hdmi-connector" },
> +	{ .compatible = "dvi-connector" },
> +	{}
> +};
> +
> +static int meson_probe_remote(struct platform_device *pdev,
> +			      struct component_match **match,
> +			      struct device_node *parent,
> +			      struct device_node *remote)
> +{
> +	struct device_node *ep, *remote_node;
> +	int count = 1;
> +
> +	/* If node is a connector, return and do not add to match table */
> +	if (of_match_node(connectors_match, remote))
> +		return 1;
> +
> +	component_match_add(&pdev->dev, match, compare_of, remote);
> +
> +	for_each_endpoint_of_node(remote, ep) {
> +		remote_node = of_graph_get_remote_port_parent(ep);
> +		if (!remote_node ||
> +		    remote_node == parent || /* Ignore parent endpoint */
> +		    !of_device_is_available(remote_node))
> +			continue;
> +
> +		count += meson_probe_remote(pdev, match, remote, remote_node);
> +
> +		of_node_put(remote_node);
> +	}
> +
> +	return count;
> +}
> +
> +static int meson_drv_probe(struct platform_device *pdev)
> +{
> +	struct component_match *match = NULL;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *ep, *remote;
> +	int count = 0;
> +
> +	for_each_endpoint_of_node(np, ep) {
> +		remote = of_graph_get_remote_port_parent(ep);
> +		if (!remote || !of_device_is_available(remote))
> +			continue;
> +
> +		count += meson_probe_remote(pdev, &match, np, remote);
> +	}
> +
> +	/* If some endpoints were found, initialize the nodes */
> +	if (count) {

What if you have more than 1 endpoint described, but module load order
conspires against you to only initialize 1 at first?
-Daniel

> +		dev_info(&pdev->dev, "Queued %d outputs on vpu\n", count);
> +
> +		return component_master_add_with_match(&pdev->dev,
> +						       &meson_drv_master_ops,
> +						       match);
> +	}
> +
> +	/* If no output endpoints were available, simply bail out */
> +	return 0;
> +};
> +
>  static const struct of_device_id dt_match[] = {
>  	{ .compatible = "amlogic,meson-gxbb-vpu" },
>  	{ .compatible = "amlogic,meson-gxl-vpu" },
> @@ -293,7 +379,6 @@ static int meson_drv_remove(struct platform_device *pdev)
>  
>  static struct platform_driver meson_drm_platform_driver = {
>  	.probe      = meson_drv_probe,
> -	.remove     = meson_drv_remove,
>  	.driver     = {
>  		.name	= "meson-drm",
>  		.of_match_table = dt_match,
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

* Re: [PATCH v2 12/13] drm/meson: Add RST to bring together kerneldoc
  2017-03-21 15:25 ` [PATCH v2 12/13] drm/meson: Add RST to bring together kerneldoc Neil Armstrong
@ 2017-04-04  9:00   ` Daniel Vetter
  2017-04-04  9:17     ` Neil Armstrong
  0 siblings, 1 reply; 31+ messages in thread
From: Daniel Vetter @ 2017-04-04  9:00 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On Tue, Mar 21, 2017 at 04:25:49PM +0100, Neil Armstrong wrote:
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

\o/ for kerneldoc!

This is awesome, but I guess it's time to extract a drivers.rst sub-file
within Doc/gpu and put all the various driver docs in there? Would be
great if you could do the follow-up for that.

Thanks, Daniel

> ---
>  Documentation/gpu/index.rst |  1 +
>  Documentation/gpu/meson.rst | 61 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 62 insertions(+)
>  create mode 100644 Documentation/gpu/meson.rst
> 
> diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst
> index e998ee0..7eceb97 100644
> --- a/Documentation/gpu/index.rst
> +++ b/Documentation/gpu/index.rst
> @@ -11,6 +11,7 @@ Linux GPU Driver Developer's Guide
>     drm-kms-helpers
>     drm-uapi
>     i915
> +   meson
>     tinydrm
>     vc4
>     vga-switcheroo
> diff --git a/Documentation/gpu/meson.rst b/Documentation/gpu/meson.rst
> new file mode 100644
> index 0000000..479f6f5
> --- /dev/null
> +++ b/Documentation/gpu/meson.rst
> @@ -0,0 +1,61 @@
> +=============================================
> +drm/meson AmLogic Meson Video Processing Unit
> +=============================================
> +
> +.. kernel-doc:: drivers/gpu/drm/meson/meson_drv.c
> +   :doc: Video Processing Unit
> +
> +Video Processing Unit
> +=====================
> +
> +The Amlogic Meson Display controller is composed of several components
> +that are going to be documented below:
> +
> +.. code::
> +
> +  DMC|---------------VPU (Video Processing Unit)----------------|------HHI------|
> +     | vd1   _______     _____________    _________________     |               |
> +  D  |-------|      |----|            |   |                |    |   HDMI PLL    |
> +  D  | vd2   | VIU  |    | Video Post |   | Video Encoders |<---|-----VCLK      |
> +  R  |-------|      |----| Processing |   |                |    |               |
> +     | osd2  |      |    |            |---| Enci ----------|----|-----VDAC------|
> +  R  |-------| CSC  |----| Scalers    |   | Encp ----------|----|----HDMI-TX----|
> +  A  | osd1  |      |    | Blenders   |   | Encl ----------|----|---------------|
> +  M  |-------|______|----|____________|   |________________|    |               |
> +  ___|__________________________________________________________|_______________|
> +
> +Video Input Unit
> +================
> +
> +.. kernel-doc:: drivers/gpu/drm/meson/meson_viu.c
> +   :doc: Video Input Unit
> +
> +Video Post Processing
> +=====================
> +
> +.. kernel-doc:: drivers/gpu/drm/meson/meson_vpp.c
> +   :doc: Video Post Processing
> +
> +Video Encoder
> +=============
> +
> +.. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c
> +   :doc: Video Encoder
> +
> +Video Canvas Management
> +=======================
> +
> +.. kernel-doc:: drivers/gpu/drm/meson/meson_canvas.c
> +   :doc: Canvas
> +
> +Video Clocks
> +============
> +
> +.. kernel-doc:: drivers/gpu/drm/meson/meson_vclk.c
> +   :doc: Video Clocks
> +
> +HDMI Video Output
> +=================
> +
> +.. kernel-doc:: drivers/gpu/drm/meson/meson_dw_hdmi.c
> +   :doc: HDMI Output
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

* Re: [PATCH v2 13/13] MAINTAINERS: update files for Amlogic DRM Driver
  2017-03-21 15:25 ` [PATCH v2 13/13] MAINTAINERS: update files for Amlogic DRM Driver Neil Armstrong
@ 2017-04-04  9:01   ` Daniel Vetter
  2017-04-04  9:18     ` Neil Armstrong
  0 siblings, 1 reply; 31+ messages in thread
From: Daniel Vetter @ 2017-04-04  9:01 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On Tue, Mar 21, 2017 at 04:25:50PM +0100, Neil Armstrong wrote:
> This patch adds the dw-hdmi bindings and RST kerneldoc to maintained files.
> 
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> ---
>  MAINTAINERS | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index e88154f..3df68c73 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -4256,6 +4256,8 @@ W:	http://linux-meson.com/
>  S:	Supported
>  F:	drivers/gpu/drm/meson/
>  F:	Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
> +F:	Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
> +F:	Documentation/gpu/meson.rst
>  T:	git git://anongit.freedesktop.org/drm/drm-meson

As discussed on irc, pls also remove the drm-meson git repo here (and ask
fdo admins to can it). To avoid confusion.
-Daniel

>  T:	git git://anongit.freedesktop.org/drm/drm-misc
>  
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

* Re: [PATCH v2 00/13] drm/meson: Initial support for HDMI Output
  2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
                   ` (12 preceding siblings ...)
  2017-03-21 15:25 ` [PATCH v2 13/13] MAINTAINERS: update files for Amlogic DRM Driver Neil Armstrong
@ 2017-04-04  9:04 ` Daniel Vetter
  2017-04-04  9:21   ` Neil Armstrong
  13 siblings, 1 reply; 31+ messages in thread
From: Daniel Vetter @ 2017-04-04  9:04 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On Tue, Mar 21, 2017 at 04:25:37PM +0100, Neil Armstrong wrote:
> The Amlogic GX SoCs implements a Synopsys DesignWare HDMI TX Controller
> in combination with a very custom PHY.
> 
> This patchset depends on Laurent Pinchart patchset merged in drm-misc-next
> and my v4 patchset at [1] to permit PHY control from outside the dw-hdmi driver.
> 
> The Synopsys DesignWare HDMI TX Controller is integrated like :
>          ___________________________________
>         |            HDMI TOP               |<= HPD
>         |___________________________________|
>         |                  |                |
> HDMI-TX-|  Synopsys HDMI   |   HDMI PHY     |=> TMDS
>         |    Controller    |________________|
>         |___________________________________|<=> DDC
> 
> And uses the following paths for Pixels Encoding :
>        _____   _____   ____________________
> vd1---|     |-|     | | VENC     /---------|----VDAC
> vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|\
> osd1--|     |-|     | | \                  | X--HDMI-TX
> osd2--|_____|-|_____| |  |\-ENCP--ENCP_DVI-|/
>                       |  |                 |
>                       |  \--ENCL-----------|----LVDS
>                       |____________________|
> 
> The ENCI and ENCP encoders pre-formats the data for the ENCI-DVI and
> ENCP-DVI encoders. Those DVI encoders will format the pixels for the
> Synopsys DesignWare HDMI TX Controller.
> 
> In order to support display modes, the ENCI and ENCP encoders needs very
> specific parameters for *each* display modes, so usage of the CEA VIC
> identifier is necessary. But the DVI timings are generated from the
> drm_mode structure in a generic way.
> 
> To simplify the first push, only the main CEA modes are supported up to
> 1920x1080p60. Supporting the 480i and 576i needs tweaking in the dw-hdmi
> in order to support the Clock Doubling necessary for these modes.
> 
> Support for more traditional modes like the EDID fallback modes is planned
> but will need tome additionnal handling along the CEA modes.
> Support for 4k2k modes needs to be able to get the EDID HDMI modes, but
> for now only the HDMI 1.4 modes are currently available in the drm_edid
> implementation.

Ok I scanned throught this and applied a bunch of comments. Mostly because
I need volunteers to review one of my own patch series that I need to
resend after some polish.

But I think it'd would be a _lot_ more useful if the various arm-soc
drivers would cross-check their driver amongst themselves. Especially
around drm bridges there's a lot of people involved, almost all hang out
on #dri-devel, so should be very easy to coordinate some cross review.

On all the patches except the dt ones: Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-Daniel

> 
> This patchset does :
>  - Fixes the CRTC handling
>  - Fixes the registers definitions
>  - Adds support for device components registration along of-graph
>  - Adds support for HDMI clocks
>  - Adds support for HDMI VENC video modes
>  - Adds support for the Custom HDMI PHY using callbacks added in [1] and [2]
>  - Adds CMA node to reserve enougth memory for 1080p display
>  - Adds the HDMI controller et connector modes on selected boards
>  - Adds a proper dt-bindings for the HDMI controller et connector
>  - Add RST documentation for Meson DRM driver
>  - Updates the MAINTAINERS file to track the new files
> 
> Changes since v1 patchset at [2] :
>  - Add the meson drm documentation from [3] to this patchset
>  - Update with new bus formats and HPD callbacks
>  - Drop all the of_machine_is_compatible
> 
> [1] http://lkml.kernel.org/r/1490109161-20529-1-git-send-email-narmstrong@baylibre.com
> [2] http://lkml.kernel.org/r/1488469207-523-1-git-send-email-narmstrong@baylibre.com
> [3] http://lkml.kernel.org/r/1488536068-9407-1-git-send-email-narmstrong@baylibre.com
> 
> Neil Armstrong (13):
>   drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable
>     sync for vsync commit
>   drm/meson: Add missing HDMI register
>   drm/meson: Add support for components
>   drm/meson: venc_cvbs: no more return -ENODEV if CVBS is not available
>   drm/meson: add support for HDMI clock support
>   drm/meson: Add support for HDMI venc modes and settings
>   drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY
>   ARM64: dts: meson-gx: Add shared CMA dma memory pool
>   ARM64: dts: meson-gx: Add support for HDMI output
>   dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension
>   drm/meson: Convert existing documentation to actual kerneldoc
>   drm/meson: Add RST to bring together kerneldoc
>   MAINTAINERS: update files for Amlogic DRM Driver
> 
>  .../bindings/display/amlogic,meson-dw-hdmi.txt     |  111 ++
>  Documentation/gpu/index.rst                        |    1 +
>  Documentation/gpu/meson.rst                        |   61 +
>  MAINTAINERS                                        |    2 +
>  .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi |   39 +
>  arch/arm64/boot/dts/amlogic/meson-gx.dtsi          |   40 +
>  .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts    |   23 +
>  arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi   |   23 +
>  arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        |   12 +
>  .../dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts    |   23 +
>  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         |   13 +
>  .../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts |   23 +
>  arch/arm64/boot/dts/amlogic/meson-gxm.dtsi         |    3 +
>  drivers/gpu/drm/meson/Kconfig                      |    6 +
>  drivers/gpu/drm/meson/Makefile                     |    1 +
>  drivers/gpu/drm/meson/meson_canvas.c               |    4 +-
>  drivers/gpu/drm/meson/meson_crtc.c                 |   15 +-
>  drivers/gpu/drm/meson/meson_drv.c                  |  118 +-
>  drivers/gpu/drm/meson/meson_drv.h                  |    3 +
>  drivers/gpu/drm/meson/meson_dw_hdmi.c              |  919 ++++++++++++++
>  drivers/gpu/drm/meson/meson_dw_hdmi.h              |  146 +++
>  drivers/gpu/drm/meson/meson_registers.h            |    1 +
>  drivers/gpu/drm/meson/meson_vclk.c                 |  632 +++++++++-
>  drivers/gpu/drm/meson/meson_vclk.h                 |    6 +-
>  drivers/gpu/drm/meson/meson_venc.c                 | 1254 +++++++++++++++++++-
>  drivers/gpu/drm/meson/meson_venc.h                 |    7 +
>  drivers/gpu/drm/meson/meson_venc_cvbs.c            |   11 +-
>  drivers/gpu/drm/meson/meson_viu.c                  |    6 +-
>  drivers/gpu/drm/meson/meson_vpp.c                  |    8 +-
>  drivers/gpu/drm/meson/meson_vpp.h                  |    2 +
>  30 files changed, 3466 insertions(+), 47 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
>  create mode 100644 Documentation/gpu/meson.rst
>  create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.c
>  create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.h
> 
> -- 
> 1.9.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

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

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

* Re: [PATCH v2 03/13] drm/meson: Add support for components
  2017-04-04  8:59   ` Daniel Vetter
@ 2017-04-04  9:08     ` Neil Armstrong
  2017-04-04  9:09       ` Daniel Vetter
  0 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-04-04  9:08 UTC (permalink / raw)
  To: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On 04/04/2017 10:59 AM, Daniel Vetter wrote:
> On Tue, Mar 21, 2017 at 04:25:40PM +0100, Neil Armstrong wrote:
>> This patch adds support for optional components connected through the
>> Device Tree endpoints scheme.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  drivers/gpu/drm/meson/meson_drv.c | 113 +++++++++++++++++++++++++++++++++-----
>>  1 file changed, 99 insertions(+), 14 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/meson/meson_drv.c b/drivers/gpu/drm/meson/meson_drv.c
>> index bc562a0..a2e9f56 100644
>> --- a/drivers/gpu/drm/meson/meson_drv.c
>> +++ b/drivers/gpu/drm/meson/meson_drv.c
>> @@ -24,6 +24,7 @@
>>  #include <linux/module.h>
>>  #include <linux/mutex.h>
>>  #include <linux/platform_device.h>
>> +#include <linux/component.h>
>>  #include <linux/of_graph.h>
>>  
>>  #include <drm/drmP.h>
>> @@ -150,9 +151,9 @@ static bool meson_vpu_has_available_connectors(struct device *dev)
>>  	.max_register   = 0x1000,
>>  };
>>  
>> -static int meson_drv_probe(struct platform_device *pdev)
>> +static int meson_drv_bind(struct device *dev)
>>  {
>> -	struct device *dev = &pdev->dev;
>> +	struct platform_device *pdev = to_platform_device(dev);
>>  	struct meson_drm *priv;
>>  	struct drm_device *drm;
>>  	struct resource *res;
>> @@ -215,6 +216,15 @@ static int meson_drv_probe(struct platform_device *pdev)
>>  
>>  	drm_vblank_init(drm, 1);
>>  	drm_mode_config_init(drm);
>> +	drm->mode_config.max_width = 3840;
>> +	drm->mode_config.max_height = 2160;
>> +	drm->mode_config.funcs = &meson_mode_config_funcs;
>> +
>> +	/* Hardware Initialization */
>> +
>> +	meson_venc_init(priv);
>> +	meson_vpp_init(priv);
>> +	meson_viu_init(priv);
>>  
>>  	/* Encoder Initialization */
>>  
>> @@ -222,11 +232,11 @@ static int meson_drv_probe(struct platform_device *pdev)
>>  	if (ret)
>>  		goto free_drm;
>>  
>> -	/* Hardware Initialization */
>> -
>> -	meson_venc_init(priv);
>> -	meson_vpp_init(priv);
>> -	meson_viu_init(priv);
>> +	ret = component_bind_all(drm->dev, drm);
>> +	if (ret) {
>> +		dev_err(drm->dev, "Couldn't bind all components\n");
>> +		goto free_drm;
>> +	}
>>  
>>  	ret = meson_plane_create(priv);
>>  	if (ret)
>> @@ -241,9 +251,6 @@ static int meson_drv_probe(struct platform_device *pdev)
>>  		goto free_drm;
>>  
>>  	drm_mode_config_reset(drm);
>> -	drm->mode_config.max_width = 8192;
>> -	drm->mode_config.max_height = 8192;
>> -	drm->mode_config.funcs = &meson_mode_config_funcs;
>>  
>>  	priv->fbdev = drm_fbdev_cma_init(drm, 32,
>>  					 drm->mode_config.num_connector);
>> @@ -268,9 +275,9 @@ static int meson_drv_probe(struct platform_device *pdev)
>>  	return ret;
>>  }
>>  
>> -static int meson_drv_remove(struct platform_device *pdev)
>> +static void meson_drv_unbind(struct device *dev)
>>  {
>> -	struct drm_device *drm = dev_get_drvdata(&pdev->dev);
>> +	struct drm_device *drm = dev_get_drvdata(dev);
>>  	struct meson_drm *priv = drm->dev_private;
>>  
>>  	drm_dev_unregister(drm);
>> @@ -280,9 +287,88 @@ static int meson_drv_remove(struct platform_device *pdev)
>>  	drm_vblank_cleanup(drm);
>>  	drm_dev_unref(drm);
>>  
>> -	return 0;
>>  }
>>  
>> +static const struct component_master_ops meson_drv_master_ops = {
>> +	.bind	= meson_drv_bind,
>> +	.unbind	= meson_drv_unbind,
>> +};
>> +
>> +static int compare_of(struct device *dev, void *data)
>> +{
>> +	DRM_DEBUG_DRIVER("Comparing of node %s with %s\n",
>> +			 of_node_full_name(dev->of_node),
>> +			 of_node_full_name(data));
>> +
>> +	return dev->of_node == data;
>> +}
>> +
>> +/* Possible connectors nodes to ignore */
>> +static const struct of_device_id connectors_match[] = {
>> +	{ .compatible = "composite-video-connector" },
>> +	{ .compatible = "svideo-connector" },
>> +	{ .compatible = "hdmi-connector" },
>> +	{ .compatible = "dvi-connector" },
>> +	{}
>> +};
>> +
>> +static int meson_probe_remote(struct platform_device *pdev,
>> +			      struct component_match **match,
>> +			      struct device_node *parent,
>> +			      struct device_node *remote)
>> +{
>> +	struct device_node *ep, *remote_node;
>> +	int count = 1;
>> +
>> +	/* If node is a connector, return and do not add to match table */
>> +	if (of_match_node(connectors_match, remote))
>> +		return 1;
>> +
>> +	component_match_add(&pdev->dev, match, compare_of, remote);
>> +
>> +	for_each_endpoint_of_node(remote, ep) {
>> +		remote_node = of_graph_get_remote_port_parent(ep);
>> +		if (!remote_node ||
>> +		    remote_node == parent || /* Ignore parent endpoint */
>> +		    !of_device_is_available(remote_node))
>> +			continue;
>> +
>> +		count += meson_probe_remote(pdev, match, remote, remote_node);
>> +
>> +		of_node_put(remote_node);
>> +	}
>> +
>> +	return count;
>> +}
>> +
>> +static int meson_drv_probe(struct platform_device *pdev)
>> +{
>> +	struct component_match *match = NULL;
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct device_node *ep, *remote;
>> +	int count = 0;
>> +
>> +	for_each_endpoint_of_node(np, ep) {
>> +		remote = of_graph_get_remote_port_parent(ep);
>> +		if (!remote || !of_device_is_available(remote))
>> +			continue;
>> +
>> +		count += meson_probe_remote(pdev, &match, np, remote);
>> +	}
>> +
>> +	/* If some endpoints were found, initialize the nodes */
>> +	if (count) {
> 
> What if you have more than 1 endpoint described, but module load order
> conspires against you to only initialize 1 at first?

As I understood, the component_bind_all() will fail until all modules are loaded
even in wrong order, no ?
I tested with multiple combinations and it worked like a charm... maybe I missed
something here !

Thanks,
Neil

> -Daniel
> 
>> +		dev_info(&pdev->dev, "Queued %d outputs on vpu\n", count);
>> +
>> +		return component_master_add_with_match(&pdev->dev,
>> +						       &meson_drv_master_ops,
>> +						       match);
>> +	}
>> +
>> +	/* If no output endpoints were available, simply bail out */
>> +	return 0;
>> +};
>> +
>>  static const struct of_device_id dt_match[] = {
>>  	{ .compatible = "amlogic,meson-gxbb-vpu" },
>>  	{ .compatible = "amlogic,meson-gxl-vpu" },
>> @@ -293,7 +379,6 @@ static int meson_drv_remove(struct platform_device *pdev)
>>  
>>  static struct platform_driver meson_drm_platform_driver = {
>>  	.probe      = meson_drv_probe,
>> -	.remove     = meson_drv_remove,
>>  	.driver     = {
>>  		.name	= "meson-drm",
>>  		.of_match_table = dt_match,
>> -- 
>> 1.9.1
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

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

* Re: [PATCH v2 03/13] drm/meson: Add support for components
  2017-04-04  9:08     ` Neil Armstrong
@ 2017-04-04  9:09       ` Daniel Vetter
  0 siblings, 0 replies; 31+ messages in thread
From: Daniel Vetter @ 2017-04-04  9:09 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On Tue, Apr 04, 2017 at 11:08:26AM +0200, Neil Armstrong wrote:
> On 04/04/2017 10:59 AM, Daniel Vetter wrote:
> > On Tue, Mar 21, 2017 at 04:25:40PM +0100, Neil Armstrong wrote:
> >> +static int meson_drv_probe(struct platform_device *pdev)
> >> +{
> >> +	struct component_match *match = NULL;
> >> +	struct device_node *np = pdev->dev.of_node;
> >> +	struct device_node *ep, *remote;
> >> +	int count = 0;
> >> +
> >> +	for_each_endpoint_of_node(np, ep) {
> >> +		remote = of_graph_get_remote_port_parent(ep);
> >> +		if (!remote || !of_device_is_available(remote))
> >> +			continue;
> >> +
> >> +		count += meson_probe_remote(pdev, &match, np, remote);
> >> +	}
> >> +
> >> +	/* If some endpoints were found, initialize the nodes */
> >> +	if (count) {
> > 
> > What if you have more than 1 endpoint described, but module load order
> > conspires against you to only initialize 1 at first?
> 
> As I understood, the component_bind_all() will fail until all modules are loaded
> even in wrong order, no ?
> I tested with multiple combinations and it worked like a charm... maybe I missed
> something here !

I misread your code, looks all fine.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 07/13] drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY
  2017-04-04  8:57   ` Daniel Vetter
@ 2017-04-04  9:16     ` Neil Armstrong
  2017-04-04 13:50       ` Daniel Vetter
  0 siblings, 1 reply; 31+ messages in thread
From: Neil Armstrong @ 2017-04-04  9:16 UTC (permalink / raw)
  To: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On 04/04/2017 10:57 AM, Daniel Vetter wrote:
> On Tue, Mar 21, 2017 at 04:25:44PM +0100, Neil Armstrong wrote:
>> The Amlogic Meson GXBB/GXL/GXM SoCs embeds a Synopsys DesignWare HDMI TX
>> Controller with a custom Bridge + PHY around the Controller.
>>
>> This driver makes uses of all the custom PHY plat data callbacks and enables
>> the compatible HDMI modes to be configured as a drm_encoder instance.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> 
> [snip]
> 
>> +static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
>> +					struct drm_crtc_state *crtc_state,
>> +					struct drm_connector_state *conn_state)
>> +{
>> +	return 0;
>> +}
> 
> Given the over-the-top complicated mode encoding you seem to have, this
> feels like it's a bit too simply.

Indeed, but the HW is really weird, every supported modes have very specific
timings/parameters so moving the mode validation code from the dw-hdmi mode_valid
to here would only make sense if we need to support a different HDMI controller.

But you are right, but I would have preferred to have a better HW for sure...

> 
>> +
>> +static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
>> +{
>> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
>> +	struct meson_drm *priv = dw_hdmi->priv;
>> +
>> +	DRM_DEBUG_DRIVER("\n");
>> +
>> +	writel_bits_relaxed(0x3, 0,
>> +			    priv->io_base + _REG(VPU_HDMI_SETTING));
>> +
>> +	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
>> +	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
>> +}
>> +
>> +static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
>> +{
>> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
>> +	struct meson_drm *priv = dw_hdmi->priv;
>> +
>> +	DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
>> +
>> +	if (priv->venc.hdmi_use_enci)
>> +		writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
>> +	else
>> +		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
>> +}
>> +
>> +static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
>> +				   struct drm_display_mode *mode,
>> +				   struct drm_display_mode *adjusted_mode)
>> +{
>> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
>> +	struct meson_drm *priv = dw_hdmi->priv;
>> +	int vic = drm_match_cea_mode(mode);
>> +
>> +	DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
>> +			 mode->base.id, mode->name, vic);
>> +
>> +	/* Should have been filtered */
>> +	if (!vic)
>> +		return;
>> +
>> +	/* VENC + VENC-DVI Mode setup */
>> +	meson_venc_hdmi_mode_set(priv, vic, mode);
> 
> So this calls a different module which export_symbol_gpls that thing. I
> have no idea why arm-soc people love modularized-to-the-function level
> drivers, but it feels over the top. amd/nouveau/i915 all smash everything
> into one driver, makes life so much easier.

I know, we are doomed on that !
But here, since the wrapping around the dw-hdmi controller is completely custom
if was necessary to add a separate encoder tied to HDMI and have the physical
encoding code in the common driver.
Note that the platform is also able to driver a LCD via LVDS, so this encoder code
should be reusable here.

> 
> Note: bridge drivers as separate .ko makes sense, but separate .ko for
> every single functional unit in your vendor IP imo totally doesn't.

Actually I added a global ko for the "DRM" driver with crtc, planes and CVBS,
and another ko for the HDMI bridge wrapping.

> 
> Not going to stop you either :-)

I totally agree on the complexity here !

> -Daniel
> 

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

* Re: [PATCH v2 12/13] drm/meson: Add RST to bring together kerneldoc
  2017-04-04  9:00   ` Daniel Vetter
@ 2017-04-04  9:17     ` Neil Armstrong
  0 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-04-04  9:17 UTC (permalink / raw)
  To: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On 04/04/2017 11:00 AM, Daniel Vetter wrote:
> On Tue, Mar 21, 2017 at 04:25:49PM +0100, Neil Armstrong wrote:
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> 
> \o/ for kerneldoc!
> 
> This is awesome, but I guess it's time to extract a drivers.rst sub-file
> within Doc/gpu and put all the various driver docs in there? Would be
> great if you could do the follow-up for that.

Ok, I'll follow up on that.

Thanks,
Neil

> 
> Thanks, Daniel
> 
>> ---
>>  Documentation/gpu/index.rst |  1 +
>>  Documentation/gpu/meson.rst | 61 +++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 62 insertions(+)
>>  create mode 100644 Documentation/gpu/meson.rst
>>
>> diff --git a/Documentation/gpu/index.rst b/Documentation/gpu/index.rst
>> index e998ee0..7eceb97 100644
>> --- a/Documentation/gpu/index.rst
>> +++ b/Documentation/gpu/index.rst
>> @@ -11,6 +11,7 @@ Linux GPU Driver Developer's Guide
>>     drm-kms-helpers
>>     drm-uapi
>>     i915
>> +   meson
>>     tinydrm
>>     vc4
>>     vga-switcheroo
>> diff --git a/Documentation/gpu/meson.rst b/Documentation/gpu/meson.rst
>> new file mode 100644
>> index 0000000..479f6f5
>> --- /dev/null
>> +++ b/Documentation/gpu/meson.rst
>> @@ -0,0 +1,61 @@
>> +=============================================
>> +drm/meson AmLogic Meson Video Processing Unit
>> +=============================================
>> +
>> +.. kernel-doc:: drivers/gpu/drm/meson/meson_drv.c
>> +   :doc: Video Processing Unit
>> +
>> +Video Processing Unit
>> +=====================
>> +
>> +The Amlogic Meson Display controller is composed of several components
>> +that are going to be documented below:
>> +
>> +.. code::
>> +
>> +  DMC|---------------VPU (Video Processing Unit)----------------|------HHI------|
>> +     | vd1   _______     _____________    _________________     |               |
>> +  D  |-------|      |----|            |   |                |    |   HDMI PLL    |
>> +  D  | vd2   | VIU  |    | Video Post |   | Video Encoders |<---|-----VCLK      |
>> +  R  |-------|      |----| Processing |   |                |    |               |
>> +     | osd2  |      |    |            |---| Enci ----------|----|-----VDAC------|
>> +  R  |-------| CSC  |----| Scalers    |   | Encp ----------|----|----HDMI-TX----|
>> +  A  | osd1  |      |    | Blenders   |   | Encl ----------|----|---------------|
>> +  M  |-------|______|----|____________|   |________________|    |               |
>> +  ___|__________________________________________________________|_______________|
>> +
>> +Video Input Unit
>> +================
>> +
>> +.. kernel-doc:: drivers/gpu/drm/meson/meson_viu.c
>> +   :doc: Video Input Unit
>> +
>> +Video Post Processing
>> +=====================
>> +
>> +.. kernel-doc:: drivers/gpu/drm/meson/meson_vpp.c
>> +   :doc: Video Post Processing
>> +
>> +Video Encoder
>> +=============
>> +
>> +.. kernel-doc:: drivers/gpu/drm/meson/meson_venc.c
>> +   :doc: Video Encoder
>> +
>> +Video Canvas Management
>> +=======================
>> +
>> +.. kernel-doc:: drivers/gpu/drm/meson/meson_canvas.c
>> +   :doc: Canvas
>> +
>> +Video Clocks
>> +============
>> +
>> +.. kernel-doc:: drivers/gpu/drm/meson/meson_vclk.c
>> +   :doc: Video Clocks
>> +
>> +HDMI Video Output
>> +=================
>> +
>> +.. kernel-doc:: drivers/gpu/drm/meson/meson_dw_hdmi.c
>> +   :doc: HDMI Output
>> -- 
>> 1.9.1
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

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

* Re: [PATCH v2 13/13] MAINTAINERS: update files for Amlogic DRM Driver
  2017-04-04  9:01   ` Daniel Vetter
@ 2017-04-04  9:18     ` Neil Armstrong
  0 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-04-04  9:18 UTC (permalink / raw)
  To: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On 04/04/2017 11:01 AM, Daniel Vetter wrote:
> On Tue, Mar 21, 2017 at 04:25:50PM +0100, Neil Armstrong wrote:
>> This patch adds the dw-hdmi bindings and RST kerneldoc to maintained files.
>>
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
>> ---
>>  MAINTAINERS | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index e88154f..3df68c73 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -4256,6 +4256,8 @@ W:	http://linux-meson.com/
>>  S:	Supported
>>  F:	drivers/gpu/drm/meson/
>>  F:	Documentation/devicetree/bindings/display/amlogic,meson-vpu.txt
>> +F:	Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
>> +F:	Documentation/gpu/meson.rst
>>  T:	git git://anongit.freedesktop.org/drm/drm-meson
> 
> As discussed on irc, pls also remove the drm-meson git repo here (and ask
> fdo admins to can it). To avoid confusion.

Ok, I already removed the line and pushed it to drm-misc-next,
I'll certainly need to fix a conflict here when pushing this one to drm-misc-next.

> -Daniel
> 
>>  T:	git git://anongit.freedesktop.org/drm/drm-misc
>>  
>> -- 
>> 1.9.1
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

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

* Re: [PATCH v2 00/13] drm/meson: Initial support for HDMI Output
  2017-04-04  9:04 ` [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Daniel Vetter
@ 2017-04-04  9:21   ` Neil Armstrong
  0 siblings, 0 replies; 31+ messages in thread
From: Neil Armstrong @ 2017-04-04  9:21 UTC (permalink / raw)
  To: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On 04/04/2017 11:04 AM, Daniel Vetter wrote:
> On Tue, Mar 21, 2017 at 04:25:37PM +0100, Neil Armstrong wrote:
>> The Amlogic GX SoCs implements a Synopsys DesignWare HDMI TX Controller
>> in combination with a very custom PHY.
>>
>> This patchset depends on Laurent Pinchart patchset merged in drm-misc-next
>> and my v4 patchset at [1] to permit PHY control from outside the dw-hdmi driver.
>>
>> The Synopsys DesignWare HDMI TX Controller is integrated like :
>>          ___________________________________
>>         |            HDMI TOP               |<= HPD
>>         |___________________________________|
>>         |                  |                |
>> HDMI-TX-|  Synopsys HDMI   |   HDMI PHY     |=> TMDS
>>         |    Controller    |________________|
>>         |___________________________________|<=> DDC
>>
>> And uses the following paths for Pixels Encoding :
>>        _____   _____   ____________________
>> vd1---|     |-|     | | VENC     /---------|----VDAC
>> vd2---| VIU |-| VPP |-|-----ENCI/-ENCI_DVI-|\
>> osd1--|     |-|     | | \                  | X--HDMI-TX
>> osd2--|_____|-|_____| |  |\-ENCP--ENCP_DVI-|/
>>                       |  |                 |
>>                       |  \--ENCL-----------|----LVDS
>>                       |____________________|
>>
>> The ENCI and ENCP encoders pre-formats the data for the ENCI-DVI and
>> ENCP-DVI encoders. Those DVI encoders will format the pixels for the
>> Synopsys DesignWare HDMI TX Controller.
>>
>> In order to support display modes, the ENCI and ENCP encoders needs very
>> specific parameters for *each* display modes, so usage of the CEA VIC
>> identifier is necessary. But the DVI timings are generated from the
>> drm_mode structure in a generic way.
>>
>> To simplify the first push, only the main CEA modes are supported up to
>> 1920x1080p60. Supporting the 480i and 576i needs tweaking in the dw-hdmi
>> in order to support the Clock Doubling necessary for these modes.
>>
>> Support for more traditional modes like the EDID fallback modes is planned
>> but will need tome additionnal handling along the CEA modes.
>> Support for 4k2k modes needs to be able to get the EDID HDMI modes, but
>> for now only the HDMI 1.4 modes are currently available in the drm_edid
>> implementation.
> 
> Ok I scanned throught this and applied a bunch of comments. Mostly because
> I need volunteers to review one of my own patch series that I need to
> resend after some polish.
> 
> But I think it'd would be a _lot_ more useful if the various arm-soc
> drivers would cross-check their driver amongst themselves. Especially
> around drm bridges there's a lot of people involved, almost all hang out
> on #dri-devel, so should be very easy to coordinate some cross review.

Seems legit, I'll try next time, but sincerely I have far less experience with DRM.
but I could at least all the arm-soc specific stuff for sure.

> 
> On all the patches except the dt ones: Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Thanks,
Neil
> -Daniel
> 
>>
>> This patchset does :
>>  - Fixes the CRTC handling
>>  - Fixes the registers definitions
>>  - Adds support for device components registration along of-graph
>>  - Adds support for HDMI clocks
>>  - Adds support for HDMI VENC video modes
>>  - Adds support for the Custom HDMI PHY using callbacks added in [1] and [2]
>>  - Adds CMA node to reserve enougth memory for 1080p display
>>  - Adds the HDMI controller et connector modes on selected boards
>>  - Adds a proper dt-bindings for the HDMI controller et connector
>>  - Add RST documentation for Meson DRM driver
>>  - Updates the MAINTAINERS file to track the new files
>>
>> Changes since v1 patchset at [2] :
>>  - Add the meson drm documentation from [3] to this patchset
>>  - Update with new bus formats and HPD callbacks
>>  - Drop all the of_machine_is_compatible
>>
>> [1] http://lkml.kernel.org/r/1490109161-20529-1-git-send-email-narmstrong@baylibre.com
>> [2] http://lkml.kernel.org/r/1488469207-523-1-git-send-email-narmstrong@baylibre.com
>> [3] http://lkml.kernel.org/r/1488536068-9407-1-git-send-email-narmstrong@baylibre.com
>>
>> Neil Armstrong (13):
>>   drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable
>>     sync for vsync commit
>>   drm/meson: Add missing HDMI register
>>   drm/meson: Add support for components
>>   drm/meson: venc_cvbs: no more return -ENODEV if CVBS is not available
>>   drm/meson: add support for HDMI clock support
>>   drm/meson: Add support for HDMI venc modes and settings
>>   drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY
>>   ARM64: dts: meson-gx: Add shared CMA dma memory pool
>>   ARM64: dts: meson-gx: Add support for HDMI output
>>   dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension
>>   drm/meson: Convert existing documentation to actual kerneldoc
>>   drm/meson: Add RST to bring together kerneldoc
>>   MAINTAINERS: update files for Amlogic DRM Driver
>>
>>  .../bindings/display/amlogic,meson-dw-hdmi.txt     |  111 ++
>>  Documentation/gpu/index.rst                        |    1 +
>>  Documentation/gpu/meson.rst                        |   61 +
>>  MAINTAINERS                                        |    2 +
>>  .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi |   39 +
>>  arch/arm64/boot/dts/amlogic/meson-gx.dtsi          |   40 +
>>  .../boot/dts/amlogic/meson-gxbb-nexbox-a95x.dts    |   23 +
>>  arch/arm64/boot/dts/amlogic/meson-gxbb-p20x.dtsi   |   23 +
>>  arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi        |   12 +
>>  .../dts/amlogic/meson-gxl-s905x-nexbox-a95x.dts    |   23 +
>>  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi         |   13 +
>>  .../arm64/boot/dts/amlogic/meson-gxm-nexbox-a1.dts |   23 +
>>  arch/arm64/boot/dts/amlogic/meson-gxm.dtsi         |    3 +
>>  drivers/gpu/drm/meson/Kconfig                      |    6 +
>>  drivers/gpu/drm/meson/Makefile                     |    1 +
>>  drivers/gpu/drm/meson/meson_canvas.c               |    4 +-
>>  drivers/gpu/drm/meson/meson_crtc.c                 |   15 +-
>>  drivers/gpu/drm/meson/meson_drv.c                  |  118 +-
>>  drivers/gpu/drm/meson/meson_drv.h                  |    3 +
>>  drivers/gpu/drm/meson/meson_dw_hdmi.c              |  919 ++++++++++++++
>>  drivers/gpu/drm/meson/meson_dw_hdmi.h              |  146 +++
>>  drivers/gpu/drm/meson/meson_registers.h            |    1 +
>>  drivers/gpu/drm/meson/meson_vclk.c                 |  632 +++++++++-
>>  drivers/gpu/drm/meson/meson_vclk.h                 |    6 +-
>>  drivers/gpu/drm/meson/meson_venc.c                 | 1254 +++++++++++++++++++-
>>  drivers/gpu/drm/meson/meson_venc.h                 |    7 +
>>  drivers/gpu/drm/meson/meson_venc_cvbs.c            |   11 +-
>>  drivers/gpu/drm/meson/meson_viu.c                  |    6 +-
>>  drivers/gpu/drm/meson/meson_vpp.c                  |    8 +-
>>  drivers/gpu/drm/meson/meson_vpp.h                  |    2 +
>>  30 files changed, 3466 insertions(+), 47 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/display/amlogic,meson-dw-hdmi.txt
>>  create mode 100644 Documentation/gpu/meson.rst
>>  create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.c
>>  create mode 100644 drivers/gpu/drm/meson/meson_dw_hdmi.h
>>
>> -- 
>> 1.9.1
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 

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

* Re: [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output
  2017-04-04  8:10   ` Neil Armstrong
@ 2017-04-04 11:57     ` Kevin Hilman
  0 siblings, 0 replies; 31+ messages in thread
From: Kevin Hilman @ 2017-04-04 11:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, dri-devel, linux-amlogic, linux-arm-kernel,
	linux-kernel, devicetree

Neil Armstrong <narmstrong@baylibre.com> writes:

> On 03/21/2017 04:25 PM, Neil Armstrong wrote:
>> Add HDMI output and connector nodes.
>> 
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

[...]

>
> Hi Kevin,
>
> Please take this one for the amlogic arm-soc DT tree.
>

Applied to v4.12/dt64,

Kevin

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

* Re: [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool
  2017-04-04  8:41   ` Neil Armstrong
@ 2017-04-04 11:57     ` Kevin Hilman
  0 siblings, 0 replies; 31+ messages in thread
From: Kevin Hilman @ 2017-04-04 11:57 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, devicetree, linux-arm-kernel, dri-devel,
	linux-kernel

Neil Armstrong <narmstrong@baylibre.com> writes:

> On 03/21/2017 04:25 PM, Neil Armstrong wrote:
>> The HDMI modes needs more CMA memory to be reserved at boot-time.
>> 
>> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

[...]

> Hi Kevin,
>
> Please take this one for the amlogic arm-soc DT tree.
>

Applied to v4.12/dt64,

Kevin

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

* Re: [PATCH v2 07/13] drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY
  2017-04-04  9:16     ` Neil Armstrong
@ 2017-04-04 13:50       ` Daniel Vetter
  0 siblings, 0 replies; 31+ messages in thread
From: Daniel Vetter @ 2017-04-04 13:50 UTC (permalink / raw)
  To: Neil Armstrong
  Cc: airlied, linux-amlogic, linux-kernel, linux-arm-kernel, dri-devel

On Tue, Apr 04, 2017 at 11:16:23AM +0200, Neil Armstrong wrote:
> On 04/04/2017 10:57 AM, Daniel Vetter wrote:
> > On Tue, Mar 21, 2017 at 04:25:44PM +0100, Neil Armstrong wrote:
> >> The Amlogic Meson GXBB/GXL/GXM SoCs embeds a Synopsys DesignWare HDMI TX
> >> Controller with a custom Bridge + PHY around the Controller.
> >>
> >> This driver makes uses of all the custom PHY plat data callbacks and enables
> >> the compatible HDMI modes to be configured as a drm_encoder instance.
> >>
> >> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
> > 
> > [snip]
> > 
> >> +static int meson_venc_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
> >> +					struct drm_crtc_state *crtc_state,
> >> +					struct drm_connector_state *conn_state)
> >> +{
> >> +	return 0;
> >> +}
> > 
> > Given the over-the-top complicated mode encoding you seem to have, this
> > feels like it's a bit too simply.
> 
> Indeed, but the HW is really weird, every supported modes have very specific
> timings/parameters so moving the mode validation code from the dw-hdmi mode_valid
> to here would only make sense if we need to support a different HDMI controller.
> 
> But you are right, but I would have preferred to have a better HW for sure...

Oh, if your constraints on the meson encoder match what dw-hdmi needs,
then the mode_valid checks in there are good enough. A comment might be
good in that case.

But it looked to me (at a very cursory glance) that the meson encoder has
some additional fun restrictions on top.

> >> +
> >> +static void meson_venc_hdmi_encoder_disable(struct drm_encoder *encoder)
> >> +{
> >> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> >> +	struct meson_drm *priv = dw_hdmi->priv;
> >> +
> >> +	DRM_DEBUG_DRIVER("\n");
> >> +
> >> +	writel_bits_relaxed(0x3, 0,
> >> +			    priv->io_base + _REG(VPU_HDMI_SETTING));
> >> +
> >> +	writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
> >> +	writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
> >> +}
> >> +
> >> +static void meson_venc_hdmi_encoder_enable(struct drm_encoder *encoder)
> >> +{
> >> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> >> +	struct meson_drm *priv = dw_hdmi->priv;
> >> +
> >> +	DRM_DEBUG_DRIVER("%s\n", priv->venc.hdmi_use_enci ? "VENCI" : "VENCP");
> >> +
> >> +	if (priv->venc.hdmi_use_enci)
> >> +		writel_relaxed(1, priv->io_base + _REG(ENCI_VIDEO_EN));
> >> +	else
> >> +		writel_relaxed(1, priv->io_base + _REG(ENCP_VIDEO_EN));
> >> +}
> >> +
> >> +static void meson_venc_hdmi_encoder_mode_set(struct drm_encoder *encoder,
> >> +				   struct drm_display_mode *mode,
> >> +				   struct drm_display_mode *adjusted_mode)
> >> +{
> >> +	struct meson_dw_hdmi *dw_hdmi = encoder_to_meson_dw_hdmi(encoder);
> >> +	struct meson_drm *priv = dw_hdmi->priv;
> >> +	int vic = drm_match_cea_mode(mode);
> >> +
> >> +	DRM_DEBUG_DRIVER("%d:\"%s\" vic %d\n",
> >> +			 mode->base.id, mode->name, vic);
> >> +
> >> +	/* Should have been filtered */
> >> +	if (!vic)
> >> +		return;
> >> +
> >> +	/* VENC + VENC-DVI Mode setup */
> >> +	meson_venc_hdmi_mode_set(priv, vic, mode);
> > 
> > So this calls a different module which export_symbol_gpls that thing. I
> > have no idea why arm-soc people love modularized-to-the-function level
> > drivers, but it feels over the top. amd/nouveau/i915 all smash everything
> > into one driver, makes life so much easier.
> 
> I know, we are doomed on that !
> But here, since the wrapping around the dw-hdmi controller is completely custom
> if was necessary to add a separate encoder tied to HDMI and have the physical
> encoding code in the common driver.
> Note that the platform is also able to driver a LCD via LVDS, so this encoder code
> should be reusable here.

I'm not talking about the custom encoder or anything like that, or code
reuse. I'm talking about doing piles of separate .ko when you could have
just one (with a bunch of component drivers contained within). At least
this is how the really big drivers all work.

Of course shared ip (like the dw-hdmi bridge driver) need to be in
separate .ko, that part completely makes sense.

> > Note: bridge drivers as separate .ko makes sense, but separate .ko for
> > every single functional unit in your vendor IP imo totally doesn't.
> 
> Actually I added a global ko for the "DRM" driver with crtc, planes and CVBS,
> and another ko for the HDMI bridge wrapping.

Or maybe I just misunderstood things, but meson_venc_hdmi_mode_set looks
like it could be pulled into this module?
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

end of thread, other threads:[~2017-04-04 13:51 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-21 15:25 [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Neil Armstrong
2017-03-21 15:25 ` [PATCH v2 01/13] drm/meson: Use crtc_state for hdisplay and fix atomic flush/enable sync for vsync commit Neil Armstrong
2017-04-04  8:49   ` Daniel Vetter
2017-03-21 15:25 ` [PATCH v2 02/13] drm/meson: Add missing HDMI register Neil Armstrong
2017-03-21 15:25 ` [PATCH v2 03/13] drm/meson: Add support for components Neil Armstrong
2017-04-04  8:59   ` Daniel Vetter
2017-04-04  9:08     ` Neil Armstrong
2017-04-04  9:09       ` Daniel Vetter
2017-03-21 15:25 ` [PATCH v2 04/13] drm/meson: venc_cvbs: no more return -ENODEV if CVBS is not available Neil Armstrong
2017-03-21 15:25 ` [PATCH v2 05/13] drm/meson: add support for HDMI clock support Neil Armstrong
2017-03-21 15:25 ` [PATCH v2 06/13] drm/meson: Add support for HDMI venc modes and settings Neil Armstrong
2017-03-21 15:25 ` [PATCH v2 07/13] drm/meson: Add support for HDMI encoder and DW-HDMI bridge + PHY Neil Armstrong
2017-04-04  8:57   ` Daniel Vetter
2017-04-04  9:16     ` Neil Armstrong
2017-04-04 13:50       ` Daniel Vetter
2017-03-21 15:25 ` [PATCH v2 08/13] ARM64: dts: meson-gx: Add shared CMA dma memory pool Neil Armstrong
2017-04-04  8:41   ` Neil Armstrong
2017-04-04 11:57     ` Kevin Hilman
2017-03-21 15:25 ` [PATCH v2 09/13] ARM64: dts: meson-gx: Add support for HDMI output Neil Armstrong
2017-04-04  8:10   ` Neil Armstrong
2017-04-04 11:57     ` Kevin Hilman
2017-03-21 15:25 ` [PATCH v2 10/13] dt-bindings: Add bindings for the Amlogic Meson dw-hdmi extension Neil Armstrong
2017-03-21 15:25 ` [PATCH v2 11/13] drm/meson: Convert existing documentation to actual kerneldoc Neil Armstrong
2017-03-21 15:25 ` [PATCH v2 12/13] drm/meson: Add RST to bring together kerneldoc Neil Armstrong
2017-04-04  9:00   ` Daniel Vetter
2017-04-04  9:17     ` Neil Armstrong
2017-03-21 15:25 ` [PATCH v2 13/13] MAINTAINERS: update files for Amlogic DRM Driver Neil Armstrong
2017-04-04  9:01   ` Daniel Vetter
2017-04-04  9:18     ` Neil Armstrong
2017-04-04  9:04 ` [PATCH v2 00/13] drm/meson: Initial support for HDMI Output Daniel Vetter
2017-04-04  9:21   ` Neil Armstrong

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