linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support
@ 2017-05-04 11:48 Icenowy Zheng
  2017-05-04 11:48 ` [PATCH v6 01/13] dt-bindings: add binding for the Allwinner DE2 CCU Icenowy Zheng
                   ` (12 more replies)
  0 siblings, 13 replies; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

I'm sorry that some patch from this version is wrongly sent
without decorations.

This patchset is the initial patchset for Allwinner DE2 support.

It contains the support of clocks in DE2 and the mixers in DE2.

The SoC used to develop this patchset is V3s, as V3s is the simplest
one of the SoCs that have DE2.
(Allwinner V3s features only one mixer, although its clock control
unit contains support for second mixer's clock; and its only video
output is RGB LCD, which is already supported in our TCON driver)

The last patch is only a testing patch, it shouldn't be merged; and
for the patch to be really usable, the RFC fix of the TCON driver [1]
is needed.

No HDMI, TV encoder or other internal bridges' support is included
in this patchset, which makes it currently not usable on H3. (Some
WIP code have already been written based on v4 of this patchset by
Jernej Skrabec and be, including TVE support (basical but usable)
and HDMI support (can display something, but still not so usable
because of some problem). )

Thanks to Jean-Francois Moine and Jernej Skrabec for their efforts
to discover the internal of DE2!

[1] https://lists.freedesktop.org/archives/dri-devel/2016-December/126264.html

Icenowy Zheng (13):
  dt-bindings: add binding for the Allwinner DE2 CCU
  clk: sunxi-ng: add support for DE2 CCU
  dt-bindings: add bindings for DE2 on V3s SoC
  drm/sun4i: return only planes for layers created
  drm/sun4i: abstract a engine type
  drm/sun4i: add a dedicated module for sun4i-backend and sun4i-layer
  drm/sun4i: add a Kconfig option for sun4i-backend
  drm/sun4i: add support for Allwinner DE2 mixers
  drm/sun4i: Add compatible string for V3s display engine
  drm/sun4i: tcon: add support for V3s TCON
  ARM: dts: sun8i: add DE2 nodes for V3s SoC
  ARM: dts: sun8i: add pinmux for LCD pins of V3s SoC
  [DO NOT MERGE] ARM: dts: sun8i: enable LCD panel of Lichee Pi Zero

 .../devicetree/bindings/clock/sun8i-de2.txt        |  30 ++
 .../bindings/display/sunxi/sun4i-drm.txt           |  29 +-
 arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts      |  36 ++
 arch/arm/boot/dts/sun8i-v3s.dtsi                   |  96 +++++
 drivers/clk/sunxi-ng/Kconfig                       |   5 +
 drivers/clk/sunxi-ng/Makefile                      |   1 +
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c               | 218 ++++++++++++
 drivers/clk/sunxi-ng/ccu-sun8i-de2.h               |  28 ++
 drivers/gpu/drm/sun4i/Kconfig                      |  20 ++
 drivers/gpu/drm/sun4i/Makefile                     |   8 +-
 drivers/gpu/drm/sun4i/sun4i_backend.c              |  72 ++--
 drivers/gpu/drm/sun4i/sun4i_backend.h              |  17 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.c                 |  32 +-
 drivers/gpu/drm/sun4i/sun4i_crtc.h                 |   5 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c                  |   6 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h                  |   2 +-
 drivers/gpu/drm/sun4i/sun4i_layer.c                |  20 +-
 drivers/gpu/drm/sun4i/sun4i_layer.h                |   7 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.c                 |  41 ++-
 drivers/gpu/drm/sun4i/sun4i_tv.c                   |   9 +-
 drivers/gpu/drm/sun4i/sun8i_layer.c                | 140 ++++++++
 drivers/gpu/drm/sun4i/sun8i_layer.h                |  36 ++
 drivers/gpu/drm/sun4i/sun8i_mixer.c                | 394 +++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun8i_mixer.h                | 137 +++++++
 drivers/gpu/drm/sun4i/sunxi_engine.h               | 112 ++++++
 include/dt-bindings/clock/sun8i-de2.h              |  18 +
 include/dt-bindings/reset/sun8i-de2.h              |  14 +
 27 files changed, 1431 insertions(+), 102 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/sun8i-de2.txt
 create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-de2.c
 create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-de2.h
 create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
 create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
 create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
 create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
 create mode 100644 drivers/gpu/drm/sun4i/sunxi_engine.h
 create mode 100644 include/dt-bindings/clock/sun8i-de2.h
 create mode 100644 include/dt-bindings/reset/sun8i-de2.h

-- 
2.12.2

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

* [PATCH v6 01/13] dt-bindings: add binding for the Allwinner DE2 CCU
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-04 11:48 ` [PATCH v6 02/13] clk: sunxi-ng: add support for " Icenowy Zheng
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

Allwinner "Display Engine 2.0" contains some clock controls in it.

In order to add them as clock drivers, we need a device tree binding.
Add the binding here.

Also add the device tree binding headers.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Acked-by: Rob Herring <robh@kernel.org>
---
Changes in v6:
- Added Rob's ACK.
- Drpoped A64's compatible as it's not appropriate now.
Changes in v5:
- Moved dt-binding headers here.
- Changed dt-binding headers' license header to SPDX license.
Changes in v4:
- Dropped the leading 0 in clock at 1000000 .
Changes in v3:
- Fill the address space length of DE2 CCU to 0x100000, just reach the start of mixer0.

 .../devicetree/bindings/clock/sun8i-de2.txt        | 30 ++++++++++++++++++++++
 include/dt-bindings/clock/sun8i-de2.h              | 18 +++++++++++++
 include/dt-bindings/reset/sun8i-de2.h              | 14 ++++++++++
 3 files changed, 62 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/sun8i-de2.txt
 create mode 100644 include/dt-bindings/clock/sun8i-de2.h
 create mode 100644 include/dt-bindings/reset/sun8i-de2.h

diff --git a/Documentation/devicetree/bindings/clock/sun8i-de2.txt b/Documentation/devicetree/bindings/clock/sun8i-de2.txt
new file mode 100644
index 000000000000..d710c0111cd3
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/sun8i-de2.txt
@@ -0,0 +1,30 @@
+Allwinner Display Engine 2.0 Clock Control Binding
+--------------------------------------------------
+
+Required properties :
+- compatible: must contain one of the following compatibles:
+		- "allwinner,sun8i-a83t-de2-clk"
+		- "allwinner,sun50i-h5-de2-clk"
+
+- reg: Must contain the registers base address and length
+- clocks: phandle to the clocks feeding the display engine subsystem.
+	  Three are needed:
+  - "mod": the display engine module clock
+  - "bus": the bus clock for the whole display engine subsystem
+- clock-names: Must contain the clock names described just above
+- resets: phandle to the reset control for the display engine subsystem.
+- #clock-cells : must contain 1
+- #reset-cells : must contain 1
+
+Example:
+de2_clocks: clock@1000000 {
+	compatible = "allwinner,sun8i-a83t-de2-clk";
+	reg = <0x01000000 0x100000>;
+	clocks = <&ccu CLK_DE>,
+		 <&ccu CLK_BUS_DE>;
+	clock-names = "mod",
+		      "bus";
+	resets = <&ccu RST_BUS_DE>;
+	#clock-cells = <1>;
+	#reset-cells = <1>;
+};
diff --git a/include/dt-bindings/clock/sun8i-de2.h b/include/dt-bindings/clock/sun8i-de2.h
new file mode 100644
index 000000000000..3bed63b524aa
--- /dev/null
+++ b/include/dt-bindings/clock/sun8i-de2.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_SUN8I_DE2_H_
+#define _DT_BINDINGS_CLOCK_SUN8I_DE2_H_
+
+#define CLK_BUS_MIXER0		0
+#define CLK_BUS_MIXER1		1
+#define CLK_BUS_WB		2
+
+#define CLK_MIXER0		6
+#define CLK_MIXER1		7
+#define CLK_WB			8
+
+#endif /* _DT_BINDINGS_CLOCK_SUN8I_DE2_H_ */
diff --git a/include/dt-bindings/reset/sun8i-de2.h b/include/dt-bindings/reset/sun8i-de2.h
new file mode 100644
index 000000000000..9526017432f0
--- /dev/null
+++ b/include/dt-bindings/reset/sun8i-de2.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2016 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+ */
+
+#ifndef _DT_BINDINGS_RESET_SUN8I_DE2_H_
+#define _DT_BINDINGS_RESET_SUN8I_DE2_H_
+
+#define RST_MIXER0	0
+#define RST_MIXER1	1
+#define RST_WB		2
+
+#endif /* _DT_BINDINGS_RESET_SUN8I_DE2_H_ */
-- 
2.12.2

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

* [PATCH v6 02/13] clk: sunxi-ng: add support for DE2 CCU
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
  2017-05-04 11:48 ` [PATCH v6 01/13] dt-bindings: add binding for the Allwinner DE2 CCU Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-04 12:50   ` Maxime Ripard
  2017-05-04 11:48 ` [PATCH v6 03/13] dt-bindings: add bindings for DE2 on V3s SoC Icenowy Zheng
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

The "Display Engine 2.0" in Allwinner newer SoCs contains a clock
management unit for its subunits, like the DE CCU in A80.

Add a sunxi-ng style driver for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
Changes in v5:
- Removed dt-bindings headers (they're now in patch 1).
Changes in v4:
- Fixed the inconsistence between mixer_div clocks' number and real clock.
Changes in v2:
- Rename sunxi-de2-ccu to sun8i-de2-ccu.

 drivers/clk/sunxi-ng/Kconfig         |   5 +
 drivers/clk/sunxi-ng/Makefile        |   1 +
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 218 +++++++++++++++++++++++++++++++++++
 drivers/clk/sunxi-ng/ccu-sun8i-de2.h |  28 +++++
 4 files changed, 252 insertions(+)
 create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-de2.c
 create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-de2.h

diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
index 64088e599404..2e4d804fbf61 100644
--- a/drivers/clk/sunxi-ng/Kconfig
+++ b/drivers/clk/sunxi-ng/Kconfig
@@ -140,6 +140,11 @@ config SUN8I_V3S_CCU
 	default MACH_SUN8I
 	depends on MACH_SUN8I || COMPILE_TEST
 
+config SUN8I_DE2_CCU
+	bool "Support for the Allwinner SoCs DE2 CCU"
+	select SUNXI_CCU_DIV
+	select SUNXI_CCU_GATE
+
 config SUN9I_A80_CCU
 	bool "Support for the Allwinner A80 CCU"
 	select SUNXI_CCU_DIV
diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
index 0ec02fe14c50..be616279450e 100644
--- a/drivers/clk/sunxi-ng/Makefile
+++ b/drivers/clk/sunxi-ng/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_SUN8I_A23_CCU)	+= ccu-sun8i-a23.o
 obj-$(CONFIG_SUN8I_A33_CCU)	+= ccu-sun8i-a33.o
 obj-$(CONFIG_SUN8I_H3_CCU)	+= ccu-sun8i-h3.o
 obj-$(CONFIG_SUN8I_V3S_CCU)	+= ccu-sun8i-v3s.o
+obj-$(CONFIG_SUN8I_DE2_CCU)	+= ccu-sun8i-de2.o
 obj-$(CONFIG_SUN8I_R_CCU)	+= ccu-sun8i-r.o
 obj-$(CONFIG_SUN9I_A80_CCU)	+= ccu-sun9i-a80.o
 obj-$(CONFIG_SUN9I_A80_CCU)	+= ccu-sun9i-a80-de.o
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
new file mode 100644
index 000000000000..adb2c344692a
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include "ccu_common.h"
+#include "ccu_div.h"
+#include "ccu_gate.h"
+#include "ccu_reset.h"
+
+#include "ccu-sun8i-de2.h"
+
+static SUNXI_CCU_GATE(bus_mixer0_clk,	"bus-mixer0",	"bus-de",
+		      0x04, BIT(0), 0);
+static SUNXI_CCU_GATE(bus_mixer1_clk,	"bus-mixer1",	"bus-de",
+		      0x04, BIT(1), 0);
+static SUNXI_CCU_GATE(bus_wb_clk,	"bus-wb",	"bus-de",
+		      0x04, BIT(2), 0);
+
+static SUNXI_CCU_GATE(mixer0_clk,	"mixer0",	"mixer0-div",
+		      0x00, BIT(0), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE(mixer1_clk,	"mixer1",	"mixer1-div",
+		      0x00, BIT(1), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE(wb_clk,		"wb",		"wb-div",
+		      0x00, BIT(2), CLK_SET_RATE_PARENT);
+
+static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4,
+		   CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4,
+		   CLK_SET_RATE_PARENT);
+static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4,
+		   CLK_SET_RATE_PARENT);
+
+static struct ccu_common *sunxi_de2_clks[] = {
+	&mixer0_clk.common,
+	&mixer1_clk.common,
+	&wb_clk.common,
+
+	&bus_mixer0_clk.common,
+	&bus_mixer1_clk.common,
+	&bus_wb_clk.common,
+
+	&mixer0_div_clk.common,
+	&mixer1_div_clk.common,
+	&wb_div_clk.common,
+};
+
+static struct clk_hw_onecell_data sunxi_de2_hw_clks = {
+	.hws	= {
+		[CLK_MIXER0]		= &mixer0_clk.common.hw,
+		[CLK_MIXER1]		= &mixer1_clk.common.hw,
+		[CLK_WB]		= &wb_clk.common.hw,
+
+		[CLK_BUS_MIXER0]	= &bus_mixer0_clk.common.hw,
+		[CLK_BUS_MIXER1]	= &bus_mixer1_clk.common.hw,
+		[CLK_BUS_WB]		= &bus_wb_clk.common.hw,
+
+		[CLK_MIXER0_DIV]	= &mixer0_div_clk.common.hw,
+		[CLK_MIXER1_DIV]	= &mixer1_div_clk.common.hw,
+		[CLK_WB_DIV]		= &wb_div_clk.common.hw,
+	},
+	.num	= CLK_NUMBER,
+};
+
+static struct ccu_reset_map sun8i_a83t_de2_resets[] = {
+	[RST_MIXER0]	= { 0x08, BIT(0) },
+	/*
+	 * For A83T, H3 and R40, mixer1 reset line is shared with wb, so
+	 * only RST_WB is exported here.
+	 */
+	[RST_WB]	= { 0x08, BIT(2) },
+};
+
+static struct ccu_reset_map sun50i_a64_de2_resets[] = {
+	[RST_MIXER0]	= { 0x08, BIT(0) },
+	[RST_MIXER1]	= { 0x08, BIT(1) },
+	[RST_WB]	= { 0x08, BIT(2) },
+};
+
+static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = {
+	.ccu_clks	= sunxi_de2_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sunxi_de2_clks),
+
+	.hw_clks	= &sunxi_de2_hw_clks,
+
+	.resets		= sun8i_a83t_de2_resets,
+	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
+};
+
+static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = {
+	.ccu_clks	= sunxi_de2_clks,
+	.num_ccu_clks	= ARRAY_SIZE(sunxi_de2_clks),
+
+	.hw_clks	= &sunxi_de2_hw_clks,
+
+	.resets		= sun50i_a64_de2_resets,
+	.num_resets	= ARRAY_SIZE(sun50i_a64_de2_resets),
+};
+
+static int sunxi_de2_clk_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct clk *bus_clk, *mod_clk;
+	struct reset_control *rstc;
+	void __iomem *reg;
+	const struct sunxi_ccu_desc *ccu_desc;
+	int ret;
+
+	ccu_desc = of_device_get_match_data(&pdev->dev);
+	if (!ccu_desc)
+		return -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reg = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(reg))
+		return PTR_ERR(reg);
+
+	bus_clk = devm_clk_get(&pdev->dev, "bus");
+	if (IS_ERR(bus_clk)) {
+		ret = PTR_ERR(bus_clk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Couldn't get bus clk: %d\n", ret);
+		return ret;
+	}
+
+	mod_clk = devm_clk_get(&pdev->dev, "mod");
+	if (IS_ERR(mod_clk)) {
+		ret = PTR_ERR(mod_clk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Couldn't get mod clk: %d\n", ret);
+		return ret;
+	}
+
+	rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+	if (IS_ERR(rstc)) {
+		ret = PTR_ERR(bus_clk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev,
+				"Couldn't get reset control: %d\n", ret);
+		return ret;
+	}
+
+	/* The clocks need to be enabled for us to access the registers */
+	ret = clk_prepare_enable(bus_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(mod_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "Couldn't enable mod clk: %d\n", ret);
+		return ret;
+	}
+
+	/* The reset control needs to be asserted for the controls to work */
+	ret = reset_control_deassert(rstc);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Couldn't deassert reset control: %d\n", ret);
+		goto err_disable_clk;
+	}
+
+	ret = sunxi_ccu_probe(pdev->dev.of_node, reg, ccu_desc);
+	if (ret)
+		goto err_assert_reset;
+
+	return 0;
+
+err_assert_reset:
+	reset_control_assert(rstc);
+err_disable_clk:
+	clk_disable_unprepare(bus_clk);
+	return ret;
+}
+
+static const struct of_device_id sunxi_de2_clk_ids[] = {
+	{
+		.compatible = "allwinner,sun8i-a83t-de2-clk",
+		.data = &sun8i_a83t_de2_clk_desc,
+	},
+	{
+		.compatible = "allwinner,sun50i-h5-de2-clk",
+		.data = &sun50i_a64_de2_clk_desc,
+	},
+	/*
+	 * The Allwinner A64 SoC needs some bit to be poke in syscon to make
+	 * DE2 really working.
+	 * So there's currently no A64 compatible here.
+	 * H5 shares the same reset line with A64, so here H5 is using the
+	 * clock description of A64.
+	 */
+	{ }
+};
+
+static struct platform_driver sunxi_de2_clk_driver = {
+	.probe	= sunxi_de2_clk_probe,
+	.driver	= {
+		.name	= "sunxi-de2-clks",
+		.of_match_table	= sunxi_de2_clk_ids,
+	},
+};
+builtin_platform_driver(sunxi_de2_clk_driver);
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.h b/drivers/clk/sunxi-ng/ccu-sun8i-de2.h
new file mode 100644
index 000000000000..530c006e0ae9
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * 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.
+ */
+
+#ifndef _CCU_SUN8I_DE2_H_
+#define _CCU_SUN8I_DE2_H_
+
+#include <dt-bindings/clock/sun8i-de2.h>
+#include <dt-bindings/reset/sun8i-de2.h>
+
+/* Intermediary clock dividers are not exported */
+#define CLK_MIXER0_DIV	3
+#define CLK_MIXER1_DIV	4
+#define CLK_WB_DIV	5
+
+#define CLK_NUMBER	(CLK_WB + 1)
+
+#endif /* _CCU_SUN8I_DE2_H_ */
-- 
2.12.2

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

* [PATCH v6 03/13] dt-bindings: add bindings for DE2 on V3s SoC
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
  2017-05-04 11:48 ` [PATCH v6 01/13] dt-bindings: add binding for the Allwinner DE2 CCU Icenowy Zheng
  2017-05-04 11:48 ` [PATCH v6 02/13] clk: sunxi-ng: add support for " Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-05  3:24   ` [linux-sunxi] " Chen-Yu Tsai
  2017-05-04 11:48 ` [PATCH v6 04/13] drm/sun4i: return only planes for layers created Icenowy Zheng
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

Allwinner V3s SoC have a display engine which have a different pipeline
with older SoCs.

Add document for it (new compatibles and the new "mixer" part).

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Acked-by: Rob Herring <robh@kernel.org>
---
Changes in v4:
- Removed the refactor at TCON chapter.
Changes in v3:
- Remove the description of having a BE directly as allwinner,pipeline.

 .../bindings/display/sunxi/sun4i-drm.txt           | 29 ++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index 7acdbf14ae1c..33452884b96e 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -41,6 +41,7 @@ Required properties:
    * allwinner,sun6i-a31-tcon
    * allwinner,sun6i-a31s-tcon
    * allwinner,sun8i-a33-tcon
+   * allwinner,sun8i-v3s-tcon
  - reg: base address and size of memory-mapped region
  - interrupts: interrupt associated to this IP
  - clocks: phandles to the clocks feeding the TCON. Three are needed:
@@ -62,7 +63,7 @@ Required properties:
   second the block connected to the TCON channel 1 (usually the TV
   encoder)
 
-On SoCs other than the A33, there is one more clock required:
+On SoCs other than the A33 and V3s, there is one more clock required:
    - 'tcon-ch1': The clock driving the TCON channel 1
 
 DRC
@@ -148,6 +149,26 @@ Required properties:
   Documentation/devicetree/bindings/media/video-interfaces.txt. The
   first port should be the input endpoints, the second one the outputs
 
+Display Engine 2.0 Mixer
+------------------------
+
+The DE2 mixer have many functionalities, currently only layer blending is
+supported.
+
+Required properties:
+  - compatible: value must be one of:
+    * allwinner,sun8i-v3s-de2-mixer
+  - reg: base address and size of the memory-mapped region.
+  - clocks: phandles to the clocks feeding the frontend and backend
+    * bus: the backend interface clock
+    * ram: the backend DRAM clock
+  - clock-names: the clock names mentioned above
+  - resets: phandles to the reset controllers driving the backend
+
+- ports: A ports node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt. The
+  first port should be the input endpoints, the second one the output
+
 
 Display Engine Pipeline
 -----------------------
@@ -162,9 +183,13 @@ Required properties:
     * allwinner,sun6i-a31-display-engine
     * allwinner,sun6i-a31s-display-engine
     * allwinner,sun8i-a33-display-engine
+    * allwinner,sun8i-v3s-display-engine
 
   - allwinner,pipelines: list of phandle to the display engine
-    frontends available.
+    pipeline entry point. For SoCs with original DE (currently
+    all SoCs supported by display engine except V3s), this
+    phandle should be a display frontend; for SoCs with DE2,
+    this phandle should be a mixer.
 
 Example:
 
-- 
2.12.2

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

* [PATCH v6 04/13] drm/sun4i: return only planes for layers created
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (2 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 03/13] dt-bindings: add bindings for DE2 on V3s SoC Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-04 11:48 ` [PATCH v6 05/13] drm/sun4i: abstract a engine type Icenowy Zheng
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

As we are going to add support for the Allwinner DE2 Mixer in sun4i-drm
driver, we will finally have two types of layers.

Each layer is bound to a drm_plane that is CRTC-specific, so we create
them when initializing CRTC (calling sun4i_layers_init, which will be
generalized in next patch). The drm_plane's will be used when creating
CRTC, but the CRTC initialization code do not care other properties of
the layer, so we let the sun4i_layers_init function return drm_plane's
only.

As we have no need to trace the layers after the CRTC is properly
created, we drop the layers pointer in sun4i_crtc struct.

Doing these things makes the CRTC code independent to the type of layer
(the sun4i_layers_init function name is still hardcoded and will be
changed in the next patch), so that we can finally gain support for the
mixer in DE2, which will has different layers.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 drivers/gpu/drm/sun4i/sun4i_crtc.c  | 23 ++++++++++++-----------
 drivers/gpu/drm/sun4i/sun4i_crtc.h  |  1 -
 drivers/gpu/drm/sun4i/sun4i_layer.c | 18 ++++++++++--------
 drivers/gpu/drm/sun4i/sun4i_layer.h |  4 ++--
 4 files changed, 24 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 3c876c3a356a..708b3543d4e9 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -139,6 +139,7 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
 				   struct sun4i_tcon *tcon)
 {
 	struct sun4i_crtc *scrtc;
+	struct drm_plane **planes;
 	struct drm_plane *primary = NULL, *cursor = NULL;
 	int ret, i;
 
@@ -149,22 +150,22 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
 	scrtc->tcon = tcon;
 
 	/* Create our layers */
-	scrtc->layers = sun4i_layers_init(drm, scrtc->backend);
-	if (IS_ERR(scrtc->layers)) {
+	planes = sun4i_layers_init(drm, scrtc);
+	if (IS_ERR(planes)) {
 		dev_err(drm->dev, "Couldn't create the planes\n");
 		return NULL;
 	}
 
 	/* find primary and cursor planes for drm_crtc_init_with_planes */
-	for (i = 0; scrtc->layers[i]; i++) {
-		struct sun4i_layer *layer = scrtc->layers[i];
+	for (i = 0; planes[i]; i++) {
+		struct drm_plane *plane = planes[i];
 
-		switch (layer->plane.type) {
+		switch (plane->type) {
 		case DRM_PLANE_TYPE_PRIMARY:
-			primary = &layer->plane;
+			primary = plane;
 			break;
 		case DRM_PLANE_TYPE_CURSOR:
-			cursor = &layer->plane;
+			cursor = plane;
 			break;
 		default:
 			break;
@@ -188,12 +189,12 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
 						   1);
 
 	/* Set possible_crtcs to this crtc for overlay planes */
-	for (i = 0; scrtc->layers[i]; i++) {
+	for (i = 0; planes[i]; i++) {
 		uint32_t possible_crtcs = BIT(drm_crtc_index(&scrtc->crtc));
-		struct sun4i_layer *layer = scrtc->layers[i];
+		struct drm_plane *plane = planes[i];
 
-		if (layer->plane.type == DRM_PLANE_TYPE_OVERLAY)
-			layer->plane.possible_crtcs = possible_crtcs;
+		if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+			plane->possible_crtcs = possible_crtcs;
 	}
 
 	return scrtc;
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h b/drivers/gpu/drm/sun4i/sun4i_crtc.h
index 230cb8f0d601..4dae3508424a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.h
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h
@@ -19,7 +19,6 @@ struct sun4i_crtc {
 
 	struct sun4i_backend		*backend;
 	struct sun4i_tcon		*tcon;
-	struct sun4i_layer		**layers;
 };
 
 static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index f26bde5b9117..e1f03e1cc0ac 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -16,6 +16,7 @@
 #include <drm/drmP.h>
 
 #include "sun4i_backend.h"
+#include "sun4i_crtc.h"
 #include "sun4i_layer.h"
 
 struct sun4i_plane_desc {
@@ -128,15 +129,16 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
 	return layer;
 }
 
-struct sun4i_layer **sun4i_layers_init(struct drm_device *drm,
-				       struct sun4i_backend *backend)
+struct drm_plane **sun4i_layers_init(struct drm_device *drm,
+				     struct sun4i_crtc *crtc)
 {
-	struct sun4i_layer **layers;
+	struct drm_plane **planes;
+	struct sun4i_backend *backend = crtc->backend;
 	int i;
 
-	layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
-			      sizeof(*layers), GFP_KERNEL);
-	if (!layers)
+	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
+			      sizeof(*planes), GFP_KERNEL);
+	if (!planes)
 		return ERR_PTR(-ENOMEM);
 
 	/*
@@ -178,8 +180,8 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm,
 				   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
 
 		layer->id = i;
-		layers[i] = layer;
+		planes[i] = &layer->plane;
 	};
 
-	return layers;
+	return planes;
 }
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index 4be1f0919df2..5ea5c994d6ea 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -26,7 +26,7 @@ plane_to_sun4i_layer(struct drm_plane *plane)
 	return container_of(plane, struct sun4i_layer, plane);
 }
 
-struct sun4i_layer **sun4i_layers_init(struct drm_device *drm,
-				       struct sun4i_backend *backend);
+struct drm_plane **sun4i_layers_init(struct drm_device *drm,
+				     struct sun4i_crtc *crtc);
 
 #endif /* _SUN4I_LAYER_H_ */
-- 
2.12.2

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

* [PATCH v6 05/13] drm/sun4i: abstract a engine type
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (3 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 04/13] drm/sun4i: return only planes for layers created Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-05  2:56   ` [linux-sunxi] " Chen-Yu Tsai
  2017-05-04 11:48 ` [PATCH v6 06/13] drm/sun4i: add a dedicated module for sun4i-backend and sun4i-layer Icenowy Zheng
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

As we are going to add support for the Allwinner DE2 engine in sun4i-drm
driver, we will finally have two types of display engines -- the DE1
backend and the DE2 mixer. They both do some display blending and feed
graphics data to TCON, so I choose to call them both "engine" here.

Abstract the engine type to a new struct with an ops struct, which contains
functions that should be called outside the engine-specified code (in
TCON, CRTC or TV Encoder code).

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
Changes in v6:
- Rebased on wens's multi-pipeline patchset.
- Split out Makefile changes.
Changes in v5:
- Really made a sunxi_engine struct type, and moved ops pointer
  into it.
- Added checked ops wrappers.
- Changed the second parameter of layers_init from crtc to engine.
Changes in v4:
- Comments to tag the color correction functions as optional.
- Check before calling the optional functions.
- Change layers_init to satisfy new PATCH v4 04/11.

 drivers/gpu/drm/sun4i/sun4i_backend.c |  68 ++++++++++++---------
 drivers/gpu/drm/sun4i/sun4i_backend.h |  17 +++---
 drivers/gpu/drm/sun4i/sun4i_crtc.c    |  11 ++--
 drivers/gpu/drm/sun4i/sun4i_crtc.h    |   4 +-
 drivers/gpu/drm/sun4i/sun4i_drv.c     |   2 +-
 drivers/gpu/drm/sun4i/sun4i_drv.h     |   2 +-
 drivers/gpu/drm/sun4i/sun4i_layer.c   |   8 +--
 drivers/gpu/drm/sun4i/sun4i_layer.h   |   5 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.c    |  36 ++++++-----
 drivers/gpu/drm/sun4i/sun4i_tv.c      |   9 ++-
 drivers/gpu/drm/sun4i/sunxi_engine.h  | 112 ++++++++++++++++++++++++++++++++++
 11 files changed, 198 insertions(+), 76 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sunxi_engine.h

diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index e53107418add..611cdcb9c182 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -25,6 +25,8 @@
 
 #include "sun4i_backend.h"
 #include "sun4i_drv.h"
+#include "sun4i_layer.h"
+#include "sunxi_engine.h"
 
 static const u32 sunxi_rgb2yuv_coef[12] = {
 	0x00000107, 0x00000204, 0x00000064, 0x00000108,
@@ -32,41 +34,38 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
 	0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
 };
 
-void sun4i_backend_apply_color_correction(struct sun4i_backend *backend)
+static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine)
 {
 	int i;
 
 	DRM_DEBUG_DRIVER("Applying RGB to YUV color correction\n");
 
 	/* Set color correction */
-	regmap_write(backend->regs, SUN4I_BACKEND_OCCTL_REG,
+	regmap_write(engine->regs, SUN4I_BACKEND_OCCTL_REG,
 		     SUN4I_BACKEND_OCCTL_ENABLE);
 
 	for (i = 0; i < 12; i++)
-		regmap_write(backend->regs, SUN4I_BACKEND_OCRCOEF_REG(i),
+		regmap_write(engine->regs, SUN4I_BACKEND_OCRCOEF_REG(i),
 			     sunxi_rgb2yuv_coef[i]);
 }
-EXPORT_SYMBOL(sun4i_backend_apply_color_correction);
 
-void sun4i_backend_disable_color_correction(struct sun4i_backend *backend)
+static void sun4i_backend_disable_color_correction(struct sunxi_engine *engine)
 {
 	DRM_DEBUG_DRIVER("Disabling color correction\n");
 
 	/* Disable color correction */
-	regmap_update_bits(backend->regs, SUN4I_BACKEND_OCCTL_REG,
+	regmap_update_bits(engine->regs, SUN4I_BACKEND_OCCTL_REG,
 			   SUN4I_BACKEND_OCCTL_ENABLE, 0);
 }
-EXPORT_SYMBOL(sun4i_backend_disable_color_correction);
 
-void sun4i_backend_commit(struct sun4i_backend *backend)
+static void sun4i_backend_commit(struct sunxi_engine *engine)
 {
 	DRM_DEBUG_DRIVER("Committing changes\n");
 
-	regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
+	regmap_write(engine->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
 		     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS |
 		     SUN4I_BACKEND_REGBUFFCTL_LOADCTL);
 }
-EXPORT_SYMBOL(sun4i_backend_commit);
 
 void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 				int layer, bool enable)
@@ -81,7 +80,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 	else
 		val = 0;
 
-	regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
+	regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
 			   SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
 }
 EXPORT_SYMBOL(sun4i_backend_layer_enable);
@@ -144,27 +143,28 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
 		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
 				 state->crtc_w, state->crtc_h);
-		regmap_write(backend->regs, SUN4I_BACKEND_DISSIZE_REG,
+		regmap_write(backend->engine.regs, SUN4I_BACKEND_DISSIZE_REG,
 			     SUN4I_BACKEND_DISSIZE(state->crtc_w,
 						   state->crtc_h));
 	}
 
 	/* Set the line width */
 	DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
-	regmap_write(backend->regs, SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
+	regmap_write(backend->engine.regs,
+		     SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
 		     fb->pitches[0] * 8);
 
 	/* Set height and width */
 	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
 			 state->crtc_w, state->crtc_h);
-	regmap_write(backend->regs, SUN4I_BACKEND_LAYSIZE_REG(layer),
+	regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYSIZE_REG(layer),
 		     SUN4I_BACKEND_LAYSIZE(state->crtc_w,
 					   state->crtc_h));
 
 	/* Set base coordinates */
 	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
 			 state->crtc_x, state->crtc_y);
-	regmap_write(backend->regs, SUN4I_BACKEND_LAYCOOR_REG(layer),
+	regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYCOOR_REG(layer),
 		     SUN4I_BACKEND_LAYCOOR(state->crtc_x,
 					   state->crtc_y));
 
@@ -185,7 +185,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 		interlaced = plane->state->crtc->state->adjusted_mode.flags
 			& DRM_MODE_FLAG_INTERLACE;
 
-	regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
+	regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
 			   SUN4I_BACKEND_MODCTL_ITLMOD_EN,
 			   interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0);
 
@@ -199,7 +199,8 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 		return ret;
 	}
 
-	regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG1(layer),
+	regmap_update_bits(backend->engine.regs,
+			   SUN4I_BACKEND_ATTCTL_REG1(layer),
 			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
 
 	return 0;
@@ -232,13 +233,14 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 	/* Write the 32 lower bits of the address (in bits) */
 	lo_paddr = paddr << 3;
 	DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
-	regmap_write(backend->regs, SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
+	regmap_write(backend->engine.regs,
+		     SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
 		     lo_paddr);
 
 	/* And the upper bits */
 	hi_paddr = paddr >> 29;
 	DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr);
-	regmap_update_bits(backend->regs, SUN4I_BACKEND_LAYFB_H4ADD_REG,
+	regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_LAYFB_H4ADD_REG,
 			   SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
 			   SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr));
 
@@ -330,6 +332,13 @@ static int sun4i_backend_of_get_id(struct device_node *node)
 	return ret;
 }
 
+static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
+	.commit				= sun4i_backend_commit,
+	.layers_init			= sun4i_layers_init,
+	.apply_color_correction		= sun4i_backend_apply_color_correction,
+	.disable_color_correction	= sun4i_backend_disable_color_correction,
+};
+
 static struct regmap_config sun4i_backend_regmap_config = {
 	.reg_bits	= 32,
 	.val_bits	= 32,
@@ -353,7 +362,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 		return -ENOMEM;
 	dev_set_drvdata(dev, backend);
 
-	backend->node = dev->of_node;
+	backend->engine.node = dev->of_node;
+	backend->engine.ops = &sun4i_backend_engine_ops;
 	backend->id = sun4i_backend_of_get_id(dev->of_node);
 	if (backend->id < 0)
 		return backend->id;
@@ -363,11 +373,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 	if (IS_ERR(regs))
 		return PTR_ERR(regs);
 
-	backend->regs = devm_regmap_init_mmio(dev, regs,
-					      &sun4i_backend_regmap_config);
-	if (IS_ERR(backend->regs)) {
+	backend->engine.regs = devm_regmap_init_mmio(dev, regs,
+						     &sun4i_backend_regmap_config);
+	if (IS_ERR(backend->engine.regs)) {
 		dev_err(dev, "Couldn't create the backend regmap\n");
-		return PTR_ERR(backend->regs);
+		return PTR_ERR(backend->engine.regs);
 	}
 
 	backend->reset = devm_reset_control_get(dev, NULL);
@@ -415,18 +425,18 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
 		}
 	}
 
-	list_add_tail(&backend->list, &drv->backend_list);
+	list_add_tail(&backend->engine.list, &drv->engine_list);
 
 	/* Reset the registers */
 	for (i = 0x800; i < 0x1000; i += 4)
-		regmap_write(backend->regs, i, 0);
+		regmap_write(backend->engine.regs, i, 0);
 
 	/* Disable registers autoloading */
-	regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
+	regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG,
 		     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
 
 	/* Enable the backend */
-	regmap_write(backend->regs, SUN4I_BACKEND_MODCTL_REG,
+	regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
 		     SUN4I_BACKEND_MODCTL_DEBE_EN |
 		     SUN4I_BACKEND_MODCTL_START_CTL);
 
@@ -448,7 +458,7 @@ static void sun4i_backend_unbind(struct device *dev, struct device *master,
 {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 
-	list_del(&backend->list);
+	list_del(&backend->engine.list);
 
 	if (of_device_is_compatible(dev->of_node,
 				    "allwinner,sun8i-a33-display-backend"))
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
index 6327a2985fe6..b022a37e8e5b 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -19,6 +19,8 @@
 #include <linux/regmap.h>
 #include <linux/reset.h>
 
+#include "sunxi_engine.h"
+
 #define SUN4I_BACKEND_MODCTL_REG		0x800
 #define SUN4I_BACKEND_MODCTL_LINE_SEL			BIT(29)
 #define SUN4I_BACKEND_MODCTL_ITLMOD_EN			BIT(28)
@@ -141,8 +143,7 @@
 #define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
 
 struct sun4i_backend {
-	struct device_node	*node;
-	struct regmap		*regs;
+	struct sunxi_engine	engine;
 
 	struct reset_control	*reset;
 
@@ -154,15 +155,13 @@ struct sun4i_backend {
 	struct reset_control	*sat_reset;
 
 	int			id;
-
-	/* Backend list management */
-	struct list_head	list;
 };
 
-void sun4i_backend_apply_color_correction(struct sun4i_backend *backend);
-void sun4i_backend_disable_color_correction(struct sun4i_backend *backend);
-
-void sun4i_backend_commit(struct sun4i_backend *backend);
+static inline struct sun4i_backend *
+engine_to_sun4i_backend(struct sunxi_engine *engine)
+{
+	return container_of(engine, struct sun4i_backend, engine);
+}
 
 void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 				int layer, bool enable);
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index 708b3543d4e9..f8c70439d1e2 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -25,10 +25,9 @@
 
 #include <video/videomode.h>
 
-#include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
-#include "sun4i_layer.h"
+#include "sunxi_engine.h"
 #include "sun4i_tcon.h"
 
 static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
@@ -56,7 +55,7 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
 
 	DRM_DEBUG_DRIVER("Committing plane changes\n");
 
-	sun4i_backend_commit(scrtc->backend);
+	sunxi_engine_commit(scrtc->engine);
 
 	if (event) {
 		crtc->state->event = NULL;
@@ -135,7 +134,7 @@ static const struct drm_crtc_funcs sun4i_crtc_funcs = {
 };
 
 struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
-				   struct sun4i_backend *backend,
+				   struct sunxi_engine *engine,
 				   struct sun4i_tcon *tcon)
 {
 	struct sun4i_crtc *scrtc;
@@ -146,11 +145,11 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
 	scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
 	if (!scrtc)
 		return ERR_PTR(-ENOMEM);
-	scrtc->backend = backend;
+	scrtc->engine = engine;
 	scrtc->tcon = tcon;
 
 	/* Create our layers */
-	planes = sun4i_layers_init(drm, scrtc);
+	planes = sunxi_engine_layers_init(drm, engine);
 	if (IS_ERR(planes)) {
 		dev_err(drm->dev, "Couldn't create the planes\n");
 		return NULL;
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h b/drivers/gpu/drm/sun4i/sun4i_crtc.h
index 4dae3508424a..bf0ce36eb518 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.h
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h
@@ -17,7 +17,7 @@ struct sun4i_crtc {
 	struct drm_crtc			crtc;
 	struct drm_pending_vblank_event	*event;
 
-	struct sun4i_backend		*backend;
+	struct sunxi_engine		*engine;
 	struct sun4i_tcon		*tcon;
 };
 
@@ -27,7 +27,7 @@ static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
 }
 
 struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
-				   struct sun4i_backend *backend,
+				   struct sunxi_engine *engine,
 				   struct sun4i_tcon *tcon);
 
 #endif /* _SUN4I_CRTC_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 89c51fd6e9af..12ede8682b5c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -101,7 +101,7 @@ static int sun4i_drv_bind(struct device *dev)
 		goto free_drm;
 	}
 	drm->dev_private = drv;
-	INIT_LIST_HEAD(&drv->backend_list);
+	INIT_LIST_HEAD(&drv->engine_list);
 	INIT_LIST_HEAD(&drv->tcon_list);
 
 	ret = of_reserved_mem_device_init(dev);
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
index 250c29017ef5..a960c89270cc 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -18,7 +18,7 @@
 #include <linux/regmap.h>
 
 struct sun4i_drv {
-	struct list_head	backend_list;
+	struct list_head	engine_list;
 	struct list_head	tcon_list;
 
 	struct drm_fbdev_cma	*fbdev;
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
index e1f03e1cc0ac..ab33e4d06782 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -11,12 +11,10 @@
  */
 
 #include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drmP.h>
 
 #include "sun4i_backend.h"
-#include "sun4i_crtc.h"
 #include "sun4i_layer.h"
 
 struct sun4i_plane_desc {
@@ -130,10 +128,10 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
 }
 
 struct drm_plane **sun4i_layers_init(struct drm_device *drm,
-				     struct sun4i_crtc *crtc)
+				     struct sunxi_engine *engine)
 {
 	struct drm_plane **planes;
-	struct sun4i_backend *backend = crtc->backend;
+	struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
 	int i;
 
 	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
@@ -175,7 +173,7 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
 
 		DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
 				 i ? "overlay" : "primary", plane->pipe);
-		regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
+		regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
 				   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
 				   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
index 5ea5c994d6ea..004b7cfe8ffb 100644
--- a/drivers/gpu/drm/sun4i/sun4i_layer.h
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -13,6 +13,8 @@
 #ifndef _SUN4I_LAYER_H_
 #define _SUN4I_LAYER_H_
 
+struct sunxi_engine;
+
 struct sun4i_layer {
 	struct drm_plane	plane;
 	struct sun4i_drv	*drv;
@@ -27,6 +29,5 @@ plane_to_sun4i_layer(struct drm_plane *plane)
 }
 
 struct drm_plane **sun4i_layers_init(struct drm_device *drm,
-				     struct sun4i_crtc *crtc);
-
+				     struct sunxi_engine *engine);
 #endif /* _SUN4I_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 29fd829aa54c..c48135a10fda 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -26,12 +26,12 @@
 #include <linux/regmap.h>
 #include <linux/reset.h>
 
-#include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_dotclock.h"
 #include "sun4i_drv.h"
 #include "sun4i_rgb.h"
 #include "sun4i_tcon.h"
+#include "sunxi_engine.h"
 
 void sun4i_tcon_disable(struct sun4i_tcon *tcon)
 {
@@ -488,12 +488,16 @@ struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node)
  * means maintaining a large list of them. Or, since the backend is
  * registered and binded before the TCON, we can just go through the
  * list of registered backends and compare the device node.
+ *
+ * As the structures now store engines instead of backends, here this
+ * function in fact searches the corresponding engine, and the ID is
+ * requested via the get_id function of the engine.
  */
-static struct sun4i_backend *sun4i_tcon_find_backend(struct sun4i_drv *drv,
+static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
 						     struct device_node *node)
 {
 	struct device_node *port, *ep, *remote;
-	struct sun4i_backend *backend;
+	struct sunxi_engine *engine;
 
 	port = of_graph_get_port_by_id(node, 0);
 	if (!port)
@@ -504,21 +508,21 @@ static struct sun4i_backend *sun4i_tcon_find_backend(struct sun4i_drv *drv,
 		if (!remote)
 			continue;
 
-		/* does this node match any registered backends? */
-		list_for_each_entry(backend, &drv->backend_list, list) {
-			if (remote == backend->node) {
+		/* does this node match any registered engines? */
+		list_for_each_entry(engine, &drv->engine_list, list) {
+			if (remote == engine->node) {
 				of_node_put(remote);
 				of_node_put(port);
-				return backend;
+				return engine;
 			}
 		}
 
 		/* keep looking through upstream ports */
-		backend = sun4i_tcon_find_backend(drv, remote);
-		if (!IS_ERR(backend)) {
+		engine = sun4i_tcon_find_engine(drv, remote);
+		if (!IS_ERR(engine)) {
 			of_node_put(remote);
 			of_node_put(port);
-			return backend;
+			return engine;
 		}
 	}
 
@@ -530,13 +534,13 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
 {
 	struct drm_device *drm = data;
 	struct sun4i_drv *drv = drm->dev_private;
-	struct sun4i_backend *backend;
+	struct sunxi_engine *engine;
 	struct sun4i_tcon *tcon;
 	int ret;
 
-	backend = sun4i_tcon_find_backend(drv, dev->of_node);
-	if (IS_ERR(backend)) {
-		dev_err(dev, "Couldn't find matching backend\n");
+	engine = sun4i_tcon_find_engine(drv, dev->of_node);
+	if (IS_ERR(engine)) {
+		dev_err(dev, "Couldn't find matching engine\n");
 		return -EPROBE_DEFER;
 	}
 
@@ -546,7 +550,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
 	dev_set_drvdata(dev, tcon);
 	tcon->drm = drm;
 	tcon->dev = dev;
-	tcon->id = backend->id;
+	tcon->id = sunxi_engine_get_id(engine);
 	tcon->quirks = of_device_get_match_data(dev);
 
 	tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
@@ -589,7 +593,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
 		goto err_free_dotclock;
 	}
 
-	tcon->crtc = sun4i_crtc_init(drm, backend, tcon);
+	tcon->crtc = sun4i_crtc_init(drm, engine, tcon);
 	if (IS_ERR(tcon->crtc)) {
 		dev_err(dev, "Couldn't create our CRTC\n");
 		ret = PTR_ERR(tcon->crtc);
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 542da220818b..a9cad00d4ee8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -22,10 +22,10 @@
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 
-#include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
 #include "sun4i_tcon.h"
+#include "sunxi_engine.h"
 
 #define SUN4I_TVE_EN_REG		0x000
 #define SUN4I_TVE_EN_DAC_MAP_MASK		GENMASK(19, 4)
@@ -353,7 +353,6 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
 	struct sun4i_tcon *tcon = crtc->tcon;
-	struct sun4i_backend *backend = crtc->backend;
 
 	DRM_DEBUG_DRIVER("Disabling the TV Output\n");
 
@@ -362,7 +361,8 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
 			   SUN4I_TVE_EN_ENABLE,
 			   0);
-	sun4i_backend_disable_color_correction(backend);
+
+	sunxi_engine_disable_color_correction(crtc->engine);
 }
 
 static void sun4i_tv_enable(struct drm_encoder *encoder)
@@ -370,11 +370,10 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
 	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
 	struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
 	struct sun4i_tcon *tcon = crtc->tcon;
-	struct sun4i_backend *backend = crtc->backend;
 
 	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
 
-	sun4i_backend_apply_color_correction(backend);
+	sunxi_engine_apply_color_correction(crtc->engine);
 
 	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
 			   SUN4I_TVE_EN_ENABLE,
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
new file mode 100644
index 000000000000..b3c6e6148568
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * 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.
+ */
+
+#ifndef _SUNXI_ENGINE_H_
+#define _SUNXI_ENGINE_H_
+
+struct sun4i_crtc;
+struct drm_plane;
+struct drm_device;
+
+struct sunxi_engine;
+
+struct sunxi_engine_ops {
+	void (*commit)(struct sunxi_engine *engine);
+	struct drm_plane **(*layers_init)(struct drm_device *drm,
+					  struct sunxi_engine *engine);
+
+	void (*apply_color_correction)(struct sunxi_engine *engine);
+	void (*disable_color_correction)(struct sunxi_engine *engine);
+	int (*get_id)(struct sunxi_engine *engine);
+};
+
+/**
+ * struct sunxi_engine - the common parts of an engine for sun4i-drm driver
+ * @ops:	the operations of the engine
+ * @regs:	the regmap of the engine
+ */
+struct sunxi_engine {
+	const struct sunxi_engine_ops	*ops;
+
+	struct device_node		*node;
+	struct regmap			*regs;
+
+	/* Engine list management */
+	struct list_head		list;
+};
+
+/**
+ * sunxi_engine_commit() - commit all changes of the engine
+ * @engine:	pointer to the engine
+ */
+static inline void
+sunxi_engine_commit(struct sunxi_engine *engine)
+{
+	if (engine->ops && engine->ops->commit)
+		engine->ops->commit(engine);
+}
+
+/**
+ * sunxi_engine_layers_init() - Create planes (layers) for the engine
+ * @drm:	pointer to the drm_device for which planes will be created
+ * @engine:	pointer to the engine
+ */
+static inline struct drm_plane **
+sunxi_engine_layers_init(struct drm_device *drm, struct sunxi_engine *engine)
+{
+	if (engine->ops && engine->ops->layers_init)
+		return engine->ops->layers_init(drm, engine);
+	return ERR_PTR(-ENOSYS);
+}
+
+/**
+ * sunxi_engine_apply_color_correction - Apply the RGB2YUV color correction
+ * @engine:	pointer to the engine
+ *
+ * This functionality is optional for an engine, however, if the engine is
+ * intended to be used with TV Encoder, the output will be incorrect
+ * without the color correction, due to TV Encoder expects the engine to
+ * output directly YUV signal.
+ */
+static inline void
+sunxi_engine_apply_color_correction(struct sunxi_engine *engine)
+{
+	if (engine->ops && engine->ops->apply_color_correction)
+		engine->ops->apply_color_correction(engine);
+}
+
+/**
+ * sunxi_engine_disable_color_correction - Disable the color space correction
+ * @engine:	pointer to the engine
+ *
+ * This function is paired with apply_color_correction().
+ */
+static inline void
+sunxi_engine_disable_color_correction(struct sunxi_engine *engine)
+{
+	if (engine->ops && engine->ops->disable_color_correction)
+		engine->ops->disable_color_correction(engine);
+}
+
+/**
+ * sunxi_engine_get_id - Get the ID of the engine.
+ * @engine:	pointer to the engine
+ *
+ * If the ID is not necessary, just do not implement it in sunxi_engine_ops,
+ * and a default -1 will be returned.
+ */
+static inline int
+sunxi_engine_get_id(struct sunxi_engine *engine)
+{
+	if (engine->ops && engine->ops->get_id)
+		return engine->ops->get_id(engine);
+
+	return -1;
+}
+#endif /* _SUNXI_ENGINE_H_ */
-- 
2.12.2

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

* [PATCH v6 06/13] drm/sun4i: add a dedicated module for sun4i-backend and sun4i-layer
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (4 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 05/13] drm/sun4i: abstract a engine type Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-05  3:10   ` [linux-sunxi] " Chen-Yu Tsai
  2017-05-04 11:48 ` [PATCH v6 07/13] drm/sun4i: add a Kconfig option for sun4i-backend Icenowy Zheng
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

Currently the direct call from CRTC code to layer code has disappeared,
instead the layer's init function is called via the backend's ops.

Add a dedicated module for sun4i-backend and sun4i-layer, and drop the
EXPORT_SYMBOL from backend code to layer code.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
Splited out patch.

 drivers/gpu/drm/sun4i/Makefile        | 5 +++--
 drivers/gpu/drm/sun4i/sun4i_backend.c | 4 ----
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 59b757350a1f..a251fb36c951 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -5,9 +5,10 @@ sun4i-tcon-y += sun4i_tcon.o
 sun4i-tcon-y += sun4i_rgb.o
 sun4i-tcon-y += sun4i_dotclock.o
 sun4i-tcon-y += sun4i_crtc.o
-sun4i-tcon-y += sun4i_layer.o
+
+sun4i-backend-y += sun4i_backend.o sun4i_layer.o
 
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
-obj-$(CONFIG_DRM_SUN4I)		+= sun4i_backend.o
+obj-$(CONFIG_DRM_SUN4I)		+= sun4i-backend.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 611cdcb9c182..fac1a414ba49 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -83,7 +83,6 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
 	regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
 			   SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
 }
-EXPORT_SYMBOL(sun4i_backend_layer_enable);
 
 static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane,
 					     u32 format, u32 *mode)
@@ -170,7 +169,6 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
 
 	return 0;
 }
-EXPORT_SYMBOL(sun4i_backend_update_layer_coord);
 
 int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 				       int layer, struct drm_plane *plane)
@@ -205,7 +203,6 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
 
 	return 0;
 }
-EXPORT_SYMBOL(sun4i_backend_update_layer_formats);
 
 int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 				      int layer, struct drm_plane *plane)
@@ -246,7 +243,6 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
 
 	return 0;
 }
-EXPORT_SYMBOL(sun4i_backend_update_layer_buffer);
 
 static int sun4i_backend_init_sat(struct device *dev) {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
-- 
2.12.2

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

* [PATCH v6 07/13] drm/sun4i: add a Kconfig option for sun4i-backend
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (5 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 06/13] drm/sun4i: add a dedicated module for sun4i-backend and sun4i-layer Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-05  3:14   ` [linux-sunxi] " Chen-Yu Tsai
  2017-05-04 11:48 ` [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers Icenowy Zheng
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

As sun4i-backend is now a dedicated module, add an Kconfig option for
it to make it optional, since some build may only use other engines.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
Splited out patch.

 drivers/gpu/drm/sun4i/Kconfig  | 10 ++++++++++
 drivers/gpu/drm/sun4i/Makefile |  2 +-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index a4b357db8856..5a8227f37cc4 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -12,3 +12,13 @@ config DRM_SUN4I
 	  Choose this option if you have an Allwinner SoC with a
 	  Display Engine. If M is selected the module will be called
 	  sun4i-drm.
+
+config DRM_SUN4I_BACKEND
+	tristate "Support for Allwinner A10 Display Engine Backend"
+	depends on DRM_SUN4I
+	default DRM_SUN4I
+	help
+	  Choose this option if you have an Allwinner SoC with the
+	  original Allwinner Display Engine, which has a backend to
+	  do some alpha blending and feed graphics to TCON. If M is
+	  selected the module will be called sun4i-backend.
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index a251fb36c951..a08df56759e3 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -9,6 +9,6 @@ sun4i-tcon-y += sun4i_crtc.o
 sun4i-backend-y += sun4i_backend.o sun4i_layer.o
 
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
-obj-$(CONFIG_DRM_SUN4I)		+= sun4i-backend.o
+obj-$(CONFIG_DRM_SUN4I_BACKEND)		+= sun4i-backend.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
-- 
2.12.2

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

* [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (6 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 07/13] drm/sun4i: add a Kconfig option for sun4i-backend Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-04 13:05   ` Maxime Ripard
  2017-05-04 11:48 ` [PATCH v6 09/13] drm/sun4i: Add compatible string for V3s display engine Icenowy Zheng
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

Allwinner have a new "Display Engine 2.0" in their new SoCs, which comes
with mixers to do graphic processing and feed data to TCON, like the old
backends and frontends.

Add support for the mixer on Allwinner V3s SoC; it's the simplest one.

Currently a lot of functions are still missing -- more investigations
are needed to gain enough information for them.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
Changes in v6:
- Rebased on wens's multi-pipeline patchset.
Changes in v5:
- Changed some code alignment.
- Request real 32-bit DMA (prepare for 64-bit SoCs).
Changes in v4:
- Killed some dead code according to Jernej.

 drivers/gpu/drm/sun4i/Kconfig       |  10 +
 drivers/gpu/drm/sun4i/Makefile      |   3 +
 drivers/gpu/drm/sun4i/sun8i_layer.c | 140 +++++++++++++
 drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 394 ++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 137 +++++++++++++
 6 files changed, 720 insertions(+)
 create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
 create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
 create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
 create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h

diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index 5a8227f37cc4..15557484520d 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
 	  original Allwinner Display Engine, which has a backend to
 	  do some alpha blending and feed graphics to TCON. If M is
 	  selected the module will be called sun4i-backend.
+
+config DRM_SUN4I_SUN8I_MIXER
+	tristate "Support for Allwinner Display Engine 2.0 Mixer"
+	depends on DRM_SUN4I
+	default MACH_SUN8I
+	help
+	  Choose this option if you have an Allwinner SoC with the
+	  Allwinner Display Engine 2.0, which has a mixer to do some
+	  graphics mixture and feed graphics to TCON, If M is
+	  selected the module will be called sun8i-mixer.
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index a08df56759e3..a876c6b3027c 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -8,7 +8,10 @@ sun4i-tcon-y += sun4i_crtc.o
 
 sun4i-backend-y += sun4i_backend.o sun4i_layer.o
 
+sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o
+
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
 obj-$(CONFIG_DRM_SUN4I_BACKEND)		+= sun4i-backend.o
+obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER)	+= sun8i-mixer.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c b/drivers/gpu/drm/sun4i/sun8i_layer.c
new file mode 100644
index 000000000000..48f33d8e013b
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on sun4i_layer.h, which is:
+ *   Copyright (C) 2015 Free Electrons
+ *   Copyright (C) 2015 NextThing Co
+ *
+ *   Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * 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.
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drmP.h>
+
+#include "sun8i_layer.h"
+#include "sun8i_mixer.h"
+
+struct sun8i_plane_desc {
+	       enum drm_plane_type     type;
+	       const uint32_t          *formats;
+	       uint32_t                nformats;
+};
+
+static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
+					    struct drm_plane_state *state)
+{
+	return 0;
+}
+
+static void sun8i_mixer_layer_atomic_disable(struct drm_plane *plane,
+					       struct drm_plane_state *old_state)
+{
+	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
+	struct sun8i_mixer *mixer = layer->mixer;
+
+	sun8i_mixer_layer_enable(mixer, layer->id, false);
+}
+
+static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
+					      struct drm_plane_state *old_state)
+{
+	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
+	struct sun8i_mixer *mixer = layer->mixer;
+
+	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
+	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
+	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
+	sun8i_mixer_layer_enable(mixer, layer->id, true);
+}
+
+static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs = {
+	.atomic_check	= sun8i_mixer_layer_atomic_check,
+	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
+	.atomic_update	= sun8i_mixer_layer_atomic_update,
+};
+
+static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
+	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
+	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
+	.destroy		= drm_plane_cleanup,
+	.disable_plane		= drm_atomic_helper_disable_plane,
+	.reset			= drm_atomic_helper_plane_reset,
+	.update_plane		= drm_atomic_helper_update_plane,
+};
+
+static const uint32_t sun8i_mixer_layer_formats[] = {
+	DRM_FORMAT_RGB888,
+	DRM_FORMAT_XRGB8888,
+};
+
+static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
+	{
+		.type = DRM_PLANE_TYPE_PRIMARY,
+		.formats = sun8i_mixer_layer_formats,
+		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
+	},
+};
+
+static struct sun8i_layer *sun8i_layer_init_one(struct drm_device *drm,
+						struct sun8i_mixer *mixer,
+						const struct sun8i_plane_desc *plane)
+{
+	struct sun8i_layer *layer;
+	int ret;
+
+	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
+	if (!layer)
+		return ERR_PTR(-ENOMEM);
+
+	/* possible crtcs are set later */
+	ret = drm_universal_plane_init(drm, &layer->plane, 0,
+				       &sun8i_mixer_layer_funcs,
+				       plane->formats, plane->nformats,
+				       plane->type, NULL);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't initialize layer\n");
+		return ERR_PTR(ret);
+	}
+
+	drm_plane_helper_add(&layer->plane,
+			     &sun8i_mixer_layer_helper_funcs);
+	layer->mixer = mixer;
+
+	return layer;
+}
+
+struct drm_plane **sun8i_layers_init(struct drm_device *drm,
+				     struct sunxi_engine *engine)
+{
+	struct drm_plane **planes;
+	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+	int i;
+
+	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
+			      sizeof(*planes), GFP_KERNEL);
+	if (!planes)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
+		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
+		struct sun8i_layer *layer;
+
+		layer = sun8i_layer_init_one(drm, mixer, plane);
+		if (IS_ERR(layer)) {
+			dev_err(drm->dev, "Couldn't initialize %s plane\n",
+				i ? "overlay" : "primary");
+			return ERR_CAST(layer);
+		};
+
+		layer->id = i;
+		planes[i] = &layer->plane;
+	};
+
+	return planes;
+}
diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h b/drivers/gpu/drm/sun4i/sun8i_layer.h
new file mode 100644
index 000000000000..e5eccd27cff0
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on sun4i_layer.h, which is:
+ *   Copyright (C) 2015 Free Electrons
+ *   Copyright (C) 2015 NextThing Co
+ *
+ *   Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * 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.
+ */
+
+#ifndef _SUN8I_LAYER_H_
+#define _SUN8I_LAYER_H_
+
+struct sunxi_engine;
+
+struct sun8i_layer {
+	struct drm_plane	plane;
+	struct sun4i_drv	*drv;
+	struct sun8i_mixer	*mixer;
+	int			id;
+};
+
+static inline struct sun8i_layer *
+plane_to_sun8i_layer(struct drm_plane *plane)
+{
+	return container_of(plane, struct sun8i_layer, plane);
+}
+
+struct drm_plane **sun8i_layers_init(struct drm_device *drm,
+				     struct sunxi_engine *engine);
+#endif /* _SUN8I_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
new file mode 100644
index 000000000000..e216b84d5bb2
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * Based on sun4i_backend.c, which is:
+ *   Copyright (C) 2015 Free Electrons
+ *   Copyright (C) 2015 NextThing Co
+ *
+ * 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.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_plane_helper.h>
+
+#include <linux/component.h>
+#include <linux/dma-mapping.h>
+#include <linux/reset.h>
+#include <linux/of_device.h>
+
+#include "sun4i_drv.h"
+#include "sun8i_mixer.h"
+#include "sun8i_layer.h"
+#include "sunxi_engine.h"
+
+void sun8i_mixer_commit(struct sunxi_engine *engine)
+{
+	DRM_DEBUG_DRIVER("Committing changes\n");
+
+	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
+		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+}
+
+void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
+				int layer, bool enable)
+{
+	u32 val;
+	/* Currently the first UI channel is used */
+	int chan = mixer->cfg->vi_num;
+
+	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
+
+	if (enable)
+		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
+	else
+		val = 0;
+
+	regmap_update_bits(mixer->engine.regs,
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
+
+	/* Set the alpha configuration */
+	regmap_update_bits(mixer->engine.regs,
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
+	regmap_update_bits(mixer->engine.regs,
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
+}
+
+static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
+					     u32 format, u32 *mode)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
+		break;
+
+	case DRM_FORMAT_RGB888:
+		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
+				     int layer, struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	/* Currently the first UI channel is used */
+	int chan = mixer->cfg->vi_num;
+
+	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
+
+	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
+		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
+				 state->crtc_w, state->crtc_h);
+		regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE,
+			     SUN8I_MIXER_SIZE(state->crtc_w,
+					      state->crtc_h));
+		DRM_DEBUG_DRIVER("Updating blender size\n");
+		regmap_write(mixer->engine.regs,
+			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
+			     SUN8I_MIXER_SIZE(state->crtc_w,
+					      state->crtc_h));
+		regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
+			     SUN8I_MIXER_SIZE(state->crtc_w,
+					      state->crtc_h));
+		DRM_DEBUG_DRIVER("Updating channel size\n");
+		regmap_write(mixer->engine.regs,
+			     SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
+			     SUN8I_MIXER_SIZE(state->crtc_w,
+					      state->crtc_h));
+	}
+
+	/* Set the line width */
+	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
+	regmap_write(mixer->engine.regs,
+		     SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
+		     fb->pitches[0]);
+
+	/* Set height and width */
+	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
+			 state->crtc_w, state->crtc_h);
+	regmap_write(mixer->engine.regs,
+		     SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
+		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
+
+	/* Set base coordinates */
+	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
+			 state->crtc_x, state->crtc_y);
+	regmap_write(mixer->engine.regs,
+		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
+		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
+
+	return 0;
+}
+
+int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
+				       int layer, struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	bool interlaced = false;
+	u32 val;
+	/* Currently the first UI channel is used */
+	int chan = mixer->cfg->vi_num;
+	int ret;
+
+	if (plane->state->crtc)
+		interlaced = plane->state->crtc->state->adjusted_mode.flags
+			& DRM_MODE_FLAG_INTERLACE;
+
+	regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTCTL,
+			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
+			   interlaced ?
+			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
+
+	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
+			 interlaced ? "on" : "off");
+
+	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
+						&val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid format\n");
+		return ret;
+	}
+
+	regmap_update_bits(mixer->engine.regs,
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
+			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
+
+	return 0;
+}
+
+int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
+				      int layer, struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	struct drm_gem_cma_object *gem;
+	dma_addr_t paddr;
+	/* Currently the first UI channel is used */
+	int chan = mixer->cfg->vi_num;
+	int bpp;
+
+	/* Get the physical address of the buffer in memory */
+	gem = drm_fb_cma_get_gem_obj(fb, 0);
+
+	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
+
+	/* Compute the start of the displayed memory */
+	bpp = fb->format->cpp[0];
+	paddr = gem->paddr + fb->offsets[0];
+	paddr += (state->src_x >> 16) * bpp;
+	paddr += (state->src_y >> 16) * fb->pitches[0];
+
+	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
+
+	regmap_write(mixer->engine.regs,
+		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
+		     lower_32_bits(paddr));
+
+	return 0;
+}
+
+static const struct sunxi_engine_ops sun8i_engine_ops = {
+	.commit		= sun8i_mixer_commit,
+	.layers_init	= sun8i_layers_init,
+};
+
+static struct regmap_config sun8i_mixer_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0xbfffc, /* guessed */
+};
+
+static int sun8i_mixer_bind(struct device *dev, struct device *master,
+			      void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun8i_mixer *mixer;
+	struct resource *res;
+	void __iomem *regs;
+	int i, ret;
+
+	/*
+	 * The mixer uses single 32-bit register to store memory
+	 * addresses, so that it cannot deal with 64-bit memory
+	 * addresses.
+	 * Restrict the DMA mask so that the mixer won't be
+	 * allocated some memory that is too high.
+	 */
+	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+	if (ret) {
+		dev_err(dev, "Cannot do 32-bit DMA.\n");
+		return ret;
+	}
+
+	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
+	if (!mixer)
+		return -ENOMEM;
+	dev_set_drvdata(dev, mixer);
+	mixer->engine.ops = &sun8i_engine_ops;
+	mixer->engine.node = dev->of_node;
+
+	mixer->cfg = of_device_get_match_data(dev);
+	if (!mixer->cfg)
+		return -EINVAL;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
+						   &sun8i_mixer_regmap_config);
+	if (IS_ERR(mixer->engine.regs)) {
+		dev_err(dev, "Couldn't create the mixer regmap\n");
+		return PTR_ERR(mixer->engine.regs);
+	}
+
+	mixer->reset = devm_reset_control_get(dev, NULL);
+	if (IS_ERR(mixer->reset)) {
+		dev_err(dev, "Couldn't get our reset line\n");
+		return PTR_ERR(mixer->reset);
+	}
+
+	ret = reset_control_deassert(mixer->reset);
+	if (ret) {
+		dev_err(dev, "Couldn't deassert our reset line\n");
+		return ret;
+	}
+
+	mixer->bus_clk = devm_clk_get(dev, "bus");
+	if (IS_ERR(mixer->bus_clk)) {
+		dev_err(dev, "Couldn't get the mixer bus clock\n");
+		ret = PTR_ERR(mixer->bus_clk);
+		goto err_assert_reset;
+	}
+	clk_prepare_enable(mixer->bus_clk);
+
+	mixer->mod_clk = devm_clk_get(dev, "mod");
+	if (IS_ERR(mixer->mod_clk)) {
+		dev_err(dev, "Couldn't get the mixer module clock\n");
+		ret = PTR_ERR(mixer->mod_clk);
+		goto err_disable_bus_clk;
+	}
+	clk_prepare_enable(mixer->mod_clk);
+
+	list_add_tail(&mixer->engine.list, &drv->engine_list);
+
+	/* Reset the registers */
+	for (i = 0x0; i < 0x20000; i += 4)
+		regmap_write(mixer->engine.regs, i, 0);
+
+	/* Enable the mixer */
+	regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
+		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
+
+	/* Initialize blender */
+	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
+		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
+	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
+		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
+	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
+		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
+	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(0),
+		     SUN8I_MIXER_BLEND_MODE_DEF);
+	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_CK_CTL,
+		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
+
+	regmap_write(mixer->engine.regs,
+		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
+		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
+
+	/* Select the first UI channel */
+	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
+			 mixer->cfg->vi_num);
+	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE,
+		     mixer->cfg->vi_num);
+
+	return 0;
+
+	clk_disable_unprepare(mixer->mod_clk);
+err_disable_bus_clk:
+	clk_disable_unprepare(mixer->bus_clk);
+err_assert_reset:
+	reset_control_assert(mixer->reset);
+	return ret;
+}
+
+static void sun8i_mixer_unbind(struct device *dev, struct device *master,
+				 void *data)
+{
+	struct sun8i_mixer *mixer = dev_get_drvdata(dev);
+
+	list_del(&mixer->engine.list);
+
+	clk_disable_unprepare(mixer->mod_clk);
+	clk_disable_unprepare(mixer->bus_clk);
+	reset_control_assert(mixer->reset);
+}
+
+static const struct component_ops sun8i_mixer_ops = {
+	.bind	= sun8i_mixer_bind,
+	.unbind	= sun8i_mixer_unbind,
+};
+
+static int sun8i_mixer_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun8i_mixer_ops);
+}
+
+static int sun8i_mixer_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun8i_mixer_ops);
+
+	return 0;
+}
+
+static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
+	.vi_num = 2,
+	.ui_num = 1,
+};
+
+static const struct of_device_id sun8i_mixer_of_table[] = {
+	{
+		.compatible = "allwinner,sun8i-v3s-de2-mixer",
+		.data = &sun8i_v3s_mixer_cfg,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
+
+static struct platform_driver sun8i_mixer_platform_driver = {
+	.probe		= sun8i_mixer_probe,
+	.remove		= sun8i_mixer_remove,
+	.driver		= {
+		.name		= "sun8i-mixer",
+		.of_match_table	= sun8i_mixer_of_table,
+	},
+};
+module_platform_driver(sun8i_mixer_platform_driver);
+
+MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
+MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
new file mode 100644
index 000000000000..4785ac090b8c
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
+ *
+ * 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.
+ */
+
+#ifndef _SUN8I_MIXER_H_
+#define _SUN8I_MIXER_H_
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include "sunxi_engine.h"
+
+#define SUN8I_MIXER_MAX_CHAN_COUNT		4
+
+#define SUN8I_MIXER_SIZE(w, h)			(((h) - 1) << 16 | ((w) - 1))
+#define SUN8I_MIXER_COORD(x, y)			((y) << 16 | (x))
+
+#define SUN8I_MIXER_GLOBAL_CTL			0x0
+#define SUN8I_MIXER_GLOBAL_STATUS		0x4
+#define SUN8I_MIXER_GLOBAL_DBUFF		0x8
+#define SUN8I_MIXER_GLOBAL_SIZE			0xc
+
+#define SUN8I_MIXER_GLOBAL_CTL_RT_EN		0x1
+
+#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE		0x1
+
+#define SUN8I_MIXER_BLEND_FCOLOR_CTL		0x1000
+#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(x)	(0x1004 + 0x10 * (x) + 0x0)
+#define SUN8I_MIXER_BLEND_ATTR_INSIZE(x)	(0x1004 + 0x10 * (x) + 0x4)
+#define SUN8I_MIXER_BLEND_ATTR_OFFSET(x)	(0x1004 + 0x10 * (x) + 0x8)
+#define SUN8I_MIXER_BLEND_ROUTE			0x1080
+#define SUN8I_MIXER_BLEND_PREMULTIPLY		0x1084
+#define SUN8I_MIXER_BLEND_BKCOLOR		0x1088
+#define SUN8I_MIXER_BLEND_OUTSIZE		0x108c
+#define SUN8I_MIXER_BLEND_MODE(x)		(0x1090 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_CK_CTL		0x10b0
+#define SUN8I_MIXER_BLEND_CK_CFG		0x10b4
+#define SUN8I_MIXER_BLEND_CK_MAX(x)		(0x10c0 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_CK_MIN(x)		(0x10e0 + 0x04 * (x))
+#define SUN8I_MIXER_BLEND_OUTCTL		0x10fc
+
+/* The following numbers are some still unknown magic numbers */
+#define SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF	0xff000000
+#define SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF	0x00000101
+#define SUN8I_MIXER_BLEND_PREMULTIPLY_DEF	0x0
+#define SUN8I_MIXER_BLEND_BKCOLOR_DEF		0xff000000
+#define SUN8I_MIXER_BLEND_MODE_DEF		0x03010301
+#define SUN8I_MIXER_BLEND_CK_CTL_DEF		0x0
+
+#define SUN8I_MIXER_BLEND_OUTCTL_INTERLACED	BIT(1)
+
+/*
+ * VI channels are not used now, but the support of them may be introduced in
+ * the future.
+ */
+
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch, layer) \
+			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x0)
+#define SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch, layer) \
+			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x4)
+#define SUN8I_MIXER_CHAN_UI_LAYER_COORD(ch, layer) \
+			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch, layer) \
+			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0xc)
+#define SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch, layer) \
+			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x10)
+#define SUN8I_MIXER_CHAN_UI_LAYER_BOT_LADDR(ch, layer) \
+			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x14)
+#define SUN8I_MIXER_CHAN_UI_LAYER_FCOLOR(ch, layer) \
+			(0x2000 + 0x1000 * (ch) + 0x20 * (layer) + 0x18)
+#define SUN8I_MIXER_CHAN_UI_TOP_HADDR(ch)	(0x2000 + 0x1000 * (ch) + 0x80)
+#define SUN8I_MIXER_CHAN_UI_BOT_HADDR(ch)	(0x2000 + 0x1000 * (ch) + 0x84)
+#define SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch)	(0x2000 + 0x1000 * (ch) + 0x88)
+
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN		BIT(0)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK	GENMASK(2, 1)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK	GENMASK(11, 8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK	GENMASK(31, 24)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF	(1 << 1)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_ARGB8888	(0 << 8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888	(4 << 8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888	(8 << 8)
+#define SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF	(0xff << 24)
+
+/*
+ * These sub-engines are still unknown now, the EN registers are here only to
+ * be used to disable these sub-engines.
+ */
+#define SUN8I_MIXER_VSU_EN			0x20000
+#define SUN8I_MIXER_GSU1_EN			0x30000
+#define SUN8I_MIXER_GSU2_EN			0x40000
+#define SUN8I_MIXER_GSU3_EN			0x50000
+#define SUN8I_MIXER_FCE_EN			0xa0000
+#define SUN8I_MIXER_BWS_EN			0xa2000
+#define SUN8I_MIXER_LTI_EN			0xa4000
+#define SUN8I_MIXER_PEAK_EN			0xa6000
+#define SUN8I_MIXER_ASE_EN			0xa8000
+#define SUN8I_MIXER_FCC_EN			0xaa000
+#define SUN8I_MIXER_DCSC_EN			0xb0000
+
+struct sun8i_mixer_cfg {
+	int		vi_num;
+	int		ui_num;
+};
+
+struct sun8i_mixer {
+	struct sunxi_engine		engine;
+
+	const struct sun8i_mixer_cfg	*cfg;
+
+	struct reset_control		*reset;
+
+	struct clk			*bus_clk;
+	struct clk			*mod_clk;
+};
+
+static inline struct sun8i_mixer *
+engine_to_sun8i_mixer(struct sunxi_engine *engine)
+{
+	return container_of(engine, struct sun8i_mixer, engine);
+}
+
+void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
+				int layer, bool enable);
+int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
+				     int layer, struct drm_plane *plane);
+int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
+				       int layer, struct drm_plane *plane);
+int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
+				      int layer, struct drm_plane *plane);
+#endif /* _SUN8I_MIXER_H_ */
-- 
2.12.2

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

* [PATCH v6 09/13] drm/sun4i: Add compatible string for V3s display engine
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (7 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-04 11:48 ` [PATCH v6 10/13] drm/sun4i: tcon: add support for V3s TCON Icenowy Zheng
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

Allwinner V3s features the new "Display Engine 2.0", which can now also
be driven with our subdrivers in sun4i-drm.

Add the compatible string for in sun4i_drv.c, in order to make the
display engine and its components probed.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 drivers/gpu/drm/sun4i/sun4i_drv.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 12ede8682b5c..dcfb241f817d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -306,6 +306,7 @@ static const struct of_device_id sun4i_drv_of_table[] = {
 	{ .compatible = "allwinner,sun6i-a31-display-engine" },
 	{ .compatible = "allwinner,sun6i-a31s-display-engine" },
 	{ .compatible = "allwinner,sun8i-a33-display-engine" },
+	{ .compatible = "allwinner,sun8i-v3s-display-engine" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);
-- 
2.12.2

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

* [PATCH v6 10/13] drm/sun4i: tcon: add support for V3s TCON
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (8 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 09/13] drm/sun4i: Add compatible string for V3s display engine Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-05  3:33   ` [linux-sunxi] " Chen-Yu Tsai
  2017-05-04 11:48 ` [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC Icenowy Zheng
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

Allwinner V3s SoC features a TCON without channel 1.

Add support for it.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 drivers/gpu/drm/sun4i/sun4i_drv.c  | 3 ++-
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 5 +++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index dcfb241f817d..367e4e8e9656 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -188,7 +188,8 @@ static bool sun4i_drv_node_is_tcon(struct device_node *node)
 	return of_device_is_compatible(node, "allwinner,sun5i-a13-tcon") ||
 		of_device_is_compatible(node, "allwinner,sun6i-a31-tcon") ||
 		of_device_is_compatible(node, "allwinner,sun6i-a31s-tcon") ||
-		of_device_is_compatible(node, "allwinner,sun8i-a33-tcon");
+		of_device_is_compatible(node, "allwinner,sun8i-a33-tcon") ||
+		of_device_is_compatible(node, "allwinner,sun8i-v3s-tcon");
 }
 
 static int compare_of(struct device *dev, void *data)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index c48135a10fda..e76acf06e91b 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -681,11 +681,16 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
 	/* nothing is supported */
 };
 
+static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
+	/* nothing is supported */
+};
+
 static const struct of_device_id sun4i_tcon_of_table[] = {
 	{ .compatible = "allwinner,sun5i-a13-tcon", .data = &sun5i_a13_quirks },
 	{ .compatible = "allwinner,sun6i-a31-tcon", .data = &sun6i_a31_quirks },
 	{ .compatible = "allwinner,sun6i-a31s-tcon", .data = &sun6i_a31s_quirks },
 	{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
+	{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
-- 
2.12.2

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

* [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (9 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 10/13] drm/sun4i: tcon: add support for V3s TCON Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-05  3:31   ` [linux-sunxi] " Chen-Yu Tsai
  2017-05-04 11:48 ` [PATCH v6 12/13] ARM: dts: sun8i: add pinmux for LCD pins of " Icenowy Zheng
  2017-05-04 11:48 ` [PATCH v6 13/13] [DO NOT MERGE] ARM: dts: sun8i: enable LCD panel of Lichee Pi Zero Icenowy Zheng
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

Allwinner V3s SoC features a "Display Engine 2.0" with only one TCON
which have RGB LCD output.

Add device nodes for it as well as the TCON.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/boot/dts/sun8i-v3s.dtsi | 87 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi
index 71075969e5e6..0a895179d8ae 100644
--- a/arch/arm/boot/dts/sun8i-v3s.dtsi
+++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
@@ -41,6 +41,10 @@
  */
 
 #include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/sun8i-v3s-ccu.h>
+#include <dt-bindings/clock/sun8i-de2.h>
+#include <dt-bindings/reset/sun8i-v3s-ccu.h>
+#include <dt-bindings/reset/sun8i-de2.h>
 
 / {
 	#address-cells = <1>;
@@ -59,6 +63,12 @@
 		};
 	};
 
+	de: display-engine {
+		compatible = "allwinner,sun8i-v3s-display-engine";
+		allwinner,pipelines = <&de2_mixer0>;
+		status = "disabled";
+	};
+
 	timer {
 		compatible = "arm,armv7-timer";
 		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -93,6 +103,83 @@
 		#size-cells = <1>;
 		ranges;
 
+		de2_clocks: clock@1000000 {
+			compatible = "allwinner,sun50i-h5-de2-clk";
+			reg = <0x01000000 0x100000>;
+			clocks = <&ccu CLK_DE>,
+				 <&ccu CLK_BUS_DE>;
+			clock-names = "mod",
+				      "bus";
+			resets = <&ccu RST_BUS_DE>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+		};
+
+		de2_mixer0: mixer@1100000 {
+			compatible = "allwinner,sun8i-v3s-de2-mixer";
+			reg = <0x01100000 0x100000>;
+			clocks = <&de2_clocks CLK_MIXER0>,
+				 <&de2_clocks CLK_BUS_MIXER0>;
+			clock-names = "mod",
+				      "bus";
+			resets = <&de2_clocks RST_MIXER0>;
+			assigned-clocks = <&de2_clocks CLK_MIXER0>;
+			assigned-clock-rates = <150000000>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				mixer0_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					mixer0_out_tcon0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon0_in_mixer0>;
+					};
+				};
+			};
+		};
+
+		tcon0: lcd-controller@1c0c000 {
+			compatible = "allwinner,sun8i-v3s-tcon";
+			reg = <0x01c0c000 0x1000>;
+			interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&ccu CLK_BUS_TCON0>,
+				 <&ccu CLK_TCON0>;
+			clock-names = "ahb",
+				      "tcon-ch0";
+			clock-output-names = "tcon-pixel-clock";
+			resets = <&ccu RST_BUS_TCON0>;
+			reset-names = "lcd";
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tcon0_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					tcon0_in_mixer0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&mixer0_out_tcon0>;
+					};
+				};
+
+				tcon0_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+				};
+			};
+		};
+
+
 		mmc0: mmc@01c0f000 {
 			compatible = "allwinner,sun7i-a20-mmc";
 			reg = <0x01c0f000 0x1000>;
-- 
2.12.2

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

* [PATCH v6 12/13] ARM: dts: sun8i: add pinmux for LCD pins of V3s SoC
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (10 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  2017-05-05  3:25   ` [linux-sunxi] " Chen-Yu Tsai
  2017-05-04 11:48 ` [PATCH v6 13/13] [DO NOT MERGE] ARM: dts: sun8i: enable LCD panel of Lichee Pi Zero Icenowy Zheng
  12 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

Allwinner V3s SoC features a set of pins that have functionality of RGB
LCD, the pins are at different pin ban than other SoCs.

Add pinctrl node for them.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/boot/dts/sun8i-v3s.dtsi | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi
index 0a895179d8ae..a37d68b227bc 100644
--- a/arch/arm/boot/dts/sun8i-v3s.dtsi
+++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
@@ -297,6 +297,15 @@
 				function = "i2c0";
 			};
 
+			lcd_rgb666_pins: lcd_rgb666@0 {
+				pins = "PE0", "PE1", "PE2", "PE3", "PE4",
+				       "PE5", "PE6", "PE7", "PE8", "PE9",
+				       "PE10", "PE11", "PE12", "PE13", "PE14",
+				       "PE15", "PE16", "PE17", "PE18", "PE19",
+				       "PE23", "PE24";
+				function = "lcd";
+			};
+
 			uart0_pins_a: uart0@0 {
 				pins = "PB8", "PB9";
 				function = "uart0";
-- 
2.12.2

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

* [PATCH v6 13/13] [DO NOT MERGE] ARM: dts: sun8i: enable LCD panel of Lichee Pi Zero
  2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
                   ` (11 preceding siblings ...)
  2017-05-04 11:48 ` [PATCH v6 12/13] ARM: dts: sun8i: add pinmux for LCD pins of " Icenowy Zheng
@ 2017-05-04 11:48 ` Icenowy Zheng
  12 siblings, 0 replies; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-04 11:48 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring, Chen-Yu Tsai
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel, dri-devel,
	linux-sunxi, Icenowy Zheng

A 480x272 QiaoDian QD43003C0-40-7LED panel is available from Lichee Pi.

This commit connects this panel to Lichee Pi Zero.

Lichee Pi also provides a 800x480 panel without accurate model number,
so do not merge this patch. It will finally come as device tree overlay.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
---
 arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts | 36 +++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts b/arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
index 387fc2aa546d..7ae72bf63cd0 100644
--- a/arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
+++ b/arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
@@ -75,6 +75,28 @@
 			gpios = <&pio 6 2 GPIO_ACTIVE_LOW>; /* PG2 */
 		};
 	};
+
+	panel: panel {
+		compatible = "qiaodian,qd43003c0-40", "simple-panel";
+		enable-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* Should be backlight */
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		port@0 {
+			reg = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			panel_input: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&tcon0_out_lcd>;
+			};
+		};
+	};
+};
+
+&de {
+	status = "okay";
 };
 
 &mmc0 {
@@ -86,6 +108,20 @@
 	status = "okay";
 };
 
+&tcon0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&lcd_rgb666_pins>;
+	status = "okay";
+
+};
+
+&tcon0_out {
+	tcon0_out_lcd: endpoint@0 {
+		reg = <0>;
+		remote-endpoint = <&panel_input>;
+	};
+};
+
 &uart0 {
 	pinctrl-0 = <&uart0_pins_a>;
 	pinctrl-names = "default";
-- 
2.12.2

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

* Re: [PATCH v6 02/13] clk: sunxi-ng: add support for DE2 CCU
  2017-05-04 11:48 ` [PATCH v6 02/13] clk: sunxi-ng: add support for " Icenowy Zheng
@ 2017-05-04 12:50   ` Maxime Ripard
  0 siblings, 0 replies; 37+ messages in thread
From: Maxime Ripard @ 2017-05-04 12:50 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

[-- Attachment #1: Type: text/plain, Size: 8356 bytes --]

On Thu, May 04, 2017 at 07:48:47PM +0800, Icenowy Zheng wrote:
> The "Display Engine 2.0" in Allwinner newer SoCs contains a clock
> management unit for its subunits, like the DE CCU in A80.
> 
> Add a sunxi-ng style driver for it.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
> Changes in v5:
> - Removed dt-bindings headers (they're now in patch 1).
> Changes in v4:
> - Fixed the inconsistence between mixer_div clocks' number and real clock.
> Changes in v2:
> - Rename sunxi-de2-ccu to sun8i-de2-ccu.
> 
>  drivers/clk/sunxi-ng/Kconfig         |   5 +
>  drivers/clk/sunxi-ng/Makefile        |   1 +
>  drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 218 +++++++++++++++++++++++++++++++++++
>  drivers/clk/sunxi-ng/ccu-sun8i-de2.h |  28 +++++
>  4 files changed, 252 insertions(+)
>  create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-de2.c
>  create mode 100644 drivers/clk/sunxi-ng/ccu-sun8i-de2.h
> 
> diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig
> index 64088e599404..2e4d804fbf61 100644
> --- a/drivers/clk/sunxi-ng/Kconfig
> +++ b/drivers/clk/sunxi-ng/Kconfig
> @@ -140,6 +140,11 @@ config SUN8I_V3S_CCU
>  	default MACH_SUN8I
>  	depends on MACH_SUN8I || COMPILE_TEST
>  
> +config SUN8I_DE2_CCU
> +	bool "Support for the Allwinner SoCs DE2 CCU"
> +	select SUNXI_CCU_DIV
> +	select SUNXI_CCU_GATE
> +
>  config SUN9I_A80_CCU
>  	bool "Support for the Allwinner A80 CCU"
>  	select SUNXI_CCU_DIV
> diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
> index 0ec02fe14c50..be616279450e 100644
> --- a/drivers/clk/sunxi-ng/Makefile
> +++ b/drivers/clk/sunxi-ng/Makefile
> @@ -25,6 +25,7 @@ obj-$(CONFIG_SUN8I_A23_CCU)	+= ccu-sun8i-a23.o
>  obj-$(CONFIG_SUN8I_A33_CCU)	+= ccu-sun8i-a33.o
>  obj-$(CONFIG_SUN8I_H3_CCU)	+= ccu-sun8i-h3.o
>  obj-$(CONFIG_SUN8I_V3S_CCU)	+= ccu-sun8i-v3s.o
> +obj-$(CONFIG_SUN8I_DE2_CCU)	+= ccu-sun8i-de2.o
>  obj-$(CONFIG_SUN8I_R_CCU)	+= ccu-sun8i-r.o
>  obj-$(CONFIG_SUN9I_A80_CCU)	+= ccu-sun9i-a80.o
>  obj-$(CONFIG_SUN9I_A80_CCU)	+= ccu-sun9i-a80-de.o
> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
> new file mode 100644
> index 000000000000..adb2c344692a
> --- /dev/null
> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
> @@ -0,0 +1,218 @@
> +/*
> + * Copyright (c) 2017 Icenowy Zheng <icenowy@aosc.io>
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * 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.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +
> +#include "ccu_common.h"
> +#include "ccu_div.h"
> +#include "ccu_gate.h"
> +#include "ccu_reset.h"
> +
> +#include "ccu-sun8i-de2.h"
> +
> +static SUNXI_CCU_GATE(bus_mixer0_clk,	"bus-mixer0",	"bus-de",
> +		      0x04, BIT(0), 0);
> +static SUNXI_CCU_GATE(bus_mixer1_clk,	"bus-mixer1",	"bus-de",
> +		      0x04, BIT(1), 0);
> +static SUNXI_CCU_GATE(bus_wb_clk,	"bus-wb",	"bus-de",
> +		      0x04, BIT(2), 0);
> +
> +static SUNXI_CCU_GATE(mixer0_clk,	"mixer0",	"mixer0-div",
> +		      0x00, BIT(0), CLK_SET_RATE_PARENT);
> +static SUNXI_CCU_GATE(mixer1_clk,	"mixer1",	"mixer1-div",
> +		      0x00, BIT(1), CLK_SET_RATE_PARENT);
> +static SUNXI_CCU_GATE(wb_clk,		"wb",		"wb-div",
> +		      0x00, BIT(2), CLK_SET_RATE_PARENT);
> +
> +static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4,
> +		   CLK_SET_RATE_PARENT);
> +static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4,
> +		   CLK_SET_RATE_PARENT);
> +static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4,
> +		   CLK_SET_RATE_PARENT);
> +
> +static struct ccu_common *sunxi_de2_clks[] = {
> +	&mixer0_clk.common,
> +	&mixer1_clk.common,
> +	&wb_clk.common,
> +
> +	&bus_mixer0_clk.common,
> +	&bus_mixer1_clk.common,
> +	&bus_wb_clk.common,
> +
> +	&mixer0_div_clk.common,
> +	&mixer1_div_clk.common,
> +	&wb_div_clk.common,
> +};
> +
> +static struct clk_hw_onecell_data sunxi_de2_hw_clks = {
> +	.hws	= {
> +		[CLK_MIXER0]		= &mixer0_clk.common.hw,
> +		[CLK_MIXER1]		= &mixer1_clk.common.hw,
> +		[CLK_WB]		= &wb_clk.common.hw,
> +
> +		[CLK_BUS_MIXER0]	= &bus_mixer0_clk.common.hw,
> +		[CLK_BUS_MIXER1]	= &bus_mixer1_clk.common.hw,
> +		[CLK_BUS_WB]		= &bus_wb_clk.common.hw,
> +
> +		[CLK_MIXER0_DIV]	= &mixer0_div_clk.common.hw,
> +		[CLK_MIXER1_DIV]	= &mixer1_div_clk.common.hw,
> +		[CLK_WB_DIV]		= &wb_div_clk.common.hw,
> +	},
> +	.num	= CLK_NUMBER,
> +};
> +
> +static struct ccu_reset_map sun8i_a83t_de2_resets[] = {
> +	[RST_MIXER0]	= { 0x08, BIT(0) },
> +	/*
> +	 * For A83T, H3 and R40, mixer1 reset line is shared with wb, so
> +	 * only RST_WB is exported here.
> +	 */
> +	[RST_WB]	= { 0x08, BIT(2) },
> +};
> +
> +static struct ccu_reset_map sun50i_a64_de2_resets[] = {
> +	[RST_MIXER0]	= { 0x08, BIT(0) },
> +	[RST_MIXER1]	= { 0x08, BIT(1) },
> +	[RST_WB]	= { 0x08, BIT(2) },
> +};
> +
> +static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = {
> +	.ccu_clks	= sunxi_de2_clks,
> +	.num_ccu_clks	= ARRAY_SIZE(sunxi_de2_clks),
> +
> +	.hw_clks	= &sunxi_de2_hw_clks,
> +
> +	.resets		= sun8i_a83t_de2_resets,
> +	.num_resets	= ARRAY_SIZE(sun8i_a83t_de2_resets),
> +};
> +
> +static const struct sunxi_ccu_desc sun50i_a64_de2_clk_desc = {
> +	.ccu_clks	= sunxi_de2_clks,
> +	.num_ccu_clks	= ARRAY_SIZE(sunxi_de2_clks),
> +
> +	.hw_clks	= &sunxi_de2_hw_clks,
> +
> +	.resets		= sun50i_a64_de2_resets,
> +	.num_resets	= ARRAY_SIZE(sun50i_a64_de2_resets),
> +};
> +
> +static int sunxi_de2_clk_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	struct clk *bus_clk, *mod_clk;
> +	struct reset_control *rstc;
> +	void __iomem *reg;
> +	const struct sunxi_ccu_desc *ccu_desc;
> +	int ret;
> +
> +	ccu_desc = of_device_get_match_data(&pdev->dev);
> +	if (!ccu_desc)
> +		return -EINVAL;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	reg = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(reg))
> +		return PTR_ERR(reg);
> +
> +	bus_clk = devm_clk_get(&pdev->dev, "bus");
> +	if (IS_ERR(bus_clk)) {
> +		ret = PTR_ERR(bus_clk);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(&pdev->dev, "Couldn't get bus clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	mod_clk = devm_clk_get(&pdev->dev, "mod");
> +	if (IS_ERR(mod_clk)) {
> +		ret = PTR_ERR(mod_clk);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(&pdev->dev, "Couldn't get mod clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
> +	if (IS_ERR(rstc)) {
> +		ret = PTR_ERR(bus_clk);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(&pdev->dev,
> +				"Couldn't get reset control: %d\n", ret);
> +		return ret;
> +	}
> +
> +	/* The clocks need to be enabled for us to access the registers */
> +	ret = clk_prepare_enable(bus_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Couldn't enable bus clk: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = clk_prepare_enable(mod_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Couldn't enable mod clk: %d\n", ret);
> +		return ret;

You're leaving the bus clock enabled here if it fails.

> +	}
> +
> +	/* The reset control needs to be asserted for the controls to work */
> +	ret = reset_control_deassert(rstc);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Couldn't deassert reset control: %d\n", ret);
> +		goto err_disable_clk;
> +	}
> +
> +	ret = sunxi_ccu_probe(pdev->dev.of_node, reg, ccu_desc);
> +	if (ret)
> +		goto err_assert_reset;
> +
> +	return 0;
> +
> +err_assert_reset:
> +	reset_control_assert(rstc);

And here you're leaving the mod_clk enabled

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-04 11:48 ` [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers Icenowy Zheng
@ 2017-05-04 13:05   ` Maxime Ripard
  2017-05-04 16:50     ` icenowy
  2017-05-04 16:52     ` icenowy
  0 siblings, 2 replies; 37+ messages in thread
From: Maxime Ripard @ 2017-05-04 13:05 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

[-- Attachment #1: Type: text/plain, Size: 20522 bytes --]

On Thu, May 04, 2017 at 07:48:53PM +0800, Icenowy Zheng wrote:
> Allwinner have a new "Display Engine 2.0" in their new SoCs, which comes
> with mixers to do graphic processing and feed data to TCON, like the old
> backends and frontends.
> 
> Add support for the mixer on Allwinner V3s SoC; it's the simplest one.
> 
> Currently a lot of functions are still missing -- more investigations
> are needed to gain enough information for them.
> 
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
> Changes in v6:
> - Rebased on wens's multi-pipeline patchset.
> Changes in v5:
> - Changed some code alignment.
> - Request real 32-bit DMA (prepare for 64-bit SoCs).
> Changes in v4:
> - Killed some dead code according to Jernej.
> 
>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>  drivers/gpu/drm/sun4i/Makefile      |   3 +
>  drivers/gpu/drm/sun4i/sun8i_layer.c | 140 +++++++++++++
>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 394 ++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 137 +++++++++++++
>  6 files changed, 720 insertions(+)
>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
> 
> diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> index 5a8227f37cc4..15557484520d 100644
> --- a/drivers/gpu/drm/sun4i/Kconfig
> +++ b/drivers/gpu/drm/sun4i/Kconfig
> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>  	  original Allwinner Display Engine, which has a backend to
>  	  do some alpha blending and feed graphics to TCON. If M is
>  	  selected the module will be called sun4i-backend.
> +
> +config DRM_SUN4I_SUN8I_MIXER

DRM_SUN8I_MIXER?

> +	tristate "Support for Allwinner Display Engine 2.0 Mixer"
> +	depends on DRM_SUN4I
> +	default MACH_SUN8I
> +	help
> +	  Choose this option if you have an Allwinner SoC with the
> +	  Allwinner Display Engine 2.0, which has a mixer to do some
> +	  graphics mixture and feed graphics to TCON, If M is
> +	  selected the module will be called sun8i-mixer.
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index a08df56759e3..a876c6b3027c 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -8,7 +8,10 @@ sun4i-tcon-y += sun4i_crtc.o
>  
>  sun4i-backend-y += sun4i_backend.o sun4i_layer.o
>  
> +sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o
> +
>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
>  obj-$(CONFIG_DRM_SUN4I_BACKEND)		+= sun4i-backend.o
> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER)	+= sun8i-mixer.o
>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c b/drivers/gpu/drm/sun4i/sun8i_layer.c
> new file mode 100644
> index 000000000000..48f33d8e013b
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
> @@ -0,0 +1,140 @@
> +/*
> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
> + *
> + * Based on sun4i_layer.h, which is:
> + *   Copyright (C) 2015 Free Electrons
> + *   Copyright (C) 2015 NextThing Co
> + *
> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * 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.
> + */
> +
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drmP.h>
> +
> +#include "sun8i_layer.h"
> +#include "sun8i_mixer.h"
> +
> +struct sun8i_plane_desc {
> +	       enum drm_plane_type     type;
> +	       const uint32_t          *formats;
> +	       uint32_t                nformats;
> +};
> +
> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
> +					    struct drm_plane_state *state)
> +{
> +	return 0;
> +}

This isn't needed.

> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane *plane,
> +					       struct drm_plane_state *old_state)
> +{
> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
> +	struct sun8i_mixer *mixer = layer->mixer;
> +
> +	sun8i_mixer_layer_enable(mixer, layer->id, false);
> +}
> +
> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
> +					      struct drm_plane_state *old_state)
> +{
> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
> +	struct sun8i_mixer *mixer = layer->mixer;
> +
> +	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
> +	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
> +	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
> +	sun8i_mixer_layer_enable(mixer, layer->id, true);
> +}
> +
> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs = {
> +	.atomic_check	= sun8i_mixer_layer_atomic_check,
> +	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
> +	.atomic_update	= sun8i_mixer_layer_atomic_update,
> +};
> +
> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
> +	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
> +	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
> +	.destroy		= drm_plane_cleanup,
> +	.disable_plane		= drm_atomic_helper_disable_plane,
> +	.reset			= drm_atomic_helper_plane_reset,
> +	.update_plane		= drm_atomic_helper_update_plane,
> +};
> +
> +static const uint32_t sun8i_mixer_layer_formats[] = {
> +	DRM_FORMAT_RGB888,
> +	DRM_FORMAT_XRGB8888,
> +};
> +
> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
> +	{
> +		.type = DRM_PLANE_TYPE_PRIMARY,
> +		.formats = sun8i_mixer_layer_formats,
> +		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
> +	},
> +};
> +
> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device *drm,
> +						struct sun8i_mixer *mixer,
> +						const struct sun8i_plane_desc *plane)
> +{
> +	struct sun8i_layer *layer;
> +	int ret;
> +
> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
> +	if (!layer)
> +		return ERR_PTR(-ENOMEM);
> +
> +	/* possible crtcs are set later */
> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
> +				       &sun8i_mixer_layer_funcs,
> +				       plane->formats, plane->nformats,
> +				       plane->type, NULL);
> +	if (ret) {
> +		dev_err(drm->dev, "Couldn't initialize layer\n");
> +		return ERR_PTR(ret);
> +	}
> +
> +	drm_plane_helper_add(&layer->plane,
> +			     &sun8i_mixer_layer_helper_funcs);
> +	layer->mixer = mixer;
> +
> +	return layer;
> +}
> +
> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> +				     struct sunxi_engine *engine)
> +{
> +	struct drm_plane **planes;
> +	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> +	int i;
> +
> +	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
> +			      sizeof(*planes), GFP_KERNEL);
> +	if (!planes)
> +		return ERR_PTR(-ENOMEM);
> +
> +	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
> +		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
> +		struct sun8i_layer *layer;
> +
> +		layer = sun8i_layer_init_one(drm, mixer, plane);
> +		if (IS_ERR(layer)) {
> +			dev_err(drm->dev, "Couldn't initialize %s plane\n",
> +				i ? "overlay" : "primary");
> +			return ERR_CAST(layer);
> +		};
> +
> +		layer->id = i;
> +		planes[i] = &layer->plane;
> +	};
> +
> +	return planes;
> +}
> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h b/drivers/gpu/drm/sun4i/sun8i_layer.h
> new file mode 100644
> index 000000000000..e5eccd27cff0
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
> + *
> + * Based on sun4i_layer.h, which is:
> + *   Copyright (C) 2015 Free Electrons
> + *   Copyright (C) 2015 NextThing Co
> + *
> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
> + *
> + * 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.
> + */
> +
> +#ifndef _SUN8I_LAYER_H_
> +#define _SUN8I_LAYER_H_
> +
> +struct sunxi_engine;
> +
> +struct sun8i_layer {
> +	struct drm_plane	plane;
> +	struct sun4i_drv	*drv;
> +	struct sun8i_mixer	*mixer;
> +	int			id;
> +};
> +
> +static inline struct sun8i_layer *
> +plane_to_sun8i_layer(struct drm_plane *plane)
> +{
> +	return container_of(plane, struct sun8i_layer, plane);
> +}
> +
> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> +				     struct sunxi_engine *engine);
> +#endif /* _SUN8I_LAYER_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> new file mode 100644
> index 000000000000..e216b84d5bb2
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> @@ -0,0 +1,394 @@
> +/*
> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
> + *
> + * Based on sun4i_backend.c, which is:
> + *   Copyright (C) 2015 Free Electrons
> + *   Copyright (C) 2015 NextThing Co
> + *
> + * 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.
> + */
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include <linux/component.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/reset.h>
> +#include <linux/of_device.h>
> +
> +#include "sun4i_drv.h"
> +#include "sun8i_mixer.h"
> +#include "sun8i_layer.h"
> +#include "sunxi_engine.h"
> +
> +void sun8i_mixer_commit(struct sunxi_engine *engine)
> +{
> +	DRM_DEBUG_DRIVER("Committing changes\n");
> +
> +	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
> +		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
> +}

This function can be static

> +
> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
> +				int layer, bool enable)
> +{
> +	u32 val;
> +	/* Currently the first UI channel is used */
> +	int chan = mixer->cfg->vi_num;
> +
> +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
> +
> +	if (enable)
> +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
> +	else
> +		val = 0;
> +
> +	regmap_update_bits(mixer->engine.regs,
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
> +
> +	/* Set the alpha configuration */
> +	regmap_update_bits(mixer->engine.regs,
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
> +	regmap_update_bits(mixer->engine.regs,
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
> +}

This one too.

> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
> +					     u32 format, u32 *mode)
> +{
> +	switch (format) {
> +	case DRM_FORMAT_XRGB8888:
> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
> +		break;
> +
> +	case DRM_FORMAT_RGB888:
> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
> +				     int layer, struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	/* Currently the first UI channel is used */
> +	int chan = mixer->cfg->vi_num;
> +
> +	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
> +
> +	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
> +		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
> +				 state->crtc_w, state->crtc_h);
> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE,
> +			     SUN8I_MIXER_SIZE(state->crtc_w,
> +					      state->crtc_h));
> +		DRM_DEBUG_DRIVER("Updating blender size\n");
> +		regmap_write(mixer->engine.regs,
> +			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
> +			     SUN8I_MIXER_SIZE(state->crtc_w,
> +					      state->crtc_h));
> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
> +			     SUN8I_MIXER_SIZE(state->crtc_w,
> +					      state->crtc_h));
> +		DRM_DEBUG_DRIVER("Updating channel size\n");
> +		regmap_write(mixer->engine.regs,
> +			     SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
> +			     SUN8I_MIXER_SIZE(state->crtc_w,
> +					      state->crtc_h));
> +	}
> +
> +	/* Set the line width */
> +	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
> +	regmap_write(mixer->engine.regs,
> +		     SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
> +		     fb->pitches[0]);
> +
> +	/* Set height and width */
> +	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
> +			 state->crtc_w, state->crtc_h);
> +	regmap_write(mixer->engine.regs,
> +		     SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
> +		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
> +
> +	/* Set base coordinates */
> +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
> +			 state->crtc_x, state->crtc_y);
> +	regmap_write(mixer->engine.regs,
> +		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
> +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));

X and Y are fixed point numbers. You want to keep only the higher 16
bits there.

> +
> +	return 0;
> +}
> +
> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
> +				       int layer, struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	bool interlaced = false;
> +	u32 val;
> +	/* Currently the first UI channel is used */
> +	int chan = mixer->cfg->vi_num;
> +	int ret;
> +
> +	if (plane->state->crtc)
> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
> +			& DRM_MODE_FLAG_INTERLACE;
> +
> +	regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTCTL,
> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
> +			   interlaced ?
> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
> +
> +	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
> +			 interlaced ? "on" : "off");
> +
> +	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
> +						&val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid format\n");
> +		return ret;
> +	}
> +
> +	regmap_update_bits(mixer->engine.regs,
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
> +
> +	return 0;
> +}
> +
> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
> +				      int layer, struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	struct drm_gem_cma_object *gem;
> +	dma_addr_t paddr;
> +	/* Currently the first UI channel is used */
> +	int chan = mixer->cfg->vi_num;
> +	int bpp;
> +
> +	/* Get the physical address of the buffer in memory */
> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
> +
> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
> +
> +	/* Compute the start of the displayed memory */
> +	bpp = fb->format->cpp[0];
> +	paddr = gem->paddr + fb->offsets[0];
> +	paddr += (state->src_x >> 16) * bpp;
> +	paddr += (state->src_y >> 16) * fb->pitches[0];
> +
> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
> +
> +	regmap_write(mixer->engine.regs,
> +		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
> +		     lower_32_bits(paddr));
> +
> +	return 0;
> +}
> +
> +static const struct sunxi_engine_ops sun8i_engine_ops = {
> +	.commit		= sun8i_mixer_commit,
> +	.layers_init	= sun8i_layers_init,
> +};
> +
> +static struct regmap_config sun8i_mixer_regmap_config = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_stride	= 4,
> +	.max_register	= 0xbfffc, /* guessed */
> +};
> +
> +static int sun8i_mixer_bind(struct device *dev, struct device *master,
> +			      void *data)
> +{
> +	struct platform_device *pdev = to_platform_device(dev);
> +	struct drm_device *drm = data;
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct sun8i_mixer *mixer;
> +	struct resource *res;
> +	void __iomem *regs;
> +	int i, ret;
> +
> +	/*
> +	 * The mixer uses single 32-bit register to store memory
> +	 * addresses, so that it cannot deal with 64-bit memory
> +	 * addresses.
> +	 * Restrict the DMA mask so that the mixer won't be
> +	 * allocated some memory that is too high.
> +	 */
> +	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
> +	if (ret) {
> +		dev_err(dev, "Cannot do 32-bit DMA.\n");
> +		return ret;
> +	}
> +
> +	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
> +	if (!mixer)
> +		return -ENOMEM;
> +	dev_set_drvdata(dev, mixer);
> +	mixer->engine.ops = &sun8i_engine_ops;
> +	mixer->engine.node = dev->of_node;
> +
> +	mixer->cfg = of_device_get_match_data(dev);
> +	if (!mixer->cfg)
> +		return -EINVAL;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	regs = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(regs))
> +		return PTR_ERR(regs);
> +
> +	mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
> +						   &sun8i_mixer_regmap_config);
> +	if (IS_ERR(mixer->engine.regs)) {
> +		dev_err(dev, "Couldn't create the mixer regmap\n");
> +		return PTR_ERR(mixer->engine.regs);
> +	}
> +
> +	mixer->reset = devm_reset_control_get(dev, NULL);
> +	if (IS_ERR(mixer->reset)) {
> +		dev_err(dev, "Couldn't get our reset line\n");
> +		return PTR_ERR(mixer->reset);
> +	}
> +
> +	ret = reset_control_deassert(mixer->reset);
> +	if (ret) {
> +		dev_err(dev, "Couldn't deassert our reset line\n");
> +		return ret;
> +	}
> +
> +	mixer->bus_clk = devm_clk_get(dev, "bus");
> +	if (IS_ERR(mixer->bus_clk)) {
> +		dev_err(dev, "Couldn't get the mixer bus clock\n");
> +		ret = PTR_ERR(mixer->bus_clk);
> +		goto err_assert_reset;
> +	}
> +	clk_prepare_enable(mixer->bus_clk);
> +
> +	mixer->mod_clk = devm_clk_get(dev, "mod");
> +	if (IS_ERR(mixer->mod_clk)) {
> +		dev_err(dev, "Couldn't get the mixer module clock\n");
> +		ret = PTR_ERR(mixer->mod_clk);
> +		goto err_disable_bus_clk;
> +	}
> +	clk_prepare_enable(mixer->mod_clk);
> +
> +	list_add_tail(&mixer->engine.list, &drv->engine_list);

You didn't call INIT_LIST_HEAD on that list.

> +
> +	/* Reset the registers */
> +	for (i = 0x0; i < 0x20000; i += 4)
> +		regmap_write(mixer->engine.regs, i, 0);
> +
> +	/* Enable the mixer */
> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
> +		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
> +
> +	/* Initialize blender */
> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
> +		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
> +		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
> +		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(0),
> +		     SUN8I_MIXER_BLEND_MODE_DEF);
> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_CK_CTL,
> +		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
> +
> +	regmap_write(mixer->engine.regs,
> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
> +
> +	/* Select the first UI channel */
> +	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
> +			 mixer->cfg->vi_num);
> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE,
> +		     mixer->cfg->vi_num);
> +
> +	return 0;
> +
> +	clk_disable_unprepare(mixer->mod_clk);

This line cannot be reached.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-04 13:05   ` Maxime Ripard
@ 2017-05-04 16:50     ` icenowy
  2017-05-04 16:57       ` icenowy
  2017-05-05 12:36       ` Maxime Ripard
  2017-05-04 16:52     ` icenowy
  1 sibling, 2 replies; 37+ messages in thread
From: icenowy @ 2017-05-04 16:50 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

在 2017-05-04 21:05,Maxime Ripard 写道:
> On Thu, May 04, 2017 at 07:48:53PM +0800, Icenowy Zheng wrote:
>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which 
>> comes
>> with mixers to do graphic processing and feed data to TCON, like the 
>> old
>> backends and frontends.
>> 
>> Add support for the mixer on Allwinner V3s SoC; it's the simplest one.
>> 
>> Currently a lot of functions are still missing -- more investigations
>> are needed to gain enough information for them.
>> 
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>> Changes in v6:
>> - Rebased on wens's multi-pipeline patchset.
>> Changes in v5:
>> - Changed some code alignment.
>> - Request real 32-bit DMA (prepare for 64-bit SoCs).
>> Changes in v4:
>> - Killed some dead code according to Jernej.
>> 
>>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>>  drivers/gpu/drm/sun4i/Makefile      |   3 +
>>  drivers/gpu/drm/sun4i/sun8i_layer.c | 140 +++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 394 
>> ++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 137 +++++++++++++
>>  6 files changed, 720 insertions(+)
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>> 
>> diff --git a/drivers/gpu/drm/sun4i/Kconfig 
>> b/drivers/gpu/drm/sun4i/Kconfig
>> index 5a8227f37cc4..15557484520d 100644
>> --- a/drivers/gpu/drm/sun4i/Kconfig
>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>>  	  original Allwinner Display Engine, which has a backend to
>>  	  do some alpha blending and feed graphics to TCON. If M is
>>  	  selected the module will be called sun4i-backend.
>> +
>> +config DRM_SUN4I_SUN8I_MIXER
> 
> DRM_SUN8I_MIXER?
> 
>> +	tristate "Support for Allwinner Display Engine 2.0 Mixer"
>> +	depends on DRM_SUN4I
>> +	default MACH_SUN8I
>> +	help
>> +	  Choose this option if you have an Allwinner SoC with the
>> +	  Allwinner Display Engine 2.0, which has a mixer to do some
>> +	  graphics mixture and feed graphics to TCON, If M is
>> +	  selected the module will be called sun8i-mixer.
>> diff --git a/drivers/gpu/drm/sun4i/Makefile 
>> b/drivers/gpu/drm/sun4i/Makefile
>> index a08df56759e3..a876c6b3027c 100644
>> --- a/drivers/gpu/drm/sun4i/Makefile
>> +++ b/drivers/gpu/drm/sun4i/Makefile
>> @@ -8,7 +8,10 @@ sun4i-tcon-y += sun4i_crtc.o
>> 
>>  sun4i-backend-y += sun4i_backend.o sun4i_layer.o
>> 
>> +sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o
>> +
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
>>  obj-$(CONFIG_DRM_SUN4I_BACKEND)		+= sun4i-backend.o
>> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER)	+= sun8i-mixer.o
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c 
>> b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> new file mode 100644
>> index 000000000000..48f33d8e013b
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> @@ -0,0 +1,140 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * 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.
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drmP.h>
>> +
>> +#include "sun8i_layer.h"
>> +#include "sun8i_mixer.h"
>> +
>> +struct sun8i_plane_desc {
>> +	       enum drm_plane_type     type;
>> +	       const uint32_t          *formats;
>> +	       uint32_t                nformats;
>> +};
>> +
>> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
>> +					    struct drm_plane_state *state)
>> +{
>> +	return 0;
>> +}
> 
> This isn't needed.
> 
>> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane *plane,
>> +					       struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_layer_enable(mixer, layer->id, false);
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
>> +					      struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
>> +	sun8i_mixer_layer_enable(mixer, layer->id, true);
>> +}
>> +
>> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs = 
>> {
>> +	.atomic_check	= sun8i_mixer_layer_atomic_check,
>> +	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
>> +	.atomic_update	= sun8i_mixer_layer_atomic_update,
>> +};
>> +
>> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
>> +	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
>> +	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
>> +	.destroy		= drm_plane_cleanup,
>> +	.disable_plane		= drm_atomic_helper_disable_plane,
>> +	.reset			= drm_atomic_helper_plane_reset,
>> +	.update_plane		= drm_atomic_helper_update_plane,
>> +};
>> +
>> +static const uint32_t sun8i_mixer_layer_formats[] = {
>> +	DRM_FORMAT_RGB888,
>> +	DRM_FORMAT_XRGB8888,
>> +};
>> +
>> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
>> +	{
>> +		.type = DRM_PLANE_TYPE_PRIMARY,
>> +		.formats = sun8i_mixer_layer_formats,
>> +		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
>> +	},
>> +};
>> +
>> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device 
>> *drm,
>> +						struct sun8i_mixer *mixer,
>> +						const struct sun8i_plane_desc *plane)
>> +{
>> +	struct sun8i_layer *layer;
>> +	int ret;
>> +
>> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
>> +	if (!layer)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	/* possible crtcs are set later */
>> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
>> +				       &sun8i_mixer_layer_funcs,
>> +				       plane->formats, plane->nformats,
>> +				       plane->type, NULL);
>> +	if (ret) {
>> +		dev_err(drm->dev, "Couldn't initialize layer\n");
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	drm_plane_helper_add(&layer->plane,
>> +			     &sun8i_mixer_layer_helper_funcs);
>> +	layer->mixer = mixer;
>> +
>> +	return layer;
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sunxi_engine *engine)
>> +{
>> +	struct drm_plane **planes;
>> +	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
>> +	int i;
>> +
>> +	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
>> +			      sizeof(*planes), GFP_KERNEL);
>> +	if (!planes)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
>> +		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
>> +		struct sun8i_layer *layer;
>> +
>> +		layer = sun8i_layer_init_one(drm, mixer, plane);
>> +		if (IS_ERR(layer)) {
>> +			dev_err(drm->dev, "Couldn't initialize %s plane\n",
>> +				i ? "overlay" : "primary");
>> +			return ERR_CAST(layer);
>> +		};
>> +
>> +		layer->id = i;
>> +		planes[i] = &layer->plane;
>> +	};
>> +
>> +	return planes;
>> +}
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h 
>> b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> new file mode 100644
>> index 000000000000..e5eccd27cff0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> @@ -0,0 +1,36 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * 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.
>> + */
>> +
>> +#ifndef _SUN8I_LAYER_H_
>> +#define _SUN8I_LAYER_H_
>> +
>> +struct sunxi_engine;
>> +
>> +struct sun8i_layer {
>> +	struct drm_plane	plane;
>> +	struct sun4i_drv	*drv;
>> +	struct sun8i_mixer	*mixer;
>> +	int			id;
>> +};
>> +
>> +static inline struct sun8i_layer *
>> +plane_to_sun8i_layer(struct drm_plane *plane)
>> +{
>> +	return container_of(plane, struct sun8i_layer, plane);
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sunxi_engine *engine);
>> +#endif /* _SUN8I_LAYER_H_ */
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
>> b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> new file mode 100644
>> index 000000000000..e216b84d5bb2
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> @@ -0,0 +1,394 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_backend.c, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + * 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.
>> + */
>> +
>> +#include <drm/drmP.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_crtc_helper.h>
>> +#include <drm/drm_fb_cma_helper.h>
>> +#include <drm/drm_gem_cma_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +#include <linux/component.h>
>> +#include <linux/dma-mapping.h>
>> +#include <linux/reset.h>
>> +#include <linux/of_device.h>
>> +
>> +#include "sun4i_drv.h"
>> +#include "sun8i_mixer.h"
>> +#include "sun8i_layer.h"
>> +#include "sunxi_engine.h"
>> +
>> +void sun8i_mixer_commit(struct sunxi_engine *engine)
>> +{
>> +	DRM_DEBUG_DRIVER("Committing changes\n");
>> +
>> +	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
>> +		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>> +}
> 
> This function can be static
> 
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> +				int layer, bool enable)
>> +{
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
>> +
>> +	if (enable)
>> +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>> +	else
>> +		val = 0;
>> +
>> +	regmap_update_bits(mixer->engine.regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>> +
>> +	/* Set the alpha configuration */
>> +	regmap_update_bits(mixer->engine.regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>> +	regmap_update_bits(mixer->engine.regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>> +}
> 
> This one too.

It's called from sun8i_layer.c, so it cannot be static.

> 
>> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
>> +					     u32 format, u32 *mode)
>> +{
>> +	switch (format) {
>> +	case DRM_FORMAT_XRGB8888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
>> +		break;
>> +
>> +	case DRM_FORMAT_RGB888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
>> +		break;
>> +
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> +				     int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>> +
>> +	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>> +		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: 
>> %u\n",
>> +				 state->crtc_w, state->crtc_h);
>> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating blender size\n");
>> +		regmap_write(mixer->engine.regs,
>> +			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating channel size\n");
>> +		regmap_write(mixer->engine.regs,
>> +			     SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +	}
>> +
>> +	/* Set the line width */
>> +	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
>> +		     fb->pitches[0]);
>> +
>> +	/* Set height and width */
>> +	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>> +			 state->crtc_w, state->crtc_h);
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
>> +		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
>> +
>> +	/* Set base coordinates */
>> +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>> +			 state->crtc_x, state->crtc_y);
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
>> +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
> 
> X and Y are fixed point numbers. You want to keep only the higher 16
> bits there.

Do you mean "lower 16 bits"? Thus should I (x & 0xffff) or ((u16)x) ?

P.S. The negative coordinates are broken, how should I deal with it? or
is the coordinates promised to be not negative?

> 
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> +				       int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	bool interlaced = false;
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int ret;
>> +
>> +	if (plane->state->crtc)
>> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
>> +			& DRM_MODE_FLAG_INTERLACE;
>> +
>> +	regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTCTL,
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
>> +			   interlaced ?
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
>> +
>> +	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
>> +			 interlaced ? "on" : "off");
>> +
>> +	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
>> +						&val);
>> +	if (ret) {
>> +		DRM_DEBUG_DRIVER("Invalid format\n");
>> +		return ret;
>> +	}
>> +
>> +	regmap_update_bits(mixer->engine.regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> +				      int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	struct drm_gem_cma_object *gem;
>> +	dma_addr_t paddr;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int bpp;
>> +
>> +	/* Get the physical address of the buffer in memory */
>> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>> +
>> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
>> +
>> +	/* Compute the start of the displayed memory */
>> +	bpp = fb->format->cpp[0];
>> +	paddr = gem->paddr + fb->offsets[0];
>> +	paddr += (state->src_x >> 16) * bpp;
>> +	paddr += (state->src_y >> 16) * fb->pitches[0];
>> +
>> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
>> +
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
>> +		     lower_32_bits(paddr));
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct sunxi_engine_ops sun8i_engine_ops = {
>> +	.commit		= sun8i_mixer_commit,
>> +	.layers_init	= sun8i_layers_init,
>> +};
>> +
>> +static struct regmap_config sun8i_mixer_regmap_config = {
>> +	.reg_bits	= 32,
>> +	.val_bits	= 32,
>> +	.reg_stride	= 4,
>> +	.max_register	= 0xbfffc, /* guessed */
>> +};
>> +
>> +static int sun8i_mixer_bind(struct device *dev, struct device 
>> *master,
>> +			      void *data)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct drm_device *drm = data;
>> +	struct sun4i_drv *drv = drm->dev_private;
>> +	struct sun8i_mixer *mixer;
>> +	struct resource *res;
>> +	void __iomem *regs;
>> +	int i, ret;
>> +
>> +	/*
>> +	 * The mixer uses single 32-bit register to store memory
>> +	 * addresses, so that it cannot deal with 64-bit memory
>> +	 * addresses.
>> +	 * Restrict the DMA mask so that the mixer won't be
>> +	 * allocated some memory that is too high.
>> +	 */
>> +	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
>> +	if (ret) {
>> +		dev_err(dev, "Cannot do 32-bit DMA.\n");
>> +		return ret;
>> +	}
>> +
>> +	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
>> +	if (!mixer)
>> +		return -ENOMEM;
>> +	dev_set_drvdata(dev, mixer);
>> +	mixer->engine.ops = &sun8i_engine_ops;
>> +	mixer->engine.node = dev->of_node;
>> +
>> +	mixer->cfg = of_device_get_match_data(dev);
>> +	if (!mixer->cfg)
>> +		return -EINVAL;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	regs = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(regs))
>> +		return PTR_ERR(regs);
>> +
>> +	mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
>> +						   &sun8i_mixer_regmap_config);
>> +	if (IS_ERR(mixer->engine.regs)) {
>> +		dev_err(dev, "Couldn't create the mixer regmap\n");
>> +		return PTR_ERR(mixer->engine.regs);
>> +	}
>> +
>> +	mixer->reset = devm_reset_control_get(dev, NULL);
>> +	if (IS_ERR(mixer->reset)) {
>> +		dev_err(dev, "Couldn't get our reset line\n");
>> +		return PTR_ERR(mixer->reset);
>> +	}
>> +
>> +	ret = reset_control_deassert(mixer->reset);
>> +	if (ret) {
>> +		dev_err(dev, "Couldn't deassert our reset line\n");
>> +		return ret;
>> +	}
>> +
>> +	mixer->bus_clk = devm_clk_get(dev, "bus");
>> +	if (IS_ERR(mixer->bus_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer bus clock\n");
>> +		ret = PTR_ERR(mixer->bus_clk);
>> +		goto err_assert_reset;
>> +	}
>> +	clk_prepare_enable(mixer->bus_clk);
>> +
>> +	mixer->mod_clk = devm_clk_get(dev, "mod");
>> +	if (IS_ERR(mixer->mod_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer module clock\n");
>> +		ret = PTR_ERR(mixer->mod_clk);
>> +		goto err_disable_bus_clk;
>> +	}
>> +	clk_prepare_enable(mixer->mod_clk);
>> +
>> +	list_add_tail(&mixer->engine.list, &drv->engine_list);
> 
> You didn't call INIT_LIST_HEAD on that list.
> 
>> +
>> +	/* Reset the registers */
>> +	for (i = 0x0; i < 0x20000; i += 4)
>> +		regmap_write(mixer->engine.regs, i, 0);
>> +
>> +	/* Enable the mixer */
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
>> +		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
>> +
>> +	/* Initialize blender */
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
>> +		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
>> +		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
>> +		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(0),
>> +		     SUN8I_MIXER_BLEND_MODE_DEF);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_CK_CTL,
>> +		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
>> +
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
>> +
>> +	/* Select the first UI channel */
>> +	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
>> +			 mixer->cfg->vi_num);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE,
>> +		     mixer->cfg->vi_num);
>> +
>> +	return 0;
>> +
>> +	clk_disable_unprepare(mixer->mod_clk);
> 
> This line cannot be reached.
> 
> Maxime

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

* Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-04 13:05   ` Maxime Ripard
  2017-05-04 16:50     ` icenowy
@ 2017-05-04 16:52     ` icenowy
  2017-05-05  3:40       ` [linux-sunxi] " Chen-Yu Tsai
  1 sibling, 1 reply; 37+ messages in thread
From: icenowy @ 2017-05-04 16:52 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

在 2017-05-04 21:05,Maxime Ripard 写道:
> On Thu, May 04, 2017 at 07:48:53PM +0800, Icenowy Zheng wrote:
>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which 
>> comes
>> with mixers to do graphic processing and feed data to TCON, like the 
>> old
>> backends and frontends.
>> 
>> Add support for the mixer on Allwinner V3s SoC; it's the simplest one.
>> 
>> Currently a lot of functions are still missing -- more investigations
>> are needed to gain enough information for them.
>> 
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>> Changes in v6:
>> - Rebased on wens's multi-pipeline patchset.
>> Changes in v5:
>> - Changed some code alignment.
>> - Request real 32-bit DMA (prepare for 64-bit SoCs).
>> Changes in v4:
>> - Killed some dead code according to Jernej.
>> 
>>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>>  drivers/gpu/drm/sun4i/Makefile      |   3 +
>>  drivers/gpu/drm/sun4i/sun8i_layer.c | 140 +++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 394 
>> ++++++++++++++++++++++++++++++++++++
>>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 137 +++++++++++++
>>  6 files changed, 720 insertions(+)
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>> 
>> diff --git a/drivers/gpu/drm/sun4i/Kconfig 
>> b/drivers/gpu/drm/sun4i/Kconfig
>> index 5a8227f37cc4..15557484520d 100644
>> --- a/drivers/gpu/drm/sun4i/Kconfig
>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>>  	  original Allwinner Display Engine, which has a backend to
>>  	  do some alpha blending and feed graphics to TCON. If M is
>>  	  selected the module will be called sun4i-backend.
>> +
>> +config DRM_SUN4I_SUN8I_MIXER
> 
> DRM_SUN8I_MIXER?
> 
>> +	tristate "Support for Allwinner Display Engine 2.0 Mixer"
>> +	depends on DRM_SUN4I
>> +	default MACH_SUN8I
>> +	help
>> +	  Choose this option if you have an Allwinner SoC with the
>> +	  Allwinner Display Engine 2.0, which has a mixer to do some
>> +	  graphics mixture and feed graphics to TCON, If M is
>> +	  selected the module will be called sun8i-mixer.
>> diff --git a/drivers/gpu/drm/sun4i/Makefile 
>> b/drivers/gpu/drm/sun4i/Makefile
>> index a08df56759e3..a876c6b3027c 100644
>> --- a/drivers/gpu/drm/sun4i/Makefile
>> +++ b/drivers/gpu/drm/sun4i/Makefile
>> @@ -8,7 +8,10 @@ sun4i-tcon-y += sun4i_crtc.o
>> 
>>  sun4i-backend-y += sun4i_backend.o sun4i_layer.o
>> 
>> +sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o
>> +
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
>>  obj-$(CONFIG_DRM_SUN4I_BACKEND)		+= sun4i-backend.o
>> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER)	+= sun8i-mixer.o
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c 
>> b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> new file mode 100644
>> index 000000000000..48f33d8e013b
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
>> @@ -0,0 +1,140 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * 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.
>> + */
>> +
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +#include <drm/drmP.h>
>> +
>> +#include "sun8i_layer.h"
>> +#include "sun8i_mixer.h"
>> +
>> +struct sun8i_plane_desc {
>> +	       enum drm_plane_type     type;
>> +	       const uint32_t          *formats;
>> +	       uint32_t                nformats;
>> +};
>> +
>> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
>> +					    struct drm_plane_state *state)
>> +{
>> +	return 0;
>> +}
> 
> This isn't needed.
> 
>> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane *plane,
>> +					       struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_layer_enable(mixer, layer->id, false);
>> +}
>> +
>> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
>> +					      struct drm_plane_state *old_state)
>> +{
>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>> +	struct sun8i_mixer *mixer = layer->mixer;
>> +
>> +	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
>> +	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
>> +	sun8i_mixer_layer_enable(mixer, layer->id, true);
>> +}
>> +
>> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs = 
>> {
>> +	.atomic_check	= sun8i_mixer_layer_atomic_check,
>> +	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
>> +	.atomic_update	= sun8i_mixer_layer_atomic_update,
>> +};
>> +
>> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
>> +	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
>> +	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
>> +	.destroy		= drm_plane_cleanup,
>> +	.disable_plane		= drm_atomic_helper_disable_plane,
>> +	.reset			= drm_atomic_helper_plane_reset,
>> +	.update_plane		= drm_atomic_helper_update_plane,
>> +};
>> +
>> +static const uint32_t sun8i_mixer_layer_formats[] = {
>> +	DRM_FORMAT_RGB888,
>> +	DRM_FORMAT_XRGB8888,
>> +};
>> +
>> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
>> +	{
>> +		.type = DRM_PLANE_TYPE_PRIMARY,
>> +		.formats = sun8i_mixer_layer_formats,
>> +		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
>> +	},
>> +};
>> +
>> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device 
>> *drm,
>> +						struct sun8i_mixer *mixer,
>> +						const struct sun8i_plane_desc *plane)
>> +{
>> +	struct sun8i_layer *layer;
>> +	int ret;
>> +
>> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
>> +	if (!layer)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	/* possible crtcs are set later */
>> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
>> +				       &sun8i_mixer_layer_funcs,
>> +				       plane->formats, plane->nformats,
>> +				       plane->type, NULL);
>> +	if (ret) {
>> +		dev_err(drm->dev, "Couldn't initialize layer\n");
>> +		return ERR_PTR(ret);
>> +	}
>> +
>> +	drm_plane_helper_add(&layer->plane,
>> +			     &sun8i_mixer_layer_helper_funcs);
>> +	layer->mixer = mixer;
>> +
>> +	return layer;
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sunxi_engine *engine)
>> +{
>> +	struct drm_plane **planes;
>> +	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
>> +	int i;
>> +
>> +	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
>> +			      sizeof(*planes), GFP_KERNEL);
>> +	if (!planes)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
>> +		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
>> +		struct sun8i_layer *layer;
>> +
>> +		layer = sun8i_layer_init_one(drm, mixer, plane);
>> +		if (IS_ERR(layer)) {
>> +			dev_err(drm->dev, "Couldn't initialize %s plane\n",
>> +				i ? "overlay" : "primary");
>> +			return ERR_CAST(layer);
>> +		};
>> +
>> +		layer->id = i;
>> +		planes[i] = &layer->plane;
>> +	};
>> +
>> +	return planes;
>> +}
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h 
>> b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> new file mode 100644
>> index 000000000000..e5eccd27cff0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
>> @@ -0,0 +1,36 @@
>> +/*
>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_layer.h, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>> + *
>> + * 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.
>> + */
>> +
>> +#ifndef _SUN8I_LAYER_H_
>> +#define _SUN8I_LAYER_H_
>> +
>> +struct sunxi_engine;
>> +
>> +struct sun8i_layer {
>> +	struct drm_plane	plane;
>> +	struct sun4i_drv	*drv;
>> +	struct sun8i_mixer	*mixer;
>> +	int			id;
>> +};
>> +
>> +static inline struct sun8i_layer *
>> +plane_to_sun8i_layer(struct drm_plane *plane)
>> +{
>> +	return container_of(plane, struct sun8i_layer, plane);
>> +}
>> +
>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>> +				     struct sunxi_engine *engine);
>> +#endif /* _SUN8I_LAYER_H_ */
>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
>> b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> new file mode 100644
>> index 000000000000..e216b84d5bb2
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>> @@ -0,0 +1,394 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * Based on sun4i_backend.c, which is:
>> + *   Copyright (C) 2015 Free Electrons
>> + *   Copyright (C) 2015 NextThing Co
>> + *
>> + * 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.
>> + */
>> +
>> +#include <drm/drmP.h>
>> +#include <drm/drm_atomic_helper.h>
>> +#include <drm/drm_crtc.h>
>> +#include <drm/drm_crtc_helper.h>
>> +#include <drm/drm_fb_cma_helper.h>
>> +#include <drm/drm_gem_cma_helper.h>
>> +#include <drm/drm_plane_helper.h>
>> +
>> +#include <linux/component.h>
>> +#include <linux/dma-mapping.h>
>> +#include <linux/reset.h>
>> +#include <linux/of_device.h>
>> +
>> +#include "sun4i_drv.h"
>> +#include "sun8i_mixer.h"
>> +#include "sun8i_layer.h"
>> +#include "sunxi_engine.h"
>> +
>> +void sun8i_mixer_commit(struct sunxi_engine *engine)
>> +{
>> +	DRM_DEBUG_DRIVER("Committing changes\n");
>> +
>> +	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
>> +		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>> +}
> 
> This function can be static
> 
>> +
>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> +				int layer, bool enable)
>> +{
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
>> +
>> +	if (enable)
>> +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>> +	else
>> +		val = 0;
>> +
>> +	regmap_update_bits(mixer->engine.regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>> +
>> +	/* Set the alpha configuration */
>> +	regmap_update_bits(mixer->engine.regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>> +	regmap_update_bits(mixer->engine.regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>> +}
> 
> This one too.
> 
>> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
>> +					     u32 format, u32 *mode)
>> +{
>> +	switch (format) {
>> +	case DRM_FORMAT_XRGB8888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
>> +		break;
>> +
>> +	case DRM_FORMAT_RGB888:
>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
>> +		break;
>> +
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>> +				     int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +
>> +	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>> +
>> +	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>> +		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: 
>> %u\n",
>> +				 state->crtc_w, state->crtc_h);
>> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating blender size\n");
>> +		regmap_write(mixer->engine.regs,
>> +			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +		DRM_DEBUG_DRIVER("Updating channel size\n");
>> +		regmap_write(mixer->engine.regs,
>> +			     SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>> +					      state->crtc_h));
>> +	}
>> +
>> +	/* Set the line width */
>> +	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
>> +		     fb->pitches[0]);
>> +
>> +	/* Set height and width */
>> +	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>> +			 state->crtc_w, state->crtc_h);
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
>> +		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
>> +
>> +	/* Set base coordinates */
>> +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>> +			 state->crtc_x, state->crtc_y);
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
>> +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
> 
> X and Y are fixed point numbers. You want to keep only the higher 16
> bits there.
> 
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>> +				       int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	bool interlaced = false;
>> +	u32 val;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int ret;
>> +
>> +	if (plane->state->crtc)
>> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
>> +			& DRM_MODE_FLAG_INTERLACE;
>> +
>> +	regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTCTL,
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
>> +			   interlaced ?
>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
>> +
>> +	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
>> +			 interlaced ? "on" : "off");
>> +
>> +	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
>> +						&val);
>> +	if (ret) {
>> +		DRM_DEBUG_DRIVER("Invalid format\n");
>> +		return ret;
>> +	}
>> +
>> +	regmap_update_bits(mixer->engine.regs,
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
>> +
>> +	return 0;
>> +}
>> +
>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>> +				      int layer, struct drm_plane *plane)
>> +{
>> +	struct drm_plane_state *state = plane->state;
>> +	struct drm_framebuffer *fb = state->fb;
>> +	struct drm_gem_cma_object *gem;
>> +	dma_addr_t paddr;
>> +	/* Currently the first UI channel is used */
>> +	int chan = mixer->cfg->vi_num;
>> +	int bpp;
>> +
>> +	/* Get the physical address of the buffer in memory */
>> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>> +
>> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
>> +
>> +	/* Compute the start of the displayed memory */
>> +	bpp = fb->format->cpp[0];
>> +	paddr = gem->paddr + fb->offsets[0];
>> +	paddr += (state->src_x >> 16) * bpp;
>> +	paddr += (state->src_y >> 16) * fb->pitches[0];
>> +
>> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
>> +
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
>> +		     lower_32_bits(paddr));
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct sunxi_engine_ops sun8i_engine_ops = {
>> +	.commit		= sun8i_mixer_commit,
>> +	.layers_init	= sun8i_layers_init,
>> +};
>> +
>> +static struct regmap_config sun8i_mixer_regmap_config = {
>> +	.reg_bits	= 32,
>> +	.val_bits	= 32,
>> +	.reg_stride	= 4,
>> +	.max_register	= 0xbfffc, /* guessed */
>> +};
>> +
>> +static int sun8i_mixer_bind(struct device *dev, struct device 
>> *master,
>> +			      void *data)
>> +{
>> +	struct platform_device *pdev = to_platform_device(dev);
>> +	struct drm_device *drm = data;
>> +	struct sun4i_drv *drv = drm->dev_private;
>> +	struct sun8i_mixer *mixer;
>> +	struct resource *res;
>> +	void __iomem *regs;
>> +	int i, ret;
>> +
>> +	/*
>> +	 * The mixer uses single 32-bit register to store memory
>> +	 * addresses, so that it cannot deal with 64-bit memory
>> +	 * addresses.
>> +	 * Restrict the DMA mask so that the mixer won't be
>> +	 * allocated some memory that is too high.
>> +	 */
>> +	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
>> +	if (ret) {
>> +		dev_err(dev, "Cannot do 32-bit DMA.\n");
>> +		return ret;
>> +	}
>> +
>> +	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
>> +	if (!mixer)
>> +		return -ENOMEM;
>> +	dev_set_drvdata(dev, mixer);
>> +	mixer->engine.ops = &sun8i_engine_ops;
>> +	mixer->engine.node = dev->of_node;
>> +
>> +	mixer->cfg = of_device_get_match_data(dev);
>> +	if (!mixer->cfg)
>> +		return -EINVAL;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	regs = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(regs))
>> +		return PTR_ERR(regs);
>> +
>> +	mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
>> +						   &sun8i_mixer_regmap_config);
>> +	if (IS_ERR(mixer->engine.regs)) {
>> +		dev_err(dev, "Couldn't create the mixer regmap\n");
>> +		return PTR_ERR(mixer->engine.regs);
>> +	}
>> +
>> +	mixer->reset = devm_reset_control_get(dev, NULL);
>> +	if (IS_ERR(mixer->reset)) {
>> +		dev_err(dev, "Couldn't get our reset line\n");
>> +		return PTR_ERR(mixer->reset);
>> +	}
>> +
>> +	ret = reset_control_deassert(mixer->reset);
>> +	if (ret) {
>> +		dev_err(dev, "Couldn't deassert our reset line\n");
>> +		return ret;
>> +	}
>> +
>> +	mixer->bus_clk = devm_clk_get(dev, "bus");
>> +	if (IS_ERR(mixer->bus_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer bus clock\n");
>> +		ret = PTR_ERR(mixer->bus_clk);
>> +		goto err_assert_reset;
>> +	}
>> +	clk_prepare_enable(mixer->bus_clk);
>> +
>> +	mixer->mod_clk = devm_clk_get(dev, "mod");
>> +	if (IS_ERR(mixer->mod_clk)) {
>> +		dev_err(dev, "Couldn't get the mixer module clock\n");
>> +		ret = PTR_ERR(mixer->mod_clk);
>> +		goto err_disable_bus_clk;
>> +	}
>> +	clk_prepare_enable(mixer->mod_clk);
>> +
>> +	list_add_tail(&mixer->engine.list, &drv->engine_list);
> 
> You didn't call INIT_LIST_HEAD on that list.

So didn't the sun4i_backend driver...

I think the mixer->engine.list only means an item in the
engine_list, and the drv->engine_list is initialized in the
sun4i_drv source code.

> 
>> +
>> +	/* Reset the registers */
>> +	for (i = 0x0; i < 0x20000; i += 4)
>> +		regmap_write(mixer->engine.regs, i, 0);
>> +
>> +	/* Enable the mixer */
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
>> +		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
>> +
>> +	/* Initialize blender */
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
>> +		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
>> +		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
>> +		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(0),
>> +		     SUN8I_MIXER_BLEND_MODE_DEF);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_CK_CTL,
>> +		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
>> +
>> +	regmap_write(mixer->engine.regs,
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
>> +
>> +	/* Select the first UI channel */
>> +	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
>> +			 mixer->cfg->vi_num);
>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE,
>> +		     mixer->cfg->vi_num);
>> +
>> +	return 0;
>> +
>> +	clk_disable_unprepare(mixer->mod_clk);
> 
> This line cannot be reached.
> 
> Maxime

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

* Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-04 16:50     ` icenowy
@ 2017-05-04 16:57       ` icenowy
  2017-05-04 17:14         ` icenowy
  2017-05-05 12:36       ` Maxime Ripard
  1 sibling, 1 reply; 37+ messages in thread
From: icenowy @ 2017-05-04 16:57 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

在 2017-05-05 00:50,icenowy@aosc.io 写道:
> 在 2017-05-04 21:05,Maxime Ripard 写道:
>> On Thu, May 04, 2017 at 07:48:53PM +0800, Icenowy Zheng wrote:
>>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which 
>>> comes
>>> with mixers to do graphic processing and feed data to TCON, like the 
>>> old
>>> backends and frontends.
>>> 
>>> Add support for the mixer on Allwinner V3s SoC; it's the simplest 
>>> one.
>>> 
>>> Currently a lot of functions are still missing -- more investigations
>>> are needed to gain enough information for them.
>>> 
>>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>>> ---
>>> Changes in v6:
>>> - Rebased on wens's multi-pipeline patchset.
>>> Changes in v5:
>>> - Changed some code alignment.
>>> - Request real 32-bit DMA (prepare for 64-bit SoCs).
>>> Changes in v4:
>>> - Killed some dead code according to Jernej.
>>> 
>>>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>>>  drivers/gpu/drm/sun4i/Makefile      |   3 +
>>>  drivers/gpu/drm/sun4i/sun8i_layer.c | 140 +++++++++++++
>>>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>>>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 394 
>>> ++++++++++++++++++++++++++++++++++++
>>>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 137 +++++++++++++
>>>  6 files changed, 720 insertions(+)
>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>>> 
>>> diff --git a/drivers/gpu/drm/sun4i/Kconfig 
>>> b/drivers/gpu/drm/sun4i/Kconfig
>>> index 5a8227f37cc4..15557484520d 100644
>>> --- a/drivers/gpu/drm/sun4i/Kconfig
>>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>>> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>>>  	  original Allwinner Display Engine, which has a backend to
>>>  	  do some alpha blending and feed graphics to TCON. If M is
>>>  	  selected the module will be called sun4i-backend.
>>> +
>>> +config DRM_SUN4I_SUN8I_MIXER
>> 
>> DRM_SUN8I_MIXER?
>> 
>>> +	tristate "Support for Allwinner Display Engine 2.0 Mixer"
>>> +	depends on DRM_SUN4I
>>> +	default MACH_SUN8I
>>> +	help
>>> +	  Choose this option if you have an Allwinner SoC with the
>>> +	  Allwinner Display Engine 2.0, which has a mixer to do some
>>> +	  graphics mixture and feed graphics to TCON, If M is
>>> +	  selected the module will be called sun8i-mixer.
>>> diff --git a/drivers/gpu/drm/sun4i/Makefile 
>>> b/drivers/gpu/drm/sun4i/Makefile
>>> index a08df56759e3..a876c6b3027c 100644
>>> --- a/drivers/gpu/drm/sun4i/Makefile
>>> +++ b/drivers/gpu/drm/sun4i/Makefile
>>> @@ -8,7 +8,10 @@ sun4i-tcon-y += sun4i_crtc.o
>>> 
>>>  sun4i-backend-y += sun4i_backend.o sun4i_layer.o
>>> 
>>> +sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o
>>> +
>>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
>>>  obj-$(CONFIG_DRM_SUN4I_BACKEND)		+= sun4i-backend.o
>>> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER)	+= sun8i-mixer.o
>>>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c 
>>> b/drivers/gpu/drm/sun4i/sun8i_layer.c
>>> new file mode 100644
>>> index 000000000000..48f33d8e013b
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
>>> @@ -0,0 +1,140 @@
>>> +/*
>>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>>> + *
>>> + * Based on sun4i_layer.h, which is:
>>> + *   Copyright (C) 2015 Free Electrons
>>> + *   Copyright (C) 2015 NextThing Co
>>> + *
>>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>>> + *
>>> + * 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.
>>> + */
>>> +
>>> +#include <drm/drm_atomic_helper.h>
>>> +#include <drm/drm_plane_helper.h>
>>> +#include <drm/drmP.h>
>>> +
>>> +#include "sun8i_layer.h"
>>> +#include "sun8i_mixer.h"
>>> +
>>> +struct sun8i_plane_desc {
>>> +	       enum drm_plane_type     type;
>>> +	       const uint32_t          *formats;
>>> +	       uint32_t                nformats;
>>> +};
>>> +
>>> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
>>> +					    struct drm_plane_state *state)
>>> +{
>>> +	return 0;
>>> +}
>> 
>> This isn't needed.
>> 
>>> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane 
>>> *plane,
>>> +					       struct drm_plane_state *old_state)
>>> +{
>>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>>> +	struct sun8i_mixer *mixer = layer->mixer;
>>> +
>>> +	sun8i_mixer_layer_enable(mixer, layer->id, false);
>>> +}
>>> +
>>> +static void sun8i_mixer_layer_atomic_update(struct drm_plane *plane,
>>> +					      struct drm_plane_state *old_state)
>>> +{
>>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>>> +	struct sun8i_mixer *mixer = layer->mixer;
>>> +
>>> +	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
>>> +	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
>>> +	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
>>> +	sun8i_mixer_layer_enable(mixer, layer->id, true);
>>> +}
>>> +
>>> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs 
>>> = {
>>> +	.atomic_check	= sun8i_mixer_layer_atomic_check,
>>> +	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
>>> +	.atomic_update	= sun8i_mixer_layer_atomic_update,
>>> +};
>>> +
>>> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
>>> +	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
>>> +	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
>>> +	.destroy		= drm_plane_cleanup,
>>> +	.disable_plane		= drm_atomic_helper_disable_plane,
>>> +	.reset			= drm_atomic_helper_plane_reset,
>>> +	.update_plane		= drm_atomic_helper_update_plane,
>>> +};
>>> +
>>> +static const uint32_t sun8i_mixer_layer_formats[] = {
>>> +	DRM_FORMAT_RGB888,
>>> +	DRM_FORMAT_XRGB8888,
>>> +};
>>> +
>>> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
>>> +	{
>>> +		.type = DRM_PLANE_TYPE_PRIMARY,
>>> +		.formats = sun8i_mixer_layer_formats,
>>> +		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
>>> +	},
>>> +};
>>> +
>>> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device 
>>> *drm,
>>> +						struct sun8i_mixer *mixer,
>>> +						const struct sun8i_plane_desc *plane)
>>> +{
>>> +	struct sun8i_layer *layer;
>>> +	int ret;
>>> +
>>> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
>>> +	if (!layer)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	/* possible crtcs are set later */
>>> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
>>> +				       &sun8i_mixer_layer_funcs,
>>> +				       plane->formats, plane->nformats,
>>> +				       plane->type, NULL);
>>> +	if (ret) {
>>> +		dev_err(drm->dev, "Couldn't initialize layer\n");
>>> +		return ERR_PTR(ret);
>>> +	}
>>> +
>>> +	drm_plane_helper_add(&layer->plane,
>>> +			     &sun8i_mixer_layer_helper_funcs);
>>> +	layer->mixer = mixer;
>>> +
>>> +	return layer;
>>> +}
>>> +
>>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>>> +				     struct sunxi_engine *engine)
>>> +{
>>> +	struct drm_plane **planes;
>>> +	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
>>> +	int i;
>>> +
>>> +	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 1,
>>> +			      sizeof(*planes), GFP_KERNEL);
>>> +	if (!planes)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
>>> +		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
>>> +		struct sun8i_layer *layer;
>>> +
>>> +		layer = sun8i_layer_init_one(drm, mixer, plane);
>>> +		if (IS_ERR(layer)) {
>>> +			dev_err(drm->dev, "Couldn't initialize %s plane\n",
>>> +				i ? "overlay" : "primary");
>>> +			return ERR_CAST(layer);
>>> +		};
>>> +
>>> +		layer->id = i;
>>> +		planes[i] = &layer->plane;
>>> +	};
>>> +
>>> +	return planes;
>>> +}
>>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h 
>>> b/drivers/gpu/drm/sun4i/sun8i_layer.h
>>> new file mode 100644
>>> index 000000000000..e5eccd27cff0
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
>>> @@ -0,0 +1,36 @@
>>> +/*
>>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>>> + *
>>> + * Based on sun4i_layer.h, which is:
>>> + *   Copyright (C) 2015 Free Electrons
>>> + *   Copyright (C) 2015 NextThing Co
>>> + *
>>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>>> + *
>>> + * 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.
>>> + */
>>> +
>>> +#ifndef _SUN8I_LAYER_H_
>>> +#define _SUN8I_LAYER_H_
>>> +
>>> +struct sunxi_engine;
>>> +
>>> +struct sun8i_layer {
>>> +	struct drm_plane	plane;
>>> +	struct sun4i_drv	*drv;
>>> +	struct sun8i_mixer	*mixer;
>>> +	int			id;
>>> +};
>>> +
>>> +static inline struct sun8i_layer *
>>> +plane_to_sun8i_layer(struct drm_plane *plane)
>>> +{
>>> +	return container_of(plane, struct sun8i_layer, plane);
>>> +}
>>> +
>>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>>> +				     struct sunxi_engine *engine);
>>> +#endif /* _SUN8I_LAYER_H_ */
>>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
>>> b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>>> new file mode 100644
>>> index 000000000000..e216b84d5bb2
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>>> @@ -0,0 +1,394 @@
>>> +/*
>>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>>> + *
>>> + * Based on sun4i_backend.c, which is:
>>> + *   Copyright (C) 2015 Free Electrons
>>> + *   Copyright (C) 2015 NextThing Co
>>> + *
>>> + * 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.
>>> + */
>>> +
>>> +#include <drm/drmP.h>
>>> +#include <drm/drm_atomic_helper.h>
>>> +#include <drm/drm_crtc.h>
>>> +#include <drm/drm_crtc_helper.h>
>>> +#include <drm/drm_fb_cma_helper.h>
>>> +#include <drm/drm_gem_cma_helper.h>
>>> +#include <drm/drm_plane_helper.h>
>>> +
>>> +#include <linux/component.h>
>>> +#include <linux/dma-mapping.h>
>>> +#include <linux/reset.h>
>>> +#include <linux/of_device.h>
>>> +
>>> +#include "sun4i_drv.h"
>>> +#include "sun8i_mixer.h"
>>> +#include "sun8i_layer.h"
>>> +#include "sunxi_engine.h"
>>> +
>>> +void sun8i_mixer_commit(struct sunxi_engine *engine)
>>> +{
>>> +	DRM_DEBUG_DRIVER("Committing changes\n");
>>> +
>>> +	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
>>> +		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>>> +}
>> 
>> This function can be static
>> 
>>> +
>>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>>> +				int layer, bool enable)
>>> +{
>>> +	u32 val;
>>> +	/* Currently the first UI channel is used */
>>> +	int chan = mixer->cfg->vi_num;
>>> +
>>> +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
>>> +
>>> +	if (enable)
>>> +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>>> +	else
>>> +		val = 0;
>>> +
>>> +	regmap_update_bits(mixer->engine.regs,
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>>> +
>>> +	/* Set the alpha configuration */
>>> +	regmap_update_bits(mixer->engine.regs,
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>>> +	regmap_update_bits(mixer->engine.regs,
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>>> +}
>> 
>> This one too.
> 
> It's called from sun8i_layer.c, so it cannot be static.
> 
>> 
>>> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
>>> +					     u32 format, u32 *mode)
>>> +{
>>> +	switch (format) {
>>> +	case DRM_FORMAT_XRGB8888:
>>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
>>> +		break;
>>> +
>>> +	case DRM_FORMAT_RGB888:
>>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
>>> +		break;
>>> +
>>> +	default:
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>>> +				     int layer, struct drm_plane *plane)
>>> +{
>>> +	struct drm_plane_state *state = plane->state;
>>> +	struct drm_framebuffer *fb = state->fb;
>>> +	/* Currently the first UI channel is used */
>>> +	int chan = mixer->cfg->vi_num;
>>> +
>>> +	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>>> +
>>> +	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>>> +		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: 
>>> %u\n",
>>> +				 state->crtc_w, state->crtc_h);
>>> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE,
>>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>>> +					      state->crtc_h));
>>> +		DRM_DEBUG_DRIVER("Updating blender size\n");
>>> +		regmap_write(mixer->engine.regs,
>>> +			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
>>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>>> +					      state->crtc_h));
>>> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
>>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>>> +					      state->crtc_h));
>>> +		DRM_DEBUG_DRIVER("Updating channel size\n");
>>> +		regmap_write(mixer->engine.regs,
>>> +			     SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
>>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>>> +					      state->crtc_h));
>>> +	}
>>> +
>>> +	/* Set the line width */
>>> +	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
>>> +	regmap_write(mixer->engine.regs,
>>> +		     SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
>>> +		     fb->pitches[0]);
>>> +
>>> +	/* Set height and width */
>>> +	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>>> +			 state->crtc_w, state->crtc_h);
>>> +	regmap_write(mixer->engine.regs,
>>> +		     SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
>>> +		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
>>> +
>>> +	/* Set base coordinates */
>>> +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>>> +			 state->crtc_x, state->crtc_y);
>>> +	regmap_write(mixer->engine.regs,
>>> +		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
>>> +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
>> 
>> X and Y are fixed point numbers. You want to keep only the higher 16
>> bits there.
> 
> Do you mean "lower 16 bits"? Thus should I (x & 0xffff) or ((u16)x) ?

Oh sorry, it's 16.16 ...

I'm misled by the sun4i_backend driver.

May I soon send out a patch to fix the sun4i_backend?

> 
> P.S. The negative coordinates are broken, how should I deal with it? or
> is the coordinates promised to be not negative?
> 
>> 
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>>> +				       int layer, struct drm_plane *plane)
>>> +{
>>> +	struct drm_plane_state *state = plane->state;
>>> +	struct drm_framebuffer *fb = state->fb;
>>> +	bool interlaced = false;
>>> +	u32 val;
>>> +	/* Currently the first UI channel is used */
>>> +	int chan = mixer->cfg->vi_num;
>>> +	int ret;
>>> +
>>> +	if (plane->state->crtc)
>>> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
>>> +			& DRM_MODE_FLAG_INTERLACE;
>>> +
>>> +	regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTCTL,
>>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
>>> +			   interlaced ?
>>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
>>> +
>>> +	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
>>> +			 interlaced ? "on" : "off");
>>> +
>>> +	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
>>> +						&val);
>>> +	if (ret) {
>>> +		DRM_DEBUG_DRIVER("Invalid format\n");
>>> +		return ret;
>>> +	}
>>> +
>>> +	regmap_update_bits(mixer->engine.regs,
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>>> +				      int layer, struct drm_plane *plane)
>>> +{
>>> +	struct drm_plane_state *state = plane->state;
>>> +	struct drm_framebuffer *fb = state->fb;
>>> +	struct drm_gem_cma_object *gem;
>>> +	dma_addr_t paddr;
>>> +	/* Currently the first UI channel is used */
>>> +	int chan = mixer->cfg->vi_num;
>>> +	int bpp;
>>> +
>>> +	/* Get the physical address of the buffer in memory */
>>> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>>> +
>>> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
>>> +
>>> +	/* Compute the start of the displayed memory */
>>> +	bpp = fb->format->cpp[0];
>>> +	paddr = gem->paddr + fb->offsets[0];
>>> +	paddr += (state->src_x >> 16) * bpp;
>>> +	paddr += (state->src_y >> 16) * fb->pitches[0];
>>> +
>>> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
>>> +
>>> +	regmap_write(mixer->engine.regs,
>>> +		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
>>> +		     lower_32_bits(paddr));
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static const struct sunxi_engine_ops sun8i_engine_ops = {
>>> +	.commit		= sun8i_mixer_commit,
>>> +	.layers_init	= sun8i_layers_init,
>>> +};
>>> +
>>> +static struct regmap_config sun8i_mixer_regmap_config = {
>>> +	.reg_bits	= 32,
>>> +	.val_bits	= 32,
>>> +	.reg_stride	= 4,
>>> +	.max_register	= 0xbfffc, /* guessed */
>>> +};
>>> +
>>> +static int sun8i_mixer_bind(struct device *dev, struct device 
>>> *master,
>>> +			      void *data)
>>> +{
>>> +	struct platform_device *pdev = to_platform_device(dev);
>>> +	struct drm_device *drm = data;
>>> +	struct sun4i_drv *drv = drm->dev_private;
>>> +	struct sun8i_mixer *mixer;
>>> +	struct resource *res;
>>> +	void __iomem *regs;
>>> +	int i, ret;
>>> +
>>> +	/*
>>> +	 * The mixer uses single 32-bit register to store memory
>>> +	 * addresses, so that it cannot deal with 64-bit memory
>>> +	 * addresses.
>>> +	 * Restrict the DMA mask so that the mixer won't be
>>> +	 * allocated some memory that is too high.
>>> +	 */
>>> +	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
>>> +	if (ret) {
>>> +		dev_err(dev, "Cannot do 32-bit DMA.\n");
>>> +		return ret;
>>> +	}
>>> +
>>> +	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
>>> +	if (!mixer)
>>> +		return -ENOMEM;
>>> +	dev_set_drvdata(dev, mixer);
>>> +	mixer->engine.ops = &sun8i_engine_ops;
>>> +	mixer->engine.node = dev->of_node;
>>> +
>>> +	mixer->cfg = of_device_get_match_data(dev);
>>> +	if (!mixer->cfg)
>>> +		return -EINVAL;
>>> +
>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +	regs = devm_ioremap_resource(dev, res);
>>> +	if (IS_ERR(regs))
>>> +		return PTR_ERR(regs);
>>> +
>>> +	mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
>>> +						   &sun8i_mixer_regmap_config);
>>> +	if (IS_ERR(mixer->engine.regs)) {
>>> +		dev_err(dev, "Couldn't create the mixer regmap\n");
>>> +		return PTR_ERR(mixer->engine.regs);
>>> +	}
>>> +
>>> +	mixer->reset = devm_reset_control_get(dev, NULL);
>>> +	if (IS_ERR(mixer->reset)) {
>>> +		dev_err(dev, "Couldn't get our reset line\n");
>>> +		return PTR_ERR(mixer->reset);
>>> +	}
>>> +
>>> +	ret = reset_control_deassert(mixer->reset);
>>> +	if (ret) {
>>> +		dev_err(dev, "Couldn't deassert our reset line\n");
>>> +		return ret;
>>> +	}
>>> +
>>> +	mixer->bus_clk = devm_clk_get(dev, "bus");
>>> +	if (IS_ERR(mixer->bus_clk)) {
>>> +		dev_err(dev, "Couldn't get the mixer bus clock\n");
>>> +		ret = PTR_ERR(mixer->bus_clk);
>>> +		goto err_assert_reset;
>>> +	}
>>> +	clk_prepare_enable(mixer->bus_clk);
>>> +
>>> +	mixer->mod_clk = devm_clk_get(dev, "mod");
>>> +	if (IS_ERR(mixer->mod_clk)) {
>>> +		dev_err(dev, "Couldn't get the mixer module clock\n");
>>> +		ret = PTR_ERR(mixer->mod_clk);
>>> +		goto err_disable_bus_clk;
>>> +	}
>>> +	clk_prepare_enable(mixer->mod_clk);
>>> +
>>> +	list_add_tail(&mixer->engine.list, &drv->engine_list);
>> 
>> You didn't call INIT_LIST_HEAD on that list.
>> 
>>> +
>>> +	/* Reset the registers */
>>> +	for (i = 0x0; i < 0x20000; i += 4)
>>> +		regmap_write(mixer->engine.regs, i, 0);
>>> +
>>> +	/* Enable the mixer */
>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
>>> +		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
>>> +
>>> +	/* Initialize blender */
>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
>>> +		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
>>> +		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
>>> +		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(0),
>>> +		     SUN8I_MIXER_BLEND_MODE_DEF);
>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_CK_CTL,
>>> +		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
>>> +
>>> +	regmap_write(mixer->engine.regs,
>>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
>>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
>>> +
>>> +	/* Select the first UI channel */
>>> +	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
>>> +			 mixer->cfg->vi_num);
>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE,
>>> +		     mixer->cfg->vi_num);
>>> +
>>> +	return 0;
>>> +
>>> +	clk_disable_unprepare(mixer->mod_clk);
>> 
>> This line cannot be reached.
>> 
>> Maxime

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

* Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-04 16:57       ` icenowy
@ 2017-05-04 17:14         ` icenowy
  0 siblings, 0 replies; 37+ messages in thread
From: icenowy @ 2017-05-04 17:14 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

在 2017-05-05 00:57,icenowy@aosc.io 写道:
> 在 2017-05-05 00:50,icenowy@aosc.io 写道:
>> 在 2017-05-04 21:05,Maxime Ripard 写道:
>>> On Thu, May 04, 2017 at 07:48:53PM +0800, Icenowy Zheng wrote:
>>>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which 
>>>> comes
>>>> with mixers to do graphic processing and feed data to TCON, like the 
>>>> old
>>>> backends and frontends.
>>>> 
>>>> Add support for the mixer on Allwinner V3s SoC; it's the simplest 
>>>> one.
>>>> 
>>>> Currently a lot of functions are still missing -- more 
>>>> investigations
>>>> are needed to gain enough information for them.
>>>> 
>>>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>>>> ---
>>>> Changes in v6:
>>>> - Rebased on wens's multi-pipeline patchset.
>>>> Changes in v5:
>>>> - Changed some code alignment.
>>>> - Request real 32-bit DMA (prepare for 64-bit SoCs).
>>>> Changes in v4:
>>>> - Killed some dead code according to Jernej.
>>>> 
>>>>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>>>>  drivers/gpu/drm/sun4i/Makefile      |   3 +
>>>>  drivers/gpu/drm/sun4i/sun8i_layer.c | 140 +++++++++++++
>>>>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>>>>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 394 
>>>> ++++++++++++++++++++++++++++++++++++
>>>>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 137 +++++++++++++
>>>>  6 files changed, 720 insertions(+)
>>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>>>> 
>>>> diff --git a/drivers/gpu/drm/sun4i/Kconfig 
>>>> b/drivers/gpu/drm/sun4i/Kconfig
>>>> index 5a8227f37cc4..15557484520d 100644
>>>> --- a/drivers/gpu/drm/sun4i/Kconfig
>>>> +++ b/drivers/gpu/drm/sun4i/Kconfig
>>>> @@ -22,3 +22,13 @@ config DRM_SUN4I_BACKEND
>>>>  	  original Allwinner Display Engine, which has a backend to
>>>>  	  do some alpha blending and feed graphics to TCON. If M is
>>>>  	  selected the module will be called sun4i-backend.
>>>> +
>>>> +config DRM_SUN4I_SUN8I_MIXER
>>> 
>>> DRM_SUN8I_MIXER?
>>> 
>>>> +	tristate "Support for Allwinner Display Engine 2.0 Mixer"
>>>> +	depends on DRM_SUN4I
>>>> +	default MACH_SUN8I
>>>> +	help
>>>> +	  Choose this option if you have an Allwinner SoC with the
>>>> +	  Allwinner Display Engine 2.0, which has a mixer to do some
>>>> +	  graphics mixture and feed graphics to TCON, If M is
>>>> +	  selected the module will be called sun8i-mixer.
>>>> diff --git a/drivers/gpu/drm/sun4i/Makefile 
>>>> b/drivers/gpu/drm/sun4i/Makefile
>>>> index a08df56759e3..a876c6b3027c 100644
>>>> --- a/drivers/gpu/drm/sun4i/Makefile
>>>> +++ b/drivers/gpu/drm/sun4i/Makefile
>>>> @@ -8,7 +8,10 @@ sun4i-tcon-y += sun4i_crtc.o
>>>> 
>>>>  sun4i-backend-y += sun4i_backend.o sun4i_layer.o
>>>> 
>>>> +sun8i-mixer-y += sun8i_mixer.o sun8i_layer.o
>>>> +
>>>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o sun4i-tcon.o
>>>>  obj-$(CONFIG_DRM_SUN4I_BACKEND)		+= sun4i-backend.o
>>>> +obj-$(CONFIG_DRM_SUN4I_SUN8I_MIXER)	+= sun8i-mixer.o
>>>>  obj-$(CONFIG_DRM_SUN4I)		+= sun6i_drc.o
>>>>  obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
>>>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.c 
>>>> b/drivers/gpu/drm/sun4i/sun8i_layer.c
>>>> new file mode 100644
>>>> index 000000000000..48f33d8e013b
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.c
>>>> @@ -0,0 +1,140 @@
>>>> +/*
>>>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>>>> + *
>>>> + * Based on sun4i_layer.h, which is:
>>>> + *   Copyright (C) 2015 Free Electrons
>>>> + *   Copyright (C) 2015 NextThing Co
>>>> + *
>>>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>>>> + *
>>>> + * 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.
>>>> + */
>>>> +
>>>> +#include <drm/drm_atomic_helper.h>
>>>> +#include <drm/drm_plane_helper.h>
>>>> +#include <drm/drmP.h>
>>>> +
>>>> +#include "sun8i_layer.h"
>>>> +#include "sun8i_mixer.h"
>>>> +
>>>> +struct sun8i_plane_desc {
>>>> +	       enum drm_plane_type     type;
>>>> +	       const uint32_t          *formats;
>>>> +	       uint32_t                nformats;
>>>> +};
>>>> +
>>>> +static int sun8i_mixer_layer_atomic_check(struct drm_plane *plane,
>>>> +					    struct drm_plane_state *state)
>>>> +{
>>>> +	return 0;
>>>> +}
>>> 
>>> This isn't needed.
>>> 
>>>> +static void sun8i_mixer_layer_atomic_disable(struct drm_plane 
>>>> *plane,
>>>> +					       struct drm_plane_state *old_state)
>>>> +{
>>>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>>>> +	struct sun8i_mixer *mixer = layer->mixer;
>>>> +
>>>> +	sun8i_mixer_layer_enable(mixer, layer->id, false);
>>>> +}
>>>> +
>>>> +static void sun8i_mixer_layer_atomic_update(struct drm_plane 
>>>> *plane,
>>>> +					      struct drm_plane_state *old_state)
>>>> +{
>>>> +	struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
>>>> +	struct sun8i_mixer *mixer = layer->mixer;
>>>> +
>>>> +	sun8i_mixer_update_layer_coord(mixer, layer->id, plane);
>>>> +	sun8i_mixer_update_layer_formats(mixer, layer->id, plane);
>>>> +	sun8i_mixer_update_layer_buffer(mixer, layer->id, plane);
>>>> +	sun8i_mixer_layer_enable(mixer, layer->id, true);
>>>> +}
>>>> +
>>>> +static struct drm_plane_helper_funcs sun8i_mixer_layer_helper_funcs 
>>>> = {
>>>> +	.atomic_check	= sun8i_mixer_layer_atomic_check,
>>>> +	.atomic_disable	= sun8i_mixer_layer_atomic_disable,
>>>> +	.atomic_update	= sun8i_mixer_layer_atomic_update,
>>>> +};
>>>> +
>>>> +static const struct drm_plane_funcs sun8i_mixer_layer_funcs = {
>>>> +	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
>>>> +	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
>>>> +	.destroy		= drm_plane_cleanup,
>>>> +	.disable_plane		= drm_atomic_helper_disable_plane,
>>>> +	.reset			= drm_atomic_helper_plane_reset,
>>>> +	.update_plane		= drm_atomic_helper_update_plane,
>>>> +};
>>>> +
>>>> +static const uint32_t sun8i_mixer_layer_formats[] = {
>>>> +	DRM_FORMAT_RGB888,
>>>> +	DRM_FORMAT_XRGB8888,
>>>> +};
>>>> +
>>>> +static const struct sun8i_plane_desc sun8i_mixer_planes[] = {
>>>> +	{
>>>> +		.type = DRM_PLANE_TYPE_PRIMARY,
>>>> +		.formats = sun8i_mixer_layer_formats,
>>>> +		.nformats = ARRAY_SIZE(sun8i_mixer_layer_formats),
>>>> +	},
>>>> +};
>>>> +
>>>> +static struct sun8i_layer *sun8i_layer_init_one(struct drm_device 
>>>> *drm,
>>>> +						struct sun8i_mixer *mixer,
>>>> +						const struct sun8i_plane_desc *plane)
>>>> +{
>>>> +	struct sun8i_layer *layer;
>>>> +	int ret;
>>>> +
>>>> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
>>>> +	if (!layer)
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +
>>>> +	/* possible crtcs are set later */
>>>> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
>>>> +				       &sun8i_mixer_layer_funcs,
>>>> +				       plane->formats, plane->nformats,
>>>> +				       plane->type, NULL);
>>>> +	if (ret) {
>>>> +		dev_err(drm->dev, "Couldn't initialize layer\n");
>>>> +		return ERR_PTR(ret);
>>>> +	}
>>>> +
>>>> +	drm_plane_helper_add(&layer->plane,
>>>> +			     &sun8i_mixer_layer_helper_funcs);
>>>> +	layer->mixer = mixer;
>>>> +
>>>> +	return layer;
>>>> +}
>>>> +
>>>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>>>> +				     struct sunxi_engine *engine)
>>>> +{
>>>> +	struct drm_plane **planes;
>>>> +	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
>>>> +	int i;
>>>> +
>>>> +	planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun8i_mixer_planes) + 
>>>> 1,
>>>> +			      sizeof(*planes), GFP_KERNEL);
>>>> +	if (!planes)
>>>> +		return ERR_PTR(-ENOMEM);
>>>> +
>>>> +	for (i = 0; i < ARRAY_SIZE(sun8i_mixer_planes); i++) {
>>>> +		const struct sun8i_plane_desc *plane = &sun8i_mixer_planes[i];
>>>> +		struct sun8i_layer *layer;
>>>> +
>>>> +		layer = sun8i_layer_init_one(drm, mixer, plane);
>>>> +		if (IS_ERR(layer)) {
>>>> +			dev_err(drm->dev, "Couldn't initialize %s plane\n",
>>>> +				i ? "overlay" : "primary");
>>>> +			return ERR_CAST(layer);
>>>> +		};
>>>> +
>>>> +		layer->id = i;
>>>> +		planes[i] = &layer->plane;
>>>> +	};
>>>> +
>>>> +	return planes;
>>>> +}
>>>> diff --git a/drivers/gpu/drm/sun4i/sun8i_layer.h 
>>>> b/drivers/gpu/drm/sun4i/sun8i_layer.h
>>>> new file mode 100644
>>>> index 000000000000..e5eccd27cff0
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/sun4i/sun8i_layer.h
>>>> @@ -0,0 +1,36 @@
>>>> +/*
>>>> + * Copyright (C) Icenowy Zheng <icenowy@aosc.io>
>>>> + *
>>>> + * Based on sun4i_layer.h, which is:
>>>> + *   Copyright (C) 2015 Free Electrons
>>>> + *   Copyright (C) 2015 NextThing Co
>>>> + *
>>>> + *   Maxime Ripard <maxime.ripard@free-electrons.com>
>>>> + *
>>>> + * 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.
>>>> + */
>>>> +
>>>> +#ifndef _SUN8I_LAYER_H_
>>>> +#define _SUN8I_LAYER_H_
>>>> +
>>>> +struct sunxi_engine;
>>>> +
>>>> +struct sun8i_layer {
>>>> +	struct drm_plane	plane;
>>>> +	struct sun4i_drv	*drv;
>>>> +	struct sun8i_mixer	*mixer;
>>>> +	int			id;
>>>> +};
>>>> +
>>>> +static inline struct sun8i_layer *
>>>> +plane_to_sun8i_layer(struct drm_plane *plane)
>>>> +{
>>>> +	return container_of(plane, struct sun8i_layer, plane);
>>>> +}
>>>> +
>>>> +struct drm_plane **sun8i_layers_init(struct drm_device *drm,
>>>> +				     struct sunxi_engine *engine);
>>>> +#endif /* _SUN8I_LAYER_H_ */
>>>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
>>>> b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>>>> new file mode 100644
>>>> index 000000000000..e216b84d5bb2
>>>> --- /dev/null
>>>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>>>> @@ -0,0 +1,394 @@
>>>> +/*
>>>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>>>> + *
>>>> + * Based on sun4i_backend.c, which is:
>>>> + *   Copyright (C) 2015 Free Electrons
>>>> + *   Copyright (C) 2015 NextThing Co
>>>> + *
>>>> + * 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.
>>>> + */
>>>> +
>>>> +#include <drm/drmP.h>
>>>> +#include <drm/drm_atomic_helper.h>
>>>> +#include <drm/drm_crtc.h>
>>>> +#include <drm/drm_crtc_helper.h>
>>>> +#include <drm/drm_fb_cma_helper.h>
>>>> +#include <drm/drm_gem_cma_helper.h>
>>>> +#include <drm/drm_plane_helper.h>
>>>> +
>>>> +#include <linux/component.h>
>>>> +#include <linux/dma-mapping.h>
>>>> +#include <linux/reset.h>
>>>> +#include <linux/of_device.h>
>>>> +
>>>> +#include "sun4i_drv.h"
>>>> +#include "sun8i_mixer.h"
>>>> +#include "sun8i_layer.h"
>>>> +#include "sunxi_engine.h"
>>>> +
>>>> +void sun8i_mixer_commit(struct sunxi_engine *engine)
>>>> +{
>>>> +	DRM_DEBUG_DRIVER("Committing changes\n");
>>>> +
>>>> +	regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
>>>> +		     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>>>> +}
>>> 
>>> This function can be static
>>> 
>>>> +
>>>> +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>>>> +				int layer, bool enable)
>>>> +{
>>>> +	u32 val;
>>>> +	/* Currently the first UI channel is used */
>>>> +	int chan = mixer->cfg->vi_num;
>>>> +
>>>> +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, 
>>>> chan);
>>>> +
>>>> +	if (enable)
>>>> +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>>>> +	else
>>>> +		val = 0;
>>>> +
>>>> +	regmap_update_bits(mixer->engine.regs,
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>>>> +
>>>> +	/* Set the alpha configuration */
>>>> +	regmap_update_bits(mixer->engine.regs,
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>>>> +	regmap_update_bits(mixer->engine.regs,
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>>>> +}
>>> 
>>> This one too.
>> 
>> It's called from sun8i_layer.c, so it cannot be static.
>> 
>>> 
>>>> +static int sun8i_mixer_drm_format_to_layer(struct drm_plane *plane,
>>>> +					     u32 format, u32 *mode)
>>>> +{
>>>> +	switch (format) {
>>>> +	case DRM_FORMAT_XRGB8888:
>>>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_XRGB8888;
>>>> +		break;
>>>> +
>>>> +	case DRM_FORMAT_RGB888:
>>>> +		*mode = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_RGB888;
>>>> +		break;
>>>> +
>>>> +	default:
>>>> +		return -EINVAL;
>>>> +	}
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +int sun8i_mixer_update_layer_coord(struct sun8i_mixer *mixer,
>>>> +				     int layer, struct drm_plane *plane)
>>>> +{
>>>> +	struct drm_plane_state *state = plane->state;
>>>> +	struct drm_framebuffer *fb = state->fb;
>>>> +	/* Currently the first UI channel is used */
>>>> +	int chan = mixer->cfg->vi_num;
>>>> +
>>>> +	DRM_DEBUG_DRIVER("Updating layer %d\n", layer);
>>>> +
>>>> +	if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>>>> +		DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: 
>>>> %u\n",
>>>> +				 state->crtc_w, state->crtc_h);
>>>> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE,
>>>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>>>> +					      state->crtc_h));
>>>> +		DRM_DEBUG_DRIVER("Updating blender size\n");
>>>> +		regmap_write(mixer->engine.regs,
>>>> +			     SUN8I_MIXER_BLEND_ATTR_INSIZE(0),
>>>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>>>> +					      state->crtc_h));
>>>> +		regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTSIZE,
>>>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>>>> +					      state->crtc_h));
>>>> +		DRM_DEBUG_DRIVER("Updating channel size\n");
>>>> +		regmap_write(mixer->engine.regs,
>>>> +			     SUN8I_MIXER_CHAN_UI_OVL_SIZE(chan),
>>>> +			     SUN8I_MIXER_SIZE(state->crtc_w,
>>>> +					      state->crtc_h));
>>>> +	}
>>>> +
>>>> +	/* Set the line width */
>>>> +	DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
>>>> +	regmap_write(mixer->engine.regs,
>>>> +		     SUN8I_MIXER_CHAN_UI_LAYER_PITCH(chan, layer),
>>>> +		     fb->pitches[0]);
>>>> +
>>>> +	/* Set height and width */
>>>> +	DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>>>> +			 state->crtc_w, state->crtc_h);
>>>> +	regmap_write(mixer->engine.regs,
>>>> +		     SUN8I_MIXER_CHAN_UI_LAYER_SIZE(chan, layer),
>>>> +		     SUN8I_MIXER_SIZE(state->crtc_w, state->crtc_h));
>>>> +
>>>> +	/* Set base coordinates */
>>>> +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>>>> +			 state->crtc_x, state->crtc_y);
>>>> +	regmap_write(mixer->engine.regs,
>>>> +		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
>>>> +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
>>> 
>>> X and Y are fixed point numbers. You want to keep only the higher 16
>>> bits there.
>> 
>> Do you mean "lower 16 bits"? Thus should I (x & 0xffff) or ((u16)x) ?
> 
> Oh sorry, it's 16.16 ...

Went wrong again... it's surely not 16.16 .
crtc_* is integer, and src_* is 16.16 .

> 
> I'm misled by the sun4i_backend driver.
> 
> May I soon send out a patch to fix the sun4i_backend?
> 
>> 
>> P.S. The negative coordinates are broken, how should I deal with it? 
>> or
>> is the coordinates promised to be not negative?

But surely we should deal with the failure of negative values.

I think I should hack the update_layer_buffer function to deal with the
failure of negative coordinates. -- The status of negative coordinate is
that the display size is croped, but at (0,0) the pixel displayed is 
still
the original (0,0), not the (-crtc_x, -crtc_y).

>> 
>>> 
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +int sun8i_mixer_update_layer_formats(struct sun8i_mixer *mixer,
>>>> +				       int layer, struct drm_plane *plane)
>>>> +{
>>>> +	struct drm_plane_state *state = plane->state;
>>>> +	struct drm_framebuffer *fb = state->fb;
>>>> +	bool interlaced = false;
>>>> +	u32 val;
>>>> +	/* Currently the first UI channel is used */
>>>> +	int chan = mixer->cfg->vi_num;
>>>> +	int ret;
>>>> +
>>>> +	if (plane->state->crtc)
>>>> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
>>>> +			& DRM_MODE_FLAG_INTERLACE;
>>>> +
>>>> +	regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_OUTCTL,
>>>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED,
>>>> +			   interlaced ?
>>>> +			   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED : 0);
>>>> +
>>>> +	DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
>>>> +			 interlaced ? "on" : "off");
>>>> +
>>>> +	ret = sun8i_mixer_drm_format_to_layer(plane, fb->format->format,
>>>> +						&val);
>>>> +	if (ret) {
>>>> +		DRM_DEBUG_DRIVER("Invalid format\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	regmap_update_bits(mixer->engine.regs,
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>>>> +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +int sun8i_mixer_update_layer_buffer(struct sun8i_mixer *mixer,
>>>> +				      int layer, struct drm_plane *plane)
>>>> +{
>>>> +	struct drm_plane_state *state = plane->state;
>>>> +	struct drm_framebuffer *fb = state->fb;
>>>> +	struct drm_gem_cma_object *gem;
>>>> +	dma_addr_t paddr;
>>>> +	/* Currently the first UI channel is used */
>>>> +	int chan = mixer->cfg->vi_num;
>>>> +	int bpp;
>>>> +
>>>> +	/* Get the physical address of the buffer in memory */
>>>> +	gem = drm_fb_cma_get_gem_obj(fb, 0);
>>>> +
>>>> +	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);
>>>> +
>>>> +	/* Compute the start of the displayed memory */
>>>> +	bpp = fb->format->cpp[0];
>>>> +	paddr = gem->paddr + fb->offsets[0];
>>>> +	paddr += (state->src_x >> 16) * bpp;
>>>> +	paddr += (state->src_y >> 16) * fb->pitches[0];
>>>> +
>>>> +	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);
>>>> +
>>>> +	regmap_write(mixer->engine.regs,
>>>> +		     SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(chan, layer),
>>>> +		     lower_32_bits(paddr));
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static const struct sunxi_engine_ops sun8i_engine_ops = {
>>>> +	.commit		= sun8i_mixer_commit,
>>>> +	.layers_init	= sun8i_layers_init,
>>>> +};
>>>> +
>>>> +static struct regmap_config sun8i_mixer_regmap_config = {
>>>> +	.reg_bits	= 32,
>>>> +	.val_bits	= 32,
>>>> +	.reg_stride	= 4,
>>>> +	.max_register	= 0xbfffc, /* guessed */
>>>> +};
>>>> +
>>>> +static int sun8i_mixer_bind(struct device *dev, struct device 
>>>> *master,
>>>> +			      void *data)
>>>> +{
>>>> +	struct platform_device *pdev = to_platform_device(dev);
>>>> +	struct drm_device *drm = data;
>>>> +	struct sun4i_drv *drv = drm->dev_private;
>>>> +	struct sun8i_mixer *mixer;
>>>> +	struct resource *res;
>>>> +	void __iomem *regs;
>>>> +	int i, ret;
>>>> +
>>>> +	/*
>>>> +	 * The mixer uses single 32-bit register to store memory
>>>> +	 * addresses, so that it cannot deal with 64-bit memory
>>>> +	 * addresses.
>>>> +	 * Restrict the DMA mask so that the mixer won't be
>>>> +	 * allocated some memory that is too high.
>>>> +	 */
>>>> +	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
>>>> +	if (ret) {
>>>> +		dev_err(dev, "Cannot do 32-bit DMA.\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
>>>> +	if (!mixer)
>>>> +		return -ENOMEM;
>>>> +	dev_set_drvdata(dev, mixer);
>>>> +	mixer->engine.ops = &sun8i_engine_ops;
>>>> +	mixer->engine.node = dev->of_node;
>>>> +
>>>> +	mixer->cfg = of_device_get_match_data(dev);
>>>> +	if (!mixer->cfg)
>>>> +		return -EINVAL;
>>>> +
>>>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>>> +	regs = devm_ioremap_resource(dev, res);
>>>> +	if (IS_ERR(regs))
>>>> +		return PTR_ERR(regs);
>>>> +
>>>> +	mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
>>>> +						   &sun8i_mixer_regmap_config);
>>>> +	if (IS_ERR(mixer->engine.regs)) {
>>>> +		dev_err(dev, "Couldn't create the mixer regmap\n");
>>>> +		return PTR_ERR(mixer->engine.regs);
>>>> +	}
>>>> +
>>>> +	mixer->reset = devm_reset_control_get(dev, NULL);
>>>> +	if (IS_ERR(mixer->reset)) {
>>>> +		dev_err(dev, "Couldn't get our reset line\n");
>>>> +		return PTR_ERR(mixer->reset);
>>>> +	}
>>>> +
>>>> +	ret = reset_control_deassert(mixer->reset);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "Couldn't deassert our reset line\n");
>>>> +		return ret;
>>>> +	}
>>>> +
>>>> +	mixer->bus_clk = devm_clk_get(dev, "bus");
>>>> +	if (IS_ERR(mixer->bus_clk)) {
>>>> +		dev_err(dev, "Couldn't get the mixer bus clock\n");
>>>> +		ret = PTR_ERR(mixer->bus_clk);
>>>> +		goto err_assert_reset;
>>>> +	}
>>>> +	clk_prepare_enable(mixer->bus_clk);
>>>> +
>>>> +	mixer->mod_clk = devm_clk_get(dev, "mod");
>>>> +	if (IS_ERR(mixer->mod_clk)) {
>>>> +		dev_err(dev, "Couldn't get the mixer module clock\n");
>>>> +		ret = PTR_ERR(mixer->mod_clk);
>>>> +		goto err_disable_bus_clk;
>>>> +	}
>>>> +	clk_prepare_enable(mixer->mod_clk);
>>>> +
>>>> +	list_add_tail(&mixer->engine.list, &drv->engine_list);
>>> 
>>> You didn't call INIT_LIST_HEAD on that list.
>>> 
>>>> +
>>>> +	/* Reset the registers */
>>>> +	for (i = 0x0; i < 0x20000; i += 4)
>>>> +		regmap_write(mixer->engine.regs, i, 0);
>>>> +
>>>> +	/* Enable the mixer */
>>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
>>>> +		     SUN8I_MIXER_GLOBAL_CTL_RT_EN);
>>>> +
>>>> +	/* Initialize blender */
>>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_FCOLOR_CTL,
>>>> +		     SUN8I_MIXER_BLEND_FCOLOR_CTL_DEF);
>>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PREMULTIPLY,
>>>> +		     SUN8I_MIXER_BLEND_PREMULTIPLY_DEF);
>>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR,
>>>> +		     SUN8I_MIXER_BLEND_BKCOLOR_DEF);
>>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_MODE(0),
>>>> +		     SUN8I_MIXER_BLEND_MODE_DEF);
>>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_CK_CTL,
>>>> +		     SUN8I_MIXER_BLEND_CK_CTL_DEF);
>>>> +
>>>> +	regmap_write(mixer->engine.regs,
>>>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR(0),
>>>> +		     SUN8I_MIXER_BLEND_ATTR_FCOLOR_DEF);
>>>> +
>>>> +	/* Select the first UI channel */
>>>> +	DRM_DEBUG_DRIVER("Selecting channel %d (first UI channel)\n",
>>>> +			 mixer->cfg->vi_num);
>>>> +	regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE,
>>>> +		     mixer->cfg->vi_num);
>>>> +
>>>> +	return 0;
>>>> +
>>>> +	clk_disable_unprepare(mixer->mod_clk);
>>> 
>>> This line cannot be reached.
>>> 
>>> Maxime

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

* Re: [linux-sunxi] [PATCH v6 05/13] drm/sun4i: abstract a engine type
  2017-05-04 11:48 ` [PATCH v6 05/13] drm/sun4i: abstract a engine type Icenowy Zheng
@ 2017-05-05  2:56   ` Chen-Yu Tsai
  2017-05-05  8:36     ` icenowy
  0 siblings, 1 reply; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  2:56 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Maxime Ripard, Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
> As we are going to add support for the Allwinner DE2 engine in sun4i-drm
> driver, we will finally have two types of display engines -- the DE1
> backend and the DE2 mixer. They both do some display blending and feed
> graphics data to TCON, so I choose to call them both "engine" here.

These engines composite different layers into a final image which is
then sent out to the TCONs. As such, "compositor" would be an accurate
name.

However, "engine" is OK, since Allwinner calls this stuff Display Engine
1.0 and 2.0. Hope there won't be a 3.0 ...

Maybe you should note that in your commit message. That is justifies the name.

>
> Abstract the engine type to a new struct with an ops struct, which contains
> functions that should be called outside the engine-specified code (in
> TCON, CRTC or TV Encoder code).
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
> Changes in v6:
> - Rebased on wens's multi-pipeline patchset.
> - Split out Makefile changes.
> Changes in v5:
> - Really made a sunxi_engine struct type, and moved ops pointer
>   into it.
> - Added checked ops wrappers.
> - Changed the second parameter of layers_init from crtc to engine.
> Changes in v4:
> - Comments to tag the color correction functions as optional.
> - Check before calling the optional functions.
> - Change layers_init to satisfy new PATCH v4 04/11.
>
>  drivers/gpu/drm/sun4i/sun4i_backend.c |  68 ++++++++++++---------
>  drivers/gpu/drm/sun4i/sun4i_backend.h |  17 +++---
>  drivers/gpu/drm/sun4i/sun4i_crtc.c    |  11 ++--
>  drivers/gpu/drm/sun4i/sun4i_crtc.h    |   4 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.c     |   2 +-
>  drivers/gpu/drm/sun4i/sun4i_drv.h     |   2 +-
>  drivers/gpu/drm/sun4i/sun4i_layer.c   |   8 +--
>  drivers/gpu/drm/sun4i/sun4i_layer.h   |   5 +-
>  drivers/gpu/drm/sun4i/sun4i_tcon.c    |  36 ++++++-----
>  drivers/gpu/drm/sun4i/sun4i_tv.c      |   9 ++-
>  drivers/gpu/drm/sun4i/sunxi_engine.h  | 112 ++++++++++++++++++++++++++++++++++
>  11 files changed, 198 insertions(+), 76 deletions(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sunxi_engine.h
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> index e53107418add..611cdcb9c182 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -25,6 +25,8 @@
>
>  #include "sun4i_backend.h"
>  #include "sun4i_drv.h"
> +#include "sun4i_layer.h"
> +#include "sunxi_engine.h"
>
>  static const u32 sunxi_rgb2yuv_coef[12] = {
>         0x00000107, 0x00000204, 0x00000064, 0x00000108,
> @@ -32,41 +34,38 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
>         0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
>  };
>
> -void sun4i_backend_apply_color_correction(struct sun4i_backend *backend)
> +static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine)
>  {
>         int i;
>
>         DRM_DEBUG_DRIVER("Applying RGB to YUV color correction\n");
>
>         /* Set color correction */
> -       regmap_write(backend->regs, SUN4I_BACKEND_OCCTL_REG,
> +       regmap_write(engine->regs, SUN4I_BACKEND_OCCTL_REG,
>                      SUN4I_BACKEND_OCCTL_ENABLE);
>
>         for (i = 0; i < 12; i++)
> -               regmap_write(backend->regs, SUN4I_BACKEND_OCRCOEF_REG(i),
> +               regmap_write(engine->regs, SUN4I_BACKEND_OCRCOEF_REG(i),
>                              sunxi_rgb2yuv_coef[i]);
>  }
> -EXPORT_SYMBOL(sun4i_backend_apply_color_correction);
>
> -void sun4i_backend_disable_color_correction(struct sun4i_backend *backend)
> +static void sun4i_backend_disable_color_correction(struct sunxi_engine *engine)
>  {
>         DRM_DEBUG_DRIVER("Disabling color correction\n");
>
>         /* Disable color correction */
> -       regmap_update_bits(backend->regs, SUN4I_BACKEND_OCCTL_REG,
> +       regmap_update_bits(engine->regs, SUN4I_BACKEND_OCCTL_REG,
>                            SUN4I_BACKEND_OCCTL_ENABLE, 0);
>  }
> -EXPORT_SYMBOL(sun4i_backend_disable_color_correction);
>
> -void sun4i_backend_commit(struct sun4i_backend *backend)
> +static void sun4i_backend_commit(struct sunxi_engine *engine)
>  {
>         DRM_DEBUG_DRIVER("Committing changes\n");
>
> -       regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
> +       regmap_write(engine->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
>                      SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS |
>                      SUN4I_BACKEND_REGBUFFCTL_LOADCTL);
>  }
> -EXPORT_SYMBOL(sun4i_backend_commit);
>
>  void sun4i_backend_layer_enable(struct sun4i_backend *backend,
>                                 int layer, bool enable)
> @@ -81,7 +80,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
>         else
>                 val = 0;
>
> -       regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
> +       regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
>                            SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
>  }
>  EXPORT_SYMBOL(sun4i_backend_layer_enable);
> @@ -144,27 +143,28 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
>         if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>                 DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n",
>                                  state->crtc_w, state->crtc_h);
> -               regmap_write(backend->regs, SUN4I_BACKEND_DISSIZE_REG,
> +               regmap_write(backend->engine.regs, SUN4I_BACKEND_DISSIZE_REG,
>                              SUN4I_BACKEND_DISSIZE(state->crtc_w,
>                                                    state->crtc_h));
>         }
>
>         /* Set the line width */
>         DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8);
> -       regmap_write(backend->regs, SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
> +       regmap_write(backend->engine.regs,
> +                    SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
>                      fb->pitches[0] * 8);
>
>         /* Set height and width */
>         DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>                          state->crtc_w, state->crtc_h);
> -       regmap_write(backend->regs, SUN4I_BACKEND_LAYSIZE_REG(layer),
> +       regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYSIZE_REG(layer),
>                      SUN4I_BACKEND_LAYSIZE(state->crtc_w,
>                                            state->crtc_h));
>
>         /* Set base coordinates */
>         DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>                          state->crtc_x, state->crtc_y);
> -       regmap_write(backend->regs, SUN4I_BACKEND_LAYCOOR_REG(layer),
> +       regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYCOOR_REG(layer),
>                      SUN4I_BACKEND_LAYCOOR(state->crtc_x,
>                                            state->crtc_y));
>
> @@ -185,7 +185,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>                 interlaced = plane->state->crtc->state->adjusted_mode.flags
>                         & DRM_MODE_FLAG_INTERLACE;
>
> -       regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
> +       regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
>                            SUN4I_BACKEND_MODCTL_ITLMOD_EN,
>                            interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0);
>
> @@ -199,7 +199,8 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
>                 return ret;
>         }
>
> -       regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG1(layer),
> +       regmap_update_bits(backend->engine.regs,
> +                          SUN4I_BACKEND_ATTCTL_REG1(layer),
>                            SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
>
>         return 0;
> @@ -232,13 +233,14 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
>         /* Write the 32 lower bits of the address (in bits) */
>         lo_paddr = paddr << 3;
>         DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr);
> -       regmap_write(backend->regs, SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
> +       regmap_write(backend->engine.regs,
> +                    SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
>                      lo_paddr);
>
>         /* And the upper bits */
>         hi_paddr = paddr >> 29;
>         DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr);
> -       regmap_update_bits(backend->regs, SUN4I_BACKEND_LAYFB_H4ADD_REG,
> +       regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_LAYFB_H4ADD_REG,
>                            SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
>                            SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr));
>
> @@ -330,6 +332,13 @@ static int sun4i_backend_of_get_id(struct device_node *node)
>         return ret;
>  }
>
> +static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
> +       .commit                         = sun4i_backend_commit,
> +       .layers_init                    = sun4i_layers_init,
> +       .apply_color_correction         = sun4i_backend_apply_color_correction,
> +       .disable_color_correction       = sun4i_backend_disable_color_correction,
> +};
> +
>  static struct regmap_config sun4i_backend_regmap_config = {
>         .reg_bits       = 32,
>         .val_bits       = 32,
> @@ -353,7 +362,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
>                 return -ENOMEM;
>         dev_set_drvdata(dev, backend);
>
> -       backend->node = dev->of_node;
> +       backend->engine.node = dev->of_node;
> +       backend->engine.ops = &sun4i_backend_engine_ops;
>         backend->id = sun4i_backend_of_get_id(dev->of_node);
>         if (backend->id < 0)
>                 return backend->id;
> @@ -363,11 +373,11 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
>         if (IS_ERR(regs))
>                 return PTR_ERR(regs);
>
> -       backend->regs = devm_regmap_init_mmio(dev, regs,
> -                                             &sun4i_backend_regmap_config);
> -       if (IS_ERR(backend->regs)) {
> +       backend->engine.regs = devm_regmap_init_mmio(dev, regs,
> +                                                    &sun4i_backend_regmap_config);
> +       if (IS_ERR(backend->engine.regs)) {
>                 dev_err(dev, "Couldn't create the backend regmap\n");
> -               return PTR_ERR(backend->regs);
> +               return PTR_ERR(backend->engine.regs);
>         }
>
>         backend->reset = devm_reset_control_get(dev, NULL);
> @@ -415,18 +425,18 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
>                 }
>         }
>
> -       list_add_tail(&backend->list, &drv->backend_list);
> +       list_add_tail(&backend->engine.list, &drv->engine_list);
>
>         /* Reset the registers */
>         for (i = 0x800; i < 0x1000; i += 4)
> -               regmap_write(backend->regs, i, 0);
> +               regmap_write(backend->engine.regs, i, 0);
>
>         /* Disable registers autoloading */
> -       regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
> +       regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG,
>                      SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
>
>         /* Enable the backend */
> -       regmap_write(backend->regs, SUN4I_BACKEND_MODCTL_REG,
> +       regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
>                      SUN4I_BACKEND_MODCTL_DEBE_EN |
>                      SUN4I_BACKEND_MODCTL_START_CTL);
>
> @@ -448,7 +458,7 @@ static void sun4i_backend_unbind(struct device *dev, struct device *master,
>  {
>         struct sun4i_backend *backend = dev_get_drvdata(dev);
>
> -       list_del(&backend->list);
> +       list_del(&backend->engine.list);
>
>         if (of_device_is_compatible(dev->of_node,
>                                     "allwinner,sun8i-a33-display-backend"))
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> index 6327a2985fe6..b022a37e8e5b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -19,6 +19,8 @@
>  #include <linux/regmap.h>
>  #include <linux/reset.h>
>
> +#include "sunxi_engine.h"
> +
>  #define SUN4I_BACKEND_MODCTL_REG               0x800
>  #define SUN4I_BACKEND_MODCTL_LINE_SEL                  BIT(29)
>  #define SUN4I_BACKEND_MODCTL_ITLMOD_EN                 BIT(28)
> @@ -141,8 +143,7 @@
>  #define SUN4I_BACKEND_PIPE_OFF(p)              (0x5000 + (0x400 * (p)))
>
>  struct sun4i_backend {
> -       struct device_node      *node;
> -       struct regmap           *regs;
> +       struct sunxi_engine     engine;
>
>         struct reset_control    *reset;
>
> @@ -154,15 +155,13 @@ struct sun4i_backend {
>         struct reset_control    *sat_reset;
>
>         int                     id;
> -
> -       /* Backend list management */
> -       struct list_head        list;
>  };
>
> -void sun4i_backend_apply_color_correction(struct sun4i_backend *backend);
> -void sun4i_backend_disable_color_correction(struct sun4i_backend *backend);
> -
> -void sun4i_backend_commit(struct sun4i_backend *backend);
> +static inline struct sun4i_backend *
> +engine_to_sun4i_backend(struct sunxi_engine *engine)
> +{
> +       return container_of(engine, struct sun4i_backend, engine);
> +}
>
>  void sun4i_backend_layer_enable(struct sun4i_backend *backend,
>                                 int layer, bool enable);
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> index 708b3543d4e9..f8c70439d1e2 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> @@ -25,10 +25,9 @@
>
>  #include <video/videomode.h>
>
> -#include "sun4i_backend.h"
>  #include "sun4i_crtc.h"
>  #include "sun4i_drv.h"
> -#include "sun4i_layer.h"
> +#include "sunxi_engine.h"
>  #include "sun4i_tcon.h"
>
>  static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
> @@ -56,7 +55,7 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
>
>         DRM_DEBUG_DRIVER("Committing plane changes\n");
>
> -       sun4i_backend_commit(scrtc->backend);
> +       sunxi_engine_commit(scrtc->engine);
>
>         if (event) {
>                 crtc->state->event = NULL;
> @@ -135,7 +134,7 @@ static const struct drm_crtc_funcs sun4i_crtc_funcs = {
>  };
>
>  struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
> -                                  struct sun4i_backend *backend,
> +                                  struct sunxi_engine *engine,
>                                    struct sun4i_tcon *tcon)
>  {
>         struct sun4i_crtc *scrtc;
> @@ -146,11 +145,11 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
>         scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
>         if (!scrtc)
>                 return ERR_PTR(-ENOMEM);
> -       scrtc->backend = backend;
> +       scrtc->engine = engine;
>         scrtc->tcon = tcon;
>
>         /* Create our layers */
> -       planes = sun4i_layers_init(drm, scrtc);
> +       planes = sunxi_engine_layers_init(drm, engine);
>         if (IS_ERR(planes)) {
>                 dev_err(drm->dev, "Couldn't create the planes\n");
>                 return NULL;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h b/drivers/gpu/drm/sun4i/sun4i_crtc.h
> index 4dae3508424a..bf0ce36eb518 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h
> @@ -17,7 +17,7 @@ struct sun4i_crtc {
>         struct drm_crtc                 crtc;
>         struct drm_pending_vblank_event *event;
>
> -       struct sun4i_backend            *backend;
> +       struct sunxi_engine             *engine;
>         struct sun4i_tcon               *tcon;
>  };
>
> @@ -27,7 +27,7 @@ static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
>  }
>
>  struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
> -                                  struct sun4i_backend *backend,
> +                                  struct sunxi_engine *engine,
>                                    struct sun4i_tcon *tcon);
>
>  #endif /* _SUN4I_CRTC_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index 89c51fd6e9af..12ede8682b5c 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -101,7 +101,7 @@ static int sun4i_drv_bind(struct device *dev)
>                 goto free_drm;
>         }
>         drm->dev_private = drv;
> -       INIT_LIST_HEAD(&drv->backend_list);
> +       INIT_LIST_HEAD(&drv->engine_list);
>         INIT_LIST_HEAD(&drv->tcon_list);
>
>         ret = of_reserved_mem_device_init(dev);
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
> index 250c29017ef5..a960c89270cc 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
> @@ -18,7 +18,7 @@
>  #include <linux/regmap.h>
>
>  struct sun4i_drv {
> -       struct list_head        backend_list;
> +       struct list_head        engine_list;
>         struct list_head        tcon_list;
>
>         struct drm_fbdev_cma    *fbdev;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> index e1f03e1cc0ac..ab33e4d06782 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -11,12 +11,10 @@
>   */
>
>  #include <drm/drm_atomic_helper.h>
> -#include <drm/drm_crtc.h>
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drmP.h>
>
>  #include "sun4i_backend.h"
> -#include "sun4i_crtc.h"
>  #include "sun4i_layer.h"

You should also include sun4i_engine.h directly.

>
>  struct sun4i_plane_desc {
> @@ -130,10 +128,10 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
>  }
>
>  struct drm_plane **sun4i_layers_init(struct drm_device *drm,
> -                                    struct sun4i_crtc *crtc)
> +                                    struct sunxi_engine *engine)
>  {
>         struct drm_plane **planes;
> -       struct sun4i_backend *backend = crtc->backend;
> +       struct sun4i_backend *backend = engine_to_sun4i_backend(engine);
>         int i;
>
>         planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1,
> @@ -175,7 +173,7 @@ struct drm_plane **sun4i_layers_init(struct drm_device *drm,
>
>                 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
>                                  i ? "overlay" : "primary", plane->pipe);
> -               regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
> +               regmap_update_bits(engine->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
>                                    SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
>                                    SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> index 5ea5c994d6ea..004b7cfe8ffb 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -13,6 +13,8 @@
>  #ifndef _SUN4I_LAYER_H_
>  #define _SUN4I_LAYER_H_
>
> +struct sunxi_engine;
> +
>  struct sun4i_layer {
>         struct drm_plane        plane;
>         struct sun4i_drv        *drv;
> @@ -27,6 +29,5 @@ plane_to_sun4i_layer(struct drm_plane *plane)
>  }
>
>  struct drm_plane **sun4i_layers_init(struct drm_device *drm,
> -                                    struct sun4i_crtc *crtc);
> -
> +                                    struct sunxi_engine *engine);

Please keep the newline.

>  #endif /* _SUN4I_LAYER_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> index 29fd829aa54c..c48135a10fda 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -26,12 +26,12 @@
>  #include <linux/regmap.h>
>  #include <linux/reset.h>
>
> -#include "sun4i_backend.h"
>  #include "sun4i_crtc.h"
>  #include "sun4i_dotclock.h"
>  #include "sun4i_drv.h"
>  #include "sun4i_rgb.h"
>  #include "sun4i_tcon.h"
> +#include "sunxi_engine.h"

Please keep the headers in alphabetical order.

>
>  void sun4i_tcon_disable(struct sun4i_tcon *tcon)
>  {
> @@ -488,12 +488,16 @@ struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node)
>   * means maintaining a large list of them. Or, since the backend is
>   * registered and binded before the TCON, we can just go through the
>   * list of registered backends and compare the device node.
> + *
> + * As the structures now store engines instead of backends, here this
> + * function in fact searches the corresponding engine, and the ID is
> + * requested via the get_id function of the engine.
>   */
> -static struct sun4i_backend *sun4i_tcon_find_backend(struct sun4i_drv *drv,
> +static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv *drv,
>                                                      struct device_node *node)
>  {
>         struct device_node *port, *ep, *remote;
> -       struct sun4i_backend *backend;
> +       struct sunxi_engine *engine;
>
>         port = of_graph_get_port_by_id(node, 0);
>         if (!port)
> @@ -504,21 +508,21 @@ static struct sun4i_backend *sun4i_tcon_find_backend(struct sun4i_drv *drv,
>                 if (!remote)
>                         continue;
>
> -               /* does this node match any registered backends? */
> -               list_for_each_entry(backend, &drv->backend_list, list) {
> -                       if (remote == backend->node) {
> +               /* does this node match any registered engines? */
> +               list_for_each_entry(engine, &drv->engine_list, list) {
> +                       if (remote == engine->node) {
>                                 of_node_put(remote);
>                                 of_node_put(port);
> -                               return backend;
> +                               return engine;
>                         }
>                 }
>
>                 /* keep looking through upstream ports */
> -               backend = sun4i_tcon_find_backend(drv, remote);
> -               if (!IS_ERR(backend)) {
> +               engine = sun4i_tcon_find_engine(drv, remote);
> +               if (!IS_ERR(engine)) {
>                         of_node_put(remote);
>                         of_node_put(port);
> -                       return backend;
> +                       return engine;
>                 }
>         }
>
> @@ -530,13 +534,13 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
>  {
>         struct drm_device *drm = data;
>         struct sun4i_drv *drv = drm->dev_private;
> -       struct sun4i_backend *backend;
> +       struct sunxi_engine *engine;
>         struct sun4i_tcon *tcon;
>         int ret;
>
> -       backend = sun4i_tcon_find_backend(drv, dev->of_node);
> -       if (IS_ERR(backend)) {
> -               dev_err(dev, "Couldn't find matching backend\n");
> +       engine = sun4i_tcon_find_engine(drv, dev->of_node);
> +       if (IS_ERR(engine)) {
> +               dev_err(dev, "Couldn't find matching engine\n");
>                 return -EPROBE_DEFER;
>         }
>
> @@ -546,7 +550,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
>         dev_set_drvdata(dev, tcon);
>         tcon->drm = drm;
>         tcon->dev = dev;
> -       tcon->id = backend->id;
> +       tcon->id = sunxi_engine_get_id(engine);
>         tcon->quirks = of_device_get_match_data(dev);
>
>         tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
> @@ -589,7 +593,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
>                 goto err_free_dotclock;
>         }
>
> -       tcon->crtc = sun4i_crtc_init(drm, backend, tcon);
> +       tcon->crtc = sun4i_crtc_init(drm, engine, tcon);
>         if (IS_ERR(tcon->crtc)) {
>                 dev_err(dev, "Couldn't create our CRTC\n");
>                 ret = PTR_ERR(tcon->crtc);
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
> index 542da220818b..a9cad00d4ee8 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_tv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
> @@ -22,10 +22,10 @@
>  #include <drm/drm_of.h>
>  #include <drm/drm_panel.h>
>
> -#include "sun4i_backend.h"
>  #include "sun4i_crtc.h"
>  #include "sun4i_drv.h"
>  #include "sun4i_tcon.h"
> +#include "sunxi_engine.h"
>
>  #define SUN4I_TVE_EN_REG               0x000
>  #define SUN4I_TVE_EN_DAC_MAP_MASK              GENMASK(19, 4)
> @@ -353,7 +353,6 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
>         struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
>         struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
>         struct sun4i_tcon *tcon = crtc->tcon;
> -       struct sun4i_backend *backend = crtc->backend;
>
>         DRM_DEBUG_DRIVER("Disabling the TV Output\n");
>
> @@ -362,7 +361,8 @@ static void sun4i_tv_disable(struct drm_encoder *encoder)
>         regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>                            SUN4I_TVE_EN_ENABLE,
>                            0);
> -       sun4i_backend_disable_color_correction(backend);
> +
> +       sunxi_engine_disable_color_correction(crtc->engine);
>  }
>
>  static void sun4i_tv_enable(struct drm_encoder *encoder)
> @@ -370,11 +370,10 @@ static void sun4i_tv_enable(struct drm_encoder *encoder)
>         struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
>         struct sun4i_crtc *crtc = drm_crtc_to_sun4i_crtc(encoder->crtc);
>         struct sun4i_tcon *tcon = crtc->tcon;
> -       struct sun4i_backend *backend = crtc->backend;
>
>         DRM_DEBUG_DRIVER("Enabling the TV Output\n");
>
> -       sun4i_backend_apply_color_correction(backend);
> +       sunxi_engine_apply_color_correction(crtc->engine);
>
>         regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>                            SUN4I_TVE_EN_ENABLE,
> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h b/drivers/gpu/drm/sun4i/sunxi_engine.h
> new file mode 100644
> index 000000000000..b3c6e6148568
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
> @@ -0,0 +1,112 @@
> +/*
> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
> + *
> + * 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.
> + */
> +
> +#ifndef _SUNXI_ENGINE_H_
> +#define _SUNXI_ENGINE_H_
> +
> +struct sun4i_crtc;

This is not used. Please remove it.


The rest looks good. Thanks for working this out. Once the minor comments
are fixed, please add my

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

> +struct drm_plane;
> +struct drm_device;
> +
> +struct sunxi_engine;
> +
> +struct sunxi_engine_ops {
> +       void (*commit)(struct sunxi_engine *engine);
> +       struct drm_plane **(*layers_init)(struct drm_device *drm,
> +                                         struct sunxi_engine *engine);
> +
> +       void (*apply_color_correction)(struct sunxi_engine *engine);
> +       void (*disable_color_correction)(struct sunxi_engine *engine);
> +       int (*get_id)(struct sunxi_engine *engine);
> +};
> +
> +/**
> + * struct sunxi_engine - the common parts of an engine for sun4i-drm driver
> + * @ops:       the operations of the engine
> + * @regs:      the regmap of the engine
> + */
> +struct sunxi_engine {
> +       const struct sunxi_engine_ops   *ops;
> +
> +       struct device_node              *node;
> +       struct regmap                   *regs;
> +
> +       /* Engine list management */
> +       struct list_head                list;
> +};
> +
> +/**
> + * sunxi_engine_commit() - commit all changes of the engine
> + * @engine:    pointer to the engine
> + */
> +static inline void
> +sunxi_engine_commit(struct sunxi_engine *engine)
> +{
> +       if (engine->ops && engine->ops->commit)
> +               engine->ops->commit(engine);
> +}
> +
> +/**
> + * sunxi_engine_layers_init() - Create planes (layers) for the engine
> + * @drm:       pointer to the drm_device for which planes will be created
> + * @engine:    pointer to the engine
> + */
> +static inline struct drm_plane **
> +sunxi_engine_layers_init(struct drm_device *drm, struct sunxi_engine *engine)
> +{
> +       if (engine->ops && engine->ops->layers_init)
> +               return engine->ops->layers_init(drm, engine);
> +       return ERR_PTR(-ENOSYS);
> +}
> +
> +/**
> + * sunxi_engine_apply_color_correction - Apply the RGB2YUV color correction
> + * @engine:    pointer to the engine
> + *
> + * This functionality is optional for an engine, however, if the engine is
> + * intended to be used with TV Encoder, the output will be incorrect
> + * without the color correction, due to TV Encoder expects the engine to
> + * output directly YUV signal.
> + */
> +static inline void
> +sunxi_engine_apply_color_correction(struct sunxi_engine *engine)
> +{
> +       if (engine->ops && engine->ops->apply_color_correction)
> +               engine->ops->apply_color_correction(engine);
> +}
> +
> +/**
> + * sunxi_engine_disable_color_correction - Disable the color space correction
> + * @engine:    pointer to the engine
> + *
> + * This function is paired with apply_color_correction().
> + */
> +static inline void
> +sunxi_engine_disable_color_correction(struct sunxi_engine *engine)
> +{
> +       if (engine->ops && engine->ops->disable_color_correction)
> +               engine->ops->disable_color_correction(engine);
> +}
> +
> +/**
> + * sunxi_engine_get_id - Get the ID of the engine.
> + * @engine:    pointer to the engine
> + *
> + * If the ID is not necessary, just do not implement it in sunxi_engine_ops,
> + * and a default -1 will be returned.
> + */
> +static inline int
> +sunxi_engine_get_id(struct sunxi_engine *engine)
> +{
> +       if (engine->ops && engine->ops->get_id)
> +               return engine->ops->get_id(engine);
> +
> +       return -1;
> +}
> +#endif /* _SUNXI_ENGINE_H_ */
> --
> 2.12.2
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

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

* Re: [linux-sunxi] [PATCH v6 06/13] drm/sun4i: add a dedicated module for sun4i-backend and sun4i-layer
  2017-05-04 11:48 ` [PATCH v6 06/13] drm/sun4i: add a dedicated module for sun4i-backend and sun4i-layer Icenowy Zheng
@ 2017-05-05  3:10   ` Chen-Yu Tsai
  0 siblings, 0 replies; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  3:10 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Maxime Ripard, Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
> Currently the direct call from CRTC code to layer code has disappeared,
> instead the layer's init function is called via the backend's ops.
>
> Add a dedicated module for sun4i-backend and sun4i-layer, and drop the
> EXPORT_SYMBOL from backend code to layer code.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* Re: [linux-sunxi] [PATCH v6 07/13] drm/sun4i: add a Kconfig option for sun4i-backend
  2017-05-04 11:48 ` [PATCH v6 07/13] drm/sun4i: add a Kconfig option for sun4i-backend Icenowy Zheng
@ 2017-05-05  3:14   ` Chen-Yu Tsai
  0 siblings, 0 replies; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  3:14 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Maxime Ripard, Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
> As sun4i-backend is now a dedicated module, add an Kconfig option for
> it to make it optional, since some build may only use other engines.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
> Splited out patch.
>
>  drivers/gpu/drm/sun4i/Kconfig  | 10 ++++++++++
>  drivers/gpu/drm/sun4i/Makefile |  2 +-
>  2 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> index a4b357db8856..5a8227f37cc4 100644
> --- a/drivers/gpu/drm/sun4i/Kconfig
> +++ b/drivers/gpu/drm/sun4i/Kconfig
> @@ -12,3 +12,13 @@ config DRM_SUN4I
>           Choose this option if you have an Allwinner SoC with a
>           Display Engine. If M is selected the module will be called
>           sun4i-drm.
> +
> +config DRM_SUN4I_BACKEND
> +       tristate "Support for Allwinner A10 Display Engine Backend"
> +       depends on DRM_SUN4I
> +       default DRM_SUN4I
> +       help
> +         Choose this option if you have an Allwinner SoC with the
> +         original Allwinner Display Engine, which has a backend to
> +         do some alpha blending and feed graphics to TCON. If M is
> +         selected the module will be called sun4i-backend.
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index a251fb36c951..a08df56759e3 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -9,6 +9,6 @@ sun4i-tcon-y += sun4i_crtc.o
>  sun4i-backend-y += sun4i_backend.o sun4i_layer.o
>
>  obj-$(CONFIG_DRM_SUN4I)                += sun4i-drm.o sun4i-tcon.o
> -obj-$(CONFIG_DRM_SUN4I)                += sun4i-backend.o
> +obj-$(CONFIG_DRM_SUN4I_BACKEND)                += sun4i-backend.o
>  obj-$(CONFIG_DRM_SUN4I)                += sun6i_drc.o
>  obj-$(CONFIG_DRM_SUN4I)                += sun4i_tv.o

Can you move sun4i-backend to the bottom in a separate section? The idea
is to have a bunch of core or common stuff, then platform specific modules.

Thanks
ChenYu

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

* Re: [linux-sunxi] [PATCH v6 03/13] dt-bindings: add bindings for DE2 on V3s SoC
  2017-05-04 11:48 ` [PATCH v6 03/13] dt-bindings: add bindings for DE2 on V3s SoC Icenowy Zheng
@ 2017-05-05  3:24   ` Chen-Yu Tsai
  0 siblings, 0 replies; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  3:24 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Maxime Ripard, Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
> Allwinner V3s SoC have a display engine which have a different pipeline
> with older SoCs.
>
> Add document for it (new compatibles and the new "mixer" part).
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> Acked-by: Rob Herring <robh@kernel.org>
> ---
> Changes in v4:
> - Removed the refactor at TCON chapter.
> Changes in v3:
> - Remove the description of having a BE directly as allwinner,pipeline.
>
>  .../bindings/display/sunxi/sun4i-drm.txt           | 29 ++++++++++++++++++++--
>  1 file changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> index 7acdbf14ae1c..33452884b96e 100644
> --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> @@ -41,6 +41,7 @@ Required properties:
>     * allwinner,sun6i-a31-tcon
>     * allwinner,sun6i-a31s-tcon
>     * allwinner,sun8i-a33-tcon
> +   * allwinner,sun8i-v3s-tcon
>   - reg: base address and size of memory-mapped region
>   - interrupts: interrupt associated to this IP
>   - clocks: phandles to the clocks feeding the TCON. Three are needed:
> @@ -62,7 +63,7 @@ Required properties:
>    second the block connected to the TCON channel 1 (usually the TV
>    encoder)
>
> -On SoCs other than the A33, there is one more clock required:
> +On SoCs other than the A33 and V3s, there is one more clock required:
>     - 'tcon-ch1': The clock driving the TCON channel 1
>
>  DRC
> @@ -148,6 +149,26 @@ Required properties:
>    Documentation/devicetree/bindings/media/video-interfaces.txt. The
>    first port should be the input endpoints, the second one the outputs
>
> +Display Engine 2.0 Mixer
> +------------------------
> +
> +The DE2 mixer have many functionalities, currently only layer blending is
> +supported.
> +
> +Required properties:
> +  - compatible: value must be one of:
> +    * allwinner,sun8i-v3s-de2-mixer
> +  - reg: base address and size of the memory-mapped region.
> +  - clocks: phandles to the clocks feeding the frontend and backend
> +    * bus: the backend interface clock
> +    * ram: the backend DRAM clock

You probably mean "mixer" here.

> +  - clock-names: the clock names mentioned above
> +  - resets: phandles to the reset controllers driving the backend

And here.

> +
> +- ports: A ports node with endpoint definitions as defined in
> +  Documentation/devicetree/bindings/media/video-interfaces.txt. The
> +  first port should be the input endpoints, the second one the output
> +
>
>  Display Engine Pipeline
>  -----------------------
> @@ -162,9 +183,13 @@ Required properties:
>      * allwinner,sun6i-a31-display-engine
>      * allwinner,sun6i-a31s-display-engine
>      * allwinner,sun8i-a33-display-engine
> +    * allwinner,sun8i-v3s-display-engine
>
>    - allwinner,pipelines: list of phandle to the display engine
> -    frontends available.
> +    pipeline entry point. For SoCs with original DE (currently
> +    all SoCs supported by display engine except V3s), this
> +    phandle should be a display frontend; for SoCs with DE2,
> +    this phandle should be a mixer.

You could simplify this to "list of phandles to the display
engine frontends (DE 1.0) or mixers (DE 2.0) available".

Regards
ChenYu

>
>  Example:
>
> --
> 2.12.2
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

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

* Re: [linux-sunxi] [PATCH v6 12/13] ARM: dts: sun8i: add pinmux for LCD pins of V3s SoC
  2017-05-04 11:48 ` [PATCH v6 12/13] ARM: dts: sun8i: add pinmux for LCD pins of " Icenowy Zheng
@ 2017-05-05  3:25   ` Chen-Yu Tsai
  0 siblings, 0 replies; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  3:25 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Maxime Ripard, Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
> Allwinner V3s SoC features a set of pins that have functionality of RGB
> LCD, the pins are at different pin ban than other SoCs.
>
> Add pinctrl node for them.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  arch/arm/boot/dts/sun8i-v3s.dtsi | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi
> index 0a895179d8ae..a37d68b227bc 100644
> --- a/arch/arm/boot/dts/sun8i-v3s.dtsi
> +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
> @@ -297,6 +297,15 @@
>                                 function = "i2c0";
>                         };
>
> +                       lcd_rgb666_pins: lcd_rgb666@0 {

Drop the trailing "@0". Otherwise,

Acked-by: Chen-Yu Tsai <wens@csie.org>

> +                               pins = "PE0", "PE1", "PE2", "PE3", "PE4",
> +                                      "PE5", "PE6", "PE7", "PE8", "PE9",
> +                                      "PE10", "PE11", "PE12", "PE13", "PE14",
> +                                      "PE15", "PE16", "PE17", "PE18", "PE19",
> +                                      "PE23", "PE24";
> +                               function = "lcd";
> +                       };
> +
>                         uart0_pins_a: uart0@0 {
>                                 pins = "PB8", "PB9";
>                                 function = "uart0";
> --
> 2.12.2
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

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

* Re: [linux-sunxi] [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC
  2017-05-04 11:48 ` [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC Icenowy Zheng
@ 2017-05-05  3:31   ` Chen-Yu Tsai
  2017-05-05  8:53     ` icenowy
  0 siblings, 1 reply; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  3:31 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Maxime Ripard, Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
> Allwinner V3s SoC features a "Display Engine 2.0" with only one TCON
> which have RGB LCD output.

Please also mention that it only has one mixer.

For the subject, you could just say "Add device nodes for the display pipeline".

>
> Add device nodes for it as well as the TCON.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
>  arch/arm/boot/dts/sun8i-v3s.dtsi | 87 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 87 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi
> index 71075969e5e6..0a895179d8ae 100644
> --- a/arch/arm/boot/dts/sun8i-v3s.dtsi
> +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
> @@ -41,6 +41,10 @@
>   */
>
>  #include <dt-bindings/interrupt-controller/arm-gic.h>
> +#include <dt-bindings/clock/sun8i-v3s-ccu.h>
> +#include <dt-bindings/clock/sun8i-de2.h>
> +#include <dt-bindings/reset/sun8i-v3s-ccu.h>
> +#include <dt-bindings/reset/sun8i-de2.h>
>
>  / {
>         #address-cells = <1>;
> @@ -59,6 +63,12 @@
>                 };
>         };
>
> +       de: display-engine {
> +               compatible = "allwinner,sun8i-v3s-display-engine";
> +               allwinner,pipelines = <&de2_mixer0>;
> +               status = "disabled";
> +       };
> +
>         timer {
>                 compatible = "arm,armv7-timer";
>                 interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
> @@ -93,6 +103,83 @@
>                 #size-cells = <1>;
>                 ranges;
>
> +               de2_clocks: clock@1000000 {
> +                       compatible = "allwinner,sun50i-h5-de2-clk";

I am a bit skeptical about this. Since the V3S only has one mixer, do the clocks
for the second one even exist?

> +                       reg = <0x01000000 0x100000>;
> +                       clocks = <&ccu CLK_DE>,
> +                                <&ccu CLK_BUS_DE>;
> +                       clock-names = "mod",
> +                                     "bus";
> +                       resets = <&ccu RST_BUS_DE>;
> +                       #clock-cells = <1>;
> +                       #reset-cells = <1>;
> +               };
> +
> +               de2_mixer0: mixer@1100000 {
> +                       compatible = "allwinner,sun8i-v3s-de2-mixer";
> +                       reg = <0x01100000 0x100000>;
> +                       clocks = <&de2_clocks CLK_MIXER0>,
> +                                <&de2_clocks CLK_BUS_MIXER0>;
> +                       clock-names = "mod",
> +                                     "bus";

Nit: could you list the bus clock first?

Regards
ChenYu

> +                       resets = <&de2_clocks RST_MIXER0>;
> +                       assigned-clocks = <&de2_clocks CLK_MIXER0>;
> +                       assigned-clock-rates = <150000000>;
> +
> +                       ports {
> +                               #address-cells = <1>;
> +                               #size-cells = <0>;
> +
> +                               mixer0_out: port@1 {
> +                                       #address-cells = <1>;
> +                                       #size-cells = <0>;
> +                                       reg = <1>;
> +
> +                                       mixer0_out_tcon0: endpoint@0 {
> +                                               reg = <0>;
> +                                               remote-endpoint = <&tcon0_in_mixer0>;
> +                                       };
> +                               };
> +                       };
> +               };
> +
> +               tcon0: lcd-controller@1c0c000 {
> +                       compatible = "allwinner,sun8i-v3s-tcon";
> +                       reg = <0x01c0c000 0x1000>;
> +                       interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
> +                       clocks = <&ccu CLK_BUS_TCON0>,
> +                                <&ccu CLK_TCON0>;
> +                       clock-names = "ahb",
> +                                     "tcon-ch0";
> +                       clock-output-names = "tcon-pixel-clock";
> +                       resets = <&ccu RST_BUS_TCON0>;
> +                       reset-names = "lcd";
> +                       status = "disabled";
> +
> +                       ports {
> +                               #address-cells = <1>;
> +                               #size-cells = <0>;
> +
> +                               tcon0_in: port@0 {
> +                                       #address-cells = <1>;
> +                                       #size-cells = <0>;
> +                                       reg = <0>;
> +
> +                                       tcon0_in_mixer0: endpoint@0 {
> +                                               reg = <0>;
> +                                               remote-endpoint = <&mixer0_out_tcon0>;
> +                                       };
> +                               };
> +
> +                               tcon0_out: port@1 {
> +                                       #address-cells = <1>;
> +                                       #size-cells = <0>;
> +                                       reg = <1>;
> +                               };
> +                       };
> +               };
> +
> +
>                 mmc0: mmc@01c0f000 {
>                         compatible = "allwinner,sun7i-a20-mmc";
>                         reg = <0x01c0f000 0x1000>;
> --
> 2.12.2
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

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

* Re: [linux-sunxi] [PATCH v6 10/13] drm/sun4i: tcon: add support for V3s TCON
  2017-05-04 11:48 ` [PATCH v6 10/13] drm/sun4i: tcon: add support for V3s TCON Icenowy Zheng
@ 2017-05-05  3:33   ` Chen-Yu Tsai
  0 siblings, 0 replies; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  3:33 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Maxime Ripard, Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
> Allwinner V3s SoC features a TCON without channel 1.
>
> Add support for it.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>

Reviewed-by: Chen-Yu Tsai <wens@csie.org>

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

* Re: [linux-sunxi] Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-04 16:52     ` icenowy
@ 2017-05-05  3:40       ` Chen-Yu Tsai
  0 siblings, 0 replies; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  3:40 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Maxime Ripard, Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

On Fri, May 5, 2017 at 12:52 AM,  <icenowy@aosc.io> wrote:
> 在 2017-05-04 21:05,Maxime Ripard 写道:
>>
>> On Thu, May 04, 2017 at 07:48:53PM +0800, Icenowy Zheng wrote:
>>>
>>> Allwinner have a new "Display Engine 2.0" in their new SoCs, which comes
>>> with mixers to do graphic processing and feed data to TCON, like the old
>>> backends and frontends.
>>>
>>> Add support for the mixer on Allwinner V3s SoC; it's the simplest one.
>>>
>>> Currently a lot of functions are still missing -- more investigations
>>> are needed to gain enough information for them.
>>>
>>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>>> ---
>>> Changes in v6:
>>> - Rebased on wens's multi-pipeline patchset.
>>> Changes in v5:
>>> - Changed some code alignment.
>>> - Request real 32-bit DMA (prepare for 64-bit SoCs).
>>> Changes in v4:
>>> - Killed some dead code according to Jernej.
>>>
>>>  drivers/gpu/drm/sun4i/Kconfig       |  10 +
>>>  drivers/gpu/drm/sun4i/Makefile      |   3 +
>>>  drivers/gpu/drm/sun4i/sun8i_layer.c | 140 +++++++++++++
>>>  drivers/gpu/drm/sun4i/sun8i_layer.h |  36 ++++
>>>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 394
>>> ++++++++++++++++++++++++++++++++++++
>>>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 137 +++++++++++++
>>>  6 files changed, 720 insertions(+)
>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.c
>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_layer.h
>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.c
>>>  create mode 100644 drivers/gpu/drm/sun4i/sun8i_mixer.h
>>>

[...]

>>> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c
>>> b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>>> new file mode 100644
>>> index 000000000000..e216b84d5bb2
>>> --- /dev/null
>>> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
>>> @@ -0,0 +1,394 @@

[...]

>>> +       list_add_tail(&mixer->engine.list, &drv->engine_list);
>>
>>
>> You didn't call INIT_LIST_HEAD on that list.
>
>
> So didn't the sun4i_backend driver...
>
> I think the mixer->engine.list only means an item in the
> engine_list, and the drv->engine_list is initialized in the
> sun4i_drv source code.

I read [1] that if the item is subsequently added to a list,
you could omit the INIT_LIST_HEAD call.

Makes sense, though you have to be sure you aren't doing anything
else with the list element.

ChenYu

[1] https://isis.poly.edu/kulesh/stuff/src/klist/

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

* Re: [linux-sunxi] [PATCH v6 05/13] drm/sun4i: abstract a engine type
  2017-05-05  2:56   ` [linux-sunxi] " Chen-Yu Tsai
@ 2017-05-05  8:36     ` icenowy
  2017-05-05  8:38       ` Chen-Yu Tsai
  0 siblings, 1 reply; 37+ messages in thread
From: icenowy @ 2017-05-05  8:36 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: devicetree, linux-sunxi, linux-kernel, dri-devel, Rob Herring,
	Maxime Ripard, linux-clk, linux-arm-kernel

在 2017-05-05 10:56,Chen-Yu Tsai 写道:
> On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
>> As we are going to add support for the Allwinner DE2 engine in 
>> sun4i-drm
>> driver, we will finally have two types of display engines -- the DE1
>> backend and the DE2 mixer. They both do some display blending and feed
>> graphics data to TCON, so I choose to call them both "engine" here.
> 
> These engines composite different layers into a final image which is
> then sent out to the TCONs. As such, "compositor" would be an accurate
> name.
> 
> However, "engine" is OK, since Allwinner calls this stuff Display 
> Engine
> 1.0 and 2.0. Hope there won't be a 3.0 ...
> 
> Maybe you should note that in your commit message. That is justifies 
> the name.
> 
>> 
>> Abstract the engine type to a new struct with an ops struct, which 
>> contains
>> functions that should be called outside the engine-specified code (in
>> TCON, CRTC or TV Encoder code).
>> 
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>> Changes in v6:
>> - Rebased on wens's multi-pipeline patchset.
>> - Split out Makefile changes.
>> Changes in v5:
>> - Really made a sunxi_engine struct type, and moved ops pointer
>>   into it.
>> - Added checked ops wrappers.
>> - Changed the second parameter of layers_init from crtc to engine.
>> Changes in v4:
>> - Comments to tag the color correction functions as optional.
>> - Check before calling the optional functions.
>> - Change layers_init to satisfy new PATCH v4 04/11.
>> 
>>  drivers/gpu/drm/sun4i/sun4i_backend.c |  68 ++++++++++++---------
>>  drivers/gpu/drm/sun4i/sun4i_backend.h |  17 +++---
>>  drivers/gpu/drm/sun4i/sun4i_crtc.c    |  11 ++--
>>  drivers/gpu/drm/sun4i/sun4i_crtc.h    |   4 +-
>>  drivers/gpu/drm/sun4i/sun4i_drv.c     |   2 +-
>>  drivers/gpu/drm/sun4i/sun4i_drv.h     |   2 +-
>>  drivers/gpu/drm/sun4i/sun4i_layer.c   |   8 +--
>>  drivers/gpu/drm/sun4i/sun4i_layer.h   |   5 +-
>>  drivers/gpu/drm/sun4i/sun4i_tcon.c    |  36 ++++++-----
>>  drivers/gpu/drm/sun4i/sun4i_tv.c      |   9 ++-
>>  drivers/gpu/drm/sun4i/sunxi_engine.h  | 112 
>> ++++++++++++++++++++++++++++++++++
>>  11 files changed, 198 insertions(+), 76 deletions(-)
>>  create mode 100644 drivers/gpu/drm/sun4i/sunxi_engine.h
>> 
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c 
>> b/drivers/gpu/drm/sun4i/sun4i_backend.c
>> index e53107418add..611cdcb9c182 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_backend.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
>> @@ -25,6 +25,8 @@
>> 
>>  #include "sun4i_backend.h"
>>  #include "sun4i_drv.h"
>> +#include "sun4i_layer.h"
>> +#include "sunxi_engine.h"
>> 
>>  static const u32 sunxi_rgb2yuv_coef[12] = {
>>         0x00000107, 0x00000204, 0x00000064, 0x00000108,
>> @@ -32,41 +34,38 @@ static const u32 sunxi_rgb2yuv_coef[12] = {
>>         0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
>>  };
>> 
>> -void sun4i_backend_apply_color_correction(struct sun4i_backend 
>> *backend)
>> +static void sun4i_backend_apply_color_correction(struct sunxi_engine 
>> *engine)
>>  {
>>         int i;
>> 
>>         DRM_DEBUG_DRIVER("Applying RGB to YUV color correction\n");
>> 
>>         /* Set color correction */
>> -       regmap_write(backend->regs, SUN4I_BACKEND_OCCTL_REG,
>> +       regmap_write(engine->regs, SUN4I_BACKEND_OCCTL_REG,
>>                      SUN4I_BACKEND_OCCTL_ENABLE);
>> 
>>         for (i = 0; i < 12; i++)
>> -               regmap_write(backend->regs, 
>> SUN4I_BACKEND_OCRCOEF_REG(i),
>> +               regmap_write(engine->regs, 
>> SUN4I_BACKEND_OCRCOEF_REG(i),
>>                              sunxi_rgb2yuv_coef[i]);
>>  }
>> -EXPORT_SYMBOL(sun4i_backend_apply_color_correction);
>> 
>> -void sun4i_backend_disable_color_correction(struct sun4i_backend 
>> *backend)
>> +static void sun4i_backend_disable_color_correction(struct 
>> sunxi_engine *engine)
>>  {
>>         DRM_DEBUG_DRIVER("Disabling color correction\n");
>> 
>>         /* Disable color correction */
>> -       regmap_update_bits(backend->regs, SUN4I_BACKEND_OCCTL_REG,
>> +       regmap_update_bits(engine->regs, SUN4I_BACKEND_OCCTL_REG,
>>                            SUN4I_BACKEND_OCCTL_ENABLE, 0);
>>  }
>> -EXPORT_SYMBOL(sun4i_backend_disable_color_correction);
>> 
>> -void sun4i_backend_commit(struct sun4i_backend *backend)
>> +static void sun4i_backend_commit(struct sunxi_engine *engine)
>>  {
>>         DRM_DEBUG_DRIVER("Committing changes\n");
>> 
>> -       regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
>> +       regmap_write(engine->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
>>                      SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS |
>>                      SUN4I_BACKEND_REGBUFFCTL_LOADCTL);
>>  }
>> -EXPORT_SYMBOL(sun4i_backend_commit);
>> 
>>  void sun4i_backend_layer_enable(struct sun4i_backend *backend,
>>                                 int layer, bool enable)
>> @@ -81,7 +80,7 @@ void sun4i_backend_layer_enable(struct sun4i_backend 
>> *backend,
>>         else
>>                 val = 0;
>> 
>> -       regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
>> +       regmap_update_bits(backend->engine.regs, 
>> SUN4I_BACKEND_MODCTL_REG,
>>                            SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
>>  }
>>  EXPORT_SYMBOL(sun4i_backend_layer_enable);
>> @@ -144,27 +143,28 @@ int sun4i_backend_update_layer_coord(struct 
>> sun4i_backend *backend,
>>         if (plane->type == DRM_PLANE_TYPE_PRIMARY) {
>>                 DRM_DEBUG_DRIVER("Primary layer, updating global size 
>> W: %u H: %u\n",
>>                                  state->crtc_w, state->crtc_h);
>> -               regmap_write(backend->regs, SUN4I_BACKEND_DISSIZE_REG,
>> +               regmap_write(backend->engine.regs, 
>> SUN4I_BACKEND_DISSIZE_REG,
>>                              SUN4I_BACKEND_DISSIZE(state->crtc_w,
>>                                                    state->crtc_h));
>>         }
>> 
>>         /* Set the line width */
>>         DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] 
>> * 8);
>> -       regmap_write(backend->regs, 
>> SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
>> +       regmap_write(backend->engine.regs,
>> +                    SUN4I_BACKEND_LAYLINEWIDTH_REG(layer),
>>                      fb->pitches[0] * 8);
>> 
>>         /* Set height and width */
>>         DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n",
>>                          state->crtc_w, state->crtc_h);
>> -       regmap_write(backend->regs, SUN4I_BACKEND_LAYSIZE_REG(layer),
>> +       regmap_write(backend->engine.regs, 
>> SUN4I_BACKEND_LAYSIZE_REG(layer),
>>                      SUN4I_BACKEND_LAYSIZE(state->crtc_w,
>>                                            state->crtc_h));
>> 
>>         /* Set base coordinates */
>>         DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>>                          state->crtc_x, state->crtc_y);
>> -       regmap_write(backend->regs, SUN4I_BACKEND_LAYCOOR_REG(layer),
>> +       regmap_write(backend->engine.regs, 
>> SUN4I_BACKEND_LAYCOOR_REG(layer),
>>                      SUN4I_BACKEND_LAYCOOR(state->crtc_x,
>>                                            state->crtc_y));
>> 
>> @@ -185,7 +185,7 @@ int sun4i_backend_update_layer_formats(struct 
>> sun4i_backend *backend,
>>                 interlaced = 
>> plane->state->crtc->state->adjusted_mode.flags
>>                         & DRM_MODE_FLAG_INTERLACE;
>> 
>> -       regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
>> +       regmap_update_bits(backend->engine.regs, 
>> SUN4I_BACKEND_MODCTL_REG,
>>                            SUN4I_BACKEND_MODCTL_ITLMOD_EN,
>>                            interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN 
>> : 0);
>> 
>> @@ -199,7 +199,8 @@ int sun4i_backend_update_layer_formats(struct 
>> sun4i_backend *backend,
>>                 return ret;
>>         }
>> 
>> -       regmap_update_bits(backend->regs, 
>> SUN4I_BACKEND_ATTCTL_REG1(layer),
>> +       regmap_update_bits(backend->engine.regs,
>> +                          SUN4I_BACKEND_ATTCTL_REG1(layer),
>>                            SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
>> 
>>         return 0;
>> @@ -232,13 +233,14 @@ int sun4i_backend_update_layer_buffer(struct 
>> sun4i_backend *backend,
>>         /* Write the 32 lower bits of the address (in bits) */
>>         lo_paddr = paddr << 3;
>>         DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", 
>> lo_paddr);
>> -       regmap_write(backend->regs, 
>> SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
>> +       regmap_write(backend->engine.regs,
>> +                    SUN4I_BACKEND_LAYFB_L32ADD_REG(layer),
>>                      lo_paddr);
>> 
>>         /* And the upper bits */
>>         hi_paddr = paddr >> 29;
>>         DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", 
>> hi_paddr);
>> -       regmap_update_bits(backend->regs, 
>> SUN4I_BACKEND_LAYFB_H4ADD_REG,
>> +       regmap_update_bits(backend->engine.regs, 
>> SUN4I_BACKEND_LAYFB_H4ADD_REG,
>>                            SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
>>                            SUN4I_BACKEND_LAYFB_H4ADD(layer, 
>> hi_paddr));
>> 
>> @@ -330,6 +332,13 @@ static int sun4i_backend_of_get_id(struct 
>> device_node *node)
>>         return ret;
>>  }
>> 
>> +static const struct sunxi_engine_ops sun4i_backend_engine_ops = {
>> +       .commit                         = sun4i_backend_commit,
>> +       .layers_init                    = sun4i_layers_init,
>> +       .apply_color_correction         = 
>> sun4i_backend_apply_color_correction,
>> +       .disable_color_correction       = 
>> sun4i_backend_disable_color_correction,
>> +};
>> +
>>  static struct regmap_config sun4i_backend_regmap_config = {
>>         .reg_bits       = 32,
>>         .val_bits       = 32,
>> @@ -353,7 +362,8 @@ static int sun4i_backend_bind(struct device *dev, 
>> struct device *master,
>>                 return -ENOMEM;
>>         dev_set_drvdata(dev, backend);
>> 
>> -       backend->node = dev->of_node;
>> +       backend->engine.node = dev->of_node;
>> +       backend->engine.ops = &sun4i_backend_engine_ops;
>>         backend->id = sun4i_backend_of_get_id(dev->of_node);
>>         if (backend->id < 0)
>>                 return backend->id;
>> @@ -363,11 +373,11 @@ static int sun4i_backend_bind(struct device 
>> *dev, struct device *master,
>>         if (IS_ERR(regs))
>>                 return PTR_ERR(regs);
>> 
>> -       backend->regs = devm_regmap_init_mmio(dev, regs,
>> -                                             
>> &sun4i_backend_regmap_config);
>> -       if (IS_ERR(backend->regs)) {
>> +       backend->engine.regs = devm_regmap_init_mmio(dev, regs,
>> +                                                    
>> &sun4i_backend_regmap_config);
>> +       if (IS_ERR(backend->engine.regs)) {
>>                 dev_err(dev, "Couldn't create the backend regmap\n");
>> -               return PTR_ERR(backend->regs);
>> +               return PTR_ERR(backend->engine.regs);
>>         }
>> 
>>         backend->reset = devm_reset_control_get(dev, NULL);
>> @@ -415,18 +425,18 @@ static int sun4i_backend_bind(struct device 
>> *dev, struct device *master,
>>                 }
>>         }
>> 
>> -       list_add_tail(&backend->list, &drv->backend_list);
>> +       list_add_tail(&backend->engine.list, &drv->engine_list);
>> 
>>         /* Reset the registers */
>>         for (i = 0x800; i < 0x1000; i += 4)
>> -               regmap_write(backend->regs, i, 0);
>> +               regmap_write(backend->engine.regs, i, 0);
>> 
>>         /* Disable registers autoloading */
>> -       regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
>> +       regmap_write(backend->engine.regs, 
>> SUN4I_BACKEND_REGBUFFCTL_REG,
>>                      SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
>> 
>>         /* Enable the backend */
>> -       regmap_write(backend->regs, SUN4I_BACKEND_MODCTL_REG,
>> +       regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG,
>>                      SUN4I_BACKEND_MODCTL_DEBE_EN |
>>                      SUN4I_BACKEND_MODCTL_START_CTL);
>> 
>> @@ -448,7 +458,7 @@ static void sun4i_backend_unbind(struct device 
>> *dev, struct device *master,
>>  {
>>         struct sun4i_backend *backend = dev_get_drvdata(dev);
>> 
>> -       list_del(&backend->list);
>> +       list_del(&backend->engine.list);
>> 
>>         if (of_device_is_compatible(dev->of_node,
>>                                     
>> "allwinner,sun8i-a33-display-backend"))
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h 
>> b/drivers/gpu/drm/sun4i/sun4i_backend.h
>> index 6327a2985fe6..b022a37e8e5b 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_backend.h
>> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
>> @@ -19,6 +19,8 @@
>>  #include <linux/regmap.h>
>>  #include <linux/reset.h>
>> 
>> +#include "sunxi_engine.h"
>> +
>>  #define SUN4I_BACKEND_MODCTL_REG               0x800
>>  #define SUN4I_BACKEND_MODCTL_LINE_SEL                  BIT(29)
>>  #define SUN4I_BACKEND_MODCTL_ITLMOD_EN                 BIT(28)
>> @@ -141,8 +143,7 @@
>>  #define SUN4I_BACKEND_PIPE_OFF(p)              (0x5000 + (0x400 * 
>> (p)))
>> 
>>  struct sun4i_backend {
>> -       struct device_node      *node;
>> -       struct regmap           *regs;
>> +       struct sunxi_engine     engine;
>> 
>>         struct reset_control    *reset;
>> 
>> @@ -154,15 +155,13 @@ struct sun4i_backend {
>>         struct reset_control    *sat_reset;
>> 
>>         int                     id;
>> -
>> -       /* Backend list management */
>> -       struct list_head        list;
>>  };
>> 
>> -void sun4i_backend_apply_color_correction(struct sun4i_backend 
>> *backend);
>> -void sun4i_backend_disable_color_correction(struct sun4i_backend 
>> *backend);
>> -
>> -void sun4i_backend_commit(struct sun4i_backend *backend);
>> +static inline struct sun4i_backend *
>> +engine_to_sun4i_backend(struct sunxi_engine *engine)
>> +{
>> +       return container_of(engine, struct sun4i_backend, engine);
>> +}
>> 
>>  void sun4i_backend_layer_enable(struct sun4i_backend *backend,
>>                                 int layer, bool enable);
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c 
>> b/drivers/gpu/drm/sun4i/sun4i_crtc.c
>> index 708b3543d4e9..f8c70439d1e2 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
>> @@ -25,10 +25,9 @@
>> 
>>  #include <video/videomode.h>
>> 
>> -#include "sun4i_backend.h"
>>  #include "sun4i_crtc.h"
>>  #include "sun4i_drv.h"
>> -#include "sun4i_layer.h"
>> +#include "sunxi_engine.h"
>>  #include "sun4i_tcon.h"
>> 
>>  static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
>> @@ -56,7 +55,7 @@ static void sun4i_crtc_atomic_flush(struct drm_crtc 
>> *crtc,
>> 
>>         DRM_DEBUG_DRIVER("Committing plane changes\n");
>> 
>> -       sun4i_backend_commit(scrtc->backend);
>> +       sunxi_engine_commit(scrtc->engine);
>> 
>>         if (event) {
>>                 crtc->state->event = NULL;
>> @@ -135,7 +134,7 @@ static const struct drm_crtc_funcs 
>> sun4i_crtc_funcs = {
>>  };
>> 
>>  struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
>> -                                  struct sun4i_backend *backend,
>> +                                  struct sunxi_engine *engine,
>>                                    struct sun4i_tcon *tcon)
>>  {
>>         struct sun4i_crtc *scrtc;
>> @@ -146,11 +145,11 @@ struct sun4i_crtc *sun4i_crtc_init(struct 
>> drm_device *drm,
>>         scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
>>         if (!scrtc)
>>                 return ERR_PTR(-ENOMEM);
>> -       scrtc->backend = backend;
>> +       scrtc->engine = engine;
>>         scrtc->tcon = tcon;
>> 
>>         /* Create our layers */
>> -       planes = sun4i_layers_init(drm, scrtc);
>> +       planes = sunxi_engine_layers_init(drm, engine);
>>         if (IS_ERR(planes)) {
>>                 dev_err(drm->dev, "Couldn't create the planes\n");
>>                 return NULL;
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h 
>> b/drivers/gpu/drm/sun4i/sun4i_crtc.h
>> index 4dae3508424a..bf0ce36eb518 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_crtc.h
>> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h
>> @@ -17,7 +17,7 @@ struct sun4i_crtc {
>>         struct drm_crtc                 crtc;
>>         struct drm_pending_vblank_event *event;
>> 
>> -       struct sun4i_backend            *backend;
>> +       struct sunxi_engine             *engine;
>>         struct sun4i_tcon               *tcon;
>>  };
>> 
>> @@ -27,7 +27,7 @@ static inline struct sun4i_crtc 
>> *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
>>  }
>> 
>>  struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
>> -                                  struct sun4i_backend *backend,
>> +                                  struct sunxi_engine *engine,
>>                                    struct sun4i_tcon *tcon);
>> 
>>  #endif /* _SUN4I_CRTC_H_ */
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c 
>> b/drivers/gpu/drm/sun4i/sun4i_drv.c
>> index 89c51fd6e9af..12ede8682b5c 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
>> @@ -101,7 +101,7 @@ static int sun4i_drv_bind(struct device *dev)
>>                 goto free_drm;
>>         }
>>         drm->dev_private = drv;
>> -       INIT_LIST_HEAD(&drv->backend_list);
>> +       INIT_LIST_HEAD(&drv->engine_list);
>>         INIT_LIST_HEAD(&drv->tcon_list);
>> 
>>         ret = of_reserved_mem_device_init(dev);
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h 
>> b/drivers/gpu/drm/sun4i/sun4i_drv.h
>> index 250c29017ef5..a960c89270cc 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_drv.h
>> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
>> @@ -18,7 +18,7 @@
>>  #include <linux/regmap.h>
>> 
>>  struct sun4i_drv {
>> -       struct list_head        backend_list;
>> +       struct list_head        engine_list;
>>         struct list_head        tcon_list;
>> 
>>         struct drm_fbdev_cma    *fbdev;
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c 
>> b/drivers/gpu/drm/sun4i/sun4i_layer.c
>> index e1f03e1cc0ac..ab33e4d06782 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_layer.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
>> @@ -11,12 +11,10 @@
>>   */
>> 
>>  #include <drm/drm_atomic_helper.h>
>> -#include <drm/drm_crtc.h>
>>  #include <drm/drm_plane_helper.h>
>>  #include <drm/drmP.h>
>> 
>>  #include "sun4i_backend.h"
>> -#include "sun4i_crtc.h"
>>  #include "sun4i_layer.h"
> 
> You should also include sun4i_engine.h directly.
> 
>> 
>>  struct sun4i_plane_desc {
>> @@ -130,10 +128,10 @@ static struct sun4i_layer 
>> *sun4i_layer_init_one(struct drm_device *drm,
>>  }
>> 
>>  struct drm_plane **sun4i_layers_init(struct drm_device *drm,
>> -                                    struct sun4i_crtc *crtc)
>> +                                    struct sunxi_engine *engine)
>>  {
>>         struct drm_plane **planes;
>> -       struct sun4i_backend *backend = crtc->backend;
>> +       struct sun4i_backend *backend = 
>> engine_to_sun4i_backend(engine);
>>         int i;
>> 
>>         planes = devm_kcalloc(drm->dev, 
>> ARRAY_SIZE(sun4i_backend_planes) + 1,
>> @@ -175,7 +173,7 @@ struct drm_plane **sun4i_layers_init(struct 
>> drm_device *drm,
>> 
>>                 DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
>>                                  i ? "overlay" : "primary", 
>> plane->pipe);
>> -               regmap_update_bits(backend->regs, 
>> SUN4I_BACKEND_ATTCTL_REG0(i),
>> +               regmap_update_bits(engine->regs, 
>> SUN4I_BACKEND_ATTCTL_REG0(i),
>>                                    
>> SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
>>                                    
>> SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe));
>> 
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h 
>> b/drivers/gpu/drm/sun4i/sun4i_layer.h
>> index 5ea5c994d6ea..004b7cfe8ffb 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
>> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
>> @@ -13,6 +13,8 @@
>>  #ifndef _SUN4I_LAYER_H_
>>  #define _SUN4I_LAYER_H_
>> 
>> +struct sunxi_engine;
>> +
>>  struct sun4i_layer {
>>         struct drm_plane        plane;
>>         struct sun4i_drv        *drv;
>> @@ -27,6 +29,5 @@ plane_to_sun4i_layer(struct drm_plane *plane)
>>  }
>> 
>>  struct drm_plane **sun4i_layers_init(struct drm_device *drm,
>> -                                    struct sun4i_crtc *crtc);
>> -
>> +                                    struct sunxi_engine *engine);
> 
> Please keep the newline.
> 
>>  #endif /* _SUN4I_LAYER_H_ */
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c 
>> b/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> index 29fd829aa54c..c48135a10fda 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
>> @@ -26,12 +26,12 @@
>>  #include <linux/regmap.h>
>>  #include <linux/reset.h>
>> 
>> -#include "sun4i_backend.h"
>>  #include "sun4i_crtc.h"
>>  #include "sun4i_dotclock.h"
>>  #include "sun4i_drv.h"
>>  #include "sun4i_rgb.h"
>>  #include "sun4i_tcon.h"
>> +#include "sunxi_engine.h"
> 
> Please keep the headers in alphabetical order.

sunxi is of course after sun4i.

> 
>> 
>>  void sun4i_tcon_disable(struct sun4i_tcon *tcon)
>>  {
>> @@ -488,12 +488,16 @@ struct drm_bridge *sun4i_tcon_find_bridge(struct 
>> device_node *node)
>>   * means maintaining a large list of them. Or, since the backend is
>>   * registered and binded before the TCON, we can just go through the
>>   * list of registered backends and compare the device node.
>> + *
>> + * As the structures now store engines instead of backends, here this
>> + * function in fact searches the corresponding engine, and the ID is
>> + * requested via the get_id function of the engine.
>>   */
>> -static struct sun4i_backend *sun4i_tcon_find_backend(struct sun4i_drv 
>> *drv,
>> +static struct sunxi_engine *sun4i_tcon_find_engine(struct sun4i_drv 
>> *drv,
>>                                                      struct 
>> device_node *node)
>>  {
>>         struct device_node *port, *ep, *remote;
>> -       struct sun4i_backend *backend;
>> +       struct sunxi_engine *engine;
>> 
>>         port = of_graph_get_port_by_id(node, 0);
>>         if (!port)
>> @@ -504,21 +508,21 @@ static struct sun4i_backend 
>> *sun4i_tcon_find_backend(struct sun4i_drv *drv,
>>                 if (!remote)
>>                         continue;
>> 
>> -               /* does this node match any registered backends? */
>> -               list_for_each_entry(backend, &drv->backend_list, list) 
>> {
>> -                       if (remote == backend->node) {
>> +               /* does this node match any registered engines? */
>> +               list_for_each_entry(engine, &drv->engine_list, list) {
>> +                       if (remote == engine->node) {
>>                                 of_node_put(remote);
>>                                 of_node_put(port);
>> -                               return backend;
>> +                               return engine;
>>                         }
>>                 }
>> 
>>                 /* keep looking through upstream ports */
>> -               backend = sun4i_tcon_find_backend(drv, remote);
>> -               if (!IS_ERR(backend)) {
>> +               engine = sun4i_tcon_find_engine(drv, remote);
>> +               if (!IS_ERR(engine)) {
>>                         of_node_put(remote);
>>                         of_node_put(port);
>> -                       return backend;
>> +                       return engine;
>>                 }
>>         }
>> 
>> @@ -530,13 +534,13 @@ static int sun4i_tcon_bind(struct device *dev, 
>> struct device *master,
>>  {
>>         struct drm_device *drm = data;
>>         struct sun4i_drv *drv = drm->dev_private;
>> -       struct sun4i_backend *backend;
>> +       struct sunxi_engine *engine;
>>         struct sun4i_tcon *tcon;
>>         int ret;
>> 
>> -       backend = sun4i_tcon_find_backend(drv, dev->of_node);
>> -       if (IS_ERR(backend)) {
>> -               dev_err(dev, "Couldn't find matching backend\n");
>> +       engine = sun4i_tcon_find_engine(drv, dev->of_node);
>> +       if (IS_ERR(engine)) {
>> +               dev_err(dev, "Couldn't find matching engine\n");
>>                 return -EPROBE_DEFER;
>>         }
>> 
>> @@ -546,7 +550,7 @@ static int sun4i_tcon_bind(struct device *dev, 
>> struct device *master,
>>         dev_set_drvdata(dev, tcon);
>>         tcon->drm = drm;
>>         tcon->dev = dev;
>> -       tcon->id = backend->id;
>> +       tcon->id = sunxi_engine_get_id(engine);
>>         tcon->quirks = of_device_get_match_data(dev);
>> 
>>         tcon->lcd_rst = devm_reset_control_get(dev, "lcd");
>> @@ -589,7 +593,7 @@ static int sun4i_tcon_bind(struct device *dev, 
>> struct device *master,
>>                 goto err_free_dotclock;
>>         }
>> 
>> -       tcon->crtc = sun4i_crtc_init(drm, backend, tcon);
>> +       tcon->crtc = sun4i_crtc_init(drm, engine, tcon);
>>         if (IS_ERR(tcon->crtc)) {
>>                 dev_err(dev, "Couldn't create our CRTC\n");
>>                 ret = PTR_ERR(tcon->crtc);
>> diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c 
>> b/drivers/gpu/drm/sun4i/sun4i_tv.c
>> index 542da220818b..a9cad00d4ee8 100644
>> --- a/drivers/gpu/drm/sun4i/sun4i_tv.c
>> +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
>> @@ -22,10 +22,10 @@
>>  #include <drm/drm_of.h>
>>  #include <drm/drm_panel.h>
>> 
>> -#include "sun4i_backend.h"
>>  #include "sun4i_crtc.h"
>>  #include "sun4i_drv.h"
>>  #include "sun4i_tcon.h"
>> +#include "sunxi_engine.h"
>> 
>>  #define SUN4I_TVE_EN_REG               0x000
>>  #define SUN4I_TVE_EN_DAC_MAP_MASK              GENMASK(19, 4)
>> @@ -353,7 +353,6 @@ static void sun4i_tv_disable(struct drm_encoder 
>> *encoder)
>>         struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
>>         struct sun4i_crtc *crtc = 
>> drm_crtc_to_sun4i_crtc(encoder->crtc);
>>         struct sun4i_tcon *tcon = crtc->tcon;
>> -       struct sun4i_backend *backend = crtc->backend;
>> 
>>         DRM_DEBUG_DRIVER("Disabling the TV Output\n");
>> 
>> @@ -362,7 +361,8 @@ static void sun4i_tv_disable(struct drm_encoder 
>> *encoder)
>>         regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>>                            SUN4I_TVE_EN_ENABLE,
>>                            0);
>> -       sun4i_backend_disable_color_correction(backend);
>> +
>> +       sunxi_engine_disable_color_correction(crtc->engine);
>>  }
>> 
>>  static void sun4i_tv_enable(struct drm_encoder *encoder)
>> @@ -370,11 +370,10 @@ static void sun4i_tv_enable(struct drm_encoder 
>> *encoder)
>>         struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
>>         struct sun4i_crtc *crtc = 
>> drm_crtc_to_sun4i_crtc(encoder->crtc);
>>         struct sun4i_tcon *tcon = crtc->tcon;
>> -       struct sun4i_backend *backend = crtc->backend;
>> 
>>         DRM_DEBUG_DRIVER("Enabling the TV Output\n");
>> 
>> -       sun4i_backend_apply_color_correction(backend);
>> +       sunxi_engine_apply_color_correction(crtc->engine);
>> 
>>         regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
>>                            SUN4I_TVE_EN_ENABLE,
>> diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h 
>> b/drivers/gpu/drm/sun4i/sunxi_engine.h
>> new file mode 100644
>> index 000000000000..b3c6e6148568
>> --- /dev/null
>> +++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
>> @@ -0,0 +1,112 @@
>> +/*
>> + * Copyright (C) 2017 Icenowy Zheng <icenowy@aosc.io>
>> + *
>> + * 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.
>> + */
>> +
>> +#ifndef _SUNXI_ENGINE_H_
>> +#define _SUNXI_ENGINE_H_
>> +
>> +struct sun4i_crtc;
> 
> This is not used. Please remove it.
> 
> 
> The rest looks good. Thanks for working this out. Once the minor 
> comments
> are fixed, please add my
> 
> Reviewed-by: Chen-Yu Tsai <wens@csie.org>
> 
>> +struct drm_plane;
>> +struct drm_device;
>> +
>> +struct sunxi_engine;
>> +
>> +struct sunxi_engine_ops {
>> +       void (*commit)(struct sunxi_engine *engine);
>> +       struct drm_plane **(*layers_init)(struct drm_device *drm,
>> +                                         struct sunxi_engine 
>> *engine);
>> +
>> +       void (*apply_color_correction)(struct sunxi_engine *engine);
>> +       void (*disable_color_correction)(struct sunxi_engine *engine);
>> +       int (*get_id)(struct sunxi_engine *engine);
>> +};
>> +
>> +/**
>> + * struct sunxi_engine - the common parts of an engine for sun4i-drm 
>> driver
>> + * @ops:       the operations of the engine
>> + * @regs:      the regmap of the engine
>> + */
>> +struct sunxi_engine {
>> +       const struct sunxi_engine_ops   *ops;
>> +
>> +       struct device_node              *node;
>> +       struct regmap                   *regs;
>> +
>> +       /* Engine list management */
>> +       struct list_head                list;
>> +};
>> +
>> +/**
>> + * sunxi_engine_commit() - commit all changes of the engine
>> + * @engine:    pointer to the engine
>> + */
>> +static inline void
>> +sunxi_engine_commit(struct sunxi_engine *engine)
>> +{
>> +       if (engine->ops && engine->ops->commit)
>> +               engine->ops->commit(engine);
>> +}
>> +
>> +/**
>> + * sunxi_engine_layers_init() - Create planes (layers) for the engine
>> + * @drm:       pointer to the drm_device for which planes will be 
>> created
>> + * @engine:    pointer to the engine
>> + */
>> +static inline struct drm_plane **
>> +sunxi_engine_layers_init(struct drm_device *drm, struct sunxi_engine 
>> *engine)
>> +{
>> +       if (engine->ops && engine->ops->layers_init)
>> +               return engine->ops->layers_init(drm, engine);
>> +       return ERR_PTR(-ENOSYS);
>> +}
>> +
>> +/**
>> + * sunxi_engine_apply_color_correction - Apply the RGB2YUV color 
>> correction
>> + * @engine:    pointer to the engine
>> + *
>> + * This functionality is optional for an engine, however, if the 
>> engine is
>> + * intended to be used with TV Encoder, the output will be incorrect
>> + * without the color correction, due to TV Encoder expects the engine 
>> to
>> + * output directly YUV signal.
>> + */
>> +static inline void
>> +sunxi_engine_apply_color_correction(struct sunxi_engine *engine)
>> +{
>> +       if (engine->ops && engine->ops->apply_color_correction)
>> +               engine->ops->apply_color_correction(engine);
>> +}
>> +
>> +/**
>> + * sunxi_engine_disable_color_correction - Disable the color space 
>> correction
>> + * @engine:    pointer to the engine
>> + *
>> + * This function is paired with apply_color_correction().
>> + */
>> +static inline void
>> +sunxi_engine_disable_color_correction(struct sunxi_engine *engine)
>> +{
>> +       if (engine->ops && engine->ops->disable_color_correction)
>> +               engine->ops->disable_color_correction(engine);
>> +}
>> +
>> +/**
>> + * sunxi_engine_get_id - Get the ID of the engine.
>> + * @engine:    pointer to the engine
>> + *
>> + * If the ID is not necessary, just do not implement it in 
>> sunxi_engine_ops,
>> + * and a default -1 will be returned.
>> + */
>> +static inline int
>> +sunxi_engine_get_id(struct sunxi_engine *engine)
>> +{
>> +       if (engine->ops && engine->ops->get_id)
>> +               return engine->ops->get_id(engine);
>> +
>> +       return -1;
>> +}
>> +#endif /* _SUNXI_ENGINE_H_ */
>> --
>> 2.12.2
>> 
>> --
>> You received this message because you are subscribed to the Google 
>> Groups "linux-sunxi" group.
>> To unsubscribe from this group and stop receiving emails from it, send 
>> an email to linux-sunxi+unsubscribe@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [linux-sunxi] [PATCH v6 05/13] drm/sun4i: abstract a engine type
  2017-05-05  8:36     ` icenowy
@ 2017-05-05  8:38       ` Chen-Yu Tsai
  0 siblings, 0 replies; 37+ messages in thread
From: Chen-Yu Tsai @ 2017-05-05  8:38 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Chen-Yu Tsai, devicetree, linux-sunxi, linux-kernel, dri-devel,
	Rob Herring, Maxime Ripard, linux-clk, linux-arm-kernel

On Fri, May 5, 2017 at 4:36 PM,  <icenowy@aosc.io> wrote:
> 在 2017-05-05 10:56,Chen-Yu Tsai 写道:
>>
>> On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
>>>
>>> As we are going to add support for the Allwinner DE2 engine in sun4i-drm
>>> driver, we will finally have two types of display engines -- the DE1
>>> backend and the DE2 mixer. They both do some display blending and feed
>>> graphics data to TCON, so I choose to call them both "engine" here.
>>
>>
>> These engines composite different layers into a final image which is
>> then sent out to the TCONs. As such, "compositor" would be an accurate
>> name.
>>
>> However, "engine" is OK, since Allwinner calls this stuff Display Engine
>> 1.0 and 2.0. Hope there won't be a 3.0 ...
>>
>> Maybe you should note that in your commit message. That is justifies the
>> name.
>>
>>>
>>> Abstract the engine type to a new struct with an ops struct, which
>>> contains
>>> functions that should be called outside the engine-specified code (in
>>> TCON, CRTC or TV Encoder code).
>>>
>>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>>> ---
>>> Changes in v6:
>>> - Rebased on wens's multi-pipeline patchset.
>>> - Split out Makefile changes.
>>> Changes in v5:
>>> - Really made a sunxi_engine struct type, and moved ops pointer
>>>   into it.
>>> - Added checked ops wrappers.
>>> - Changed the second parameter of layers_init from crtc to engine.
>>> Changes in v4:
>>> - Comments to tag the color correction functions as optional.
>>> - Check before calling the optional functions.
>>> - Change layers_init to satisfy new PATCH v4 04/11.
>>>
>>>  drivers/gpu/drm/sun4i/sun4i_backend.c |  68 ++++++++++++---------
>>>  drivers/gpu/drm/sun4i/sun4i_backend.h |  17 +++---
>>>  drivers/gpu/drm/sun4i/sun4i_crtc.c    |  11 ++--
>>>  drivers/gpu/drm/sun4i/sun4i_crtc.h    |   4 +-
>>>  drivers/gpu/drm/sun4i/sun4i_drv.c     |   2 +-
>>>  drivers/gpu/drm/sun4i/sun4i_drv.h     |   2 +-
>>>  drivers/gpu/drm/sun4i/sun4i_layer.c   |   8 +--
>>>  drivers/gpu/drm/sun4i/sun4i_layer.h   |   5 +-
>>>  drivers/gpu/drm/sun4i/sun4i_tcon.c    |  36 ++++++-----
>>>  drivers/gpu/drm/sun4i/sun4i_tv.c      |   9 ++-
>>>  drivers/gpu/drm/sun4i/sunxi_engine.h  | 112
>>> ++++++++++++++++++++++++++++++++++
>>>  11 files changed, 198 insertions(+), 76 deletions(-)
>>>  create mode 100644 drivers/gpu/drm/sun4i/sunxi_engine.h
>>>

[...]

>>> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h
>>> b/drivers/gpu/drm/sun4i/sun4i_layer.h
>>> index 5ea5c994d6ea..004b7cfe8ffb 100644
>>> --- a/drivers/gpu/drm/sun4i/sun4i_layer.h
>>> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
>>> @@ -13,6 +13,8 @@
>>>  #ifndef _SUN4I_LAYER_H_
>>>  #define _SUN4I_LAYER_H_
>>>
>>> +struct sunxi_engine;
>>> +
>>>  struct sun4i_layer {
>>>         struct drm_plane        plane;
>>>         struct sun4i_drv        *drv;
>>> @@ -27,6 +29,5 @@ plane_to_sun4i_layer(struct drm_plane *plane)
>>>  }
>>>
>>>  struct drm_plane **sun4i_layers_init(struct drm_device *drm,
>>> -                                    struct sun4i_crtc *crtc);
>>> -
>>> +                                    struct sunxi_engine *engine);
>>
>>
>> Please keep the newline.
>>
>>>  #endif /* _SUN4I_LAYER_H_ */
>>> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c
>>> b/drivers/gpu/drm/sun4i/sun4i_tcon.c
>>> index 29fd829aa54c..c48135a10fda 100644
>>> --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
>>> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
>>> @@ -26,12 +26,12 @@
>>>  #include <linux/regmap.h>
>>>  #include <linux/reset.h>
>>>
>>> -#include "sun4i_backend.h"
>>>  #include "sun4i_crtc.h"
>>>  #include "sun4i_dotclock.h"
>>>  #include "sun4i_drv.h"
>>>  #include "sun4i_rgb.h"
>>>  #include "sun4i_tcon.h"
>>> +#include "sunxi_engine.h"
>>
>>
>> Please keep the headers in alphabetical order.
>
>
> sunxi is of course after sun4i.

Sorry. My bad. :(

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

* Re: [linux-sunxi] [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC
  2017-05-05  3:31   ` [linux-sunxi] " Chen-Yu Tsai
@ 2017-05-05  8:53     ` icenowy
  2017-05-05 12:30       ` Maxime Ripard
  0 siblings, 1 reply; 37+ messages in thread
From: icenowy @ 2017-05-05  8:53 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Maxime Ripard, Rob Herring, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi,
	linux-kernel-owner

在 2017-05-05 11:31,Chen-Yu Tsai 写道:
> On Thu, May 4, 2017 at 7:48 PM, Icenowy Zheng <icenowy@aosc.io> wrote:
>> Allwinner V3s SoC features a "Display Engine 2.0" with only one TCON
>> which have RGB LCD output.
> 
> Please also mention that it only has one mixer.
> 
> For the subject, you could just say "Add device nodes for the display 
> pipeline".
> 
>> 
>> Add device nodes for it as well as the TCON.
>> 
>> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
>> ---
>>  arch/arm/boot/dts/sun8i-v3s.dtsi | 87 
>> ++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 87 insertions(+)
>> 
>> diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi 
>> b/arch/arm/boot/dts/sun8i-v3s.dtsi
>> index 71075969e5e6..0a895179d8ae 100644
>> --- a/arch/arm/boot/dts/sun8i-v3s.dtsi
>> +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi
>> @@ -41,6 +41,10 @@
>>   */
>> 
>>  #include <dt-bindings/interrupt-controller/arm-gic.h>
>> +#include <dt-bindings/clock/sun8i-v3s-ccu.h>
>> +#include <dt-bindings/clock/sun8i-de2.h>
>> +#include <dt-bindings/reset/sun8i-v3s-ccu.h>
>> +#include <dt-bindings/reset/sun8i-de2.h>
>> 
>>  / {
>>         #address-cells = <1>;
>> @@ -59,6 +63,12 @@
>>                 };
>>         };
>> 
>> +       de: display-engine {
>> +               compatible = "allwinner,sun8i-v3s-display-engine";
>> +               allwinner,pipelines = <&de2_mixer0>;
>> +               status = "disabled";
>> +       };
>> +
>>         timer {
>>                 compatible = "arm,armv7-timer";
>>                 interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | 
>> IRQ_TYPE_LEVEL_LOW)>,
>> @@ -93,6 +103,83 @@
>>                 #size-cells = <1>;
>>                 ranges;
>> 
>> +               de2_clocks: clock@1000000 {
>> +                       compatible = "allwinner,sun50i-h5-de2-clk";
> 
> I am a bit skeptical about this. Since the V3S only has one mixer, do 
> the clocks
> for the second one even exist?

It's described in the de_clock.c in the BSP source code, and in hardware
these bits can be really set (although without clock output).

So I use this compatible which has still the extra clocks.

> 
>> +                       reg = <0x01000000 0x100000>;
>> +                       clocks = <&ccu CLK_DE>,
>> +                                <&ccu CLK_BUS_DE>;
>> +                       clock-names = "mod",
>> +                                     "bus";
>> +                       resets = <&ccu RST_BUS_DE>;
>> +                       #clock-cells = <1>;
>> +                       #reset-cells = <1>;
>> +               };
>> +
>> +               de2_mixer0: mixer@1100000 {
>> +                       compatible = "allwinner,sun8i-v3s-de2-mixer";
>> +                       reg = <0x01100000 0x100000>;
>> +                       clocks = <&de2_clocks CLK_MIXER0>,
>> +                                <&de2_clocks CLK_BUS_MIXER0>;
>> +                       clock-names = "mod",
>> +                                     "bus";
> 
> Nit: could you list the bus clock first?
> 
> Regards
> ChenYu
> 
>> +                       resets = <&de2_clocks RST_MIXER0>;
>> +                       assigned-clocks = <&de2_clocks CLK_MIXER0>;
>> +                       assigned-clock-rates = <150000000>;
>> +
>> +                       ports {
>> +                               #address-cells = <1>;
>> +                               #size-cells = <0>;
>> +
>> +                               mixer0_out: port@1 {
>> +                                       #address-cells = <1>;
>> +                                       #size-cells = <0>;
>> +                                       reg = <1>;
>> +
>> +                                       mixer0_out_tcon0: endpoint@0 {
>> +                                               reg = <0>;
>> +                                               remote-endpoint = 
>> <&tcon0_in_mixer0>;
>> +                                       };
>> +                               };
>> +                       };
>> +               };
>> +
>> +               tcon0: lcd-controller@1c0c000 {
>> +                       compatible = "allwinner,sun8i-v3s-tcon";
>> +                       reg = <0x01c0c000 0x1000>;
>> +                       interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
>> +                       clocks = <&ccu CLK_BUS_TCON0>,
>> +                                <&ccu CLK_TCON0>;
>> +                       clock-names = "ahb",
>> +                                     "tcon-ch0";
>> +                       clock-output-names = "tcon-pixel-clock";
>> +                       resets = <&ccu RST_BUS_TCON0>;
>> +                       reset-names = "lcd";
>> +                       status = "disabled";
>> +
>> +                       ports {
>> +                               #address-cells = <1>;
>> +                               #size-cells = <0>;
>> +
>> +                               tcon0_in: port@0 {
>> +                                       #address-cells = <1>;
>> +                                       #size-cells = <0>;
>> +                                       reg = <0>;
>> +
>> +                                       tcon0_in_mixer0: endpoint@0 {
>> +                                               reg = <0>;
>> +                                               remote-endpoint = 
>> <&mixer0_out_tcon0>;
>> +                                       };
>> +                               };
>> +
>> +                               tcon0_out: port@1 {
>> +                                       #address-cells = <1>;
>> +                                       #size-cells = <0>;
>> +                                       reg = <1>;
>> +                               };
>> +                       };
>> +               };
>> +
>> +
>>                 mmc0: mmc@01c0f000 {
>>                         compatible = "allwinner,sun7i-a20-mmc";
>>                         reg = <0x01c0f000 0x1000>;
>> --
>> 2.12.2
>> 
>> --
>> You received this message because you are subscribed to the Google 
>> Groups "linux-sunxi" group.
>> To unsubscribe from this group and stop receiving emails from it, send 
>> an email to linux-sunxi+unsubscribe@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.

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

* Re: [linux-sunxi] [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC
  2017-05-05  8:53     ` icenowy
@ 2017-05-05 12:30       ` Maxime Ripard
  2017-05-05 12:34         ` Icenowy Zheng
  0 siblings, 1 reply; 37+ messages in thread
From: Maxime Ripard @ 2017-05-05 12:30 UTC (permalink / raw)
  To: icenowy
  Cc: Chen-Yu Tsai, Rob Herring, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi,
	linux-kernel-owner

[-- Attachment #1: Type: text/plain, Size: 724 bytes --]

On Fri, May 05, 2017 at 04:53:43PM +0800, icenowy@aosc.io wrote:
> > > +               de2_clocks: clock@1000000 {
> > > +                       compatible = "allwinner,sun50i-h5-de2-clk";
> > 
> > I am a bit skeptical about this. Since the V3S only has one mixer, do
> > the clocks
> > for the second one even exist?
> 
> It's described in the de_clock.c in the BSP source code, and in hardware
> these bits can be really set (although without clock output).
> 
> So I use this compatible which has still the extra clocks.

If it's not usable, then it shouldn't be in the code, it's basically
dead code.

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [linux-sunxi] [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC
  2017-05-05 12:30       ` Maxime Ripard
@ 2017-05-05 12:34         ` Icenowy Zheng
  2017-05-09 19:26           ` Maxime Ripard
  0 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-05 12:34 UTC (permalink / raw)
  To: linux-arm-kernel, Maxime Ripard
  Cc: devicetree, linux-kernel-owner, linux-sunxi, linux-kernel,
	dri-devel, Chen-Yu Tsai, Rob Herring, linux-clk,
	linux-arm-kernel



于 2017年5月5日 GMT+08:00 下午8:30:35, Maxime Ripard <maxime.ripard@free-electrons.com> 写到:
>On Fri, May 05, 2017 at 04:53:43PM +0800, icenowy@aosc.io wrote:
>> > > +               de2_clocks: clock@1000000 {
>> > > +                       compatible =
>"allwinner,sun50i-h5-de2-clk";
>> > 
>> > I am a bit skeptical about this. Since the V3S only has one mixer,
>do
>> > the clocks
>> > for the second one even exist?
>> 
>> It's described in the de_clock.c in the BSP source code, and in
>hardware
>> these bits can be really set (although without clock output).
>> 
>> So I use this compatible which has still the extra clocks.
>
>If it's not usable, then it shouldn't be in the code, it's basically
>dead code.

Thus should we have one more DE2 CCU compatible without mixer1
clocks for V3s?

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

* Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-04 16:50     ` icenowy
  2017-05-04 16:57       ` icenowy
@ 2017-05-05 12:36       ` Maxime Ripard
  2017-05-05 12:39         ` Icenowy Zheng
  1 sibling, 1 reply; 37+ messages in thread
From: Maxime Ripard @ 2017-05-05 12:36 UTC (permalink / raw)
  To: icenowy
  Cc: Rob Herring, Chen-Yu Tsai, linux-clk, devicetree,
	linux-arm-kernel, linux-kernel, dri-devel, linux-sunxi

[-- Attachment #1: Type: text/plain, Size: 2159 bytes --]

On Fri, May 05, 2017 at 12:50:51AM +0800, icenowy@aosc.io wrote:
> > > +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
> > > +				int layer, bool enable)
> > > +{
> > > +	u32 val;
> > > +	/* Currently the first UI channel is used */
> > > +	int chan = mixer->cfg->vi_num;
> > > +
> > > +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer, chan);
> > > +
> > > +	if (enable)
> > > +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
> > > +	else
> > > +		val = 0;
> > > +
> > > +	regmap_update_bits(mixer->engine.regs,
> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
> > > +
> > > +	/* Set the alpha configuration */
> > > +	regmap_update_bits(mixer->engine.regs,
> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
> > > +	regmap_update_bits(mixer->engine.regs,
> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
> > > +}
> > 
> > This one too.
> 
> It's called from sun8i_layer.c, so it cannot be static.

Fair enough.

> > > +	/* Set base coordinates */
> > > +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
> > > +			 state->crtc_x, state->crtc_y);
> > > +	regmap_write(mixer->engine.regs,
> > > +		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
> > > +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
> > 
> > X and Y are fixed point numbers. You want to keep only the higher 16
> > bits there.
> 
> Do you mean "lower 16 bits"? Thus should I (x & 0xffff) or ((u16)x) ?

Nevermind, I got confused with src_x and src_y.

> P.S. The negative coordinates are broken, how should I deal with it? or
> is the coordinates promised to be not negative?

Adjust the buffer base address, and use a shorter line. You have such
an example in the sun4i code.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-05 12:36       ` Maxime Ripard
@ 2017-05-05 12:39         ` Icenowy Zheng
  2017-05-09 20:19           ` Maxime Ripard
  0 siblings, 1 reply; 37+ messages in thread
From: Icenowy Zheng @ 2017-05-05 12:39 UTC (permalink / raw)
  To: linux-arm-kernel, Maxime Ripard
  Cc: devicetree, linux-sunxi, linux-kernel, dri-devel, Chen-Yu Tsai,
	Rob Herring, linux-clk



于 2017年5月5日 GMT+08:00 下午8:36:18, Maxime Ripard <maxime.ripard@free-electrons.com> 写到:
>On Fri, May 05, 2017 at 12:50:51AM +0800, icenowy@aosc.io wrote:
>> > > +void sun8i_mixer_layer_enable(struct sun8i_mixer *mixer,
>> > > +				int layer, bool enable)
>> > > +{
>> > > +	u32 val;
>> > > +	/* Currently the first UI channel is used */
>> > > +	int chan = mixer->cfg->vi_num;
>> > > +
>> > > +	DRM_DEBUG_DRIVER("Enabling layer %d in channel %d\n", layer,
>chan);
>> > > +
>> > > +	if (enable)
>> > > +		val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
>> > > +	else
>> > > +		val = 0;
>> > > +
>> > > +	regmap_update_bits(mixer->engine.regs,
>> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN, val);
>> > > +
>> > > +	/* Set the alpha configuration */
>> > > +	regmap_update_bits(mixer->engine.regs,
>> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK,
>> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_DEF);
>> > > +	regmap_update_bits(mixer->engine.regs,
>> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(chan, layer),
>> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK,
>> > > +			   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_DEF);
>> > > +}
>> > 
>> > This one too.
>> 
>> It's called from sun8i_layer.c, so it cannot be static.
>
>Fair enough.
>
>> > > +	/* Set base coordinates */
>> > > +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
>> > > +			 state->crtc_x, state->crtc_y);
>> > > +	regmap_write(mixer->engine.regs,
>> > > +		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
>> > > +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
>> > 
>> > X and Y are fixed point numbers. You want to keep only the higher
>16
>> > bits there.
>> 
>> Do you mean "lower 16 bits"? Thus should I (x & 0xffff) or ((u16)x) ?
>
>Nevermind, I got confused with src_x and src_y.
>
>> P.S. The negative coordinates are broken, how should I deal with it?
>or
>> is the coordinates promised to be not negative?
>
>Adjust the buffer base address, and use a shorter line. You have such
>an example in the sun4i code.

Are they these two lines:
```
paddr += (state->src_x >> 16) * bpp;
paddr += (state->src_y >> 16) * fb->pitches[0];
```

I think I copied them here, so I don't need to mind this problem any more, right?

>
>Maxime

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

* Re: [linux-sunxi] [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC
  2017-05-05 12:34         ` Icenowy Zheng
@ 2017-05-09 19:26           ` Maxime Ripard
  0 siblings, 0 replies; 37+ messages in thread
From: Maxime Ripard @ 2017-05-09 19:26 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: linux-arm-kernel, devicetree, linux-kernel-owner, linux-sunxi,
	linux-kernel, dri-devel, Chen-Yu Tsai, Rob Herring, linux-clk

[-- Attachment #1: Type: text/plain, Size: 1117 bytes --]

1;4601;0c
On Fri, May 05, 2017 at 08:34:16PM +0800, Icenowy Zheng wrote:
> 
> 
> 于 2017年5月5日 GMT+08:00 下午8:30:35, Maxime Ripard <maxime.ripard@free-electrons.com> 写到:
> >On Fri, May 05, 2017 at 04:53:43PM +0800, icenowy@aosc.io wrote:
> >> > > +               de2_clocks: clock@1000000 {
> >> > > +                       compatible =
> >"allwinner,sun50i-h5-de2-clk";
> >> > 
> >> > I am a bit skeptical about this. Since the V3S only has one mixer,
> >do
> >> > the clocks
> >> > for the second one even exist?
> >> 
> >> It's described in the de_clock.c in the BSP source code, and in
> >hardware
> >> these bits can be really set (although without clock output).
> >> 
> >> So I use this compatible which has still the extra clocks.
> >
> >If it's not usable, then it shouldn't be in the code, it's basically
> >dead code.
> 
> Thus should we have one more DE2 CCU compatible without mixer1
> clocks for V3s?

If those clocks don't exist on v3s, then yes.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers
  2017-05-05 12:39         ` Icenowy Zheng
@ 2017-05-09 20:19           ` Maxime Ripard
  0 siblings, 0 replies; 37+ messages in thread
From: Maxime Ripard @ 2017-05-09 20:19 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: linux-arm-kernel, devicetree, linux-sunxi, linux-kernel,
	dri-devel, Chen-Yu Tsai, Rob Herring, linux-clk

[-- Attachment #1: Type: text/plain, Size: 1363 bytes --]

On Fri, May 05, 2017 at 08:39:31PM +0800, Icenowy Zheng wrote:
> >> > > +	/* Set base coordinates */
> >> > > +	DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n",
> >> > > +			 state->crtc_x, state->crtc_y);
> >> > > +	regmap_write(mixer->engine.regs,
> >> > > +		     SUN8I_MIXER_CHAN_UI_LAYER_COORD(chan, layer),
> >> > > +		     SUN8I_MIXER_COORD(state->crtc_x, state->crtc_y));
> >> > 
> >> > X and Y are fixed point numbers. You want to keep only the higher
> >16
> >> > bits there.
> >> 
> >> Do you mean "lower 16 bits"? Thus should I (x & 0xffff) or ((u16)x) ?
> >
> >Nevermind, I got confused with src_x and src_y.
> >
> >> P.S. The negative coordinates are broken, how should I deal with it?
> >or
> >> is the coordinates promised to be not negative?
> >
> >Adjust the buffer base address, and use a shorter line. You have such
> >an example in the sun4i code.
> 
> Are they these two lines:
> ```
> paddr += (state->src_x >> 16) * bpp;
> paddr += (state->src_y >> 16) * fb->pitches[0];
> ```
> 
> I think I copied them here, so I don't need to mind this problem any
> more, right?

Hmmm, yes, probably. That's pretty easy to test anyway, you just need
to set up a plane with a negative base coordinate.

Maxime

-- 
Maxime Ripard, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

end of thread, other threads:[~2017-05-09 20:19 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-04 11:48 [PATCH v6 00/13] Initial Allwinner Display Engine 2.0 Support Icenowy Zheng
2017-05-04 11:48 ` [PATCH v6 01/13] dt-bindings: add binding for the Allwinner DE2 CCU Icenowy Zheng
2017-05-04 11:48 ` [PATCH v6 02/13] clk: sunxi-ng: add support for " Icenowy Zheng
2017-05-04 12:50   ` Maxime Ripard
2017-05-04 11:48 ` [PATCH v6 03/13] dt-bindings: add bindings for DE2 on V3s SoC Icenowy Zheng
2017-05-05  3:24   ` [linux-sunxi] " Chen-Yu Tsai
2017-05-04 11:48 ` [PATCH v6 04/13] drm/sun4i: return only planes for layers created Icenowy Zheng
2017-05-04 11:48 ` [PATCH v6 05/13] drm/sun4i: abstract a engine type Icenowy Zheng
2017-05-05  2:56   ` [linux-sunxi] " Chen-Yu Tsai
2017-05-05  8:36     ` icenowy
2017-05-05  8:38       ` Chen-Yu Tsai
2017-05-04 11:48 ` [PATCH v6 06/13] drm/sun4i: add a dedicated module for sun4i-backend and sun4i-layer Icenowy Zheng
2017-05-05  3:10   ` [linux-sunxi] " Chen-Yu Tsai
2017-05-04 11:48 ` [PATCH v6 07/13] drm/sun4i: add a Kconfig option for sun4i-backend Icenowy Zheng
2017-05-05  3:14   ` [linux-sunxi] " Chen-Yu Tsai
2017-05-04 11:48 ` [PATCH v6 08/13] drm/sun4i: add support for Allwinner DE2 mixers Icenowy Zheng
2017-05-04 13:05   ` Maxime Ripard
2017-05-04 16:50     ` icenowy
2017-05-04 16:57       ` icenowy
2017-05-04 17:14         ` icenowy
2017-05-05 12:36       ` Maxime Ripard
2017-05-05 12:39         ` Icenowy Zheng
2017-05-09 20:19           ` Maxime Ripard
2017-05-04 16:52     ` icenowy
2017-05-05  3:40       ` [linux-sunxi] " Chen-Yu Tsai
2017-05-04 11:48 ` [PATCH v6 09/13] drm/sun4i: Add compatible string for V3s display engine Icenowy Zheng
2017-05-04 11:48 ` [PATCH v6 10/13] drm/sun4i: tcon: add support for V3s TCON Icenowy Zheng
2017-05-05  3:33   ` [linux-sunxi] " Chen-Yu Tsai
2017-05-04 11:48 ` [PATCH v6 11/13] ARM: dts: sun8i: add DE2 nodes for V3s SoC Icenowy Zheng
2017-05-05  3:31   ` [linux-sunxi] " Chen-Yu Tsai
2017-05-05  8:53     ` icenowy
2017-05-05 12:30       ` Maxime Ripard
2017-05-05 12:34         ` Icenowy Zheng
2017-05-09 19:26           ` Maxime Ripard
2017-05-04 11:48 ` [PATCH v6 12/13] ARM: dts: sun8i: add pinmux for LCD pins of " Icenowy Zheng
2017-05-05  3:25   ` [linux-sunxi] " Chen-Yu Tsai
2017-05-04 11:48 ` [PATCH v6 13/13] [DO NOT MERGE] ARM: dts: sun8i: enable LCD panel of Lichee Pi Zero Icenowy Zheng

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