linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/19] drm: Add Allwinner A10 display engine support
@ 2015-10-30 14:20 Maxime Ripard
  2015-10-30 14:20 ` [PATCH 01/19] clk: sunxi: Add display clock Maxime Ripard
                   ` (20 more replies)
  0 siblings, 21 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

Hi everyone,

The Allwinner SoCs (except for the very latest ones) all share the
same set of controllers, loosely coupled together to form the display
pipeline.

Depending on the SoC, the number of instances of the controller will
change (2 instances of each in the A10, only one in the A13, for
example), and the output availables will change too (HDMI, composite,
VGA on the A20, none of them on the A13).

On most featured SoCs, it looks like that:

 +--------------------------------------------+
 |                    RAM                     |
 +--------------------------------------------+
       |            |      |            |
       v            |      |            v
 +----------------+ |      | +----------------+
 |    Frontend    | |      | |    Frontend    |
 +----------------+ |      | +----------------+
         |          |      |         |
         v          |      |         v
 +----------------+ |      | +----------------+
 |    Backend     |<+      +>|    Backend     |
 +----------------+          +----------------+
         |                           |
         v                           v
 +----------------+          +----------------+---> LVDS
 |      TCON      |          |      TCON      |---> RGB
 +----------------+          +----------------+
       |       +---+       +---+          |
       |           |       |              |
       v           v       v              v
 +------------+  +------------+  +------------+---> VGA
 | TV Encoder |  |    HDMI    |  | TV Encoder |---> Composite
 +------------+  +------------+  +------------+

The current code only assumes that there is a single instance of all
the controllers. It also supports only the RGB and Composite
interfaces.

A few more things are missing though, and will be supported
eventually:
  - Overscan support
  - Asynchronous page flip
  - Multiple plane support
  - Composite / VGA Hotplug detection
  - More outputs
  - Support for several videos pipelines

And there's one big gotcha: thhe code to parse the mode from the
kernel commandline doesn't seem to support named modes. Since we
expose the various TV standards through named modes, it means that
there's no way to use a particular standard to display something
during the kernel boot. The default will always be used, in other
words, PAL.

A few more questions that are probably going to be raised during the
review:
  - How do you associate private data to a mode, for example to deal
    with the non-generic, driver-specific settings required to deal
    with the various TV standards? drm_display_mode seems to have a
    private field, but it isn't always preserved.
  - How do you setup properties in the kernel command line? In order
    to have a decent display during boot on relevant interfaces, you
    probably want to setup the overscan beforehand. Overscan seems to
    be handled through properties, and afaik, there's no way to set
    that from the cmdline. Should we use a kernel parameter to set the
    default value instead?

Thanks!
Maxime

Maxime Ripard (19):
  clk: sunxi: Add display clock
  clk: sunxi: Add PLL3 clock
  clk: sunxi: Add TCON channel0 clock
  clk: sunxi: Add TCON channel1 clock
  clk: sunxi: add DRAM gates
  clk: sunxi: Add Allwinner R8 AHB gates support
  drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
  drm: Add Allwinner A10 Display Engine support
  drm: sun4i: Add DT bindings documentation
  drm: sun4i: Add RGB output
  drm: sun4i: Add composite output
  drm: sun4i: tv: Add PAL output standard
  drm: sun4i: tv: Add NTSC output standard
  ARM: sun5i: dt: Add pll3 and pll7 clocks
  ARM: sun5i: dt: Add display and TCON clocks
  ARM: sun5i: dt: Add DRAM gates
  ARM: sun5i: dt: Add display blocks to the DTSI
  ARM: sun5i: r8: Add AHB gates to the DTSI
  ARM: sun5i: chip: Enable the TV Encoder

 .../devicetree/bindings/drm/sunxi/sun4i-drm.txt    | 122 ++++
 arch/arm/boot/dts/sun5i-a10s.dtsi                  |   9 +-
 arch/arm/boot/dts/sun5i-a13.dtsi                   |   3 +-
 arch/arm/boot/dts/sun5i-r8.dtsi                    |  46 +-
 arch/arm/boot/dts/sun5i.dtsi                       | 137 +++++
 drivers/clk/sunxi/Makefile                         |   4 +
 drivers/clk/sunxi/clk-simple-gates.c               |   4 +
 drivers/clk/sunxi/clk-sun4i-display.c              | 199 +++++++
 drivers/clk/sunxi/clk-sun4i-pll3.c                 |  84 +++
 drivers/clk/sunxi/clk-sun4i-tcon-ch0.c             | 173 ++++++
 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c             | 167 ++++++
 drivers/gpu/drm/Kconfig                            |   2 +
 drivers/gpu/drm/Makefile                           |   3 +-
 drivers/gpu/drm/panel/panel-simple.c               |  26 +
 drivers/gpu/drm/sun4i/Kconfig                      |  14 +
 drivers/gpu/drm/sun4i/Makefile                     |  11 +
 drivers/gpu/drm/sun4i/sun4i_backend.c              | 271 +++++++++
 drivers/gpu/drm/sun4i/sun4i_backend.h              | 159 ++++++
 drivers/gpu/drm/sun4i/sun4i_crtc.c                 | 117 ++++
 drivers/gpu/drm/sun4i/sun4i_crtc.h                 |  31 ++
 drivers/gpu/drm/sun4i/sun4i_drv.c                  | 296 ++++++++++
 drivers/gpu/drm/sun4i/sun4i_drv.h                  |  30 +
 drivers/gpu/drm/sun4i/sun4i_framebuffer.c          |  54 ++
 drivers/gpu/drm/sun4i/sun4i_framebuffer.h          |  19 +
 drivers/gpu/drm/sun4i/sun4i_layer.c                | 111 ++++
 drivers/gpu/drm/sun4i/sun4i_layer.h                |  30 +
 drivers/gpu/drm/sun4i/sun4i_rgb.c                  | 243 ++++++++
 drivers/gpu/drm/sun4i/sun4i_rgb.h                  |  18 +
 drivers/gpu/drm/sun4i/sun4i_tcon.c                 | 478 ++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_tcon.h                 | 182 ++++++
 drivers/gpu/drm/sun4i/sun4i_tv.c                   | 619 +++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_tv.h                   |  18 +
 32 files changed, 3673 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt
 create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c
 create mode 100644 drivers/clk/sunxi/clk-sun4i-pll3.c
 create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch0.c
 create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
 create mode 100644 drivers/gpu/drm/sun4i/Kconfig
 create mode 100644 drivers/gpu/drm/sun4i/Makefile
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_backend.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_backend.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_crtc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_crtc.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_drv.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_drv.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_framebuffer.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_framebuffer.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_layer.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_layer.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_rgb.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_rgb.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tcon.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tcon.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.h

-- 
2.6.2


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

* [PATCH 01/19] clk: sunxi: Add display clock
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 21:29   ` Stephen Boyd
  2015-10-31 10:28   ` Chen-Yu Tsai
  2015-10-30 14:20 ` [PATCH 02/19] clk: sunxi: Add PLL3 clock Maxime Ripard
                   ` (19 subsequent siblings)
  20 siblings, 2 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The A10 SoCs and its relatives has a special clock controller to drive the
display engines (both frontend and backend).

Add a driver for it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi/Makefile            |   1 +
 drivers/clk/sunxi/clk-sun4i-display.c | 199 ++++++++++++++++++++++++++++++++++
 2 files changed, 200 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c

diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index cb4c299214ce..a9e1a5885846 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -9,6 +9,7 @@ obj-y += clk-a10-mod1.o
 obj-y += clk-a10-pll2.o
 obj-y += clk-a20-gmac.o
 obj-y += clk-mod0.o
+obj-y += clk-sun4i-display.o
 obj-y += clk-simple-gates.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
diff --git a/drivers/clk/sunxi/clk-sun4i-display.c b/drivers/clk/sunxi/clk-sun4i-display.c
new file mode 100644
index 000000000000..f13b095c6d7a
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun4i-display.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2015 Maxime Ripard
+ *
+ * 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.
+ *
+ * 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-provider.h>
+#include <linux/of_address.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define SUN4I_A10_DISPLAY_PARENTS	3
+
+#define SUN4I_A10_DISPLAY_GATE_BIT	31
+#define SUN4I_A10_DISPLAY_RESET_BIT	30
+#define SUN4I_A10_DISPLAY_MUX_MASK	3
+#define SUN4I_A10_DISPLAY_MUX_SHIFT	24
+#define SUN4I_A10_DISPLAY_DIV_WIDTH	4
+#define SUN4I_A10_DISPLAY_DIV_SHIFT	0
+
+struct reset_data {
+	void __iomem			*reg;
+	spinlock_t			*lock;
+	struct reset_controller_dev	rcdev;
+};
+
+static DEFINE_SPINLOCK(sun4i_a10_display_lock);
+
+static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev,
+				    unsigned long id)
+{
+	struct reset_data *data = container_of(rcdev,
+					       struct reset_data,
+					       rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg & ~BIT(SUN4I_A10_DISPLAY_RESET_BIT), data->reg);
+
+	spin_unlock_irqrestore(data->lock, flags);
+
+	return 0;
+}
+
+static int sun4i_a10_display_deassert(struct reset_controller_dev *rcdev,
+				      unsigned long id)
+{
+	struct reset_data *data = container_of(rcdev,
+						   struct reset_data,
+						   rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg | BIT(SUN4I_A10_DISPLAY_RESET_BIT), data->reg);
+
+	spin_unlock_irqrestore(data->lock, flags);
+
+	return 0;
+}
+
+static int sun4i_a10_display_status(struct reset_controller_dev *rcdev,
+				    unsigned long id)
+{
+	struct reset_data *data = container_of(rcdev,
+					       struct reset_data,
+					       rcdev);
+
+	return !(readl(data->reg) & BIT(SUN4I_A10_DISPLAY_RESET_BIT));
+}
+
+static struct reset_control_ops sun4i_a10_display_reset_ops = {
+	.assert		= sun4i_a10_display_assert,
+	.deassert	= sun4i_a10_display_deassert,
+	.status		= sun4i_a10_display_status,
+};
+
+static int sun4i_a10_display_reset_xlate(struct reset_controller_dev *rcdev,
+					 const struct of_phandle_args *spec)
+{
+	if (WARN_ON(spec->args_count != rcdev->of_reset_n_cells))
+		return -EINVAL;
+
+	/* We only have a single reset signal */
+	return 0;
+}
+
+static void __init sun4i_a10_display_setup(struct device_node *node)
+{
+	const char *parents[SUN4I_A10_DISPLAY_PARENTS];
+	const char *clk_name = node->name;
+	struct reset_data *reset_data;
+	struct clk_divider *div;
+	struct clk_gate *gate;
+	struct clk_mux *mux;
+	void __iomem *reg;
+	struct clk *clk;
+	int i;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg)) {
+		pr_err("%s: Could not map the clock registers\n", clk_name);
+		return;
+	}
+
+	for (i = 0; i < SUN4I_A10_DISPLAY_PARENTS; i++)
+		parents[i] = of_clk_get_parent_name(node, i);
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return;
+
+	mux->reg = reg;
+	mux->shift = SUN4I_A10_DISPLAY_MUX_SHIFT;
+	mux->mask = SUN4I_A10_DISPLAY_MUX_MASK;
+	mux->lock = &sun4i_a10_display_lock;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		goto free_mux;
+
+	gate->reg = reg;
+	gate->bit_idx = SUN4I_A10_DISPLAY_GATE_BIT;
+	gate->lock = &sun4i_a10_display_lock;
+
+	div = kzalloc(sizeof(*div), GFP_KERNEL);
+	if (!div)
+		goto free_gate;
+
+	div->reg = reg;
+	div->shift = SUN4I_A10_DISPLAY_DIV_SHIFT;
+	div->width = SUN4I_A10_DISPLAY_DIV_WIDTH;
+	div->lock = &sun4i_a10_display_lock;
+
+	clk = clk_register_composite(NULL, clk_name,
+				     parents, SUN4I_A10_DISPLAY_PARENTS,
+				     &mux->hw, &clk_mux_ops,
+				     &div->hw, &clk_divider_ops,
+				     &gate->hw, &clk_gate_ops,
+				     0);
+	if (IS_ERR(clk)) {
+		pr_err("%s: Couldn't register the clock\n", clk_name);
+		goto free_div;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
+	if (!reset_data)
+		goto free_clk;
+
+	reset_data->reg = reg;
+	reset_data->lock = &sun4i_a10_display_lock;
+	reset_data->rcdev.nr_resets = 1;
+	reset_data->rcdev.ops = &sun4i_a10_display_reset_ops;
+	reset_data->rcdev.of_node = node;
+	reset_data->rcdev.of_reset_n_cells = 0;
+	reset_data->rcdev.of_xlate = &sun4i_a10_display_reset_xlate;
+
+	if (reset_controller_register(&reset_data->rcdev)) {
+		pr_err("%s: Couldn't register the reset controller\n",
+		       clk_name);
+		goto free_reset;
+	}
+
+	return;
+
+free_reset:
+	kfree(reset_data);
+free_clk:
+	clk_unregister(clk);
+free_div:
+	kfree(div);
+free_gate:
+	kfree(gate);
+free_mux:
+	kfree(mux);
+}
+
+CLK_OF_DECLARE(sun4i_a10_display, "allwinner,sun4i-a10-display-clk",
+	       sun4i_a10_display_setup);
-- 
2.6.2


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

* [PATCH 02/19] clk: sunxi: Add PLL3 clock
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
  2015-10-30 14:20 ` [PATCH 01/19] clk: sunxi: Add display clock Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 21:32   ` Stephen Boyd
  2015-10-30 14:20 ` [PATCH 03/19] clk: sunxi: Add TCON channel0 clock Maxime Ripard
                   ` (18 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The A10 SoCs and relatives have a PLL controller to drive the PLL3 and
PLL7, clocked from a 3MHz oscillator, that drives the display related
clocks (GPU, display engine, TCON, etc.)

Add a driver for it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi/Makefile         |  3 +-
 drivers/clk/sunxi/clk-sun4i-pll3.c | 84 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/sunxi/clk-sun4i-pll3.c

diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index a9e1a5885846..40c32ffd912c 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -9,8 +9,9 @@ obj-y += clk-a10-mod1.o
 obj-y += clk-a10-pll2.o
 obj-y += clk-a20-gmac.o
 obj-y += clk-mod0.o
-obj-y += clk-sun4i-display.o
 obj-y += clk-simple-gates.o
+obj-y += clk-sun4i-display.o
+obj-y += clk-sun4i-pll3.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
 obj-y += clk-sun9i-mmc.o
diff --git a/drivers/clk/sunxi/clk-sun4i-pll3.c b/drivers/clk/sunxi/clk-sun4i-pll3.c
new file mode 100644
index 000000000000..7ea178bf19fa
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun4i-pll3.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 Maxime Ripard
+ *
+ * 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.
+ *
+ * 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-provider.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define SUN4I_A10_PLL3_GATE_BIT	31
+#define SUN4I_A10_PLL3_DIV_WIDTH	7
+#define SUN4I_A10_PLL3_DIV_SHIFT	0
+
+static DEFINE_SPINLOCK(sun4i_a10_pll3_lock);
+
+static void __init sun4i_a10_pll3_setup(struct device_node *node)
+{
+	const char *clk_name = node->name, *parent;
+	struct clk_factor *mult;
+	struct clk_gate *gate;
+	void __iomem *reg;
+	struct clk *clk;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+	parent = of_clk_get_parent_name(node, 0);
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg)) {
+		pr_err("%s: Could not map the clock registers\n", clk_name);
+		return;
+	}
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return;
+
+	gate->reg = reg;
+	gate->bit_idx = SUN4I_A10_PLL3_GATE_BIT;
+	gate->lock = &sun4i_a10_pll3_lock;
+
+	mult = kzalloc(sizeof(*mult), GFP_KERNEL);
+	if (!mult)
+		goto free_gate;
+
+	mult->reg = reg;
+	mult->shift = SUN4I_A10_PLL3_DIV_SHIFT;
+	mult->width = SUN4I_A10_PLL3_DIV_WIDTH;
+	mult->lock = &sun4i_a10_pll3_lock;
+
+	clk = clk_register_composite(NULL, clk_name,
+				     &parent, 1,
+				     NULL, NULL,
+				     &mult->hw, &clk_factor_ops,
+				     &gate->hw, &clk_gate_ops,
+				     0);
+	if (IS_ERR(clk)) {
+		pr_err("%s: Couldn't register the clock\n", clk_name);
+		goto free_mult;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	return;
+
+free_mult:
+	kfree(mult);
+free_gate:
+	kfree(gate);
+}
+
+CLK_OF_DECLARE(sun4i_a10_pll3, "allwinner,sun4i-a10-pll3-clk",
+	       sun4i_a10_pll3_setup);
-- 
2.6.2


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

* [PATCH 03/19] clk: sunxi: Add TCON channel0 clock
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
  2015-10-30 14:20 ` [PATCH 01/19] clk: sunxi: Add display clock Maxime Ripard
  2015-10-30 14:20 ` [PATCH 02/19] clk: sunxi: Add PLL3 clock Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-31 10:19   ` Chen-Yu Tsai
  2015-10-30 14:20 ` [PATCH 04/19] clk: sunxi: Add TCON channel1 clock Maxime Ripard
                   ` (17 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The TCON is a controller generating the timings to output videos signals,
acting like both a CRTC and an encoder.

It has two channels depending on the output, each channel being driven by
its own clock (and own clock controller).

Add a driver for the channel 0 clock.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi/Makefile             |   1 +
 drivers/clk/sunxi/clk-sun4i-tcon-ch0.c | 173 +++++++++++++++++++++++++++++++++
 2 files changed, 174 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch0.c

diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 40c32ffd912c..7821b2b63d58 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -12,6 +12,7 @@ obj-y += clk-mod0.o
 obj-y += clk-simple-gates.o
 obj-y += clk-sun4i-display.o
 obj-y += clk-sun4i-pll3.o
+obj-y += clk-sun4i-tcon-ch0.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
 obj-y += clk-sun9i-mmc.o
diff --git a/drivers/clk/sunxi/clk-sun4i-tcon-ch0.c b/drivers/clk/sunxi/clk-sun4i-tcon-ch0.c
new file mode 100644
index 000000000000..db10cfb94a1d
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch0.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2015 Maxime Ripard
+ *
+ * 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.
+ *
+ * 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-provider.h>
+#include <linux/of_address.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define SUN4I_A10_TCON_CH0_PARENTS	4
+
+#define SUN4I_A10_TCON_CH0_GATE_BIT	31
+#define SUN4I_A10_TCON_CH0_RESET_SHIFT	29
+#define SUN4I_A10_TCON_CH0_MUX_MASK	3
+#define SUN4I_A10_TCON_CH0_MUX_SHIFT	24
+
+struct reset_data {
+	void __iomem			*reg;
+	spinlock_t			*lock;
+	struct reset_controller_dev	rcdev;
+};
+
+static DEFINE_SPINLOCK(sun4i_a10_tcon_ch0_lock);
+
+static int sun4i_a10_tcon_ch0_assert(struct reset_controller_dev *rcdev,
+				     unsigned long id)
+{
+	struct reset_data *data = container_of(rcdev,
+					       struct reset_data,
+					       rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg & ~BIT(SUN4I_A10_TCON_CH0_RESET_SHIFT + id), data->reg);
+
+	spin_unlock_irqrestore(data->lock, flags);
+
+	return 0;
+}
+
+static int sun4i_a10_tcon_ch0_deassert(struct reset_controller_dev *rcdev,
+				       unsigned long id)
+{
+	struct reset_data *data = container_of(rcdev,
+						   struct reset_data,
+						   rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg | BIT(SUN4I_A10_TCON_CH0_RESET_SHIFT + id), data->reg);
+
+	spin_unlock_irqrestore(data->lock, flags);
+
+	return 0;
+}
+
+static int sun4i_a10_tcon_ch0_status(struct reset_controller_dev *rcdev,
+				     unsigned long id)
+{
+	struct reset_data *data = container_of(rcdev,
+					       struct reset_data,
+					       rcdev);
+
+	return !(readl(data->reg) & BIT(SUN4I_A10_TCON_CH0_RESET_SHIFT + id));
+}
+
+static struct reset_control_ops sun4i_a10_tcon_ch0_reset_ops = {
+	.assert		= sun4i_a10_tcon_ch0_assert,
+	.deassert	= sun4i_a10_tcon_ch0_deassert,
+	.status		= sun4i_a10_tcon_ch0_status,
+};
+
+static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node)
+{
+	const char *parents[SUN4I_A10_TCON_CH0_PARENTS];
+	const char *clk_name = node->name;
+	struct reset_data *reset_data;
+	struct clk_gate *gate;
+	struct clk_mux *mux;
+	void __iomem *reg;
+	struct clk *clk;
+	int i;
+
+	of_property_read_string(node, "clock-output-names", &clk_name);
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg)) {
+		pr_err("%s: Could not map the clock registers\n", clk_name);
+		return;
+	}
+
+	for (i = 0; i < SUN4I_A10_TCON_CH0_PARENTS; i++)
+		parents[i] = of_clk_get_parent_name(node, i);
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return;
+
+	mux->reg = reg;
+	mux->shift = SUN4I_A10_TCON_CH0_MUX_SHIFT;
+	mux->mask = SUN4I_A10_TCON_CH0_MUX_MASK;
+	mux->lock = &sun4i_a10_tcon_ch0_lock;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		goto free_mux;
+
+	gate->reg = reg;
+	gate->bit_idx = SUN4I_A10_TCON_CH0_GATE_BIT;
+	gate->lock = &sun4i_a10_tcon_ch0_lock;
+
+	clk = clk_register_composite(NULL, clk_name,
+				     parents, SUN4I_A10_TCON_CH0_PARENTS,
+				     &mux->hw, &clk_mux_ops,
+				     NULL, NULL,
+				     &gate->hw, &clk_gate_ops,
+				     0);
+	if (IS_ERR(clk)) {
+		pr_err("%s: Couldn't register the clock\n", clk_name);
+		goto free_gate;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
+	if (!reset_data)
+		goto free_clk;
+
+	reset_data->reg = reg;
+	reset_data->lock = &sun4i_a10_tcon_ch0_lock;
+	reset_data->rcdev.nr_resets = 2;
+	reset_data->rcdev.ops = &sun4i_a10_tcon_ch0_reset_ops;
+	reset_data->rcdev.of_node = node;
+
+	if (reset_controller_register(&reset_data->rcdev)) {
+		pr_err("%s: Couldn't register the reset controller\n",
+		       clk_name);
+		goto free_reset;
+	}
+
+	return;
+
+free_reset:
+	kfree(reset_data);
+free_clk:
+	clk_unregister(clk);
+free_gate:
+	kfree(gate);
+free_mux:
+	kfree(mux);
+}
+
+CLK_OF_DECLARE(sun4i_a10_tcon_ch0, "allwinner,sun4i-a10-tcon-ch0-clk",
+	       sun4i_a10_tcon_ch0_setup);
-- 
2.6.2


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

* [PATCH 04/19] clk: sunxi: Add TCON channel1 clock
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (2 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 03/19] clk: sunxi: Add TCON channel0 clock Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 21:37   ` Stephen Boyd
  2015-10-31  9:53   ` Chen-Yu Tsai
  2015-10-30 14:20 ` [PATCH 05/19] clk: sunxi: add DRAM gates Maxime Ripard
                   ` (16 subsequent siblings)
  20 siblings, 2 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The TCON is a controller generating the timings to output videos signals,
acting like both a CRTC and an encoder.

It has two channels depending on the output, each channel being driven by
its own clock (and own clock controller).

Add a driver for the channel 1 clock.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi/Makefile             |   1 +
 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c | 167 +++++++++++++++++++++++++++++++++
 2 files changed, 168 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c

diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 7821b2b63d58..ed59ee4b3a85 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -13,6 +13,7 @@ obj-y += clk-simple-gates.o
 obj-y += clk-sun4i-display.o
 obj-y += clk-sun4i-pll3.o
 obj-y += clk-sun4i-tcon-ch0.o
+obj-y += clk-sun4i-tcon-ch1.o
 obj-y += clk-sun8i-mbus.o
 obj-y += clk-sun9i-core.o
 obj-y += clk-sun9i-mmc.o
diff --git a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
new file mode 100644
index 000000000000..9f2ab52b0bf9
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2015 Maxime Ripard
+ *
+ * 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.
+ *
+ * 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-provider.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define SUN4I_TCON_CH1_SCLK_NAME_LEN	32
+
+#define SUN4I_A10_TCON_CH1_SCLK1_PARENTS	2
+#define SUN4I_A10_TCON_CH1_SCLK2_PARENTS	4
+
+#define SUN4I_A10_TCON_CH1_SCLK2_GATE_BIT	31
+#define SUN4I_A10_TCON_CH1_SCLK2_MUX_MASK	3
+#define SUN4I_A10_TCON_CH1_SCLK2_MUX_SHIFT	24
+#define SUN4I_A10_TCON_CH1_SCLK2_DIV_WIDTH	4
+#define SUN4I_A10_TCON_CH1_SCLK2_DIV_SHIFT	0
+
+#define SUN4I_A10_TCON_CH1_SCLK1_GATE_BIT	15
+#define SUN4I_A10_TCON_CH1_SCLK1_MUX_MASK	1
+#define SUN4I_A10_TCON_CH1_SCLK1_MUX_SHIFT	11
+
+static DEFINE_SPINLOCK(sun4i_a10_tcon_ch1_lock);
+
+static void __init sun4i_a10_tcon_ch1_setup(struct device_node *node)
+{
+	const char *sclk1_parents[SUN4I_A10_TCON_CH1_SCLK1_PARENTS];
+	const char *sclk2_parents[SUN4I_A10_TCON_CH1_SCLK2_PARENTS];
+	const char *sclk1_name = node->name;
+	char sclk2_name[SUN4I_TCON_CH1_SCLK_NAME_LEN];
+	char sclk2d2_name[SUN4I_TCON_CH1_SCLK_NAME_LEN];
+	struct clk_gate *sclk1_gate, *sclk2_gate;
+	struct clk_mux *sclk1_mux, *sclk2_mux;
+	struct clk *sclk1, *sclk2, *sclk2d2;
+	struct clk_divider *sclk2_div;
+	void __iomem *reg;
+	int i;
+
+	of_property_read_string(node, "clock-output-names",
+				&sclk1_name);
+
+	snprintf(sclk2_name, SUN4I_TCON_CH1_SCLK_NAME_LEN,
+		 "%s2", sclk1_name);
+
+	snprintf(sclk2d2_name, SUN4I_TCON_CH1_SCLK_NAME_LEN,
+		 "%s2d2", sclk1_name);
+
+	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+	if (IS_ERR(reg)) {
+		pr_err("%s: Could not map the clock registers\n", sclk2_name);
+		return;
+	}
+
+	for (i = 0; i < SUN4I_A10_TCON_CH1_SCLK2_PARENTS; i++)
+		sclk2_parents[i] = of_clk_get_parent_name(node, i);
+
+	sclk2_mux = kzalloc(sizeof(*sclk2_mux), GFP_KERNEL);
+	if (!sclk2_mux)
+		return;
+
+	sclk2_mux->reg = reg;
+	sclk2_mux->shift = SUN4I_A10_TCON_CH1_SCLK2_MUX_SHIFT;
+	sclk2_mux->mask = SUN4I_A10_TCON_CH1_SCLK2_MUX_MASK;
+	sclk2_mux->lock = &sun4i_a10_tcon_ch1_lock;
+
+	sclk2_gate = kzalloc(sizeof(*sclk2_gate), GFP_KERNEL);
+	if (!sclk2_gate)
+		goto free_sclk2_mux;
+
+	sclk2_gate->reg = reg;
+	sclk2_gate->bit_idx = SUN4I_A10_TCON_CH1_SCLK2_GATE_BIT;
+	sclk2_gate->lock = &sun4i_a10_tcon_ch1_lock;
+
+	sclk2_div = kzalloc(sizeof(*sclk2_div), GFP_KERNEL);
+	if (!sclk2_div)
+		goto free_sclk2_gate;
+
+	sclk2_div->reg = reg;
+	sclk2_div->shift = SUN4I_A10_TCON_CH1_SCLK2_DIV_SHIFT;
+	sclk2_div->width = SUN4I_A10_TCON_CH1_SCLK2_DIV_WIDTH;
+	sclk2_div->lock = &sun4i_a10_tcon_ch1_lock;
+
+	sclk2 = clk_register_composite(NULL, sclk2_name, sclk2_parents,
+				       SUN4I_A10_TCON_CH1_SCLK2_PARENTS,
+				       &sclk2_mux->hw, &clk_mux_ops,
+				       &sclk2_div->hw, &clk_divider_ops,
+				       &sclk2_gate->hw, &clk_gate_ops,
+				       0);
+	if (IS_ERR(sclk2)) {
+		pr_err("%s: Couldn't register the clock\n", sclk2_name);
+		goto free_sclk2_div;
+	}
+
+	sclk2d2 = clk_register_fixed_factor(NULL, sclk2d2_name, sclk2_name, 0,
+					    1, 2);
+	if (IS_ERR(sclk2d2)) {
+		pr_err("%s: Couldn't register the clock\n", sclk2d2_name);
+		goto free_sclk2;
+	}
+
+	sclk1_parents[0] = sclk2_name;
+	sclk1_parents[1] = sclk2d2_name;
+
+	sclk1_mux = kzalloc(sizeof(*sclk1_mux), GFP_KERNEL);
+	if (!sclk1_mux)
+		goto free_sclk2d2;
+
+	sclk1_mux->reg = reg;
+	sclk1_mux->shift = SUN4I_A10_TCON_CH1_SCLK1_MUX_SHIFT;
+	sclk1_mux->mask = SUN4I_A10_TCON_CH1_SCLK1_MUX_MASK;
+	sclk1_mux->lock = &sun4i_a10_tcon_ch1_lock;
+
+	sclk1_gate = kzalloc(sizeof(*sclk1_gate), GFP_KERNEL);
+	if (!sclk1_gate)
+		goto free_sclk1_mux;
+
+	sclk1_gate->reg = reg;
+	sclk1_gate->bit_idx = SUN4I_A10_TCON_CH1_SCLK1_GATE_BIT;
+	sclk1_gate->lock = &sun4i_a10_tcon_ch1_lock;
+
+	sclk1 = clk_register_composite(NULL, sclk1_name, sclk1_parents,
+				       SUN4I_A10_TCON_CH1_SCLK1_PARENTS,
+				       &sclk1_mux->hw, &clk_mux_ops,
+				       NULL, NULL,
+				       &sclk1_gate->hw, &clk_gate_ops,
+				       0);
+	if (IS_ERR(sclk1)) {
+		pr_err("%s: Couldn't register the clock\n", sclk1_name);
+		goto free_sclk1_gate;
+	}
+
+	of_clk_add_provider(node, of_clk_src_simple_get, sclk1);
+
+	return;
+
+free_sclk1_gate:
+	kfree(sclk1_gate);
+free_sclk1_mux:
+	kfree(sclk1_mux);
+free_sclk2d2:
+	clk_unregister(sclk2d2);
+free_sclk2:
+	clk_unregister(sclk2);
+free_sclk2_div:
+	kfree(sclk2_div);
+free_sclk2_gate:
+	kfree(sclk2_gate);
+free_sclk2_mux:
+	kfree(sclk2_mux);
+}
+
+CLK_OF_DECLARE(sun4i_a10_tcon_ch1, "allwinner,sun4i-a10-tcon-ch1-clk",
+	       sun4i_a10_tcon_ch1_setup);
-- 
2.6.2


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

* [PATCH 05/19] clk: sunxi: add DRAM gates
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (3 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 04/19] clk: sunxi: Add TCON channel1 clock Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-11-09  4:18   ` Chen-Yu Tsai
  2015-10-30 14:20 ` [PATCH 06/19] clk: sunxi: Add Allwinner R8 AHB gates support Maxime Ripard
                   ` (15 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The Allwinner SoCs have a gate controller to gate the access to the DRAM
clock to the some devices that need to access the DRAM directly (mostly
display / image related IPs).

Use a simple gates driver to support it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi/clk-simple-gates.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
index 0214c6548afd..5666c767fa14 100644
--- a/drivers/clk/sunxi/clk-simple-gates.c
+++ b/drivers/clk/sunxi/clk-simple-gates.c
@@ -112,6 +112,8 @@ CLK_OF_DECLARE(sun5i_a13_apb0, "allwinner,sun5i-a13-apb0-gates-clk",
 	       sunxi_simple_gates_init);
 CLK_OF_DECLARE(sun5i_a13_apb1, "allwinner,sun5i-a13-apb1-gates-clk",
 	       sunxi_simple_gates_init);
+CLK_OF_DECLARE(sun5i_a13_dram, "allwinner,sun5i-a13-dram-gates-clk",
+	       sunxi_simple_gates_init);
 CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-gates-clk",
 	       sunxi_simple_gates_init);
 CLK_OF_DECLARE(sun6i_a31_apb1, "allwinner,sun6i-a31-apb1-gates-clk",
-- 
2.6.2


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

* [PATCH 06/19] clk: sunxi: Add Allwinner R8 AHB gates support
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (4 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 05/19] clk: sunxi: add DRAM gates Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 16:01   ` Chen-Yu Tsai
  2015-10-30 14:20 ` [PATCH 07/19] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
                   ` (14 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The R8 has yet another array of gates for AHB. Let's add it to the list of
compatibles we can deal with.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi/clk-simple-gates.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
index 5666c767fa14..e3190a8687a8 100644
--- a/drivers/clk/sunxi/clk-simple-gates.c
+++ b/drivers/clk/sunxi/clk-simple-gates.c
@@ -158,5 +158,7 @@ CLK_OF_DECLARE(sun5i_a10s_ahb, "allwinner,sun5i-a10s-ahb-gates-clk",
 	       sun4i_a10_ahb_init);
 CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner,sun5i-a13-ahb-gates-clk",
 	       sun4i_a10_ahb_init);
+CLK_OF_DECLARE(sun5i_r8_ahb, "allwinner,sun5i-r8-ahb-gates-clk",
+	       sun4i_a10_ahb_init);
 CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
 	       sun4i_a10_ahb_init);
-- 
2.6.2


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

* [PATCH 07/19] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (5 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 06/19] clk: sunxi: Add Allwinner R8 AHB gates support Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 17:32   ` Thierry Reding
  2015-10-30 14:20 ` [PATCH 08/19] drm: Add Allwinner A10 Display Engine support Maxime Ripard
                   ` (13 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

Add support for the Olimex LCD-OLinuXino-4.3TS panel to the DRM simple
panel driver.

It is a 480x272 panel connected through a 24-bits RGB interface.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/panel/panel-simple.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index f97b73ec4713..3a9ecb64d1e6 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1096,6 +1096,29 @@ static const struct panel_desc shelly_sca07010_bfn_lnn = {
 	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
 };
 
+static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = {
+	.clock = 9000,
+	.hdisplay = 480,
+	.hsync_start = 480 + 5,
+	.hsync_end = 480 + 5 + 30,
+	.htotal = 480 + 5 + 30 + 10,
+	.vdisplay = 272,
+	.vsync_start = 272 + 8,
+	.vsync_end = 272 + 8 + 5,
+	.vtotal = 272 + 8 + 5 + 3,
+	.vrefresh = 60,
+};
+
+static const struct panel_desc olimex_lcd_olinuxino_43ts = {
+	.modes = &olimex_lcd_olinuxino_43ts_mode,
+	.num_modes = 1,
+	.size = {
+		.width = 105,
+		.height = 67,
+	},
+	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
 static const struct of_device_id platform_of_match[] = {
 	{
 		.compatible = "ampire,am800480r3tmqwa1h",
@@ -1191,6 +1214,9 @@ static const struct of_device_id platform_of_match[] = {
 		.compatible = "shelly,sca07010-bfn-lnn",
 		.data = &shelly_sca07010_bfn_lnn,
 	}, {
+		.compatible = "olimex,lcd-olinuxino-43-ts",
+		.data = &olimex_lcd_olinuxino_43ts,
+	}, {
 		/* sentinel */
 	}
 };
-- 
2.6.2


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

* [PATCH 08/19] drm: Add Allwinner A10 Display Engine support
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (6 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 07/19] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 14:44   ` Daniel Vetter
  2015-10-30 14:20 ` [PATCH 09/19] drm: sun4i: Add DT bindings documentation Maxime Ripard
                   ` (12 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The Allwinner A10 and subsequent SoCs share the same display pipeline, with
variations in the number of controllers (1 or 2), or the presence or not of
some output (HDMI, TV, VGA) or not.

This hardware supports 4 layers and 32 sprites, even though we only support
one primary layer for now.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/Kconfig                   |   2 +
 drivers/gpu/drm/Makefile                  |   3 +-
 drivers/gpu/drm/sun4i/Kconfig             |  14 +
 drivers/gpu/drm/sun4i/Makefile            |   8 +
 drivers/gpu/drm/sun4i/sun4i_backend.c     | 271 +++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_backend.h     | 159 ++++++++++
 drivers/gpu/drm/sun4i/sun4i_crtc.c        | 117 ++++++++
 drivers/gpu/drm/sun4i/sun4i_crtc.h        |  31 ++
 drivers/gpu/drm/sun4i/sun4i_drv.c         | 281 ++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_drv.h         |  30 ++
 drivers/gpu/drm/sun4i/sun4i_framebuffer.c |  54 ++++
 drivers/gpu/drm/sun4i/sun4i_framebuffer.h |  19 ++
 drivers/gpu/drm/sun4i/sun4i_layer.c       | 111 +++++++
 drivers/gpu/drm/sun4i/sun4i_layer.h       |  30 ++
 drivers/gpu/drm/sun4i/sun4i_tcon.c        | 478 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_tcon.h        | 182 ++++++++++++
 16 files changed, 1789 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/sun4i/Kconfig
 create mode 100644 drivers/gpu/drm/sun4i/Makefile
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_backend.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_backend.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_crtc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_crtc.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_drv.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_drv.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_framebuffer.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_framebuffer.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_layer.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_layer.h
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tcon.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tcon.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 1a0a8df2eed8..ecf93fafa33c 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -239,6 +239,8 @@ source "drivers/gpu/drm/rcar-du/Kconfig"
 
 source "drivers/gpu/drm/shmobile/Kconfig"
 
+source "drivers/gpu/drm/sun4i/Kconfig"
+
 source "drivers/gpu/drm/omapdrm/Kconfig"
 
 source "drivers/gpu/drm/tilcdc/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 45e7719846b1..2e5f547db672 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -1,4 +1,4 @@
-#
+
 # Makefile for the drm device driver.  This driver provides support for the
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
@@ -58,6 +58,7 @@ obj-$(CONFIG_DRM_ARMADA) += armada/
 obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
 obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
 obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
+obj-$(CONFIG_DRM_SUN4I) += sun4i/
 obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
 obj-y			+= tilcdc/
 obj-$(CONFIG_DRM_QXL) += qxl/
diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
new file mode 100644
index 000000000000..99510e64e91a
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -0,0 +1,14 @@
+config DRM_SUN4I
+	tristate "DRM Support for Allwinner A10 Display Engine"
+	depends on DRM && ARM
+	depends on ARCH_SUNXI || COMPILE_TEST
+	select DRM_GEM_CMA_HELPER
+	select DRM_KMS_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_PANEL
+	select REGMAP_MMIO
+	select VIDEOMODE_HELPERS
+	help
+	  Choose this option if you have an Allwinner SoC with a
+	  Display Engine. If M is selected the module will be called
+	  sun4i-drm.
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
new file mode 100644
index 000000000000..bc2df12beb42
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -0,0 +1,8 @@
+sun4i-drm-y += sun4i_backend.o
+sun4i-drm-y += sun4i_crtc.o
+sun4i-drm-y += sun4i_drv.o
+sun4i-drm-y += sun4i_framebuffer.o
+sun4i-drm-y += sun4i_layer.o
+sun4i-drm-y += sun4i_tcon.o
+
+obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
new file mode 100644
index 000000000000..74eac55f1244
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -0,0 +1,271 @@
+/*
+ * 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/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 "sun4i_backend.h"
+#include "sun4i_drv.h"
+
+static u32 sunxi_rgb2yuv_coef[12] = {
+	0x00000107, 0x00000204, 0x00000064, 0x00000108,
+	0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
+	0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
+};
+
+void sun4i_backend_apply_color_correction(struct sun4i_backend *backend)
+{
+	int i;
+
+	/* Set color correction */
+	regmap_write(backend->regs, SUN4I_BACKEND_OCCTL_REG,
+		     SUN4I_BACKEND_OCCTL_ENABLE);
+
+	for (i = 0; i < 12; i++)
+		regmap_write(backend->regs, SUN4I_BACKEND_OCRCOEF_REG(i),
+			     sunxi_rgb2yuv_coef[i]);
+}
+
+void sun4i_backend_commit(struct sun4i_backend *backend)
+{
+	DRM_DEBUG_DRIVER("Committing changes\n");
+
+	regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
+		     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS |
+		     SUN4I_BACKEND_REGBUFFCTL_LOADCTL);
+}
+
+void sun4i_backend_layer_enable(struct sun4i_backend *backend,
+				int layer, bool enable)
+{
+	u32 val;
+
+	DRM_DEBUG_DRIVER("Enabling layer %d\n", layer);
+
+	if (enable)
+		val = SUN4I_BACKEND_MODCTL_LAY_EN(layer);
+	else
+		val = 0;
+
+	regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
+			   SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
+}
+
+static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)
+{
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
+		*mode = SUN4I_BACKEND_LAY_FBFMT_XRGB8888;
+		break;
+
+	case DRM_FORMAT_RGB888:
+		*mode = SUN4I_BACKEND_LAY_FBFMT_RGB888;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
+				     int layer, struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+
+	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(backend->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),
+		     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),
+		     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),
+		     SUN4I_BACKEND_LAYCOOR(state->crtc_x,
+					   state->crtc_y));
+
+	return 0;
+}
+
+int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
+				       int layer, struct drm_plane *plane)
+{
+	struct drm_plane_state *state = plane->state;
+	struct drm_framebuffer *fb = state->fb;
+	bool interlaced = false;
+	u32 val;
+	int ret;
+
+	if (plane->state->crtc)
+		interlaced = plane->state->crtc->state->adjusted_mode.flags
+			& DRM_MODE_FLAG_INTERLACE;
+
+	regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
+			   SUN4I_BACKEND_MODCTL_ITLMOD_EN,
+			   interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0);
+
+	DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
+			 interlaced ? "on" : "off");
+
+	ret = sun4i_backend_drm_format_to_layer(fb->pixel_format, &val);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Invalid format\n");
+		return val;
+	}
+
+	regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG1(layer),
+			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
+
+	return 0;
+}
+
+int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
+				      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;
+	u32 lo_paddr, hi_paddr;
+	dma_addr_t paddr;
+	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 @ 0x%x\n", gem->paddr);
+
+	/* Compute the start of the displayed memory */
+	bpp = drm_format_plane_cpp(fb->pixel_format, 0);
+	paddr = gem->paddr + fb->offsets[0];
+	paddr += state->src_x * bpp;
+	paddr += state->src_y * fb->pitches[0];
+
+	DRM_DEBUG_DRIVER("Setting buffer address to 0x%x\n", paddr);
+
+	/* 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),
+		     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,
+			   SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
+			   SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr));
+
+	return 0;
+}
+
+static struct regmap_config sun4i_backend_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0x5800,
+	.name		= "backend",
+};
+
+struct sun4i_backend *sun4i_backend_init(struct drm_device *drm)
+{
+	struct sun4i_backend *backend;
+	struct resource *res;
+	void __iomem *regs;
+	int i;
+
+	backend = devm_kzalloc(drm->dev, sizeof(*backend), GFP_KERNEL);
+	if (!backend)
+		return ERR_PTR(-ENOMEM);
+
+	res = platform_get_resource_byname(to_platform_device(drm->dev),
+					   IORESOURCE_MEM, "backend0");
+	regs = devm_ioremap_resource(drm->dev, res);
+	if (IS_ERR(regs)) {
+		dev_err(drm->dev, "Couldn't map the backend0 registers\n");
+		return ERR_CAST(regs);
+	}
+
+	backend->regs = devm_regmap_init_mmio(drm->dev, regs,
+					      &sun4i_backend_regmap_config);
+	if (IS_ERR(backend->regs)) {
+		dev_err(drm->dev, "Couldn't create the backend0 regmap\n");
+		return ERR_CAST(backend->regs);
+	}
+
+	backend->bus_clk = devm_clk_get(drm->dev, "backend0-bus");
+	if (IS_ERR(backend->bus_clk)) {
+		dev_err(drm->dev, "Couldn't get the backend bus clock\n");
+		return ERR_CAST(backend->bus_clk);
+	}
+	clk_prepare_enable(backend->bus_clk);
+
+	backend->mod_clk = devm_clk_get(drm->dev, "backend0-mod");
+	if (IS_ERR(backend->mod_clk)) {
+		dev_err(drm->dev, "Couldn't get the backend module clock\n");
+		return ERR_CAST(backend->mod_clk);
+	}
+	clk_prepare_enable(backend->mod_clk);
+
+	backend->ram_clk = devm_clk_get(drm->dev, "backend0-ram");
+	if (IS_ERR(backend->ram_clk)) {
+		dev_err(drm->dev, "Couldn't get the backend RAM clock\n");
+		return ERR_CAST(backend->ram_clk);
+	}
+	clk_prepare_enable(backend->ram_clk);
+
+	/* Reset the registers */
+	for (i = 0x800; i < 0x1000; i += 4)
+		regmap_write(backend->regs, i, 0);
+
+	/* Disable registers autoloading */
+	regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
+		     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
+
+	/* Enable the backend */
+	regmap_write(backend->regs, SUN4I_BACKEND_MODCTL_REG,
+		     SUN4I_BACKEND_MODCTL_DEBE_EN |
+		     SUN4I_BACKEND_MODCTL_START_CTL);
+
+	return backend;
+}
+
+void sun4i_backend_free(struct sun4i_backend *backend)
+{
+	clk_disable_unprepare(backend->ram_clk);
+	clk_disable_unprepare(backend->mod_clk);
+	clk_disable_unprepare(backend->bus_clk);
+}
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
new file mode 100644
index 000000000000..8b3dca39d089
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -0,0 +1,159 @@
+/*
+ * 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 _SUN4I_BACKEND_H_
+#define _SUN4I_BACKEND_H_
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#define SUN4I_BACKEND_MODCTL_REG		0x800
+#define SUN4I_BACKEND_MODCTL_LINE_SEL			BIT(29)
+#define SUN4I_BACKEND_MODCTL_ITLMOD_EN			BIT(28)
+#define SUN4I_BACKEND_MODCTL_OUT_SEL			GENMASK(22, 20)
+#define SUN4I_BACKEND_MODCTL_OUT_LCD				(0 << 20)
+#define SUN4I_BACKEND_MODCTL_OUT_FE0				(6 << 20)
+#define SUN4I_BACKEND_MODCTL_OUT_FE1				(7 << 20)
+#define SUN4I_BACKEND_MODCTL_HWC_EN			BIT(16)
+#define SUN4I_BACKEND_MODCTL_LAY_EN(l)			BIT(8 + l)
+#define SUN4I_BACKEND_MODCTL_OCSC_EN			BIT(5)
+#define SUN4I_BACKEND_MODCTL_DFLK_EN			BIT(4)
+#define SUN4I_BACKEND_MODCTL_DLP_START_CTL		BIT(2)
+#define SUN4I_BACKEND_MODCTL_START_CTL			BIT(1)
+#define SUN4I_BACKEND_MODCTL_DEBE_EN			BIT(0)
+
+#define SUN4I_BACKEND_BACKCOLOR_REG		0x804
+#define SUN4I_BACKEND_BACKCOLOR(r, g, b)		(((r) << 16) | ((g) << 8) | (b))
+
+#define SUN4I_BACKEND_DISSIZE_REG		0x808
+#define SUN4I_BACKEND_DISSIZE(w, h)			(((((h) - 1) & 0xffff) << 16) | \
+							 (((w) - 1) & 0xffff))
+
+#define SUN4I_BACKEND_LAYSIZE_REG(l)		(0x810 + (0x4 * (l)))
+#define SUN4I_BACKEND_LAYSIZE(w, h)			(((((h) - 1) & 0x1fff) << 16) | \
+							 (((w) - 1) & 0x1fff))
+
+#define SUN4I_BACKEND_LAYCOOR_REG(l)		(0x820 + (0x4 * (l)))
+#define SUN4I_BACKEND_LAYCOOR(x, y)			((((u32)(y) & 0xffff) << 16) | \
+							 ((u32)(x) & 0xffff))
+
+#define SUN4I_BACKEND_LAYLINEWIDTH_REG(l)	(0x840 + (0x4 * (l)))
+
+#define SUN4I_BACKEND_LAYFB_L32ADD_REG(l)	(0x850 + (0x4 * (l)))
+
+#define SUN4I_BACKEND_LAYFB_H4ADD_REG		0x860
+#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l)		GENMASK(3 + ((l) * 8), 0)
+#define SUN4I_BACKEND_LAYFB_H4ADD(l, val)			((val) << ((l) * 8))
+
+#define SUN4I_BACKEND_REGBUFFCTL_REG		0x870
+#define SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS		BIT(1)
+#define SUN4I_BACKEND_REGBUFFCTL_LOADCTL		BIT(0)
+
+#define SUN4I_BACKEND_CKMAX_REG			0x880
+#define SUN4I_BACKEND_CKMIN_REG			0x884
+#define SUN4I_BACKEND_CKCFG_REG			0x888
+#define SUN4I_BACKEND_ATTCTL_REG0(l)		(0x890 + (0x4 * (l)))
+
+#define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
+#define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
+#define SUN4I_BACKEND_ATTCTL_REG1_LAY_WSCAFCT		GENMASK(13, 12)
+#define SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT		GENMASK(11, 8)
+#define SUN4I_BACKEND_LAY_FBFMT_1BPP				(0 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_2BPP				(1 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_4BPP				(2 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_8BPP				(3 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_RGB655				(4 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_RGB565				(5 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_RGB556				(6 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_ARGB1555			(7 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_RGBA5551			(8 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_XRGB8888			(9 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_ARGB8888			(10 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_RGB888				(11 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_ARGB4444			(12 << 8)
+#define SUN4I_BACKEND_LAY_FBFMT_RGBA4444			(13 << 8)
+
+#define SUN4I_BACKEND_DLCDPCTL_REG		0x8b0
+#define SUN4I_BACKEND_DLCDPFRMBUF_ADDRCTL_REG	0x8b4
+#define SUN4I_BACKEND_DLCDPCOOR_REG0		0x8b8
+#define SUN4I_BACKEND_DLCDPCOOR_REG1		0x8bc
+
+#define SUN4I_BACKEND_INT_EN_REG		0x8c0
+#define SUN4I_BACKEND_INT_FLAG_REG		0x8c4
+#define SUN4I_BACKEND_REG_LOAD_FINISHED			BIT(1)
+
+#define SUN4I_BACKEND_HWCCTL_REG		0x8d8
+#define SUN4I_BACKEND_HWCFBCTL_REG		0x8e0
+#define SUN4I_BACKEND_WBCTL_REG			0x8f0
+#define SUN4I_BACKEND_WBADD_REG			0x8f4
+#define SUN4I_BACKEND_WBLINEWIDTH_REG		0x8f8
+#define SUN4I_BACKEND_SPREN_REG			0x900
+#define SUN4I_BACKEND_SPRFMTCTL_REG		0x908
+#define SUN4I_BACKEND_SPRALPHACTL_REG		0x90c
+#define SUN4I_BACKEND_IYUVCTL_REG		0x920
+#define SUN4I_BACKEND_IYUVADD_REG(c)		(0x930 + (0x4 * (c)))
+#define SUN4I_BACKEND_IYUVLINEWITDTH_REG(c)	(0x940 + (0x4 * (c)))
+#define SUN4I_BACKEND_YGCOEF_REG(c)		(0x950 + (0x4 * (c)))
+#define SUN4I_BACKEND_YGCONS_REG		0x95c
+#define SUN4I_BACKEND_URCOEF_REG(c)		(0x960 + (0x4 * (c)))
+#define SUN4I_BACKEND_URCONS_REG		0x96c
+#define SUN4I_BACKEND_VBCOEF_REG(c)		(0x970 + (0x4 * (c)))
+#define SUN4I_BACKEND_VBCONS_REG		0x97c
+#define SUN4I_BACKEND_KSCTL_REG			0x980
+#define SUN4I_BACKEND_KSBKCOLOR_REG		0x984
+#define SUN4I_BACKEND_KSFSTLINEWIDTH_REG	0x988
+#define SUN4I_BACKEND_KSVSCAFCT_REG		0x98c
+#define SUN4I_BACKEND_KSHSCACOEF_REG(x)		(0x9a0 + (0x4 * (x)))
+#define SUN4I_BACKEND_OCCTL_REG			0x9c0
+#define SUN4I_BACKEND_OCCTL_ENABLE			BIT(0)
+
+#define SUN4I_BACKEND_OCRCOEF_REG(x)		(0x9d0 + (0x4 * (x)))
+#define SUN4I_BACKEND_OCRCONS_REG		0x9dc
+#define SUN4I_BACKEND_OCGCOEF_REG(x)		(0x9e0 + (0x4 * (x)))
+#define SUN4I_BACKEND_OCGCONS_REG		0x9ec
+#define SUN4I_BACKEND_OCBCOEF_REG(x)		(0x9f0 + (0x4 * (x)))
+#define SUN4I_BACKEND_OCBCONS_REG		0x9fc
+#define SUN4I_BACKEND_SPRCOORCTL_REG(s)		(0xa00 + (0x4 * (s)))
+#define SUN4I_BACKEND_SPRATTCTL_REG(s)		(0xb00 + (0x4 * (s)))
+#define SUN4I_BACKEND_SPRADD_REG(s)		(0xc00 + (0x4 * (s)))
+#define SUN4I_BACKEND_SPRLINEWIDTH_REG(s)	(0xd00 + (0x4 * (s)))
+
+#define SUN4I_BACKEND_SPRPALTAB_OFF		0x4000
+#define SUN4I_BACKEND_GAMMATAB_OFF		0x4400
+#define SUN4I_BACKEND_HWCPATTERN_OFF		0x4800
+#define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
+#define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
+
+struct sun4i_backend {
+	struct regmap	*regs;
+
+	struct clk	*bus_clk;
+	struct clk	*mod_clk;
+	struct clk	*ram_clk;
+};
+
+void sun4i_backend_apply_color_correction(struct sun4i_backend *backend);
+void sun4i_backend_commit(struct sun4i_backend *backend);
+
+void sun4i_backend_layer_enable(struct sun4i_backend *backend,
+				int layer, bool enable);
+int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
+				     int layer, struct drm_plane *plane);
+int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
+				       int layer, struct drm_plane *plane);
+int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
+				      int layer, struct drm_plane *plane);
+
+struct sun4i_backend *sun4i_backend_init(struct drm_device *drm);
+void sun4i_backend_free(struct sun4i_backend *backend);
+
+#endif /* _SUN4I_BACKEND_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
new file mode 100644
index 000000000000..ec4045fc31ee
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -0,0 +1,117 @@
+/*
+ * 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/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modes.h>
+
+#include <linux/clk-provider.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#include <video/videomode.h>
+
+#include "sun4i_crtc.h"
+#include "sun4i_drv.h"
+#include "sun4i_tcon.h"
+
+static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+{
+	struct drm_pending_vblank_event *event = crtc->state->event;
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+	struct drm_device *dev = crtc->dev;
+	unsigned long flags;
+
+	if (event) {
+		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
+
+		spin_lock_irqsave(&dev->event_lock, flags);
+		scrtc->event = event;
+		spin_unlock_irqrestore(&dev->event_lock, flags);
+	 }
+}
+
+static void sun4i_crtc_disable(struct drm_crtc *crtc)
+{
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+	struct sun4i_drv *drv = scrtc->drv;
+
+	DRM_DEBUG_DRIVER("Disabling the CRTC\n");
+
+	if (!scrtc->enabled)
+		return;
+
+	sun4i_tcon_disable(drv->tcon);
+
+	scrtc->enabled = false;
+}
+
+static void sun4i_crtc_enable(struct drm_crtc *crtc)
+{
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+	struct sun4i_drv *drv = scrtc->drv;
+
+	DRM_DEBUG_DRIVER("Enabling the CRTC\n");
+
+	if (scrtc->enabled)
+		return;
+
+	sun4i_tcon_enable(drv->tcon);
+
+	scrtc->enabled = true;
+}
+
+static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
+	.atomic_begin	= sun4i_crtc_atomic_begin,
+	.disable	= sun4i_crtc_disable,
+	.enable		= sun4i_crtc_enable,
+};
+
+static const struct drm_crtc_funcs sun4i_crtc_funcs = {
+	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
+	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,
+	.destroy		= drm_crtc_cleanup,
+	.page_flip		= drm_atomic_helper_page_flip,
+	.reset			= drm_atomic_helper_crtc_reset,
+	.set_config		= drm_atomic_helper_set_config,
+};
+
+struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_crtc *scrtc;
+	int ret;
+
+	scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
+	if (!scrtc)
+		return NULL;
+	scrtc->drv = drv;
+
+	ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
+					drv->primary,
+					NULL,
+					&sun4i_crtc_funcs);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't init DRM CRTC\n");
+		return NULL;
+	}
+
+	drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs);
+	drm_crtc_vblank_reset(&scrtc->crtc);
+
+	return scrtc;
+}
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h b/drivers/gpu/drm/sun4i/sun4i_crtc.h
new file mode 100644
index 000000000000..6c6b989c1b60
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h
@@ -0,0 +1,31 @@
+/*
+ * 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 _SUN4I_CRTC_H_
+#define _SUN4I_CRTC_H_
+
+struct sun4i_crtc {
+	struct drm_crtc			crtc;
+	struct drm_pending_vblank_event	*event;
+
+	bool				enabled;
+	struct sun4i_drv			*drv;
+};
+
+static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
+{
+	return container_of(crtc, struct sun4i_crtc, crtc);
+}
+
+struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm);
+
+#endif /* _SUN4I_CRTC_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
new file mode 100644
index 000000000000..fc26f3903f52
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -0,0 +1,281 @@
+/*
+ * 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/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+
+#include "sun4i_backend.h"
+#include "sun4i_crtc.h"
+#include "sun4i_drv.h"
+#include "sun4i_framebuffer.h"
+#include "sun4i_layer.h"
+#include "sun4i_tcon.h"
+
+static void sun4i_drv_preclose(struct drm_device *drm,
+			       struct drm_file *file_priv)
+{
+}
+
+static void sun4i_drv_lastclose(struct drm_device *drm)
+{
+}
+
+static int sun4i_drv_connector_plug_all(struct drm_device *drm)
+{
+	struct drm_connector *connector, *failed;
+	int ret;
+
+	mutex_lock(&drm->mode_config.mutex);
+	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+		ret = drm_connector_register(connector);
+		if (ret) {
+			failed = connector;
+			goto err;
+		}
+	}
+	mutex_unlock(&drm->mode_config.mutex);
+	return 0;
+
+err:
+	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+		if (failed == connector)
+			break;
+
+		drm_connector_unregister(connector);
+	}
+	mutex_unlock(&drm->mode_config.mutex);
+
+	return ret;
+}
+
+static int sun4i_drv_enable_vblank(struct drm_device *drm, int pipe)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	DRM_DEBUG_DRIVER("Enabling VBLANK on pipe %d\n", pipe);
+
+	sun4i_tcon_enable_vblank(tcon, true);
+
+	return 0;
+}
+
+static void sun4i_drv_disable_vblank(struct drm_device *drm, int pipe)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	DRM_DEBUG_DRIVER("Disabling VBLANK on pipe %d\n", pipe);
+
+	sun4i_tcon_enable_vblank(tcon, false);
+}
+
+static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	int ret;
+
+	drv = devm_kzalloc(drm->dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv)
+		return -ENOMEM;
+
+	drm->dev_private = drv;
+
+	drm_vblank_init(drm, 1);
+	drm_mode_config_init(drm);
+
+	/* Prepare the backend */
+	drv->backend = sun4i_backend_init(drm);
+	if (IS_ERR(drv->backend)) {
+		dev_err(drm->dev, "Couldn't initialise our backend\n");
+		return PTR_ERR(drv->backend);
+	}
+
+	/* Prepare the TCON */
+	drv->tcon = sun4i_tcon_init(drm);
+	if (!drv->tcon) {
+		dev_err(drm->dev, "Couldn't initialise our TCON\n");
+		ret = -EINVAL;
+		goto err_free_backend;
+	}
+
+	/* Create our layers */
+	drv->layers = sun4i_layers_init(drm);
+	if (!drv->layers) {
+		dev_err(drm->dev, "Couldn't create the planes\n");
+		ret = -EINVAL;
+		goto err_free_tcon;
+	}
+
+	/* Create our CRTC */
+	drv->crtc = sun4i_crtc_init(drm);
+	if (!drv->crtc) {
+		dev_err(drm->dev, "Couldn't create the CRTC\n");
+		ret = -EINVAL;
+		goto err_free_layers;
+	}
+
+	/* Create our outputs */
+
+	/* Create our framebuffer */
+	drv->fbdev = sun4i_framebuffer_init(drm);
+	if (IS_ERR(drv->fbdev)) {
+		dev_err(drm->dev, "Couldn't create our framebuffer\n");
+		ret = PTR_ERR(drv->fbdev);
+		goto err_free_crtc;
+	}
+
+	/* Enable connectors polling */
+	drm_kms_helper_poll_init(drm);
+
+	return 0;
+
+err_free_crtc:
+err_free_layers:
+err_free_tcon:
+	sun4i_tcon_free(drv->tcon);
+err_free_backend:
+	sun4i_backend_free(drv->backend);
+
+	return ret;
+}
+
+static int sun4i_drv_unload(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+
+	drm_kms_helper_poll_fini(drm);
+	sun4i_framebuffer_free(drm);
+	sun4i_tcon_free(drv->tcon);
+	sun4i_backend_free(drv->backend);
+	drm_vblank_cleanup(drm);
+
+	return 0;
+}
+
+static const struct file_operations sun4i_drv_fops = {
+	.owner		= THIS_MODULE,
+	.open		= drm_open,
+	.release	= drm_release,
+	.unlocked_ioctl	= drm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= drm_compat_ioctl,
+#endif
+	.poll		= drm_poll,
+	.read		= drm_read,
+	.llseek		= no_llseek,
+	.mmap		= drm_gem_cma_mmap,
+};
+
+static struct drm_driver sun4i_drv_driver = {
+	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME,
+
+	/* Generic Operations */
+	.load			= sun4i_drv_load,
+	.unload			= sun4i_drv_unload,
+	.preclose		= sun4i_drv_preclose,
+	.lastclose		= sun4i_drv_lastclose,
+	.fops			= &sun4i_drv_fops,
+	.name			= "sun4i-drm",
+	.desc			= "Allwinner sun4i Display Engine",
+	.date			= "20150629",
+	.major			= 1,
+	.minor			= 0,
+
+	/* GEM Operations */
+	.gem_free_object	= drm_gem_cma_free_object,
+	.gem_vm_ops		= &drm_gem_cma_vm_ops,
+
+	/* PRIME Operations */
+	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
+	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
+	.gem_prime_import	= drm_gem_prime_import,
+	.gem_prime_export	= drm_gem_prime_export,
+	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
+	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
+	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
+	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
+	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
+
+	/* Frame Buffer Operations */
+	.dumb_create		= drm_gem_cma_dumb_create,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+
+	/* VBlank Operations */
+	.get_vblank_counter	= drm_vblank_count,
+	.enable_vblank		= sun4i_drv_enable_vblank,
+	.disable_vblank		= sun4i_drv_disable_vblank,
+};
+
+static int sun4i_drv_probe(struct platform_device *pdev)
+{
+	struct drm_device *drm;
+	int ret;
+
+	drm = drm_dev_alloc(&sun4i_drv_driver, &pdev->dev);
+	if (!drm)
+		return -ENOMEM;
+
+	ret = drm_dev_set_unique(drm, dev_name(drm->dev));
+	if (ret)
+		goto free_drm;
+
+	ret = drm_dev_register(drm, 0);
+	if (ret)
+		goto free_drm;
+
+	ret = sun4i_drv_connector_plug_all(drm);
+	if (ret)
+		goto unregister_drm;
+
+	return 0;
+
+unregister_drm:
+	drm_dev_unregister(drm);
+free_drm:
+	drm_dev_unref(drm);
+	return ret;
+}
+
+static int sun4i_drv_remove(struct platform_device *pdev)
+{
+	struct drm_device *drm = platform_get_drvdata(pdev);
+
+	drm_dev_unregister(drm);
+	drm_dev_unref(drm);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_drv_of_table[] = {
+	{ .compatible = "allwinner,sun5i-a13-display-engine" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);
+
+static struct platform_driver sun4i_drv_platform_driver = {
+	.probe		= sun4i_drv_probe,
+	.remove		= sun4i_drv_remove,
+	.driver		= {
+		.name		= "sun4i-drm",
+		.of_match_table	= sun4i_drv_of_table,
+	},
+};
+module_platform_driver(sun4i_drv_platform_driver);
+
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 Display Engine DRM/KMS Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
new file mode 100644
index 000000000000..9a897914b85d
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -0,0 +1,30 @@
+/*
+ * 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 _SUN4I_DRV_H_
+#define _SUN4I_DRV_H_
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+struct sun4i_drv {
+	struct sun4i_backend	*backend;
+	struct sun4i_crtc	*crtc;
+	struct sun4i_tcon	*tcon;
+
+	struct drm_plane	*primary;
+	struct drm_fbdev_cma	*fbdev;
+
+	struct sun4i_layer	*layers;
+};
+
+#endif /* _SUN4I_DRV_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
new file mode 100644
index 000000000000..68072b8cddab
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -0,0 +1,54 @@
+/*
+ * 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_fb_cma_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drmP.h>
+
+#include "sun4i_drv.h"
+
+static void sun4i_de_output_poll_changed(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+
+	if (drv->fbdev)
+		drm_fbdev_cma_hotplug_event(drv->fbdev);
+}
+
+static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
+	.output_poll_changed	= sun4i_de_output_poll_changed,
+	.atomic_check		= drm_atomic_helper_check,
+	.atomic_commit		= drm_atomic_helper_commit,
+	.fb_create		= drm_fb_cma_create,
+};
+
+struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
+{
+	drm_mode_config_reset(drm);
+
+	drm->mode_config.max_width = 8192;
+	drm->mode_config.max_height = 8192;
+
+	drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
+
+	return drm_fbdev_cma_init(drm, 32,
+				  drm->mode_config.num_crtc,
+				  drm->mode_config.num_connector);
+}
+
+void sun4i_framebuffer_free(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+
+	drm_fbdev_cma_fini(drv->fbdev);
+	drm_mode_config_cleanup(drm);
+}
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.h b/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
new file mode 100644
index 000000000000..3afd65252ee0
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
@@ -0,0 +1,19 @@
+/*
+ * 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 _SUN4I_FRAMEBUFFER_H_
+#define _SUN4I_FRAMEBUFFER_H_
+
+struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm);
+void sun4i_framebuffer_free(struct drm_device *drm);
+
+#endif /* _SUN4I_FRAMEBUFFER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
new file mode 100644
index 000000000000..c23ee7638ed8
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -0,0 +1,111 @@
+/*
+ * 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_crtc.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drmP.h>
+
+#include "sun4i_backend.h"
+#include "sun4i_drv.h"
+#include "sun4i_layer.h"
+
+static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
+					    struct drm_plane_state *state)
+{
+	return 0;
+}
+
+static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
+					       struct drm_plane_state *old_state)
+{
+	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
+	struct sun4i_drv *drv = layer->drv;
+	struct sun4i_backend *backend = drv->backend;
+
+	sun4i_backend_layer_enable(backend, layer->id, false);
+	sun4i_backend_commit(backend);
+}
+
+static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
+					      struct drm_plane_state *old_state)
+{
+	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
+	struct sun4i_drv *drv = layer->drv;
+	struct sun4i_backend *backend = drv->backend;
+
+	sun4i_backend_update_layer_coord(backend, layer->id, plane);
+	sun4i_backend_update_layer_formats(backend, layer->id, plane);
+	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
+	sun4i_backend_layer_enable(backend, layer->id, true);
+	sun4i_backend_commit(backend);
+}
+
+static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
+	.atomic_check	= sun4i_backend_layer_atomic_check,
+	.atomic_disable	= sun4i_backend_layer_atomic_disable,
+	.atomic_update	= sun4i_backend_layer_atomic_update,
+};
+
+static const struct drm_plane_funcs sun4i_backend_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 sun4i_backend_layer_formats[] = {
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_RGB888,
+};
+
+static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
+						enum drm_plane_type type)
+{
+	struct sun4i_layer *layer;
+	int ret;
+
+	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
+	if (!layer)
+		return ERR_PTR(-ENOMEM);
+
+	ret = drm_universal_plane_init(drm, &layer->plane, 0,
+				       &sun4i_backend_layer_funcs,
+				       sun4i_backend_layer_formats,
+				       ARRAY_SIZE(sun4i_backend_layer_formats),
+				       type);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't initialize layer\n");
+		return ERR_PTR(ret);
+	}
+
+	drm_plane_helper_add(&layer->plane,
+			     &sun4i_backend_layer_helper_funcs);
+
+	return layer;
+}
+
+struct sun4i_layer *sun4i_layers_init(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_layer *layers;
+
+	/* TODO: Fix the number of layers */
+	layers = sun4i_layer_init_one(drm, DRM_PLANE_TYPE_PRIMARY);
+	layers->drv = drv;
+
+	drv->primary = &layers->plane;
+
+	return layers;
+}
diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
new file mode 100644
index 000000000000..e90972969a03
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
@@ -0,0 +1,30 @@
+/*
+ * 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 _SUN4I_LAYER_H_
+#define _SUN4I_LAYER_H_
+
+struct sun4i_layer {
+	struct drm_plane	plane;
+	struct sun4i_drv	*drv;
+	int			id;
+};
+
+static inline struct sun4i_layer *
+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);
+
+#endif /* _SUN4I_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
new file mode 100644
index 000000000000..bd68bcea6c04
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -0,0 +1,478 @@
+/*
+ * 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/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_modes.h>
+
+#include <linux/clk-provider.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#include "sun4i_crtc.h"
+#include "sun4i_drv.h"
+#include "sun4i_tcon.h"
+
+void sun4i_tcon_disable(struct sun4i_tcon *tcon)
+{
+	if (!tcon->enabled)
+		return;
+
+	DRM_DEBUG_DRIVER("Disabling TCON\n");
+
+	/* Disable the TCON */
+	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+			   SUN4I_TCON_GCTL_TCON_ENABLE, 0);
+
+	tcon->enabled = false;
+}
+
+void sun4i_tcon_enable(struct sun4i_tcon *tcon)
+{
+	if (tcon->enabled)
+		return;
+
+	DRM_DEBUG_DRIVER("Enabling TCON\n");
+
+	/* Enable the TCON */
+	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+			   SUN4I_TCON_GCTL_TCON_ENABLE,
+			   SUN4I_TCON_GCTL_TCON_ENABLE);
+
+	tcon->enabled = true;
+}
+
+static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
+					struct sun4i_crtc *scrtc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->event_lock, flags);
+	if (scrtc->event) {
+		drm_send_vblank_event(dev, 0, scrtc->event);
+		drm_vblank_put(dev, 0);
+		scrtc->event = NULL;
+	}
+	spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static irqreturn_t sun4i_tcon_handler(int irq, void *private)
+{
+	struct drm_device *drm = private;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_tcon *tcon = drv->tcon;
+	struct sun4i_crtc *scrtc = drv->crtc;
+	unsigned int status;
+
+	regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
+
+	if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
+			SUN4I_TCON_GINT0_VBLANK_INT(1))))
+		return IRQ_NONE;
+
+	drm_handle_vblank(scrtc->crtc.dev, 0);
+	sun4i_tcon_finish_page_flip(drm, scrtc);
+
+	/* Acknowledge the interrupt */
+	regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG,
+		     status);
+
+	return IRQ_HANDLED;
+}
+
+static int sun4i_tcon_create_pixel_clock(struct drm_device *drm,
+					 struct sun4i_tcon *tcon,
+					 struct device_node *np)
+{
+	const char *pixel_clk_name;
+	const char *sclk_name;
+	struct clk_divider *div;
+	struct clk_gate *gate;
+
+	sclk_name = __clk_get_name(tcon->sclk0);
+	of_property_read_string_index(np, "clock-output-names", 0,
+				      &pixel_clk_name);
+
+	div = devm_kzalloc(drm->dev, sizeof(*div), GFP_KERNEL);
+	if (!div)
+		return -ENOMEM;
+
+	div->regmap = tcon->regs;
+	div->offset = SUN4I_TCON0_DCLK_REG;
+	div->shift = SUN4I_TCON0_DCLK_DIV_SHIFT;
+	div->width = SUN4I_TCON0_DCLK_DIV_WIDTH;
+	div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
+
+	gate = devm_kzalloc(drm->dev, sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		return -ENOMEM;
+
+	gate->regmap = tcon->regs;
+	gate->offset = SUN4I_TCON0_DCLK_REG;
+	gate->bit_idx = SUN4I_TCON0_DCLK_GATE_BIT;
+
+	tcon->dclk = clk_register_composite(drm->dev, pixel_clk_name,
+					    &sclk_name, 1,
+					    NULL, NULL,
+					    &div->hw, &clk_divider_ops,
+					    &gate->hw, &clk_gate_ops,
+					    CLK_USE_REGMAP);
+
+	return 0;
+}
+
+static int sun4i_tcon_init_clocks(struct drm_device *drm,
+				  struct sun4i_tcon *tcon,
+				  struct device_node *np)
+{
+	tcon->clk = of_clk_get_by_name(np, "ahb");
+	if (IS_ERR(tcon->clk)) {
+		dev_err(drm->dev, "Couldn't get the TCON bus clock\n");
+		return PTR_ERR(tcon->clk);
+	}
+	clk_prepare_enable(tcon->clk);
+
+	tcon->sclk0 = of_clk_get_by_name(np, "tcon-ch0");
+	if (IS_ERR(tcon->sclk0)) {
+		dev_err(drm->dev, "Couldn't get the TCON bus clock\n");
+		return PTR_ERR(tcon->sclk0);
+	}
+
+	tcon->sclk1 = of_clk_get_by_name(np, "tcon-ch1");
+	if (IS_ERR(tcon->sclk1)) {
+		dev_err(drm->dev, "Couldn't get the TCON bus clock\n");
+		return PTR_ERR(tcon->sclk1);
+	}
+
+	return sun4i_tcon_create_pixel_clock(drm, tcon, np);
+}
+
+static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
+{
+	clk_unregister(tcon->dclk);
+	clk_put(tcon->sclk1);
+	clk_put(tcon->sclk0);
+	clk_disable_unprepare(tcon->clk);
+	clk_put(tcon->clk);
+}
+
+static int sun4i_tcon_init_irq(struct drm_device *drm,
+			       struct sun4i_tcon *tcon,
+			       struct device_node *np)
+{
+	int irq, ret;
+
+	irq = of_irq_get(np, 0);
+	if (irq < 0) {
+		dev_err(drm->dev, "Couldn't retrieve the TCON interrupt\n");
+		return irq;
+	}
+
+	ret = devm_request_irq(drm->dev, irq, sun4i_tcon_handler, 0,
+			       dev_name(drm->dev), tcon);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't request the IRQ\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct regmap_config sun4i_tcon_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= 0x800,
+	.name		= "tcon",
+};
+
+static int sun4i_tcon_init_regmap(struct drm_device *drm,
+				  struct sun4i_tcon *tcon,
+				  struct device_node *np)
+{
+	struct resource res;
+	void __iomem *regs;
+	int ret;
+
+	ret = of_address_to_resource(np, 0, &res);
+	regs = devm_ioremap_resource(drm->dev, &res);
+	if (IS_ERR(regs)) {
+		dev_err(drm->dev, "Couldn't map the TCON registers\n");
+		return PTR_ERR(regs);
+	}
+
+	tcon->regs = devm_regmap_init_mmio(drm->dev, regs,
+					   &sun4i_tcon_regmap_config);
+	if (IS_ERR(tcon->regs)) {
+		dev_err(drm->dev, "Couldn't create the TCON regmap\n");
+		return PTR_ERR(tcon->regs);
+	}
+
+	/* Make sure the TCON is disabled and all IRQs are off */
+	regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0);
+	regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0);
+	regmap_write(tcon->regs, SUN4I_TCON_GINT1_REG, 0);
+
+	/* Disable IO lines and set them to tristate */
+	regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0);
+	regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0);
+
+	return 0;
+}
+
+struct sun4i_tcon *sun4i_tcon_init(struct drm_device *drm)
+{
+	struct sun4i_de *de = drm->dev_private;
+	struct sun4i_tcon *tcon;
+	struct device_node *np;
+	int ret = 0;
+
+	tcon = devm_kzalloc(drm->dev, sizeof(*tcon), GFP_KERNEL);
+	if (!tcon)
+		return NULL;
+	tcon->de = de;
+
+	np = of_parse_phandle(drm->dev->of_node, "allwinner,tcon", 0);
+	if (!np) {
+		dev_err(drm->dev, "Couldn't find the tcon node\n");
+		return NULL;
+	}
+
+	ret = sun4i_tcon_init_regmap(drm, tcon, np);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't init our TCON regmap\n");
+		goto err_node_put;
+	}
+
+	ret = sun4i_tcon_init_clocks(drm, tcon, np);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't init our TCON clocks\n");
+		goto err_free_regmap;
+	}
+
+	ret = sun4i_tcon_init_irq(drm, tcon, np);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't init our TCON interrupts\n");
+		goto err_free_clocks;
+	}
+
+	return tcon;
+
+err_free_clocks:
+	sun4i_tcon_free_clocks(tcon);
+err_free_regmap:
+err_node_put:
+	of_node_put(np);
+	return NULL;
+}
+
+void sun4i_tcon_free(struct sun4i_tcon *tcon)
+{
+	sun4i_tcon_free_clocks(tcon);
+}
+
+void sun4i_tcon_disable_channel(struct sun4i_tcon *tcon, int channel)
+{
+	/* Disable the TCON's channel */
+	if (channel == 0) {
+		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
+				   SUN4I_TCON0_CTL_TCON_ENABLE, 0);
+		clk_disable_unprepare(tcon->dclk);
+	} else if (channel == 1) {
+		regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
+				   SUN4I_TCON1_CTL_TCON_ENABLE, 0);
+		clk_disable_unprepare(tcon->sclk1);
+	}
+}
+
+void sun4i_tcon_enable_channel(struct sun4i_tcon *tcon, int channel)
+{
+	/* Enable the TCON's channel */
+	if (channel == 0) {
+		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
+				   SUN4I_TCON0_CTL_TCON_ENABLE,
+				   SUN4I_TCON0_CTL_TCON_ENABLE);
+		clk_prepare_enable(tcon->dclk);
+	} else if (channel == 1) {
+		regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
+				   SUN4I_TCON1_CTL_TCON_ENABLE,
+				   SUN4I_TCON1_CTL_TCON_ENABLE);
+		clk_prepare_enable(tcon->sclk1);
+	}
+}
+
+void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
+{
+	u32 mask, val = 0;
+
+	DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
+
+	mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
+	       SUN4I_TCON_GINT0_VBLANK_ENABLE(1);
+
+	if (enable)
+		val = mask;
+
+	regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val);
+}
+
+static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
+				    int channel)
+{
+	int delay = mode->vtotal - mode->vdisplay;
+
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		delay /= 2;
+
+	if (channel == 1)
+		delay -= 2;
+
+	delay = min(delay, 30);
+
+	DRM_DEBUG_DRIVER("TCON %d clock delay %u\n", channel, delay);
+
+	return delay;
+}
+
+void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
+			  struct drm_display_mode *mode)
+{
+	unsigned int bp, hsync, vsync;
+	u8 clk_delay;
+	u32 val;
+
+	/* Adjust clock delay */
+	clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
+	regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
+			   SUN4I_TCON0_CTL_CLK_DELAY_MASK,
+			   SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
+
+	/* Set the resolution */
+	regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
+		     SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
+		     SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
+
+	/* Set horizontal display timings */
+	bp = mode->crtc_htotal - mode->crtc_hsync_end;
+	DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
+			 mode->crtc_htotal, bp);
+	regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
+		     SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) |
+		     SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
+
+	/* Set vertical display timings */
+	bp = mode->crtc_vtotal - mode->crtc_vsync_end;
+	DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
+			 mode->crtc_vtotal, bp);
+	regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
+		     SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal) |
+		     SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
+
+	/* Set Hsync and Vsync length */
+	hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
+	vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
+	DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
+	regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG,
+		     SUN4I_TCON0_BASIC3_V_SYNC(vsync) |
+		     SUN4I_TCON0_BASIC3_H_SYNC(hsync));
+
+	/* TODO: Fix pixel clock phase shift */
+	val = SUN4I_TCON0_IO_POL_DCLK_PHASE(1);
+
+	/* Setup the polarity of the various signals */
+	if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
+		val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
+
+	if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
+		val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
+
+	/* Map output pins to channel 0 */
+	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+			   SUN4I_TCON_GCTL_IOMAP_MASK,
+			   SUN4I_TCON_GCTL_IOMAP_TCON0);
+
+	regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
+
+	/* Enable the output on the pins */
+	regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
+}
+
+void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
+			  struct drm_display_mode *mode)
+{
+	unsigned int bp, hsync, vsync;
+	u8 clk_delay;
+	u32 val;
+
+	/* Adjust clock delay */
+	clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
+	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
+			   SUN4I_TCON1_CTL_CLK_DELAY_MASK,
+			   SUN4I_TCON1_CTL_CLK_DELAY(clk_delay));
+
+	/* Set interlaced mode */
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		val = SUN4I_TCON1_CTL_INTERLACE_ENABLE;
+	else
+		val = 0;
+	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
+			   SUN4I_TCON1_CTL_INTERLACE_ENABLE,
+			   val);
+
+	/* Set the input resolution */
+	regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
+		     SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
+		     SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
+
+	/* Set the upscaling resolution */
+	regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
+		     SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
+		     SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
+
+	/* Set the output resolution */
+	regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
+		     SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
+		     SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
+
+	/* Set horizontal display timings */
+	bp = mode->crtc_htotal - mode->crtc_hsync_end;
+	DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
+			 mode->htotal, bp);
+	regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
+		     SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
+		     SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
+
+	/* Set vertical display timings */
+	bp = mode->crtc_vtotal - mode->crtc_vsync_end;
+	DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
+			 mode->vtotal, bp);
+	regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG,
+		     SUN4I_TCON1_BASIC4_V_TOTAL(mode->vtotal) |
+		     SUN4I_TCON1_BASIC4_V_BACKPORCH(bp));
+
+	/* Set Hsync and Vsync length */
+	hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
+	vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
+	DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
+	regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG,
+		     SUN4I_TCON1_BASIC5_V_SYNC(vsync) |
+		     SUN4I_TCON1_BASIC5_H_SYNC(hsync));
+
+	/* Map output pins to channel 1 */
+	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+			   SUN4I_TCON_GCTL_IOMAP_MASK,
+			   SUN4I_TCON_GCTL_IOMAP_TCON1);
+}
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
new file mode 100644
index 000000000000..4faf9d2d3df2
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2015 Free Electrons
+ * Copyright (C) 2015 NextThing Co
+ *
+ * Boris Brezillon <boris.brezillon@free-electrons.com>
+ * 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 __SUN4I_TCON_H__
+#define __SUN4I_TCON_H__
+
+#include <drm/drm_crtc.h>
+
+#include <linux/kernel.h>
+
+#define SUN4I_TCON_GCTL_REG			0x0
+#define SUN4I_TCON_GCTL_TCON_ENABLE			BIT(31)
+#define SUN4I_TCON_GCTL_IOMAP_MASK			BIT(0)
+#define SUN4I_TCON_GCTL_IOMAP_TCON1			(1 << 0)
+#define SUN4I_TCON_GCTL_IOMAP_TCON0			(0 << 0)
+
+#define SUN4I_TCON_GINT0_REG			0x4
+#define SUN4I_TCON_GINT0_VBLANK_ENABLE(pipe)		BIT(31 - (pipe))
+#define SUN4I_TCON_GINT0_VBLANK_INT(pipe)		BIT(15 - (pipe))
+
+#define SUN4I_TCON_GINT1_REG			0x8
+#define SUN4I_TCON_FRM_CTL_REG			0x10
+
+#define SUN4I_TCON0_CTL_REG			0x40
+#define SUN4I_TCON0_CTL_TCON_ENABLE			BIT(31)
+#define SUN4I_TCON0_CTL_CLK_DELAY_MASK			GENMASK(8, 4)
+#define SUN4I_TCON0_CTL_CLK_DELAY(delay)		((delay << 4) & SUN4I_TCON0_CTL_CLK_DELAY_MASK)
+
+#define SUN4I_TCON0_DCLK_REG			0x44
+#define SUN4I_TCON0_DCLK_GATE_BIT			(31)
+#define SUN4I_TCON0_DCLK_DIV_SHIFT			(0)
+#define SUN4I_TCON0_DCLK_DIV_WIDTH			(7)
+
+#define SUN4I_TCON0_BASIC0_REG			0x48
+#define SUN4I_TCON0_BASIC0_X(width)			((((width) - 1) & 0x7ff) << 16)
+#define SUN4I_TCON0_BASIC0_Y(height)			((((height) - 1) & 0x7ff) << 0)
+
+#define SUN4I_TCON0_BASIC1_REG			0x4c
+#define SUN4I_TCON0_BASIC1_H_TOTAL(total)		(((total) - 1) << 16)
+#define SUN4I_TCON0_BASIC1_H_BACKPORCH(bp)		(((bp) - 1) << 0)
+
+#define SUN4I_TCON0_BASIC2_REG			0x50
+#define SUN4I_TCON0_BASIC2_V_TOTAL(total)		(((total) * 2) << 16)
+#define SUN4I_TCON0_BASIC2_V_BACKPORCH(bp)		(((bp) - 1) << 0)
+
+#define SUN4I_TCON0_BASIC3_REG			0x54
+#define SUN4I_TCON0_BASIC3_H_SYNC(width)		((((width) - 1) & 0x3ff) << 16)
+#define SUN4I_TCON0_BASIC3_V_SYNC(height)		((((height) - 1) & 0x3ff) << 0)
+
+#define SUN4I_TCON0_HV_IF_REG			0x58
+#define SUN4I_TCON0_CPU_IF_REG			0x60
+#define SUN4I_TCON0_CPU_WR_REG			0x64
+#define SUN4I_TCON0_CPU_RD0_REG			0x68
+#define SUN4I_TCON0_CPU_RDA_REG			0x6c
+#define SUN4I_TCON0_TTL0_REG			0x70
+#define SUN4I_TCON0_TTL1_REG			0x74
+#define SUN4I_TCON0_TTL2_REG			0x78
+#define SUN4I_TCON0_TTL3_REG			0x7c
+#define SUN4I_TCON0_TTL4_REG			0x80
+#define SUN4I_TCON0_LVDS_IF_REG			0x84
+#define SUN4I_TCON0_IO_POL_REG			0x88
+#define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase)		((phase & 3) << 28)
+#define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE		BIT(25)
+#define SUN4I_TCON0_IO_POL_VSYNC_POSITIVE		BIT(24)
+
+#define SUN4I_TCON0_IO_TRI_REG			0x8c
+#define SUN4I_TCON0_IO_TRI_HSYNC_DISABLE		BIT(25)
+#define SUN4I_TCON0_IO_TRI_VSYNC_DISABLE		BIT(24)
+#define SUN4I_TCON0_IO_TRI_DATA_PINS_DISABLE(pins)	GENMASK(pins, 0)
+
+#define SUN4I_TCON1_CTL_REG			0x90
+#define SUN4I_TCON1_CTL_TCON_ENABLE			BIT(31)
+#define SUN4I_TCON1_CTL_INTERLACE_ENABLE		BIT(20)
+#define SUN4I_TCON1_CTL_CLK_DELAY_MASK			GENMASK(8, 4)
+#define SUN4I_TCON1_CTL_CLK_DELAY(delay)		((delay << 4) & SUN4I_TCON1_CTL_CLK_DELAY_MASK)
+
+#define SUN4I_TCON1_BASIC0_REG			0x94
+#define SUN4I_TCON1_BASIC0_X(width)			((((width) - 1) & 0x7ff) << 16)
+#define SUN4I_TCON1_BASIC0_Y(height)			((((height) - 1) & 0x7ff) << 0)
+
+#define SUN4I_TCON1_BASIC1_REG			0x98
+#define SUN4I_TCON1_BASIC1_X(width)			((((width) - 1) & 0x7ff) << 16)
+#define SUN4I_TCON1_BASIC1_Y(height)			((((height) - 1) & 0x7ff) << 0)
+
+#define SUN4I_TCON1_BASIC2_REG			0x9c
+#define SUN4I_TCON1_BASIC2_X(width)			((((width) - 1) & 0x7ff) << 16)
+#define SUN4I_TCON1_BASIC2_Y(height)			((((height) - 1) & 0x7ff) << 0)
+
+#define SUN4I_TCON1_BASIC3_REG			0xa0
+#define SUN4I_TCON1_BASIC3_H_TOTAL(total)		(((total) - 1) << 16)
+#define SUN4I_TCON1_BASIC3_H_BACKPORCH(bp)		(((bp) - 1) << 0)
+
+#define SUN4I_TCON1_BASIC4_REG			0xa4
+#define SUN4I_TCON1_BASIC4_V_TOTAL(total)		((total) << 16)
+#define SUN4I_TCON1_BASIC4_V_BACKPORCH(bp)		(((bp) - 1) << 0)
+
+#define SUN4I_TCON1_BASIC5_REG			0xa8
+#define SUN4I_TCON1_BASIC5_H_SYNC(width)		((((width) - 1) & 0x3ff) << 16)
+#define SUN4I_TCON1_BASIC5_V_SYNC(height)		((((height) - 1) & 0x3ff) << 0)
+
+#define SUN4I_TCON1_IO_POL_REG			0xf0
+#define SUN4I_TCON1_IO_TRI_REG			0xf4
+#define SUN4I_TCON_CEU_CTL_REG			0x100
+#define SUN4I_TCON_CEU_MUL_RR_REG		0x110
+#define SUN4I_TCON_CEU_MUL_RG_REG		0x114
+#define SUN4I_TCON_CEU_MUL_RB_REG		0x118
+#define SUN4I_TCON_CEU_ADD_RC_REG		0x11c
+#define SUN4I_TCON_CEU_MUL_GR_REG		0x120
+#define SUN4I_TCON_CEU_MUL_GG_REG		0x124
+#define SUN4I_TCON_CEU_MUL_GB_REG		0x128
+#define SUN4I_TCON_CEU_ADD_GC_REG		0x12c
+#define SUN4I_TCON_CEU_MUL_BR_REG		0x130
+#define SUN4I_TCON_CEU_MUL_BG_REG		0x134
+#define SUN4I_TCON_CEU_MUL_BB_REG		0x138
+#define SUN4I_TCON_CEU_ADD_BC_REG		0x13c
+#define SUN4I_TCON_CEU_RANGE_R_REG		0x140
+#define SUN4I_TCON_CEU_RANGE_G_REG		0x144
+#define SUN4I_TCON_CEU_RANGE_B_REG		0x148
+#define SUN4I_TCON1_FILL_CTL_REG		0x300
+#define SUN4I_TCON1_FILL_BEG0_REG		0x304
+#define SUN4I_TCON1_FILL_END0_REG		0x308
+#define SUN4I_TCON1_FILL_DATA0_REG		0x30c
+#define SUN4I_TCON1_FILL_BEG1_REG		0x310
+#define SUN4I_TCON1_FILL_END1_REG		0x314
+#define SUN4I_TCON1_FILL_DATA1_REG		0x318
+#define SUN4I_TCON1_FILL_BEG2_REG		0x31c
+#define SUN4I_TCON1_FILL_END2_REG		0x320
+#define SUN4I_TCON1_FILL_DATA2_REG		0x324
+#define SUN4I_TCON1_GAMMA_TABLE_REG		0x400
+
+#define SUN4I_TCON_MAX_CHANNELS		2
+
+struct sun4i_tcon {
+	struct sun4i_de			*de;
+
+	struct regmap			*regs;
+
+	/* Main bus clock */
+	struct clk			*clk;
+
+	/* Clocks for the TCON channels */
+	struct clk			*sclk0;
+	struct clk			*sclk1;
+
+	/* Pixel clock */
+	struct clk			*dclk;
+
+	bool				enabled;
+};
+
+struct sun4i_tcon *sun4i_tcon_init(struct drm_device *drm);
+void sun4i_tcon_free(struct sun4i_tcon *tcon);
+
+/* Global Control */
+void sun4i_tcon_disable(struct sun4i_tcon *tcon);
+void sun4i_tcon_enable(struct sun4i_tcon *tcon);
+
+/* Channel Control */
+void sun4i_tcon_disable_channel(struct sun4i_tcon *tcon, int channel);
+void sun4i_tcon_enable_channel(struct sun4i_tcon *tcon, int channel);
+
+void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
+
+/* Mode Related Controls */
+void sun4i_tcon_switch_interlace(struct sun4i_tcon *tcon,
+				 bool enable);
+void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
+			  struct drm_display_mode *mode);
+void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
+			  struct drm_display_mode *mode);
+
+#endif /* __SUN4I_TCON_H__ */
-- 
2.6.2


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

* [PATCH 09/19] drm: sun4i: Add DT bindings documentation
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (7 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 08/19] drm: Add Allwinner A10 Display Engine support Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 16:40   ` Rob Herring
  2015-10-30 14:20 ` [PATCH 10/19] drm: sun4i: Add RGB output Maxime Ripard
                   ` (11 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The display pipeline of the Allwinner A10 is involving several loosely
coupled components.

Add a documentation for the bindings.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 .../devicetree/bindings/drm/sunxi/sun4i-drm.txt    | 122 +++++++++++++++++++++
 1 file changed, 122 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt

diff --git a/Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt
new file mode 100644
index 000000000000..dbdccef787b4
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt
@@ -0,0 +1,122 @@
+Allwinner A10 Display Pipeline
+==============================
+
+The Allwinner A10 Display pipeline is composed of several components
+that are going to be documented below:
+
+TV Encoder
+----------
+
+The TV Encoder supports the composite and VGA output. It is one end of
+the pipeline.
+
+Required properties:
+ - compatible: value should be "allwinner,sun4i-a10-tv-encoder".
+ - reg: base address and size of memory-mapped region
+ - clocks: the clocks driving the TV encoder
+
+TCON
+----
+
+The TCON acts as a CRTC and encoder for RGB / LVDS interfaces.
+
+Required properties:
+ - compatible: value should be "allwinner,sun4i-a10-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:
+   - 'ahb': the interface clocks
+   - 'tcon-ch0': The clock driving the TCON channel 0
+   - 'tcon-ch1': The clock driving the TCON channel 0
+
+ - clock-names: the clock names mentionned above
+ - clock-output-names: Name of the pixel clock created
+
+
+Display Engine Backend
+----------------------
+
+The display engine backend exposes layers and sprites to the
+system. It's split into two components, the frontend and backend, the
+frontend doing formats conversion, scaling, deinterlacing, while the
+backend actually manages the layers.
+
+Required properties:
+  - compatible: value must be one of:
+    * allwinner,sun5i-a13-display-engine
+
+  - reg: base address and size of the memory-mapped region. Two are needed:
+    * backend0: registers of the display engine backend
+    * frontend0: registers of the display engine frontend
+  - reg_names: the region names mentionned above.
+
+  - interrupts: frontend interrupt phandle
+
+  - clocks: phandles to the clocks feeding the frontend and backend
+    * backend0-bus: the backend interface clock
+    * backend0-mod: the backend module clock
+    * backend0-ram: the backend DRAM clock
+    * frontend0-bus: the frontend interface clock
+    * frontend0-mod: the frontend module clock
+    * frontend0-ram: the frontend DRAM clock
+  - clock-names: the clock names mentionned above
+
+  - resets: phandles to the reset controllers. Two are needed:
+    * backend0: backend reset controller
+    * frontend0: frontend reset controller
+  - reset-names: the reset names mentionned above
+
+  - allwinner,tcon: phandle to the TCON in our pipeline
+
+Optional properties:
+  - allwinner,tv-encoder: phandle to the TV Encoder in our pipeline
+  - allwinner,panel: phandle to the panel used in our RGB interface
+
+Example:
+
+panel: panel {
+	compatible = "olimex,lcd-olinuxino-43-ts";
+};
+
+tve: encoder@01c0a000 {
+	compatible = "allwinner,sun4i-a10-tv-encoder";
+	reg = <0x01c0a000 0x1000>;
+	clocks = <&ahb_gates 34>;
+};
+
+tcon: lcd-controller@01c0c000 {
+	compatible = "allwinner,sun4i-a10-tcon";
+	reg = <0x01c0c000 0x1000>;
+	interrupts = <44>;
+	clocks = <&ahb_gates 36>,
+		 <&tcon_ch0_clk>,
+		 <&tcon_ch1_clk>;
+	clock-names = "ahb",
+		      "tcon-ch0",
+		      "tcon-ch1";
+	clock-output-names = "tcon-pixel-clock";
+};
+
+de: display-engine@01e00000 {
+	compatible = "allwinner,sun5i-a13-display-engine";
+	reg = <0x01e00000 0x20000>,
+	      <0x01e60000 0x10000>;
+	reg-names = "frontend0",
+		    "backend0";
+	interrupts = <47>;
+	interrupt-names = "engine0";
+	clocks = <&ahb_gates 46>, <&de_fe_clk>,
+		 <&dram_gates 25>, <&ahb_gates 44>,
+		 <&de_be_clk>, <&dram_gates 26>;
+	clock-names = "frontend0-bus", "frontend0-mod",
+		      "frontend0-ram", "backend0-bus",
+		      "backend0-mod", "backend0-ram";
+	resets = <&de_fe_clk>,
+		 <&de_be_clk>;
+	reset-names = "frontend0",
+		      "backend0";
+
+	allwinner,tcon = <&tcon>;
+	allwinner,tv-encoder = <&tve>;
+	allwinner,panel = <&panel>;
+};
-- 
2.6.2


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

* [PATCH 10/19] drm: sun4i: Add RGB output
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (8 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 09/19] drm: sun4i: Add DT bindings documentation Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 14:20 ` [PATCH 11/19] drm: sun4i: Add composite output Maxime Ripard
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

One of the A10 display pipeline possible output is an RGB interface to
drive LCD panels directly. This is done through the first channel of the
TCON that will output our video signals directly.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/Makefile    |   2 +
 drivers/gpu/drm/sun4i/sun4i_drv.c |   9 +-
 drivers/gpu/drm/sun4i/sun4i_rgb.c | 243 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_rgb.h |  18 +++
 4 files changed, 271 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_rgb.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_rgb.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index bc2df12beb42..4d230b658a05 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -5,4 +5,6 @@ sun4i-drm-y += sun4i_framebuffer.o
 sun4i-drm-y += sun4i_layer.o
 sun4i-drm-y += sun4i_tcon.o
 
+sun4i-drm-y += sun4i_rgb.o
+
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index fc26f3903f52..f2c9c8a2eb75 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -20,6 +20,7 @@
 #include "sun4i_drv.h"
 #include "sun4i_framebuffer.h"
 #include "sun4i_layer.h"
+#include "sun4i_rgb.h"
 #include "sun4i_tcon.h"
 
 static void sun4i_drv_preclose(struct drm_device *drm,
@@ -127,13 +128,18 @@ static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
 	}
 
 	/* Create our outputs */
+	ret = sun4i_rgb_init(drm);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't create our RGB output\n");
+		goto err_free_crtc;
+	}
 
 	/* Create our framebuffer */
 	drv->fbdev = sun4i_framebuffer_init(drm);
 	if (IS_ERR(drv->fbdev)) {
 		dev_err(drm->dev, "Couldn't create our framebuffer\n");
 		ret = PTR_ERR(drv->fbdev);
-		goto err_free_crtc;
+		goto err_free_rgb;
 	}
 
 	/* Enable connectors polling */
@@ -141,6 +147,7 @@ static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
 
 	return 0;
 
+err_free_rgb:
 err_free_crtc:
 err_free_layers:
 err_free_tcon:
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
new file mode 100644
index 000000000000..426b16b26aec
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -0,0 +1,243 @@
+/*
+ * 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 <linux/clk.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include "sun4i_drv.h"
+#include "sun4i_tcon.h"
+
+struct sun4i_rgb {
+	struct drm_connector	connector;
+	struct drm_encoder	encoder;
+	struct drm_panel	*panel;
+
+	struct sun4i_drv	*drv;
+
+	bool			enabled;
+};
+
+static inline struct sun4i_rgb *
+drm_connector_to_sun4i_rgb(struct drm_connector *connector)
+{
+	return container_of(connector, struct sun4i_rgb,
+			    connector);
+}
+
+static inline struct sun4i_rgb *
+drm_encoder_to_sun4i_rgb(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct sun4i_rgb,
+			    encoder);
+}
+
+static int sun4i_rgb_get_modes(struct drm_connector *connector)
+{
+	struct sun4i_rgb *rgb =
+		drm_connector_to_sun4i_rgb(connector);
+
+	return rgb->panel->funcs->get_modes(rgb->panel);
+}
+
+static int sun4i_rgb_mode_valid(struct drm_connector *connector,
+				struct drm_display_mode *mode)
+{
+	DRM_DEBUG_DRIVER("Validating modes...\n");
+
+	if ((mode->hsync_start < 1) || (mode->hsync_start > 0x3ff) ||
+	    (mode->htotal < 1) || (mode->htotal > 0xfff))
+		return MODE_H_ILLEGAL;
+
+	DRM_DEBUG_DRIVER("Horizontal parameters OK\n");
+
+	if ((mode->vsync_start < 1) || (mode->vsync_start > 0x3ff) ||
+	    (mode->vtotal < 1) || (mode->vtotal > 0xfff))
+		return MODE_V_ILLEGAL;
+
+	DRM_DEBUG_DRIVER("Vertical parameters OK\n");
+
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+sun4i_rgb_best_encoder(struct drm_connector *connector)
+{
+	struct sun4i_rgb *rgb =
+		drm_connector_to_sun4i_rgb(connector);
+
+	return &rgb->encoder;
+}
+
+static struct drm_connector_helper_funcs sun4i_rgb_con_helper_funcs = {
+	.get_modes	= sun4i_rgb_get_modes,
+	.mode_valid	= sun4i_rgb_mode_valid,
+	.best_encoder	= sun4i_rgb_best_encoder,
+};
+
+static enum drm_connector_status
+sun4i_rgb_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static void
+sun4i_rgb_connector_destroy(struct drm_connector *connector)
+{
+	struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
+
+	drm_panel_detach(rgb->panel);
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs sun4i_rgb_con_funcs = {
+	.dpms			= drm_atomic_helper_connector_dpms,
+	.detect			= sun4i_rgb_connector_detect,
+	.fill_modes		= drm_helper_probe_single_connector_modes,
+	.destroy		= sun4i_rgb_connector_destroy,
+	.reset			= drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
+};
+
+static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
+{
+	struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
+	struct sun4i_drv *drv = rgb->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	if (rgb->enabled)
+		return;
+
+	DRM_DEBUG_DRIVER("Enabling RGB output\n");
+
+	drm_panel_enable(rgb->panel);
+	sun4i_tcon_enable_channel(tcon, 0);
+
+	rgb->enabled = true;
+}
+
+static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
+{
+	struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
+	struct sun4i_drv *drv = rgb->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	if (!rgb->enabled)
+		return;
+
+	DRM_DEBUG_DRIVER("Disabling RGB output\n");
+
+	sun4i_tcon_disable_channel(tcon, 0);
+	drm_panel_disable(rgb->panel);
+
+	rgb->enabled = false;
+}
+
+static bool sun4i_rgb_encoder_mode_fixup(struct drm_encoder *encoder,
+					 const struct drm_display_mode *mode,
+					 struct drm_display_mode *adjusted)
+{
+	return true;
+}
+
+static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
+				       struct drm_display_mode *mode,
+				       struct drm_display_mode *adjusted_mode)
+{
+	struct sun4i_rgb *rgb = drm_encoder_to_sun4i_rgb(encoder);
+	struct sun4i_drv *drv = rgb->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	sun4i_tcon0_mode_set(tcon, mode);
+
+	clk_set_rate(tcon->dclk, mode->crtc_clock * 1000);
+}
+
+static struct drm_encoder_helper_funcs sun4i_rgb_enc_helper_funcs = {
+	.mode_fixup	= sun4i_rgb_encoder_mode_fixup,
+	.mode_set	= sun4i_rgb_encoder_mode_set,
+	.disable	= sun4i_rgb_encoder_disable,
+	.enable		= sun4i_rgb_encoder_enable,
+};
+
+static void sun4i_rgb_enc_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+
+static struct drm_encoder_funcs sun4i_rgb_enc_funcs = {
+	.destroy	= sun4i_rgb_enc_destroy,
+};
+
+int sun4i_rgb_init(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_rgb *rgb;
+	struct device_node *np;
+	int ret;
+
+	rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL);
+	if (!rgb)
+		return -ENOMEM;
+	rgb->drv = drv;
+
+	np = of_parse_phandle(drm->dev->of_node, "allwinner,panel", 0);
+	if (!np) {
+		dev_err(drm->dev, "Couldn't find our panel DT node\n");
+		return -ENODEV;
+	}
+
+	rgb->panel = of_drm_find_panel(np);
+	if (!rgb->panel) {
+		dev_err(drm->dev, "Couldn't find our panel\n");
+		return -EPROBE_DEFER;
+	}
+
+	drm_encoder_helper_add(&rgb->encoder,
+			       &sun4i_rgb_enc_helper_funcs);
+	ret = drm_encoder_init(drm,
+			       &rgb->encoder,
+			       &sun4i_rgb_enc_funcs,
+			       DRM_MODE_ENCODER_NONE);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't initialise the rgb encoder\n");
+		goto err_out;
+	}
+
+	/* The RGB encoder can only work with the TCON channel 0 */
+	rgb->encoder.possible_crtcs = BIT(0);
+
+	drm_connector_helper_add(&rgb->connector,
+				 &sun4i_rgb_con_helper_funcs);
+	ret = drm_connector_init(drm, &rgb->connector,
+				 &sun4i_rgb_con_funcs,
+				 DRM_MODE_CONNECTOR_Unknown);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't initialise the rgb connector\n");
+		goto err_cleanup_connector;
+	}
+
+	drm_mode_connector_attach_encoder(&rgb->connector, &rgb->encoder);
+
+	drm_panel_attach(rgb->panel, &rgb->connector);
+
+	return 0;
+
+err_cleanup_connector:
+	drm_encoder_cleanup(&rgb->encoder);
+err_out:
+	return ret;
+}
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.h b/drivers/gpu/drm/sun4i/sun4i_rgb.h
new file mode 100644
index 000000000000..7c4da4c8acdd
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.h
@@ -0,0 +1,18 @@
+/*
+ * 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 _SUN4I_RGB_H_
+#define _SUN4I_RGB_H_
+
+int sun4i_rgb_init(struct drm_device *drm);
+
+#endif /* _SUN4I_RGB_H_ */
-- 
2.6.2


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

* [PATCH 11/19] drm: sun4i: Add composite output
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (9 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 10/19] drm: sun4i: Add RGB output Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-11-02  2:53   ` [linux-sunxi] " Jonathan Liu
  2015-10-30 14:20 ` [PATCH 12/19] drm: sun4i: tv: Add PAL output standard Maxime Ripard
                   ` (9 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

Some Allwinner SoCs have an IP called the TV encoder that is used to output
composite and VGA signals. In such a case, we need to use the second TCON
channel.

Add support for that TV encoder.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/Makefile    |   1 +
 drivers/gpu/drm/sun4i/sun4i_drv.c |  10 +-
 drivers/gpu/drm/sun4i/sun4i_tv.c  | 532 ++++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_tv.h  |  18 ++
 4 files changed, 560 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.c
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 4d230b658a05..fc0dc8be82d9 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -6,5 +6,6 @@ sun4i-drm-y += sun4i_layer.o
 sun4i-drm-y += sun4i_tcon.o
 
 sun4i-drm-y += sun4i_rgb.o
+sun4i-drm-y += sun4i_tv.o
 
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index f2c9c8a2eb75..3cf7a9e89afa 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -22,6 +22,7 @@
 #include "sun4i_layer.h"
 #include "sun4i_rgb.h"
 #include "sun4i_tcon.h"
+#include "sun4i_tv.h"
 
 static void sun4i_drv_preclose(struct drm_device *drm,
 			       struct drm_file *file_priv)
@@ -134,12 +135,18 @@ static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
 		goto err_free_crtc;
 	}
 
+	ret = sun4i_tv_init(drm);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't create our RGB output\n");
+		goto err_free_rgb;
+	}
+
 	/* Create our framebuffer */
 	drv->fbdev = sun4i_framebuffer_init(drm);
 	if (IS_ERR(drv->fbdev)) {
 		dev_err(drm->dev, "Couldn't create our framebuffer\n");
 		ret = PTR_ERR(drv->fbdev);
-		goto err_free_rgb;
+		goto err_free_tv;
 	}
 
 	/* Enable connectors polling */
@@ -147,6 +154,7 @@ static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
 
 	return 0;
 
+err_free_tv:
 err_free_rgb:
 err_free_crtc:
 err_free_layers:
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
new file mode 100644
index 000000000000..dc55e340410c
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -0,0 +1,532 @@
+/*
+ * 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 <linux/clk.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include "sun4i_backend.h"
+#include "sun4i_drv.h"
+#include "sun4i_tcon.h"
+
+#define SUN4I_TVE_EN_REG		0x000
+#define SUN4I_TVE_EN_DAC_MAP_MASK		GENMASK(19, 4)
+#define SUN4I_TVE_EN_DAC_MAP(dac, out)		(((out) & 0xf) << (dac + 1) * 4)
+#define SUN4I_TVE_EN_ENABLE			BIT(0)
+
+#define SUN4I_TVE_CFG0_REG		0x004
+#define SUN4I_TVE_CFG0_DAC_CONTROL_54M		BIT(26)
+#define SUN4I_TVE_CFG0_CORE_DATAPATH_54M	BIT(25)
+#define SUN4I_TVE_CFG0_CORE_CONTROL_54M		BIT(24)
+#define SUN4I_TVE_CFG0_YC_EN			BIT(17)
+#define SUN4I_TVE_CFG0_COMP_EN			BIT(16)
+#define SUN4I_TVE_CFG0_RES(x)			((x) & 0xf)
+#define SUN4I_TVE_CFG0_RES_480i			SUN4I_TVE_CFG0_RES(0)
+#define SUN4I_TVE_CFG0_RES_576i			SUN4I_TVE_CFG0_RES(1)
+
+#define SUN4I_TVE_DAC0_REG		0x008
+#define SUN4I_TVE_DAC0_CLOCK_INVERT		BIT(24)
+#define SUN4I_TVE_DAC0_LUMA(x)			(((x) & 3) << 20)
+#define SUN4I_TVE_DAC0_LUMA_0_4			SUN4I_TVE_DAC0_LUMA(3)
+#define SUN4I_TVE_DAC0_CHROMA(x)		(((x) & 3) << 18)
+#define SUN4I_TVE_DAC0_CHROMA_0_75		SUN4I_TVE_DAC0_CHROMA(3)
+#define SUN4I_TVE_DAC0_INTERNAL_DAC(x)		(((x) & 3) << 16)
+#define SUN4I_TVE_DAC0_INTERNAL_DAC_37_5_OHMS	SUN4I_TVE_DAC0_INTERNAL_DAC(3)
+#define SUN4I_TVE_DAC0_DAC_EN(dac)		BIT(dac)
+
+#define SUN4I_TVE_NOTCH_REG		0x00c
+#define SUN4I_TVE_NOTCH_DAC0_TO_DAC_DLY(dac, x)	((4 - (x)) << (dac * 3))
+
+#define SUN4I_TVE_CHROMA_FREQ_REG	0x010
+
+#define SUN4I_TVE_PORCH_REG		0x014
+#define SUN4I_TVE_PORCH_BACK(x)			((x) << 16)
+#define SUN4I_TVE_PORCH_FRONT(x)		(x)
+
+#define SUN4I_TVE_LINE_REG		0x01c
+#define SUN4I_TVE_LINE_FIRST(x)			((x) << 16)
+#define SUN4I_TVE_LINE_NUMBER(x)		(x)
+
+#define SUN4I_TVE_LEVEL_REG		0x020
+#define SUN4I_TVE_LEVEL_BLANK(x)		((x) << 16)
+#define SUN4I_TVE_LEVEL_BLACK(x)		(x)
+
+#define SUN4I_TVE_DAC1_REG		0x024
+#define SUN4I_TVE_DAC1_AMPLITUDE(dac, x)	((x) << (dac * 8))
+
+#define SUN4I_TVE_DETECT_STA_REG	0x038
+#define SUN4I_TVE_DETECT_STA_DAC(dac)		BIT((dac * 8))
+#define SUN4I_TVE_DETECT_STA_UNCONNECTED		0
+#define SUN4I_TVE_DETECT_STA_CONNECTED			1
+#define SUN4I_TVE_DETECT_STA_GROUND			2
+
+#define SUN4I_TVE_CB_CR_LVL_REG		0x10c
+#define SUN4I_TVE_CB_CR_LVL_CR_BURST(x)		((x) << 8)
+#define SUN4I_TVE_CB_CR_LVL_CB_BURST(x)		(x)
+
+#define SUN4I_TVE_TINT_BURST_PHASE_REG	0x110
+#define SUN4I_TVE_TINT_BURST_PHASE_CHROMA(x)	(x)
+
+#define SUN4I_TVE_BURST_WIDTH_REG	0x114
+#define SUN4I_TVE_BURST_WIDTH_BREEZEWAY(x)	((x) << 16)
+#define SUN4I_TVE_BURST_WIDTH_BURST_WIDTH(x)	((x) << 8)
+#define SUN4I_TVE_BURST_WIDTH_HSYNC_WIDTH(x)	(x)
+
+#define SUN4I_TVE_CB_CR_GAIN_REG	0x118
+#define SUN4I_TVE_CB_CR_GAIN_CR(x)		((x) << 8)
+#define SUN4I_TVE_CB_CR_GAIN_CB(x)		(x)
+
+#define SUN4I_TVE_SYNC_VBI_REG		0x11c
+#define SUN4I_TVE_SYNC_VBI_SYNC(x)		((x) << 16)
+#define SUN4I_TVE_SYNC_VBI_VBLANK(x)		(x)
+
+#define SUN4I_TVE_ACTIVE_LINE_REG	0x124
+#define SUN4I_TVE_ACTIVE_LINE(x)		(x)
+
+#define SUN4I_TVE_CHROMA_REG		0x128
+#define SUN4I_TVE_CHROMA_COMP_GAIN(x)		((x) & 3)
+#define SUN4I_TVE_CHROMA_COMP_GAIN_50		SUN4I_TVE_CHROMA_COMP_GAIN(2)
+
+#define SUN4I_TVE_12C_REG		0x12c
+#define SUN4I_TVE_12C_NOTCH_WIDTH_WIDE		BIT(8)
+#define SUN4I_TVE_12C_COMP_YUV_EN		BIT(0)
+
+#define SUN4I_TVE_RESYNC_REG		0x130
+#define SUN4I_TVE_RESYNC_FIELD			BIT(31)
+#define SUN4I_TVE_RESYNC_LINE(x)		((x) << 16)
+#define SUN4I_TVE_RESYNC_PIXEL(x)		(x)
+
+#define SUN4I_TVE_SLAVE_REG		0x134
+
+#define SUN4I_TVE_WSS_DATA2_REG		0x244
+
+struct color_gains {
+	u16	cb;
+	u16	cr;
+};
+
+struct burst_levels {
+	u16	cb;
+	u16	cr;
+};
+
+struct video_levels {
+	u16	black;
+	u16	blank;
+};
+
+struct resync_parameters {
+	bool	field;
+	u16	line;
+	u16	pixel;
+};
+
+struct tv_mode {
+	char		*name;
+
+	u32		mode;
+	u32		chroma_freq;
+	u16		back_porch;
+	u16		front_porch;
+	u16		line_number;
+	u16		vblank_level;
+
+	u32		hdisplay;
+	u16		hfront_porch;
+	u16		hsync_len;
+	u16		hback_porch;
+
+	u32		vdisplay;
+	u16		vfront_porch;
+	u16		vsync_len;
+	u16		vback_porch;
+
+	bool		yc_en;
+	bool		dac3_en;
+	bool		dac_bit25_en;
+
+	struct color_gains		*color_gains;
+	struct burst_levels		*burst_levels;
+	struct video_levels		*video_levels;
+	struct resync_parameters	*resync_params;
+};
+
+struct sun4i_tv {
+	struct drm_connector	connector;
+	struct drm_encoder	encoder;
+
+	struct clk		*clk;
+	struct regmap		*regs;
+
+	struct sun4i_drv	*drv;
+};
+
+struct tv_mode tv_modes[] = {
+};
+
+static inline struct sun4i_tv *
+drm_encoder_to_sun4i_tv(struct drm_encoder *encoder)
+{
+	return container_of(encoder, struct sun4i_tv,
+			    encoder);
+}
+
+static inline struct sun4i_tv *
+drm_connector_to_sun4i_tv(struct drm_connector *connector)
+{
+	return container_of(connector, struct sun4i_tv,
+			    connector);
+}
+
+/*
+ * FIXME: If only the drm_display_mode private field was usable, this
+ * could go away...
+ *
+ * So far, it doesn't seem to be preserved when the mode is passed by
+ * to mode_set for some reason.
+ */
+static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+		struct tv_mode *tv_mode = &tv_modes[i];
+
+		if (!strcmp(mode->name, tv_mode->name))
+			return tv_mode;
+	}
+
+	return NULL;
+}
+
+static int sun4i_tv_atomic_check(struct drm_encoder *encoder,
+				 struct drm_crtc_state *crtc_state,
+				 struct drm_connector_state *conn_state)
+{
+	return 0;
+}
+
+static void sun4i_tv_disable(struct drm_encoder *encoder)
+{
+	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
+	struct sun4i_drv *drv = tv->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	DRM_DEBUG_DRIVER("Disabling the TV Output\n");
+
+	sun4i_tcon_disable_channel(tcon, 1);
+
+	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
+			   SUN4I_TVE_EN_ENABLE,
+			   0);
+}
+
+static void sun4i_tv_enable(struct drm_encoder *encoder)
+{
+	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
+	struct sun4i_drv *drv = tv->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	DRM_DEBUG_DRIVER("Enabling the TV Output\n");
+
+	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
+			   SUN4I_TVE_EN_ENABLE,
+			   SUN4I_TVE_EN_ENABLE);
+
+	sun4i_tcon_enable_channel(tcon, 1);
+}
+
+static void sun4i_tv_mode_set(struct drm_encoder *encoder,
+			      struct drm_display_mode *mode,
+			      struct drm_display_mode *adjusted_mode)
+{
+	struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder);
+	struct sun4i_drv *drv = tv->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+	struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode);
+
+	sun4i_backend_apply_color_correction(drv->backend);
+	sun4i_tcon1_mode_set(tcon, mode);
+
+	/* Enable and map the DAC to the output */
+	regmap_update_bits(tv->regs, SUN4I_TVE_EN_REG,
+			   SUN4I_TVE_EN_DAC_MAP_MASK,
+			   SUN4I_TVE_EN_DAC_MAP(0, 1) |
+			   SUN4I_TVE_EN_DAC_MAP(1, 2) |
+			   SUN4I_TVE_EN_DAC_MAP(2, 3) |
+			   SUN4I_TVE_EN_DAC_MAP(3, 4));
+
+	/* Set PAL settings */
+	regmap_write(tv->regs, SUN4I_TVE_CFG0_REG,
+		     tv_mode->mode |
+		     (tv_mode->yc_en ? SUN4I_TVE_CFG0_YC_EN : 0) |
+		     SUN4I_TVE_CFG0_COMP_EN |
+		     SUN4I_TVE_CFG0_DAC_CONTROL_54M |
+		     SUN4I_TVE_CFG0_CORE_DATAPATH_54M |
+		     SUN4I_TVE_CFG0_CORE_CONTROL_54M);
+
+	/* Configure the DAC for a composite output */
+	regmap_write(tv->regs, SUN4I_TVE_DAC0_REG,
+		     SUN4I_TVE_DAC0_DAC_EN(0) |
+		     (tv_mode->dac3_en ? SUN4I_TVE_DAC0_DAC_EN(3) : 0) |
+		     SUN4I_TVE_DAC0_INTERNAL_DAC_37_5_OHMS |
+		     SUN4I_TVE_DAC0_CHROMA_0_75 |
+		     SUN4I_TVE_DAC0_LUMA_0_4 |
+		     SUN4I_TVE_DAC0_CLOCK_INVERT |
+		     (tv_mode->dac_bit25_en ? BIT(25) : 0) |
+		     BIT(30));
+
+	/* Configure the sample delay between DAC0 and the other DAC */
+	regmap_write(tv->regs, SUN4I_TVE_NOTCH_REG,
+		     SUN4I_TVE_NOTCH_DAC0_TO_DAC_DLY(1, 0) |
+		     SUN4I_TVE_NOTCH_DAC0_TO_DAC_DLY(2, 0));
+
+	regmap_write(tv->regs, SUN4I_TVE_CHROMA_FREQ_REG,
+		     tv_mode->chroma_freq);
+
+	/* Set the front and back porch */
+	regmap_write(tv->regs, SUN4I_TVE_PORCH_REG,
+		     SUN4I_TVE_PORCH_BACK(tv_mode->back_porch) |
+		     SUN4I_TVE_PORCH_FRONT(tv_mode->front_porch));
+
+	/* Set the lines setup */
+	regmap_write(tv->regs, SUN4I_TVE_LINE_REG,
+		     SUN4I_TVE_LINE_FIRST(22) |
+		     SUN4I_TVE_LINE_NUMBER(tv_mode->line_number));
+
+	regmap_write(tv->regs, SUN4I_TVE_LEVEL_REG,
+		     SUN4I_TVE_LEVEL_BLANK(tv_mode->video_levels->blank) |
+		     SUN4I_TVE_LEVEL_BLACK(tv_mode->video_levels->black));
+
+	regmap_write(tv->regs, SUN4I_TVE_DAC1_REG,
+		     SUN4I_TVE_DAC1_AMPLITUDE(0, 0x18) |
+		     SUN4I_TVE_DAC1_AMPLITUDE(1, 0x18) |
+		     SUN4I_TVE_DAC1_AMPLITUDE(2, 0x18) |
+		     SUN4I_TVE_DAC1_AMPLITUDE(3, 0x18));
+
+	regmap_write(tv->regs, SUN4I_TVE_CB_CR_LVL_REG,
+		     SUN4I_TVE_CB_CR_LVL_CB_BURST(tv_mode->burst_levels->cb) |
+		     SUN4I_TVE_CB_CR_LVL_CR_BURST(tv_mode->burst_levels->cr));
+
+	/* Set burst width for a composite output */
+	regmap_write(tv->regs, SUN4I_TVE_BURST_WIDTH_REG,
+		     SUN4I_TVE_BURST_WIDTH_HSYNC_WIDTH(126) |
+		     SUN4I_TVE_BURST_WIDTH_BURST_WIDTH(68) |
+		     SUN4I_TVE_BURST_WIDTH_BREEZEWAY(22));
+
+	regmap_write(tv->regs, SUN4I_TVE_CB_CR_GAIN_REG,
+		     SUN4I_TVE_CB_CR_GAIN_CB(tv_mode->color_gains->cb) |
+		     SUN4I_TVE_CB_CR_GAIN_CR(tv_mode->color_gains->cr));
+
+	regmap_write(tv->regs, SUN4I_TVE_SYNC_VBI_REG,
+		     SUN4I_TVE_SYNC_VBI_SYNC(0x10) |
+		     SUN4I_TVE_SYNC_VBI_VBLANK(tv_mode->vblank_level));
+
+	regmap_write(tv->regs, SUN4I_TVE_ACTIVE_LINE_REG,
+		     SUN4I_TVE_ACTIVE_LINE(1440));
+
+	/* Set composite chroma gain to 50 % */
+	regmap_write(tv->regs, SUN4I_TVE_CHROMA_REG,
+		     SUN4I_TVE_CHROMA_COMP_GAIN_50);
+
+	regmap_write(tv->regs, SUN4I_TVE_12C_REG,
+		     SUN4I_TVE_12C_COMP_YUV_EN |
+		     SUN4I_TVE_12C_NOTCH_WIDTH_WIDE);
+
+	regmap_write(tv->regs, SUN4I_TVE_RESYNC_REG,
+		     SUN4I_TVE_RESYNC_PIXEL(tv_mode->resync_params->pixel) |
+		     SUN4I_TVE_RESYNC_LINE(tv_mode->resync_params->line) |
+		     (tv_mode->resync_params->field ?
+		      SUN4I_TVE_RESYNC_FIELD : 0));
+
+	regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0);
+
+	clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
+}
+
+static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = {
+	.atomic_check	= sun4i_tv_atomic_check,
+	.disable	= sun4i_tv_disable,
+	.enable		= sun4i_tv_enable,
+	.mode_set	= sun4i_tv_mode_set,
+};
+
+static void sun4i_tv_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+
+static struct drm_encoder_funcs sun4i_tv_funcs = {
+	.destroy	= sun4i_tv_destroy,
+};
+
+static struct regmap_config sun4i_tv_regmap_config = {
+	.reg_bits	= 32,
+	.val_bits	= 32,
+	.reg_stride	= 4,
+	.max_register	= SUN4I_TVE_WSS_DATA2_REG,
+	.name		= "tv-encoder",
+};
+
+static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+		struct drm_display_mode *mode = drm_mode_create(connector->dev);
+		struct tv_mode *tv_mode = &tv_modes[i];
+
+		DRM_DEBUG_DRIVER("Creating mode %s\n", tv_mode->name);
+
+		strcpy(mode->name, tv_mode->name);
+		mode->type = DRM_MODE_TYPE_DRIVER;
+		mode->clock = 13500;
+		mode->flags = DRM_MODE_FLAG_INTERLACE;
+
+		mode->hdisplay = tv_mode->hdisplay;
+		mode->hsync_start = mode->hdisplay + tv_mode->hfront_porch;
+		mode->hsync_end = mode->hsync_start + tv_mode->hsync_len;
+		mode->htotal = mode->hsync_end  + tv_mode->hback_porch;
+
+		mode->vdisplay = tv_mode->vdisplay;
+		mode->vsync_start = mode->vdisplay + tv_mode->vfront_porch;
+		mode->vsync_end = mode->vsync_start + tv_mode->vsync_len;
+		mode->vtotal = mode->vsync_end  + tv_mode->vback_porch;
+
+		drm_mode_probed_add(connector, mode);
+	}
+
+	return i;
+}
+
+static int sun4i_tv_comp_mode_valid(struct drm_connector *connector,
+				    struct drm_display_mode *mode)
+{
+	/* TODO */
+	return MODE_OK;
+}
+
+static struct drm_encoder *
+sun4i_tv_comp_best_encoder(struct drm_connector *connector)
+{
+	struct sun4i_tv *tv = drm_connector_to_sun4i_tv(connector);
+
+	return &tv->encoder;
+}
+
+static struct drm_connector_helper_funcs sun4i_tv_comp_connector_helper_funcs = {
+	.get_modes	= sun4i_tv_comp_get_modes,
+	.mode_valid	= sun4i_tv_comp_mode_valid,
+	.best_encoder	= sun4i_tv_comp_best_encoder,
+};
+
+static enum drm_connector_status
+sun4i_tv_comp_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static void
+sun4i_tv_comp_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs sun4i_tv_comp_connector_funcs = {
+	.dpms			= drm_atomic_helper_connector_dpms,
+	.detect			= sun4i_tv_comp_connector_detect,
+	.fill_modes		= drm_helper_probe_single_connector_modes,
+	.destroy		= sun4i_tv_comp_connector_destroy,
+	.reset			= drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state	= drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state	= drm_atomic_helper_connector_destroy_state,
+};
+
+int sun4i_tv_init(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	struct device_node *np;
+	struct sun4i_tv *tv;
+	struct resource res;
+	void __iomem *regs;
+	int ret;
+
+	tv = devm_kzalloc(drm->dev, sizeof(*tv), GFP_KERNEL);
+	if (!tv)
+		return -ENOMEM;
+	tv->drv = drv;
+
+	np = of_parse_phandle(drm->dev->of_node, "allwinner,tv-encoder", 0);
+	if (!np) {
+		dev_err(drm->dev, "Couldn't find the TV encoder node\n");
+		return -ENODEV;
+	}
+
+	ret = of_address_to_resource(np, 0, &res);
+	regs = devm_ioremap_resource(drm->dev, &res);
+	if (IS_ERR(regs)) {
+		dev_err(drm->dev, "Couldn't map the TV encoder registers\n");
+		return PTR_ERR(regs);
+	}
+
+	tv->regs = devm_regmap_init_mmio(drm->dev, regs,
+					  &sun4i_tv_regmap_config);
+	if (IS_ERR(tv->regs)) {
+		dev_err(drm->dev, "Couldn't create the TV encoder regmap\n");
+		return PTR_ERR(tv->regs);
+	}
+
+	tv->clk = of_clk_get(np, 0);
+	if (IS_ERR(tv->clk)) {
+		dev_err(drm->dev, "Couldn't get the TV encoder clock\n");
+		return PTR_ERR(tv->clk);
+	}
+	clk_prepare_enable(tv->clk);
+
+	drm_encoder_helper_add(&tv->encoder,
+			       &sun4i_tv_helper_funcs);
+	ret = drm_encoder_init(drm,
+			       &tv->encoder,
+			       &sun4i_tv_funcs,
+			       DRM_MODE_ENCODER_TVDAC);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't initialise the TV encoder\n");
+		return ret;
+	}
+
+	tv->encoder.possible_crtcs = BIT(0);
+
+	drm_connector_helper_add(&tv->connector,
+				 &sun4i_tv_comp_connector_helper_funcs);
+	ret = drm_connector_init(drm, &tv->connector,
+				 &sun4i_tv_comp_connector_funcs,
+				 DRM_MODE_CONNECTOR_Composite);
+	if (ret) {
+		dev_err(drm->dev,
+			"Couldn't initialise the Composite connector\n");
+		goto err_cleanup_connector;
+	}
+	tv->connector.interlace_allowed = true;
+
+	drm_mode_connector_attach_encoder(&tv->connector, &tv->encoder);
+
+	return 0;
+
+err_cleanup_connector:
+	drm_encoder_cleanup(&tv->encoder);
+	return ret;
+}
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.h b/drivers/gpu/drm/sun4i/sun4i_tv.h
new file mode 100644
index 000000000000..7e39f3581bf9
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.h
@@ -0,0 +1,18 @@
+/*
+ * 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 _SUN4I_TV_H_
+#define _SUN4I_TV_H_
+
+int sun4i_tv_init(struct drm_device *drm);
+
+#endif /* _SUN4I_TV_H_ */
-- 
2.6.2


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

* [PATCH 12/19] drm: sun4i: tv: Add PAL output standard
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (10 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 11/19] drm: sun4i: Add composite output Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 14:20 ` [PATCH 13/19] drm: sun4i: tv: Add NTSC " Maxime Ripard
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

Now that we have support for the composite output, we can start adding new
supported standards. Start with PAL, and we will add other eventually.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_tv.c | 42 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index dc55e340410c..4b95d04ff457 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -175,7 +175,49 @@ struct sun4i_tv {
 	struct sun4i_drv	*drv;
 };
 
+struct video_levels pal_video_levels = {
+	.black = 252,	.blank = 252,
+};
+
+struct burst_levels pal_burst_levels = {
+	.cb = 40,	.cr = 40,
+};
+
+struct color_gains pal_color_gains = {
+	.cb = 224,	.cr = 224,
+};
+
+struct resync_parameters pal_resync_parameters = {
+	.field = true,	.line = 13,	.pixel = 12,
+};
+
 struct tv_mode tv_modes[] = {
+	{
+		.name		= "PAL",
+		.mode		= SUN4I_TVE_CFG0_RES_576i,
+		.chroma_freq	= 0x2a098acb,
+
+		.back_porch	= 138,
+		.front_porch	= 24,
+		.line_number	= 625,
+
+		.hdisplay	= 720,
+		.hfront_porch	= 3,
+		.hsync_len	= 2,
+		.hback_porch	= 139,
+
+		.vdisplay	= 576,
+		.vfront_porch	= 28,
+		.vsync_len	= 2,
+		.vback_porch	= 19,
+
+		.vblank_level	= 252,
+
+		.color_gains	= &pal_color_gains,
+		.burst_levels	= &pal_burst_levels,
+		.video_levels	= &pal_video_levels,
+		.resync_params	= &pal_resync_parameters,
+	},
 };
 
 static inline struct sun4i_tv *
-- 
2.6.2


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

* [PATCH 13/19] drm: sun4i: tv: Add NTSC output standard
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (11 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 12/19] drm: sun4i: tv: Add PAL output standard Maxime Ripard
@ 2015-10-30 14:20 ` Maxime Ripard
  2015-10-30 14:21 ` [PATCH 14/19] ARM: sun5i: dt: Add pll3 and pll7 clocks Maxime Ripard
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:20 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

Add the settings to support the NTSC standard.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/sun4i/sun4i_tv.c | 45 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
index 4b95d04ff457..b460406d744c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -175,24 +175,69 @@ struct sun4i_tv {
 	struct sun4i_drv	*drv;
 };
 
+struct video_levels ntsc_video_levels = {
+	.black = 282,	.blank = 240,
+};
+
 struct video_levels pal_video_levels = {
 	.black = 252,	.blank = 252,
 };
 
+struct burst_levels ntsc_burst_levels = {
+	.cb = 79,	.cr = 0,
+};
+
 struct burst_levels pal_burst_levels = {
 	.cb = 40,	.cr = 40,
 };
 
+struct color_gains ntsc_color_gains = {
+	.cb = 160,	.cr = 160,
+};
+
 struct color_gains pal_color_gains = {
 	.cb = 224,	.cr = 224,
 };
 
+struct resync_parameters ntsc_resync_parameters = {
+	.field = false,	.line = 14,	.pixel = 12,
+};
+
 struct resync_parameters pal_resync_parameters = {
 	.field = true,	.line = 13,	.pixel = 12,
 };
 
 struct tv_mode tv_modes[] = {
 	{
+		.name		= "NTSC",
+		.mode		= SUN4I_TVE_CFG0_RES_480i,
+		.chroma_freq	= 0x21f07c1f,
+		.yc_en		= true,
+		.dac3_en	= true,
+		.dac_bit25_en	= true,
+
+		.back_porch	= 118,
+		.front_porch	= 32,
+		.line_number	= 525,
+
+		.hdisplay	= 720,
+		.hfront_porch	= 18,
+		.hsync_len	= 2,
+		.hback_porch	= 118,
+
+		.vdisplay	= 480,
+		.vfront_porch	= 26,
+		.vsync_len	= 2,
+		.vback_porch	= 17,
+
+		.vblank_level	= 240,
+
+		.color_gains	= &ntsc_color_gains,
+		.burst_levels	= &ntsc_burst_levels,
+		.video_levels	= &ntsc_video_levels,
+		.resync_params	= &ntsc_resync_parameters,
+	},
+	{
 		.name		= "PAL",
 		.mode		= SUN4I_TVE_CFG0_RES_576i,
 		.chroma_freq	= 0x2a098acb,
-- 
2.6.2


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

* [PATCH 14/19] ARM: sun5i: dt: Add pll3 and pll7 clocks
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (12 preceding siblings ...)
  2015-10-30 14:20 ` [PATCH 13/19] drm: sun4i: tv: Add NTSC " Maxime Ripard
@ 2015-10-30 14:21 ` Maxime Ripard
  2015-11-09  4:24   ` Chen-Yu Tsai
  2015-10-30 14:21 ` [PATCH 15/19] ARM: sun5i: dt: Add display and TCON clocks Maxime Ripard
                   ` (6 subsequent siblings)
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:21 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

Enable the pll3 and pll7 clocks in the DT that are used to drive the
display-related clocks.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun5i.dtsi | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index 59a9426e3bd4..bde9a545b79f 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -88,6 +88,15 @@
 			clock-output-names = "osc24M";
 		};
 
+		osc3M: osc3M_clk {
+			compatible = "fixed-factor-clock";
+			#clock-cells = <0>;
+			clock-div = <8>;
+			clock-mult = <1>;
+			clocks = <&osc24M>;
+			clock-output-names = "osc3M";
+		};
+
 		osc32k: clk@0 {
 			#clock-cells = <0>;
 			compatible = "fixed-clock";
@@ -112,6 +121,14 @@
 					     "pll2-4x", "pll2-8x";
 		};
 
+		pll3: clk@01c20010 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-pll3-clk";
+			reg = <0x01c20010 0x4>;
+			clocks = <&osc3M>;
+			clock-output-names = "pll3";
+		};
+
 		pll4: clk@01c20018 {
 			#clock-cells = <0>;
 			compatible = "allwinner,sun4i-a10-pll1-clk";
@@ -136,6 +153,14 @@
 			clock-output-names = "pll6_sata", "pll6_other", "pll6";
 		};
 
+		pll7: clk@01c20030 {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-pll3-clk";
+			reg = <0x01c20030 0x4>;
+			clocks = <&osc3M>;
+			clock-output-names = "pll7";
+		};
+
 		/* dummy is 200M */
 		cpu: cpu@01c20054 {
 			#clock-cells = <0>;
-- 
2.6.2


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

* [PATCH 15/19] ARM: sun5i: dt: Add display and TCON clocks
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (13 preceding siblings ...)
  2015-10-30 14:21 ` [PATCH 14/19] ARM: sun5i: dt: Add pll3 and pll7 clocks Maxime Ripard
@ 2015-10-30 14:21 ` Maxime Ripard
  2015-10-30 14:21 ` [PATCH 16/19] ARM: sun5i: dt: Add DRAM gates Maxime Ripard
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:21 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

Enable the display and TCON (channel 0 and channel 1) clocks that are going
to be needed to drive the display engine, tcon and TV encoders.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun5i-a10s.dtsi |  8 +++---
 arch/arm/boot/dts/sun5i-a13.dtsi  |  3 ++-
 arch/arm/boot/dts/sun5i-r8.dtsi   |  5 ++--
 arch/arm/boot/dts/sun5i.dtsi      | 53 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index bddd0de88af6..0981a9e2db3b 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -65,8 +65,9 @@
 			compatible = "allwinner,simple-framebuffer",
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0-hdmi";
-			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
-				 <&ahb_gates 44>;
+			clocks = <&ahb_gates 36>, <&ahb_gates 43>,
+				 <&ahb_gates 44>, <&de_be_clk>,
+				 <&tcon_ch1_clk>;
 			status = "disabled";
 		};
 
@@ -74,7 +75,8 @@
 			compatible = "allwinner,simple-framebuffer",
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0";
-			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
+			clocks = <&ahb_gates 36>, <&ahb_gates 44>,
+				 <&de_be_clk>, <&tcon_ch0_clk>;
 			status = "disabled";
 		};
 
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index d910d3a6c41c..130644d7e054 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -61,7 +61,8 @@
 			compatible = "allwinner,simple-framebuffer",
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0";
-			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
+			clocks = <&ahb_gates 36>, <&ahb_gates 44>, <&de_be_clk>,
+				 <&tcon_ch0_clk>;
 			status = "disabled";
 		};
 	};
diff --git a/arch/arm/boot/dts/sun5i-r8.dtsi b/arch/arm/boot/dts/sun5i-r8.dtsi
index 0ef865601ac9..b1e4e0170d51 100644
--- a/arch/arm/boot/dts/sun5i-r8.dtsi
+++ b/arch/arm/boot/dts/sun5i-r8.dtsi
@@ -51,8 +51,9 @@
 			compatible = "allwinner,simple-framebuffer",
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0-tve0";
-			clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
-				 <&ahb_gates 44>;
+			clocks = <&ahb_gates 34>, <&ahb_gates 36>,
+				 <&ahb_gates 44>, <&de_be_clk>,
+				 <&tcon_ch1_clk>;
 			status = "disabled";
 		};
 	};
diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index bde9a545b79f..861c5a621e70 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -129,6 +129,15 @@
 			clock-output-names = "pll3";
 		};
 
+		pll3x2: pll3x2_clk {
+			compatible = "fixed-factor-clock";
+			#clock-cells = <0>;
+			clock-div = <1>;
+			clock-mult = <2>;
+			clocks = <&pll3>;
+			clock-output-names = "pll3x2";
+		};
+
 		pll4: clk@01c20018 {
 			#clock-cells = <0>;
 			compatible = "allwinner,sun4i-a10-pll1-clk";
@@ -161,6 +170,15 @@
 			clock-output-names = "pll7";
 		};
 
+		pll7x2: pll7x2_clk {
+			compatible = "fixed-factor-clock";
+			#clock-cells = <0>;
+			clock-div = <1>;
+			clock-mult = <2>;
+			clocks = <&pll7>;
+			clock-output-names = "pll7x2";
+		};
+
 		/* dummy is 200M */
 		cpu: cpu@01c20054 {
 			#clock-cells = <0>;
@@ -320,6 +338,41 @@
 			clock-output-names = "usb_ohci0", "usb_phy";
 		};
 
+		de_be_clk: clk@01c20104 {
+			#clock-cells = <0>;
+			#reset-cells = <0>;
+			compatible = "allwinner,sun4i-a10-display-clk";
+			reg = <0x01c20104 0x4>;
+			clocks = <&pll3>, <&pll7>, <&pll5 1>;
+			clock-output-names = "de-be";
+		};
+
+		de_fe_clk: clk@01c2010c {
+			#clock-cells = <0>;
+			#reset-cells = <0>;
+			compatible = "allwinner,sun4i-a10-display-clk";
+			reg = <0x01c2010c 0x4>;
+			clocks = <&pll3>, <&pll7>, <&pll5 1>;
+			clock-output-names = "de-fe";
+		};
+
+		tcon_ch0_clk: clk@01c20118 {
+			#clock-cells = <0>;
+			#reset-cells = <1>;
+			compatible = "allwinner,sun4i-a10-tcon-ch0-clk";
+			reg = <0x01c20118 0x4>;
+			clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
+			clock-output-names = "tcon-ch0-sclk";
+		};
+
+		tcon_ch1_clk: clk@01c2012c {
+			#clock-cells = <0>;
+			compatible = "allwinner,sun4i-a10-tcon-ch1-clk";
+			reg = <0x01c2012c 0x4>;
+			clocks = <&pll3>, <&pll7>, <&pll3x2>, <&pll7x2>;
+			clock-output-names = "tcon-ch1-sclk";
+		};
+
 		codec_clk: clk@01c20140 {
 			#clock-cells = <0>;
 			compatible = "allwinner,sun4i-a10-codec-clk";
-- 
2.6.2


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

* [PATCH 16/19] ARM: sun5i: dt: Add DRAM gates
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (14 preceding siblings ...)
  2015-10-30 14:21 ` [PATCH 15/19] ARM: sun5i: dt: Add display and TCON clocks Maxime Ripard
@ 2015-10-30 14:21 ` Maxime Ripard
  2015-10-30 14:21 ` [PATCH 17/19] ARM: sun5i: dt: Add display blocks to the DTSI Maxime Ripard
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:21 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The DRAM gates control whether the image / display devices on the SoC have
access to the DRAM clock or not.

Enable it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun5i-a10s.dtsi |  5 +++--
 arch/arm/boot/dts/sun5i-a13.dtsi  |  2 +-
 arch/arm/boot/dts/sun5i-r8.dtsi   |  2 +-
 arch/arm/boot/dts/sun5i.dtsi      | 19 +++++++++++++++++++
 4 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 0981a9e2db3b..c996b5d1851a 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -67,7 +67,7 @@
 			allwinner,pipeline = "de_be0-lcd0-hdmi";
 			clocks = <&ahb_gates 36>, <&ahb_gates 43>,
 				 <&ahb_gates 44>, <&de_be_clk>,
-				 <&tcon_ch1_clk>;
+				 <&tcon_ch1_clk>, <&dram_gates 26>;
 			status = "disabled";
 		};
 
@@ -76,7 +76,8 @@
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0";
 			clocks = <&ahb_gates 36>, <&ahb_gates 44>,
-				 <&de_be_clk>, <&tcon_ch0_clk>;
+				 <&de_be_clk>, <&tcon_ch0_clk>,
+				 <&dram_gates 26>;
 			status = "disabled";
 		};
 
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 130644d7e054..17b36b942d38 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -62,7 +62,7 @@
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0";
 			clocks = <&ahb_gates 36>, <&ahb_gates 44>, <&de_be_clk>,
-				 <&tcon_ch0_clk>;
+				 <&tcon_ch0_clk>, <&dram_gates 26>;
 			status = "disabled";
 		};
 	};
diff --git a/arch/arm/boot/dts/sun5i-r8.dtsi b/arch/arm/boot/dts/sun5i-r8.dtsi
index b1e4e0170d51..691d3de75b35 100644
--- a/arch/arm/boot/dts/sun5i-r8.dtsi
+++ b/arch/arm/boot/dts/sun5i-r8.dtsi
@@ -53,7 +53,7 @@
 			allwinner,pipeline = "de_be0-lcd0-tve0";
 			clocks = <&ahb_gates 34>, <&ahb_gates 36>,
 				 <&ahb_gates 44>, <&de_be_clk>,
-				 <&tcon_ch1_clk>;
+				 <&tcon_ch1_clk>, <&dram_gates 26>;
 			status = "disabled";
 		};
 	};
diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index 861c5a621e70..426db76c0fe6 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -338,6 +338,25 @@
 			clock-output-names = "usb_ohci0", "usb_phy";
 		};
 
+		dram_gates: clk@01c20100 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun5i-a13-dram-gates-clk";
+			reg = <0x01c20100 0x4>;
+			clocks = <&pll5 0>;
+			clock-indices = <0>,
+					<1>,
+					<25>,
+					<26>,
+					<29>,
+					<31>;
+			clock-output-names = "dram_ve",
+					     "dram_csi",
+					     "dram_de_fe",
+					     "dram_de_be",
+					     "dram_ace",
+					     "dram_iep";
+		};
+
 		de_be_clk: clk@01c20104 {
 			#clock-cells = <0>;
 			#reset-cells = <0>;
-- 
2.6.2


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

* [PATCH 17/19] ARM: sun5i: dt: Add display blocks to the DTSI
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (15 preceding siblings ...)
  2015-10-30 14:21 ` [PATCH 16/19] ARM: sun5i: dt: Add DRAM gates Maxime Ripard
@ 2015-10-30 14:21 ` Maxime Ripard
  2015-10-30 14:21 ` [PATCH 18/19] ARM: sun5i: r8: Add AHB gates " Maxime Ripard
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:21 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The TCON and Display Engines are the two most important members of the
display pipeline.

With this alone, we can already use the display to an RGB interface.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun5i.dtsi | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index 426db76c0fe6..a67f4bdf5bcc 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -481,6 +481,20 @@
 			#size-cells = <0>;
 		};
 
+		tcon: lcd-controller@01c0c000 {
+			compatible = "allwinner,sun4i-a10-tcon";
+			reg = <0x01c0c000 0x1000>;
+			interrupts = <44>;
+			clocks = <&ahb_gates 36>,
+				 <&tcon_ch0_clk>,
+				 <&tcon_ch1_clk>;
+			clock-names = "ahb",
+				      "tcon-ch0",
+				      "tcon-ch1";
+			clock-output-names = "tcon-pixel-clock";
+			status = "disabled";
+		};
+
 		mmc0: mmc@01c0f000 {
 			compatible = "allwinner,sun5i-a13-mmc";
 			reg = <0x01c0f000 0x1000>;
@@ -767,5 +781,31 @@
 			interrupts = <82>, <83>;
 			clocks = <&ahb_gates 28>;
 		};
+
+		de: display-engine@01e00000 {
+			compatible = "allwinner,sun5i-a13-display-engine";
+			reg = <0x01e00000 0x20000>,
+			      <0x01e60000 0x10000>;
+			reg-names = "frontend0",
+				    "backend0";
+			interrupts = <47>;
+			interrupt-names = "engine0";
+			clocks = <&ahb_gates 46>, <&de_fe_clk>,
+				 <&dram_gates 25>, <&ahb_gates 44>,
+				 <&de_be_clk>, <&dram_gates 26>;
+			clock-names = "frontend0-bus", "frontend0-mod",
+				      "frontend0-ram", "backend0-bus",
+				      "backend0-mod", "backend0-ram";
+			resets = <&de_fe_clk>,
+				 <&de_be_clk>;
+			reset-names = "frontend0",
+				      "backend0";
+
+			allwinner,tcon = <&tcon>;
+
+			assigned-clocks = <&de_be_clk>;
+			assigned-clock-rates = <300000000>;
+			status = "disabled";
+		};
 	};
 };
-- 
2.6.2


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

* [PATCH 18/19] ARM: sun5i: r8: Add AHB gates to the DTSI
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (16 preceding siblings ...)
  2015-10-30 14:21 ` [PATCH 17/19] ARM: sun5i: dt: Add display blocks to the DTSI Maxime Ripard
@ 2015-10-30 14:21 ` Maxime Ripard
  2015-10-30 14:21 ` [PATCH 19/19] ARM: sun5i: chip: Enable the TV Encoder Maxime Ripard
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:21 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

Add the gates definition to the R8 DTSI.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun5i-r8.dtsi | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/arch/arm/boot/dts/sun5i-r8.dtsi b/arch/arm/boot/dts/sun5i-r8.dtsi
index 691d3de75b35..d69df3a73cbf 100644
--- a/arch/arm/boot/dts/sun5i-r8.dtsi
+++ b/arch/arm/boot/dts/sun5i-r8.dtsi
@@ -57,4 +57,33 @@
 			status = "disabled";
 		};
 	};
+
+	clocks {
+		ahb_gates: clk@01c20060 {
+			#clock-cells = <1>;
+			compatible = "allwinner,sun5i-r8-ahb-gates-clk";
+			reg = <0x01c20060 0x8>;
+			clocks = <&ahb>;
+			clock-indices = <0>, <1>,
+					<2>, <5>, <6>,
+					<7>, <8>, <9>,
+					<10>, <13>,
+					<14>, <20>,
+					<21>, <22>,
+					<28>, <32>, <34>,
+					<36>, <40>, <44>,
+					<46>, <51>,
+					<52>;
+			clock-output-names = "ahb_usbotg", "ahb_ehci",
+					     "ahb_ohci", "ahb_ss", "ahb_dma",
+					     "ahb_bist", "ahb_mmc0", "ahb_mmc1",
+					     "ahb_mmc2", "ahb_nand",
+					     "ahb_sdram", "ahb_spi0",
+					     "ahb_spi1", "ahb_spi2",
+					     "ahb_stimer", "ahb_ve", "ahb_tve",
+					     "ahb_lcd", "ahb_csi", "ahb_de_be",
+					     "ahb_de_fe", "ahb_iep",
+					     "ahb_mali400";
+		};
+	};
 };
-- 
2.6.2


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

* [PATCH 19/19] ARM: sun5i: chip: Enable the TV Encoder
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (17 preceding siblings ...)
  2015-10-30 14:21 ` [PATCH 18/19] ARM: sun5i: r8: Add AHB gates " Maxime Ripard
@ 2015-10-30 14:21 ` Maxime Ripard
  2015-10-30 15:20   ` Chen-Yu Tsai
  2015-10-30 14:52 ` [PATCH 00/19] drm: Add Allwinner A10 display engine support Daniel Vetter
  2015-11-09  3:43 ` Chen-Yu Tsai
  20 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-10-30 14:21 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter, Maxime Ripard

The TV encoder is used to drive VGA and composite display.

Enable it on the CHIP

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 arch/arm/boot/dts/sun5i-r8.dtsi | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/sun5i-r8.dtsi b/arch/arm/boot/dts/sun5i-r8.dtsi
index d69df3a73cbf..e39c903da864 100644
--- a/arch/arm/boot/dts/sun5i-r8.dtsi
+++ b/arch/arm/boot/dts/sun5i-r8.dtsi
@@ -86,4 +86,16 @@
 					     "ahb_mali400";
 		};
 	};
+
+	soc@01c00000 {
+		tve: encoder@01c0a000 {
+			compatible = "allwinner,sun4i-a10-tv-encoder";
+			reg = <0x01c0a000 0x1000>;
+			clocks = <&ahb_gates 34>;
+		};
+	};
+};
+
+&de {
+	allwinner,tv-encoder = <&tve>;
 };
-- 
2.6.2


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

* Re: [PATCH 08/19] drm: Add Allwinner A10 Display Engine support
  2015-10-30 14:20 ` [PATCH 08/19] drm: Add Allwinner A10 Display Engine support Maxime Ripard
@ 2015-10-30 14:44   ` Daniel Vetter
  2015-11-11 22:14     ` Maxime Ripard
  0 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2015-10-30 14:44 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 03:20:54PM +0100, Maxime Ripard wrote:
> The Allwinner A10 and subsequent SoCs share the same display pipeline, with
> variations in the number of controllers (1 or 2), or the presence or not of
> some output (HDMI, TV, VGA) or not.
> 
> This hardware supports 4 layers and 32 sprites, even though we only support
> one primary layer for now.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Quickly (well, very quickly because jetlag and between travels) read
through this. Looks good overall, bunch of comments below.

Cheers, Daniel

> ---
>  drivers/gpu/drm/Kconfig                   |   2 +
>  drivers/gpu/drm/Makefile                  |   3 +-
>  drivers/gpu/drm/sun4i/Kconfig             |  14 +
>  drivers/gpu/drm/sun4i/Makefile            |   8 +
>  drivers/gpu/drm/sun4i/sun4i_backend.c     | 271 +++++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_backend.h     | 159 ++++++++++
>  drivers/gpu/drm/sun4i/sun4i_crtc.c        | 117 ++++++++
>  drivers/gpu/drm/sun4i/sun4i_crtc.h        |  31 ++
>  drivers/gpu/drm/sun4i/sun4i_drv.c         | 281 ++++++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_drv.h         |  30 ++
>  drivers/gpu/drm/sun4i/sun4i_framebuffer.c |  54 ++++
>  drivers/gpu/drm/sun4i/sun4i_framebuffer.h |  19 ++
>  drivers/gpu/drm/sun4i/sun4i_layer.c       | 111 +++++++
>  drivers/gpu/drm/sun4i/sun4i_layer.h       |  30 ++
>  drivers/gpu/drm/sun4i/sun4i_tcon.c        | 478 ++++++++++++++++++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_tcon.h        | 182 ++++++++++++
>  16 files changed, 1789 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/sun4i/Kconfig
>  create mode 100644 drivers/gpu/drm/sun4i/Makefile
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_backend.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_backend.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_crtc.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_crtc.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_drv.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_drv.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_framebuffer.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_framebuffer.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_layer.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_layer.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_tcon.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_tcon.h
> 
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 1a0a8df2eed8..ecf93fafa33c 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -239,6 +239,8 @@ source "drivers/gpu/drm/rcar-du/Kconfig"
>  
>  source "drivers/gpu/drm/shmobile/Kconfig"
>  
> +source "drivers/gpu/drm/sun4i/Kconfig"
> +
>  source "drivers/gpu/drm/omapdrm/Kconfig"
>  
>  source "drivers/gpu/drm/tilcdc/Kconfig"
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 45e7719846b1..2e5f547db672 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -1,4 +1,4 @@
> -#
> +
>  # Makefile for the drm device driver.  This driver provides support for the
>  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
>  
> @@ -58,6 +58,7 @@ obj-$(CONFIG_DRM_ARMADA) += armada/
>  obj-$(CONFIG_DRM_ATMEL_HLCDC)	+= atmel-hlcdc/
>  obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
>  obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
> +obj-$(CONFIG_DRM_SUN4I) += sun4i/
>  obj-$(CONFIG_DRM_OMAP)	+= omapdrm/
>  obj-y			+= tilcdc/
>  obj-$(CONFIG_DRM_QXL) += qxl/
> diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
> new file mode 100644
> index 000000000000..99510e64e91a
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/Kconfig
> @@ -0,0 +1,14 @@
> +config DRM_SUN4I
> +	tristate "DRM Support for Allwinner A10 Display Engine"
> +	depends on DRM && ARM
> +	depends on ARCH_SUNXI || COMPILE_TEST
> +	select DRM_GEM_CMA_HELPER
> +	select DRM_KMS_HELPER
> +	select DRM_KMS_CMA_HELPER
> +	select DRM_PANEL
> +	select REGMAP_MMIO
> +	select VIDEOMODE_HELPERS
> +	help
> +	  Choose this option if you have an Allwinner SoC with a
> +	  Display Engine. If M is selected the module will be called
> +	  sun4i-drm.
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> new file mode 100644
> index 000000000000..bc2df12beb42
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -0,0 +1,8 @@
> +sun4i-drm-y += sun4i_backend.o
> +sun4i-drm-y += sun4i_crtc.o
> +sun4i-drm-y += sun4i_drv.o
> +sun4i-drm-y += sun4i_framebuffer.o
> +sun4i-drm-y += sun4i_layer.o
> +sun4i-drm-y += sun4i_tcon.o
> +
> +obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
> new file mode 100644
> index 000000000000..74eac55f1244
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
> @@ -0,0 +1,271 @@
> +/*
> + * 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/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 "sun4i_backend.h"
> +#include "sun4i_drv.h"
> +
> +static u32 sunxi_rgb2yuv_coef[12] = {
> +	0x00000107, 0x00000204, 0x00000064, 0x00000108,
> +	0x00003f69, 0x00003ed6, 0x000001c1, 0x00000808,
> +	0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808
> +};
> +
> +void sun4i_backend_apply_color_correction(struct sun4i_backend *backend)
> +{
> +	int i;
> +
> +	/* Set color correction */
> +	regmap_write(backend->regs, SUN4I_BACKEND_OCCTL_REG,
> +		     SUN4I_BACKEND_OCCTL_ENABLE);
> +
> +	for (i = 0; i < 12; i++)
> +		regmap_write(backend->regs, SUN4I_BACKEND_OCRCOEF_REG(i),
> +			     sunxi_rgb2yuv_coef[i]);
> +}
> +
> +void sun4i_backend_commit(struct sun4i_backend *backend)
> +{
> +	DRM_DEBUG_DRIVER("Committing changes\n");
> +
> +	regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
> +		     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS |
> +		     SUN4I_BACKEND_REGBUFFCTL_LOADCTL);
> +}
> +
> +void sun4i_backend_layer_enable(struct sun4i_backend *backend,
> +				int layer, bool enable)
> +{
> +	u32 val;
> +
> +	DRM_DEBUG_DRIVER("Enabling layer %d\n", layer);
> +
> +	if (enable)
> +		val = SUN4I_BACKEND_MODCTL_LAY_EN(layer);
> +	else
> +		val = 0;
> +
> +	regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
> +			   SUN4I_BACKEND_MODCTL_LAY_EN(layer), val);
> +}
> +
> +static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode)
> +{
> +	switch (format) {
> +	case DRM_FORMAT_XRGB8888:
> +		*mode = SUN4I_BACKEND_LAY_FBFMT_XRGB8888;
> +		break;
> +
> +	case DRM_FORMAT_RGB888:
> +		*mode = SUN4I_BACKEND_LAY_FBFMT_RGB888;
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
> +				     int layer, struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +
> +	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(backend->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),
> +		     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),
> +		     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),
> +		     SUN4I_BACKEND_LAYCOOR(state->crtc_x,
> +					   state->crtc_y));
> +
> +	return 0;
> +}
> +
> +int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
> +				       int layer, struct drm_plane *plane)
> +{
> +	struct drm_plane_state *state = plane->state;
> +	struct drm_framebuffer *fb = state->fb;
> +	bool interlaced = false;
> +	u32 val;
> +	int ret;
> +
> +	if (plane->state->crtc)
> +		interlaced = plane->state->crtc->state->adjusted_mode.flags
> +			& DRM_MODE_FLAG_INTERLACE;
> +
> +	regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG,
> +			   SUN4I_BACKEND_MODCTL_ITLMOD_EN,
> +			   interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0);
> +
> +	DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
> +			 interlaced ? "on" : "off");
> +
> +	ret = sun4i_backend_drm_format_to_layer(fb->pixel_format, &val);
> +	if (ret) {
> +		DRM_DEBUG_DRIVER("Invalid format\n");
> +		return val;
> +	}
> +
> +	regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG1(layer),
> +			   SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val);
> +
> +	return 0;
> +}
> +
> +int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
> +				      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;
> +	u32 lo_paddr, hi_paddr;
> +	dma_addr_t paddr;
> +	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 @ 0x%x\n", gem->paddr);
> +
> +	/* Compute the start of the displayed memory */
> +	bpp = drm_format_plane_cpp(fb->pixel_format, 0);
> +	paddr = gem->paddr + fb->offsets[0];
> +	paddr += state->src_x * bpp;
> +	paddr += state->src_y * fb->pitches[0];
> +
> +	DRM_DEBUG_DRIVER("Setting buffer address to 0x%x\n", paddr);
> +
> +	/* 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),
> +		     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,
> +			   SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer),
> +			   SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr));
> +
> +	return 0;
> +}
> +
> +static struct regmap_config sun4i_backend_regmap_config = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_stride	= 4,
> +	.max_register	= 0x5800,
> +	.name		= "backend",
> +};
> +
> +struct sun4i_backend *sun4i_backend_init(struct drm_device *drm)
> +{
> +	struct sun4i_backend *backend;
> +	struct resource *res;
> +	void __iomem *regs;
> +	int i;
> +
> +	backend = devm_kzalloc(drm->dev, sizeof(*backend), GFP_KERNEL);
> +	if (!backend)
> +		return ERR_PTR(-ENOMEM);
> +
> +	res = platform_get_resource_byname(to_platform_device(drm->dev),
> +					   IORESOURCE_MEM, "backend0");
> +	regs = devm_ioremap_resource(drm->dev, res);
> +	if (IS_ERR(regs)) {
> +		dev_err(drm->dev, "Couldn't map the backend0 registers\n");
> +		return ERR_CAST(regs);
> +	}
> +
> +	backend->regs = devm_regmap_init_mmio(drm->dev, regs,
> +					      &sun4i_backend_regmap_config);
> +	if (IS_ERR(backend->regs)) {
> +		dev_err(drm->dev, "Couldn't create the backend0 regmap\n");
> +		return ERR_CAST(backend->regs);
> +	}
> +
> +	backend->bus_clk = devm_clk_get(drm->dev, "backend0-bus");
> +	if (IS_ERR(backend->bus_clk)) {
> +		dev_err(drm->dev, "Couldn't get the backend bus clock\n");
> +		return ERR_CAST(backend->bus_clk);
> +	}
> +	clk_prepare_enable(backend->bus_clk);
> +
> +	backend->mod_clk = devm_clk_get(drm->dev, "backend0-mod");
> +	if (IS_ERR(backend->mod_clk)) {
> +		dev_err(drm->dev, "Couldn't get the backend module clock\n");
> +		return ERR_CAST(backend->mod_clk);
> +	}
> +	clk_prepare_enable(backend->mod_clk);
> +
> +	backend->ram_clk = devm_clk_get(drm->dev, "backend0-ram");
> +	if (IS_ERR(backend->ram_clk)) {
> +		dev_err(drm->dev, "Couldn't get the backend RAM clock\n");
> +		return ERR_CAST(backend->ram_clk);
> +	}
> +	clk_prepare_enable(backend->ram_clk);
> +
> +	/* Reset the registers */
> +	for (i = 0x800; i < 0x1000; i += 4)
> +		regmap_write(backend->regs, i, 0);
> +
> +	/* Disable registers autoloading */
> +	regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG,
> +		     SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS);
> +
> +	/* Enable the backend */
> +	regmap_write(backend->regs, SUN4I_BACKEND_MODCTL_REG,
> +		     SUN4I_BACKEND_MODCTL_DEBE_EN |
> +		     SUN4I_BACKEND_MODCTL_START_CTL);
> +
> +	return backend;
> +}
> +
> +void sun4i_backend_free(struct sun4i_backend *backend)
> +{
> +	clk_disable_unprepare(backend->ram_clk);
> +	clk_disable_unprepare(backend->mod_clk);
> +	clk_disable_unprepare(backend->bus_clk);
> +}
> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
> new file mode 100644
> index 000000000000..8b3dca39d089
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -0,0 +1,159 @@
> +/*
> + * 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 _SUN4I_BACKEND_H_
> +#define _SUN4I_BACKEND_H_
> +
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +
> +#define SUN4I_BACKEND_MODCTL_REG		0x800
> +#define SUN4I_BACKEND_MODCTL_LINE_SEL			BIT(29)
> +#define SUN4I_BACKEND_MODCTL_ITLMOD_EN			BIT(28)
> +#define SUN4I_BACKEND_MODCTL_OUT_SEL			GENMASK(22, 20)
> +#define SUN4I_BACKEND_MODCTL_OUT_LCD				(0 << 20)
> +#define SUN4I_BACKEND_MODCTL_OUT_FE0				(6 << 20)
> +#define SUN4I_BACKEND_MODCTL_OUT_FE1				(7 << 20)
> +#define SUN4I_BACKEND_MODCTL_HWC_EN			BIT(16)
> +#define SUN4I_BACKEND_MODCTL_LAY_EN(l)			BIT(8 + l)
> +#define SUN4I_BACKEND_MODCTL_OCSC_EN			BIT(5)
> +#define SUN4I_BACKEND_MODCTL_DFLK_EN			BIT(4)
> +#define SUN4I_BACKEND_MODCTL_DLP_START_CTL		BIT(2)
> +#define SUN4I_BACKEND_MODCTL_START_CTL			BIT(1)
> +#define SUN4I_BACKEND_MODCTL_DEBE_EN			BIT(0)
> +
> +#define SUN4I_BACKEND_BACKCOLOR_REG		0x804
> +#define SUN4I_BACKEND_BACKCOLOR(r, g, b)		(((r) << 16) | ((g) << 8) | (b))
> +
> +#define SUN4I_BACKEND_DISSIZE_REG		0x808
> +#define SUN4I_BACKEND_DISSIZE(w, h)			(((((h) - 1) & 0xffff) << 16) | \
> +							 (((w) - 1) & 0xffff))
> +
> +#define SUN4I_BACKEND_LAYSIZE_REG(l)		(0x810 + (0x4 * (l)))
> +#define SUN4I_BACKEND_LAYSIZE(w, h)			(((((h) - 1) & 0x1fff) << 16) | \
> +							 (((w) - 1) & 0x1fff))
> +
> +#define SUN4I_BACKEND_LAYCOOR_REG(l)		(0x820 + (0x4 * (l)))
> +#define SUN4I_BACKEND_LAYCOOR(x, y)			((((u32)(y) & 0xffff) << 16) | \
> +							 ((u32)(x) & 0xffff))
> +
> +#define SUN4I_BACKEND_LAYLINEWIDTH_REG(l)	(0x840 + (0x4 * (l)))
> +
> +#define SUN4I_BACKEND_LAYFB_L32ADD_REG(l)	(0x850 + (0x4 * (l)))
> +
> +#define SUN4I_BACKEND_LAYFB_H4ADD_REG		0x860
> +#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l)		GENMASK(3 + ((l) * 8), 0)
> +#define SUN4I_BACKEND_LAYFB_H4ADD(l, val)			((val) << ((l) * 8))
> +
> +#define SUN4I_BACKEND_REGBUFFCTL_REG		0x870
> +#define SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS		BIT(1)
> +#define SUN4I_BACKEND_REGBUFFCTL_LOADCTL		BIT(0)
> +
> +#define SUN4I_BACKEND_CKMAX_REG			0x880
> +#define SUN4I_BACKEND_CKMIN_REG			0x884
> +#define SUN4I_BACKEND_CKCFG_REG			0x888
> +#define SUN4I_BACKEND_ATTCTL_REG0(l)		(0x890 + (0x4 * (l)))
> +
> +#define SUN4I_BACKEND_ATTCTL_REG1(l)		(0x8a0 + (0x4 * (l)))
> +#define SUN4I_BACKEND_ATTCTL_REG1_LAY_HSCAFCT		GENMASK(15, 14)
> +#define SUN4I_BACKEND_ATTCTL_REG1_LAY_WSCAFCT		GENMASK(13, 12)
> +#define SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT		GENMASK(11, 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_1BPP				(0 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_2BPP				(1 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_4BPP				(2 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_8BPP				(3 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_RGB655				(4 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_RGB565				(5 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_RGB556				(6 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_ARGB1555			(7 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_RGBA5551			(8 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_XRGB8888			(9 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_ARGB8888			(10 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_RGB888				(11 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_ARGB4444			(12 << 8)
> +#define SUN4I_BACKEND_LAY_FBFMT_RGBA4444			(13 << 8)
> +
> +#define SUN4I_BACKEND_DLCDPCTL_REG		0x8b0
> +#define SUN4I_BACKEND_DLCDPFRMBUF_ADDRCTL_REG	0x8b4
> +#define SUN4I_BACKEND_DLCDPCOOR_REG0		0x8b8
> +#define SUN4I_BACKEND_DLCDPCOOR_REG1		0x8bc
> +
> +#define SUN4I_BACKEND_INT_EN_REG		0x8c0
> +#define SUN4I_BACKEND_INT_FLAG_REG		0x8c4
> +#define SUN4I_BACKEND_REG_LOAD_FINISHED			BIT(1)
> +
> +#define SUN4I_BACKEND_HWCCTL_REG		0x8d8
> +#define SUN4I_BACKEND_HWCFBCTL_REG		0x8e0
> +#define SUN4I_BACKEND_WBCTL_REG			0x8f0
> +#define SUN4I_BACKEND_WBADD_REG			0x8f4
> +#define SUN4I_BACKEND_WBLINEWIDTH_REG		0x8f8
> +#define SUN4I_BACKEND_SPREN_REG			0x900
> +#define SUN4I_BACKEND_SPRFMTCTL_REG		0x908
> +#define SUN4I_BACKEND_SPRALPHACTL_REG		0x90c
> +#define SUN4I_BACKEND_IYUVCTL_REG		0x920
> +#define SUN4I_BACKEND_IYUVADD_REG(c)		(0x930 + (0x4 * (c)))
> +#define SUN4I_BACKEND_IYUVLINEWITDTH_REG(c)	(0x940 + (0x4 * (c)))
> +#define SUN4I_BACKEND_YGCOEF_REG(c)		(0x950 + (0x4 * (c)))
> +#define SUN4I_BACKEND_YGCONS_REG		0x95c
> +#define SUN4I_BACKEND_URCOEF_REG(c)		(0x960 + (0x4 * (c)))
> +#define SUN4I_BACKEND_URCONS_REG		0x96c
> +#define SUN4I_BACKEND_VBCOEF_REG(c)		(0x970 + (0x4 * (c)))
> +#define SUN4I_BACKEND_VBCONS_REG		0x97c
> +#define SUN4I_BACKEND_KSCTL_REG			0x980
> +#define SUN4I_BACKEND_KSBKCOLOR_REG		0x984
> +#define SUN4I_BACKEND_KSFSTLINEWIDTH_REG	0x988
> +#define SUN4I_BACKEND_KSVSCAFCT_REG		0x98c
> +#define SUN4I_BACKEND_KSHSCACOEF_REG(x)		(0x9a0 + (0x4 * (x)))
> +#define SUN4I_BACKEND_OCCTL_REG			0x9c0
> +#define SUN4I_BACKEND_OCCTL_ENABLE			BIT(0)
> +
> +#define SUN4I_BACKEND_OCRCOEF_REG(x)		(0x9d0 + (0x4 * (x)))
> +#define SUN4I_BACKEND_OCRCONS_REG		0x9dc
> +#define SUN4I_BACKEND_OCGCOEF_REG(x)		(0x9e0 + (0x4 * (x)))
> +#define SUN4I_BACKEND_OCGCONS_REG		0x9ec
> +#define SUN4I_BACKEND_OCBCOEF_REG(x)		(0x9f0 + (0x4 * (x)))
> +#define SUN4I_BACKEND_OCBCONS_REG		0x9fc
> +#define SUN4I_BACKEND_SPRCOORCTL_REG(s)		(0xa00 + (0x4 * (s)))
> +#define SUN4I_BACKEND_SPRATTCTL_REG(s)		(0xb00 + (0x4 * (s)))
> +#define SUN4I_BACKEND_SPRADD_REG(s)		(0xc00 + (0x4 * (s)))
> +#define SUN4I_BACKEND_SPRLINEWIDTH_REG(s)	(0xd00 + (0x4 * (s)))
> +
> +#define SUN4I_BACKEND_SPRPALTAB_OFF		0x4000
> +#define SUN4I_BACKEND_GAMMATAB_OFF		0x4400
> +#define SUN4I_BACKEND_HWCPATTERN_OFF		0x4800
> +#define SUN4I_BACKEND_HWCCOLORTAB_OFF		0x4c00
> +#define SUN4I_BACKEND_PIPE_OFF(p)		(0x5000 + (0x400 * (p)))
> +
> +struct sun4i_backend {
> +	struct regmap	*regs;
> +
> +	struct clk	*bus_clk;
> +	struct clk	*mod_clk;
> +	struct clk	*ram_clk;
> +};
> +
> +void sun4i_backend_apply_color_correction(struct sun4i_backend *backend);
> +void sun4i_backend_commit(struct sun4i_backend *backend);
> +
> +void sun4i_backend_layer_enable(struct sun4i_backend *backend,
> +				int layer, bool enable);
> +int sun4i_backend_update_layer_coord(struct sun4i_backend *backend,
> +				     int layer, struct drm_plane *plane);
> +int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
> +				       int layer, struct drm_plane *plane);
> +int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
> +				      int layer, struct drm_plane *plane);
> +
> +struct sun4i_backend *sun4i_backend_init(struct drm_device *drm);
> +void sun4i_backend_free(struct sun4i_backend *backend);
> +
> +#endif /* _SUN4I_BACKEND_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> new file mode 100644
> index 000000000000..ec4045fc31ee
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
> @@ -0,0 +1,117 @@
> +/*
> + * 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/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_modes.h>
> +
> +#include <linux/clk-provider.h>
> +#include <linux/ioport.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/regmap.h>
> +
> +#include <video/videomode.h>
> +
> +#include "sun4i_crtc.h"
> +#include "sun4i_drv.h"
> +#include "sun4i_tcon.h"
> +
> +static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
> +				    struct drm_crtc_state *old_state)
> +{
> +	struct drm_pending_vblank_event *event = crtc->state->event;
> +	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
> +	struct drm_device *dev = crtc->dev;
> +	unsigned long flags;
> +
> +	if (event) {
> +		WARN_ON(drm_crtc_vblank_get(crtc) != 0);
> +
> +		spin_lock_irqsave(&dev->event_lock, flags);
> +		scrtc->event = event;
> +		spin_unlock_irqrestore(&dev->event_lock, flags);
> +	 }
> +}
> +
> +static void sun4i_crtc_disable(struct drm_crtc *crtc)
> +{
> +	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
> +	struct sun4i_drv *drv = scrtc->drv;
> +
> +	DRM_DEBUG_DRIVER("Disabling the CRTC\n");
> +
> +	if (!scrtc->enabled)
> +		return;

Please don't do this - the atomic state should always reflect the true hw
state (fix that up with either hw state readout or reset in the ->reset
callbacks), and the atomic helpers guarantee that they'll never call you
when not needed. If you don't trust them do a WARN_ON at least, but no
early silent returns.

Personally I'd just rip it out, it's too much trouble. And for debugging
the atomic helpers already trace it all (or at least should).

> +
> +	sun4i_tcon_disable(drv->tcon);
> +
> +	scrtc->enabled = false;
> +}
> +
> +static void sun4i_crtc_enable(struct drm_crtc *crtc)
> +{
> +	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
> +	struct sun4i_drv *drv = scrtc->drv;
> +
> +	DRM_DEBUG_DRIVER("Enabling the CRTC\n");
> +
> +	if (scrtc->enabled)
> +		return;
> +
> +	sun4i_tcon_enable(drv->tcon);
> +
> +	scrtc->enabled = true;
> +}
> +
> +static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
> +	.atomic_begin	= sun4i_crtc_atomic_begin,
> +	.disable	= sun4i_crtc_disable,
> +	.enable		= sun4i_crtc_enable,
> +};
> +
> +static const struct drm_crtc_funcs sun4i_crtc_funcs = {
> +	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
> +	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,
> +	.destroy		= drm_crtc_cleanup,
> +	.page_flip		= drm_atomic_helper_page_flip,
> +	.reset			= drm_atomic_helper_crtc_reset,
> +	.set_config		= drm_atomic_helper_set_config,
> +};
> +
> +struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm)
> +{
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct sun4i_crtc *scrtc;
> +	int ret;
> +
> +	scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
> +	if (!scrtc)
> +		return NULL;
> +	scrtc->drv = drv;
> +
> +	ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
> +					drv->primary,
> +					NULL,
> +					&sun4i_crtc_funcs);
> +	if (ret) {
> +		dev_err(drm->dev, "Couldn't init DRM CRTC\n");
> +		return NULL;
> +	}
> +
> +	drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs);
> +	drm_crtc_vblank_reset(&scrtc->crtc);
> +
> +	return scrtc;
> +}
> diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h b/drivers/gpu/drm/sun4i/sun4i_crtc.h
> new file mode 100644
> index 000000000000..6c6b989c1b60
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h
> @@ -0,0 +1,31 @@
> +/*
> + * 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 _SUN4I_CRTC_H_
> +#define _SUN4I_CRTC_H_
> +
> +struct sun4i_crtc {
> +	struct drm_crtc			crtc;
> +	struct drm_pending_vblank_event	*event;
> +
> +	bool				enabled;
> +	struct sun4i_drv			*drv;
> +};
> +
> +static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc)
> +{
> +	return container_of(crtc, struct sun4i_crtc, crtc);
> +}
> +
> +struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm);
> +
> +#endif /* _SUN4I_CRTC_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> new file mode 100644
> index 000000000000..fc26f3903f52
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -0,0 +1,281 @@
> +/*
> + * 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/drmP.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +
> +#include "sun4i_backend.h"
> +#include "sun4i_crtc.h"
> +#include "sun4i_drv.h"
> +#include "sun4i_framebuffer.h"
> +#include "sun4i_layer.h"
> +#include "sun4i_tcon.h"
> +
> +static void sun4i_drv_preclose(struct drm_device *drm,
> +			       struct drm_file *file_priv)
> +{
> +}
> +
> +static void sun4i_drv_lastclose(struct drm_device *drm)
> +{
> +}
> +
> +static int sun4i_drv_connector_plug_all(struct drm_device *drm)

Laurent Pinchart has this as a rfc patch for drm core, please coordinate
with him and rebase on top of his patches.

> +{
> +	struct drm_connector *connector, *failed;
> +	int ret;
> +
> +	mutex_lock(&drm->mode_config.mutex);
> +	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
> +		ret = drm_connector_register(connector);
> +		if (ret) {
> +			failed = connector;
> +			goto err;
> +		}
> +	}
> +	mutex_unlock(&drm->mode_config.mutex);
> +	return 0;
> +
> +err:
> +	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
> +		if (failed == connector)
> +			break;
> +
> +		drm_connector_unregister(connector);
> +	}
> +	mutex_unlock(&drm->mode_config.mutex);
> +
> +	return ret;
> +}
> +
> +static int sun4i_drv_enable_vblank(struct drm_device *drm, int pipe)
> +{
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct sun4i_tcon *tcon = drv->tcon;
> +
> +	DRM_DEBUG_DRIVER("Enabling VBLANK on pipe %d\n", pipe);
> +
> +	sun4i_tcon_enable_vblank(tcon, true);
> +
> +	return 0;

atomic helpers rely on enable_vblank failing correctly when the pipe is
off and vlbanks will never happen. You probably need a correct error code
here that checks crtc->state->active (well not that directly but something
derived from it, since the pointer chase would be racy).

I know it's a bit a mess since we don't have kms-native vblank driver
hooks yet and really the drm core should get this right for you. It'll
happen eventually, but drm_irq.c is a bit moldy ;-)

> +}
> +
> +static void sun4i_drv_disable_vblank(struct drm_device *drm, int pipe)
> +{
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct sun4i_tcon *tcon = drv->tcon;
> +
> +	DRM_DEBUG_DRIVER("Disabling VBLANK on pipe %d\n", pipe);
> +
> +	sun4i_tcon_enable_vblank(tcon, false);
> +}
> +
> +static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)

load/unload callbacks are depracated since fundamentally racy, and we
can't fix that due to the pile of legacy dri1 drivers. Please use
drm_dev_alloc/register/unregister/unref functions instead, with the
load/unload code placed in between to avoid races with userspace seeing
the device/driver (e.g. in sysfs) while it's in a partially defunct state.

Relevant kerneldoc has the details, at least in linux-next.

> +{
> +	struct sun4i_drv *drv = drm->dev_private;
> +	int ret;
> +
> +	drv = devm_kzalloc(drm->dev, sizeof(*drv), GFP_KERNEL);
> +	if (!drv)
> +		return -ENOMEM;
> +
> +	drm->dev_private = drv;
> +
> +	drm_vblank_init(drm, 1);
> +	drm_mode_config_init(drm);
> +
> +	/* Prepare the backend */
> +	drv->backend = sun4i_backend_init(drm);
> +	if (IS_ERR(drv->backend)) {
> +		dev_err(drm->dev, "Couldn't initialise our backend\n");
> +		return PTR_ERR(drv->backend);
> +	}
> +
> +	/* Prepare the TCON */
> +	drv->tcon = sun4i_tcon_init(drm);
> +	if (!drv->tcon) {
> +		dev_err(drm->dev, "Couldn't initialise our TCON\n");
> +		ret = -EINVAL;
> +		goto err_free_backend;
> +	}
> +
> +	/* Create our layers */
> +	drv->layers = sun4i_layers_init(drm);
> +	if (!drv->layers) {
> +		dev_err(drm->dev, "Couldn't create the planes\n");
> +		ret = -EINVAL;
> +		goto err_free_tcon;
> +	}
> +
> +	/* Create our CRTC */
> +	drv->crtc = sun4i_crtc_init(drm);
> +	if (!drv->crtc) {
> +		dev_err(drm->dev, "Couldn't create the CRTC\n");
> +		ret = -EINVAL;
> +		goto err_free_layers;
> +	}
> +
> +	/* Create our outputs */
> +
> +	/* Create our framebuffer */
> +	drv->fbdev = sun4i_framebuffer_init(drm);
> +	if (IS_ERR(drv->fbdev)) {
> +		dev_err(drm->dev, "Couldn't create our framebuffer\n");
> +		ret = PTR_ERR(drv->fbdev);
> +		goto err_free_crtc;
> +	}
> +
> +	/* Enable connectors polling */
> +	drm_kms_helper_poll_init(drm);
> +
> +	return 0;
> +
> +err_free_crtc:
> +err_free_layers:
> +err_free_tcon:
> +	sun4i_tcon_free(drv->tcon);
> +err_free_backend:
> +	sun4i_backend_free(drv->backend);
> +
> +	return ret;
> +}
> +
> +static int sun4i_drv_unload(struct drm_device *drm)
> +{
> +	struct sun4i_drv *drv = drm->dev_private;
> +
> +	drm_kms_helper_poll_fini(drm);
> +	sun4i_framebuffer_free(drm);
> +	sun4i_tcon_free(drv->tcon);
> +	sun4i_backend_free(drv->backend);
> +	drm_vblank_cleanup(drm);
> +
> +	return 0;
> +}
> +
> +static const struct file_operations sun4i_drv_fops = {
> +	.owner		= THIS_MODULE,
> +	.open		= drm_open,
> +	.release	= drm_release,
> +	.unlocked_ioctl	= drm_ioctl,
> +#ifdef CONFIG_COMPAT
> +	.compat_ioctl	= drm_compat_ioctl,
> +#endif
> +	.poll		= drm_poll,
> +	.read		= drm_read,
> +	.llseek		= no_llseek,
> +	.mmap		= drm_gem_cma_mmap,
> +};
> +
> +static struct drm_driver sun4i_drv_driver = {
> +	.driver_features	= DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME,
> +
> +	/* Generic Operations */
> +	.load			= sun4i_drv_load,
> +	.unload			= sun4i_drv_unload,
> +	.preclose		= sun4i_drv_preclose,
> +	.lastclose		= sun4i_drv_lastclose,
> +	.fops			= &sun4i_drv_fops,
> +	.name			= "sun4i-drm",
> +	.desc			= "Allwinner sun4i Display Engine",
> +	.date			= "20150629",
> +	.major			= 1,
> +	.minor			= 0,
> +
> +	/* GEM Operations */
> +	.gem_free_object	= drm_gem_cma_free_object,
> +	.gem_vm_ops		= &drm_gem_cma_vm_ops,
> +
> +	/* PRIME Operations */
> +	.prime_handle_to_fd	= drm_gem_prime_handle_to_fd,
> +	.prime_fd_to_handle	= drm_gem_prime_fd_to_handle,
> +	.gem_prime_import	= drm_gem_prime_import,
> +	.gem_prime_export	= drm_gem_prime_export,
> +	.gem_prime_get_sg_table	= drm_gem_cma_prime_get_sg_table,
> +	.gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> +	.gem_prime_vmap		= drm_gem_cma_prime_vmap,
> +	.gem_prime_vunmap	= drm_gem_cma_prime_vunmap,
> +	.gem_prime_mmap		= drm_gem_cma_prime_mmap,
> +
> +	/* Frame Buffer Operations */
> +	.dumb_create		= drm_gem_cma_dumb_create,
> +	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
> +	.dumb_destroy		= drm_gem_dumb_destroy,
> +
> +	/* VBlank Operations */
> +	.get_vblank_counter	= drm_vblank_count,
> +	.enable_vblank		= sun4i_drv_enable_vblank,
> +	.disable_vblank		= sun4i_drv_disable_vblank,
> +};
> +
> +static int sun4i_drv_probe(struct platform_device *pdev)
> +{
> +	struct drm_device *drm;
> +	int ret;
> +
> +	drm = drm_dev_alloc(&sun4i_drv_driver, &pdev->dev);
> +	if (!drm)
> +		return -ENOMEM;
> +
> +	ret = drm_dev_set_unique(drm, dev_name(drm->dev));
> +	if (ret)
> +		goto free_drm;
> +
> +	ret = drm_dev_register(drm, 0);
> +	if (ret)
> +		goto free_drm;
> +
> +	ret = sun4i_drv_connector_plug_all(drm);
> +	if (ret)
> +		goto unregister_drm;
> +
> +	return 0;
> +
> +unregister_drm:
> +	drm_dev_unregister(drm);
> +free_drm:
> +	drm_dev_unref(drm);
> +	return ret;
> +}
> +
> +static int sun4i_drv_remove(struct platform_device *pdev)
> +{
> +	struct drm_device *drm = platform_get_drvdata(pdev);
> +
> +	drm_dev_unregister(drm);
> +	drm_dev_unref(drm);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id sun4i_drv_of_table[] = {
> +	{ .compatible = "allwinner,sun5i-a13-display-engine" },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, sun4i_drv_of_table);
> +
> +static struct platform_driver sun4i_drv_platform_driver = {
> +	.probe		= sun4i_drv_probe,
> +	.remove		= sun4i_drv_remove,
> +	.driver		= {
> +		.name		= "sun4i-drm",
> +		.of_match_table	= sun4i_drv_of_table,
> +	},
> +};
> +module_platform_driver(sun4i_drv_platform_driver);
> +
> +MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
> +MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
> +MODULE_DESCRIPTION("Allwinner A10 Display Engine DRM/KMS Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h
> new file mode 100644
> index 000000000000..9a897914b85d
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
> @@ -0,0 +1,30 @@
> +/*
> + * 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 _SUN4I_DRV_H_
> +#define _SUN4I_DRV_H_
> +
> +#include <linux/clk.h>
> +#include <linux/regmap.h>
> +
> +struct sun4i_drv {
> +	struct sun4i_backend	*backend;
> +	struct sun4i_crtc	*crtc;
> +	struct sun4i_tcon	*tcon;
> +
> +	struct drm_plane	*primary;
> +	struct drm_fbdev_cma	*fbdev;
> +
> +	struct sun4i_layer	*layers;
> +};
> +
> +#endif /* _SUN4I_DRV_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
> new file mode 100644
> index 000000000000..68072b8cddab
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
> @@ -0,0 +1,54 @@
> +/*
> + * 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_fb_cma_helper.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drmP.h>
> +
> +#include "sun4i_drv.h"
> +
> +static void sun4i_de_output_poll_changed(struct drm_device *drm)
> +{
> +	struct sun4i_drv *drv = drm->dev_private;
> +
> +	if (drv->fbdev)
> +		drm_fbdev_cma_hotplug_event(drv->fbdev);
> +}
> +
> +static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
> +	.output_poll_changed	= sun4i_de_output_poll_changed,
> +	.atomic_check		= drm_atomic_helper_check,
> +	.atomic_commit		= drm_atomic_helper_commit,
> +	.fb_create		= drm_fb_cma_create,
> +};
> +
> +struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm)
> +{
> +	drm_mode_config_reset(drm);
> +
> +	drm->mode_config.max_width = 8192;
> +	drm->mode_config.max_height = 8192;
> +
> +	drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
> +
> +	return drm_fbdev_cma_init(drm, 32,
> +				  drm->mode_config.num_crtc,
> +				  drm->mode_config.num_connector);
> +}
> +
> +void sun4i_framebuffer_free(struct drm_device *drm)
> +{
> +	struct sun4i_drv *drv = drm->dev_private;
> +
> +	drm_fbdev_cma_fini(drv->fbdev);
> +	drm_mode_config_cleanup(drm);
> +}
> diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.h b/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
> new file mode 100644
> index 000000000000..3afd65252ee0
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.h
> @@ -0,0 +1,19 @@
> +/*
> + * 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 _SUN4I_FRAMEBUFFER_H_
> +#define _SUN4I_FRAMEBUFFER_H_
> +
> +struct drm_fbdev_cma *sun4i_framebuffer_init(struct drm_device *drm);
> +void sun4i_framebuffer_free(struct drm_device *drm);
> +
> +#endif /* _SUN4I_FRAMEBUFFER_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c
> new file mode 100644
> index 000000000000..c23ee7638ed8
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
> @@ -0,0 +1,111 @@
> +/*
> + * 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_crtc.h>
> +#include <drm/drm_plane_helper.h>
> +#include <drm/drmP.h>
> +
> +#include "sun4i_backend.h"
> +#include "sun4i_drv.h"
> +#include "sun4i_layer.h"
> +
> +static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
> +					    struct drm_plane_state *state)
> +{
> +	return 0;
> +}
> +
> +static void sun4i_backend_layer_atomic_disable(struct drm_plane *plane,
> +					       struct drm_plane_state *old_state)
> +{
> +	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
> +	struct sun4i_drv *drv = layer->drv;
> +	struct sun4i_backend *backend = drv->backend;
> +
> +	sun4i_backend_layer_enable(backend, layer->id, false);
> +	sun4i_backend_commit(backend);
> +}
> +
> +static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
> +					      struct drm_plane_state *old_state)
> +{
> +	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
> +	struct sun4i_drv *drv = layer->drv;
> +	struct sun4i_backend *backend = drv->backend;
> +
> +	sun4i_backend_update_layer_coord(backend, layer->id, plane);
> +	sun4i_backend_update_layer_formats(backend, layer->id, plane);
> +	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
> +	sun4i_backend_layer_enable(backend, layer->id, true);
> +	sun4i_backend_commit(backend);

Not idea how exactly your hw works, but the call to sun4i_backend_commit
probably should be in the crtc->atomic_flush function, to make sure that
plane updates across multiple planes are indeed atomic.

> +}
> +
> +static struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
> +	.atomic_check	= sun4i_backend_layer_atomic_check,
> +	.atomic_disable	= sun4i_backend_layer_atomic_disable,
> +	.atomic_update	= sun4i_backend_layer_atomic_update,
> +};
> +
> +static const struct drm_plane_funcs sun4i_backend_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 sun4i_backend_layer_formats[] = {
> +	DRM_FORMAT_XRGB8888,
> +	DRM_FORMAT_RGB888,
> +};
> +
> +static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
> +						enum drm_plane_type type)
> +{
> +	struct sun4i_layer *layer;
> +	int ret;
> +
> +	layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
> +	if (!layer)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ret = drm_universal_plane_init(drm, &layer->plane, 0,
> +				       &sun4i_backend_layer_funcs,
> +				       sun4i_backend_layer_formats,
> +				       ARRAY_SIZE(sun4i_backend_layer_formats),
> +				       type);
> +	if (ret) {
> +		dev_err(drm->dev, "Couldn't initialize layer\n");
> +		return ERR_PTR(ret);
> +	}
> +
> +	drm_plane_helper_add(&layer->plane,
> +			     &sun4i_backend_layer_helper_funcs);
> +
> +	return layer;
> +}
> +
> +struct sun4i_layer *sun4i_layers_init(struct drm_device *drm)
> +{
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct sun4i_layer *layers;
> +
> +	/* TODO: Fix the number of layers */
> +	layers = sun4i_layer_init_one(drm, DRM_PLANE_TYPE_PRIMARY);
> +	layers->drv = drv;
> +
> +	drv->primary = &layers->plane;
> +
> +	return layers;
> +}
> diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h
> new file mode 100644
> index 000000000000..e90972969a03
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h
> @@ -0,0 +1,30 @@
> +/*
> + * 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 _SUN4I_LAYER_H_
> +#define _SUN4I_LAYER_H_
> +
> +struct sun4i_layer {
> +	struct drm_plane	plane;
> +	struct sun4i_drv	*drv;
> +	int			id;
> +};
> +
> +static inline struct sun4i_layer *
> +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);
> +
> +#endif /* _SUN4I_LAYER_H_ */
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> new file mode 100644
> index 000000000000..bd68bcea6c04
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
> @@ -0,0 +1,478 @@
> +/*
> + * 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/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_modes.h>
> +
> +#include <linux/clk-provider.h>
> +#include <linux/ioport.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/regmap.h>
> +
> +#include "sun4i_crtc.h"
> +#include "sun4i_drv.h"
> +#include "sun4i_tcon.h"
> +
> +void sun4i_tcon_disable(struct sun4i_tcon *tcon)
> +{
> +	if (!tcon->enabled)
> +		return;

Same comments here about uncessary state tracking, please add at least a
WARN_ON to catch brokeness in higher levels.

> +
> +	DRM_DEBUG_DRIVER("Disabling TCON\n");
> +
> +	/* Disable the TCON */
> +	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> +			   SUN4I_TCON_GCTL_TCON_ENABLE, 0);
> +
> +	tcon->enabled = false;
> +}
> +
> +void sun4i_tcon_enable(struct sun4i_tcon *tcon)
> +{
> +	if (tcon->enabled)
> +		return;
> +
> +	DRM_DEBUG_DRIVER("Enabling TCON\n");
> +
> +	/* Enable the TCON */
> +	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> +			   SUN4I_TCON_GCTL_TCON_ENABLE,
> +			   SUN4I_TCON_GCTL_TCON_ENABLE);
> +
> +	tcon->enabled = true;
> +}
> +
> +static void sun4i_tcon_finish_page_flip(struct drm_device *dev,
> +					struct sun4i_crtc *scrtc)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&dev->event_lock, flags);
> +	if (scrtc->event) {
> +		drm_send_vblank_event(dev, 0, scrtc->event);
> +		drm_vblank_put(dev, 0);
> +		scrtc->event = NULL;
> +	}
> +	spin_unlock_irqrestore(&dev->event_lock, flags);
> +}
> +
> +static irqreturn_t sun4i_tcon_handler(int irq, void *private)
> +{
> +	struct drm_device *drm = private;
> +	struct sun4i_drv *drv = drm->dev_private;
> +	struct sun4i_tcon *tcon = drv->tcon;
> +	struct sun4i_crtc *scrtc = drv->crtc;
> +	unsigned int status;
> +
> +	regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
> +
> +	if (!(status & (SUN4I_TCON_GINT0_VBLANK_INT(0) |
> +			SUN4I_TCON_GINT0_VBLANK_INT(1))))
> +		return IRQ_NONE;
> +
> +	drm_handle_vblank(scrtc->crtc.dev, 0);
> +	sun4i_tcon_finish_page_flip(drm, scrtc);
> +
> +	/* Acknowledge the interrupt */
> +	regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG,
> +		     status);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int sun4i_tcon_create_pixel_clock(struct drm_device *drm,
> +					 struct sun4i_tcon *tcon,
> +					 struct device_node *np)
> +{
> +	const char *pixel_clk_name;
> +	const char *sclk_name;
> +	struct clk_divider *div;
> +	struct clk_gate *gate;
> +
> +	sclk_name = __clk_get_name(tcon->sclk0);
> +	of_property_read_string_index(np, "clock-output-names", 0,
> +				      &pixel_clk_name);
> +
> +	div = devm_kzalloc(drm->dev, sizeof(*div), GFP_KERNEL);
> +	if (!div)
> +		return -ENOMEM;
> +
> +	div->regmap = tcon->regs;
> +	div->offset = SUN4I_TCON0_DCLK_REG;
> +	div->shift = SUN4I_TCON0_DCLK_DIV_SHIFT;
> +	div->width = SUN4I_TCON0_DCLK_DIV_WIDTH;
> +	div->flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
> +
> +	gate = devm_kzalloc(drm->dev, sizeof(*gate), GFP_KERNEL);
> +	if (!gate)
> +		return -ENOMEM;
> +
> +	gate->regmap = tcon->regs;
> +	gate->offset = SUN4I_TCON0_DCLK_REG;
> +	gate->bit_idx = SUN4I_TCON0_DCLK_GATE_BIT;
> +
> +	tcon->dclk = clk_register_composite(drm->dev, pixel_clk_name,
> +					    &sclk_name, 1,
> +					    NULL, NULL,
> +					    &div->hw, &clk_divider_ops,
> +					    &gate->hw, &clk_gate_ops,
> +					    CLK_USE_REGMAP);
> +
> +	return 0;
> +}
> +
> +static int sun4i_tcon_init_clocks(struct drm_device *drm,
> +				  struct sun4i_tcon *tcon,
> +				  struct device_node *np)
> +{
> +	tcon->clk = of_clk_get_by_name(np, "ahb");
> +	if (IS_ERR(tcon->clk)) {
> +		dev_err(drm->dev, "Couldn't get the TCON bus clock\n");
> +		return PTR_ERR(tcon->clk);
> +	}
> +	clk_prepare_enable(tcon->clk);
> +
> +	tcon->sclk0 = of_clk_get_by_name(np, "tcon-ch0");
> +	if (IS_ERR(tcon->sclk0)) {
> +		dev_err(drm->dev, "Couldn't get the TCON bus clock\n");
> +		return PTR_ERR(tcon->sclk0);
> +	}
> +
> +	tcon->sclk1 = of_clk_get_by_name(np, "tcon-ch1");
> +	if (IS_ERR(tcon->sclk1)) {
> +		dev_err(drm->dev, "Couldn't get the TCON bus clock\n");
> +		return PTR_ERR(tcon->sclk1);
> +	}
> +
> +	return sun4i_tcon_create_pixel_clock(drm, tcon, np);
> +}
> +
> +static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
> +{
> +	clk_unregister(tcon->dclk);
> +	clk_put(tcon->sclk1);
> +	clk_put(tcon->sclk0);
> +	clk_disable_unprepare(tcon->clk);
> +	clk_put(tcon->clk);
> +}
> +
> +static int sun4i_tcon_init_irq(struct drm_device *drm,
> +			       struct sun4i_tcon *tcon,
> +			       struct device_node *np)
> +{
> +	int irq, ret;
> +
> +	irq = of_irq_get(np, 0);
> +	if (irq < 0) {
> +		dev_err(drm->dev, "Couldn't retrieve the TCON interrupt\n");
> +		return irq;
> +	}
> +
> +	ret = devm_request_irq(drm->dev, irq, sun4i_tcon_handler, 0,
> +			       dev_name(drm->dev), tcon);
> +	if (ret) {
> +		dev_err(drm->dev, "Couldn't request the IRQ\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct regmap_config sun4i_tcon_regmap_config = {
> +	.reg_bits	= 32,
> +	.val_bits	= 32,
> +	.reg_stride	= 4,
> +	.max_register	= 0x800,
> +	.name		= "tcon",
> +};
> +
> +static int sun4i_tcon_init_regmap(struct drm_device *drm,
> +				  struct sun4i_tcon *tcon,
> +				  struct device_node *np)
> +{
> +	struct resource res;
> +	void __iomem *regs;
> +	int ret;
> +
> +	ret = of_address_to_resource(np, 0, &res);
> +	regs = devm_ioremap_resource(drm->dev, &res);
> +	if (IS_ERR(regs)) {
> +		dev_err(drm->dev, "Couldn't map the TCON registers\n");
> +		return PTR_ERR(regs);
> +	}
> +
> +	tcon->regs = devm_regmap_init_mmio(drm->dev, regs,
> +					   &sun4i_tcon_regmap_config);
> +	if (IS_ERR(tcon->regs)) {
> +		dev_err(drm->dev, "Couldn't create the TCON regmap\n");
> +		return PTR_ERR(tcon->regs);
> +	}
> +
> +	/* Make sure the TCON is disabled and all IRQs are off */
> +	regmap_write(tcon->regs, SUN4I_TCON_GCTL_REG, 0);
> +	regmap_write(tcon->regs, SUN4I_TCON_GINT0_REG, 0);
> +	regmap_write(tcon->regs, SUN4I_TCON_GINT1_REG, 0);
> +
> +	/* Disable IO lines and set them to tristate */
> +	regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, ~0);
> +	regmap_write(tcon->regs, SUN4I_TCON1_IO_TRI_REG, ~0);
> +
> +	return 0;
> +}
> +
> +struct sun4i_tcon *sun4i_tcon_init(struct drm_device *drm)
> +{
> +	struct sun4i_de *de = drm->dev_private;
> +	struct sun4i_tcon *tcon;
> +	struct device_node *np;
> +	int ret = 0;
> +
> +	tcon = devm_kzalloc(drm->dev, sizeof(*tcon), GFP_KERNEL);
> +	if (!tcon)
> +		return NULL;
> +	tcon->de = de;
> +
> +	np = of_parse_phandle(drm->dev->of_node, "allwinner,tcon", 0);
> +	if (!np) {
> +		dev_err(drm->dev, "Couldn't find the tcon node\n");
> +		return NULL;
> +	}
> +
> +	ret = sun4i_tcon_init_regmap(drm, tcon, np);
> +	if (ret) {
> +		dev_err(drm->dev, "Couldn't init our TCON regmap\n");
> +		goto err_node_put;
> +	}
> +
> +	ret = sun4i_tcon_init_clocks(drm, tcon, np);
> +	if (ret) {
> +		dev_err(drm->dev, "Couldn't init our TCON clocks\n");
> +		goto err_free_regmap;
> +	}
> +
> +	ret = sun4i_tcon_init_irq(drm, tcon, np);
> +	if (ret) {
> +		dev_err(drm->dev, "Couldn't init our TCON interrupts\n");
> +		goto err_free_clocks;
> +	}
> +
> +	return tcon;
> +
> +err_free_clocks:
> +	sun4i_tcon_free_clocks(tcon);
> +err_free_regmap:
> +err_node_put:
> +	of_node_put(np);
> +	return NULL;
> +}
> +
> +void sun4i_tcon_free(struct sun4i_tcon *tcon)
> +{
> +	sun4i_tcon_free_clocks(tcon);
> +}
> +
> +void sun4i_tcon_disable_channel(struct sun4i_tcon *tcon, int channel)
> +{
> +	/* Disable the TCON's channel */
> +	if (channel == 0) {
> +		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> +				   SUN4I_TCON0_CTL_TCON_ENABLE, 0);
> +		clk_disable_unprepare(tcon->dclk);
> +	} else if (channel == 1) {
> +		regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> +				   SUN4I_TCON1_CTL_TCON_ENABLE, 0);
> +		clk_disable_unprepare(tcon->sclk1);
> +	}
> +}
> +
> +void sun4i_tcon_enable_channel(struct sun4i_tcon *tcon, int channel)
> +{
> +	/* Enable the TCON's channel */
> +	if (channel == 0) {
> +		regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> +				   SUN4I_TCON0_CTL_TCON_ENABLE,
> +				   SUN4I_TCON0_CTL_TCON_ENABLE);
> +		clk_prepare_enable(tcon->dclk);
> +	} else if (channel == 1) {
> +		regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> +				   SUN4I_TCON1_CTL_TCON_ENABLE,
> +				   SUN4I_TCON1_CTL_TCON_ENABLE);
> +		clk_prepare_enable(tcon->sclk1);
> +	}
> +}
> +
> +void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable)
> +{
> +	u32 mask, val = 0;
> +
> +	DRM_DEBUG_DRIVER("%sabling VBLANK interrupt\n", enable ? "En" : "Dis");
> +
> +	mask = SUN4I_TCON_GINT0_VBLANK_ENABLE(0) |
> +	       SUN4I_TCON_GINT0_VBLANK_ENABLE(1);
> +
> +	if (enable)
> +		val = mask;
> +
> +	regmap_update_bits(tcon->regs, SUN4I_TCON_GINT0_REG, mask, val);
> +}
> +
> +static int sun4i_tcon_get_clk_delay(struct drm_display_mode *mode,
> +				    int channel)
> +{
> +	int delay = mode->vtotal - mode->vdisplay;
> +
> +	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> +		delay /= 2;
> +
> +	if (channel == 1)
> +		delay -= 2;
> +
> +	delay = min(delay, 30);
> +
> +	DRM_DEBUG_DRIVER("TCON %d clock delay %u\n", channel, delay);
> +
> +	return delay;
> +}
> +
> +void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> +			  struct drm_display_mode *mode)
> +{
> +	unsigned int bp, hsync, vsync;
> +	u8 clk_delay;
> +	u32 val;
> +
> +	/* Adjust clock delay */
> +	clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
> +	regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
> +			   SUN4I_TCON0_CTL_CLK_DELAY_MASK,
> +			   SUN4I_TCON0_CTL_CLK_DELAY(clk_delay));
> +
> +	/* Set the resolution */
> +	regmap_write(tcon->regs, SUN4I_TCON0_BASIC0_REG,
> +		     SUN4I_TCON0_BASIC0_X(mode->crtc_hdisplay) |
> +		     SUN4I_TCON0_BASIC0_Y(mode->crtc_vdisplay));
> +
> +	/* Set horizontal display timings */
> +	bp = mode->crtc_htotal - mode->crtc_hsync_end;
> +	DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
> +			 mode->crtc_htotal, bp);
> +	regmap_write(tcon->regs, SUN4I_TCON0_BASIC1_REG,
> +		     SUN4I_TCON0_BASIC1_H_TOTAL(mode->crtc_htotal) |
> +		     SUN4I_TCON0_BASIC1_H_BACKPORCH(bp));
> +
> +	/* Set vertical display timings */
> +	bp = mode->crtc_vtotal - mode->crtc_vsync_end;
> +	DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
> +			 mode->crtc_vtotal, bp);
> +	regmap_write(tcon->regs, SUN4I_TCON0_BASIC2_REG,
> +		     SUN4I_TCON0_BASIC2_V_TOTAL(mode->crtc_vtotal) |
> +		     SUN4I_TCON0_BASIC2_V_BACKPORCH(bp));
> +
> +	/* Set Hsync and Vsync length */
> +	hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
> +	vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
> +	DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
> +	regmap_write(tcon->regs, SUN4I_TCON0_BASIC3_REG,
> +		     SUN4I_TCON0_BASIC3_V_SYNC(vsync) |
> +		     SUN4I_TCON0_BASIC3_H_SYNC(hsync));
> +
> +	/* TODO: Fix pixel clock phase shift */
> +	val = SUN4I_TCON0_IO_POL_DCLK_PHASE(1);
> +
> +	/* Setup the polarity of the various signals */
> +	if (!(mode->flags & DRM_MODE_FLAG_PHSYNC))
> +		val |= SUN4I_TCON0_IO_POL_HSYNC_POSITIVE;
> +
> +	if (!(mode->flags & DRM_MODE_FLAG_PVSYNC))
> +		val |= SUN4I_TCON0_IO_POL_VSYNC_POSITIVE;
> +
> +	/* Map output pins to channel 0 */
> +	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> +			   SUN4I_TCON_GCTL_IOMAP_MASK,
> +			   SUN4I_TCON_GCTL_IOMAP_TCON0);
> +
> +	regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
> +
> +	/* Enable the output on the pins */
> +	regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0);
> +}
> +
> +void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> +			  struct drm_display_mode *mode)
> +{
> +	unsigned int bp, hsync, vsync;
> +	u8 clk_delay;
> +	u32 val;
> +
> +	/* Adjust clock delay */
> +	clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
> +	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> +			   SUN4I_TCON1_CTL_CLK_DELAY_MASK,
> +			   SUN4I_TCON1_CTL_CLK_DELAY(clk_delay));
> +
> +	/* Set interlaced mode */
> +	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> +		val = SUN4I_TCON1_CTL_INTERLACE_ENABLE;
> +	else
> +		val = 0;
> +	regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG,
> +			   SUN4I_TCON1_CTL_INTERLACE_ENABLE,
> +			   val);
> +
> +	/* Set the input resolution */
> +	regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
> +		     SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
> +		     SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
> +
> +	/* Set the upscaling resolution */
> +	regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
> +		     SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
> +		     SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
> +
> +	/* Set the output resolution */
> +	regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
> +		     SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
> +		     SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
> +
> +	/* Set horizontal display timings */
> +	bp = mode->crtc_htotal - mode->crtc_hsync_end;
> +	DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
> +			 mode->htotal, bp);
> +	regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
> +		     SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
> +		     SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
> +
> +	/* Set vertical display timings */
> +	bp = mode->crtc_vtotal - mode->crtc_vsync_end;
> +	DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
> +			 mode->vtotal, bp);
> +	regmap_write(tcon->regs, SUN4I_TCON1_BASIC4_REG,
> +		     SUN4I_TCON1_BASIC4_V_TOTAL(mode->vtotal) |
> +		     SUN4I_TCON1_BASIC4_V_BACKPORCH(bp));
> +
> +	/* Set Hsync and Vsync length */
> +	hsync = mode->crtc_hsync_end - mode->crtc_hsync_start;
> +	vsync = mode->crtc_vsync_end - mode->crtc_vsync_start;
> +	DRM_DEBUG_DRIVER("Setting HSYNC %d, VSYNC %d\n", hsync, vsync);
> +	regmap_write(tcon->regs, SUN4I_TCON1_BASIC5_REG,
> +		     SUN4I_TCON1_BASIC5_V_SYNC(vsync) |
> +		     SUN4I_TCON1_BASIC5_H_SYNC(hsync));
> +
> +	/* Map output pins to channel 1 */
> +	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
> +			   SUN4I_TCON_GCTL_IOMAP_MASK,
> +			   SUN4I_TCON_GCTL_IOMAP_TCON1);
> +}
> diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> new file mode 100644
> index 000000000000..4faf9d2d3df2
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
> @@ -0,0 +1,182 @@
> +/*
> + * Copyright (C) 2015 Free Electrons
> + * Copyright (C) 2015 NextThing Co
> + *
> + * Boris Brezillon <boris.brezillon@free-electrons.com>
> + * 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 __SUN4I_TCON_H__
> +#define __SUN4I_TCON_H__
> +
> +#include <drm/drm_crtc.h>
> +
> +#include <linux/kernel.h>
> +
> +#define SUN4I_TCON_GCTL_REG			0x0
> +#define SUN4I_TCON_GCTL_TCON_ENABLE			BIT(31)
> +#define SUN4I_TCON_GCTL_IOMAP_MASK			BIT(0)
> +#define SUN4I_TCON_GCTL_IOMAP_TCON1			(1 << 0)
> +#define SUN4I_TCON_GCTL_IOMAP_TCON0			(0 << 0)
> +
> +#define SUN4I_TCON_GINT0_REG			0x4
> +#define SUN4I_TCON_GINT0_VBLANK_ENABLE(pipe)		BIT(31 - (pipe))
> +#define SUN4I_TCON_GINT0_VBLANK_INT(pipe)		BIT(15 - (pipe))
> +
> +#define SUN4I_TCON_GINT1_REG			0x8
> +#define SUN4I_TCON_FRM_CTL_REG			0x10
> +
> +#define SUN4I_TCON0_CTL_REG			0x40
> +#define SUN4I_TCON0_CTL_TCON_ENABLE			BIT(31)
> +#define SUN4I_TCON0_CTL_CLK_DELAY_MASK			GENMASK(8, 4)
> +#define SUN4I_TCON0_CTL_CLK_DELAY(delay)		((delay << 4) & SUN4I_TCON0_CTL_CLK_DELAY_MASK)
> +
> +#define SUN4I_TCON0_DCLK_REG			0x44
> +#define SUN4I_TCON0_DCLK_GATE_BIT			(31)
> +#define SUN4I_TCON0_DCLK_DIV_SHIFT			(0)
> +#define SUN4I_TCON0_DCLK_DIV_WIDTH			(7)
> +
> +#define SUN4I_TCON0_BASIC0_REG			0x48
> +#define SUN4I_TCON0_BASIC0_X(width)			((((width) - 1) & 0x7ff) << 16)
> +#define SUN4I_TCON0_BASIC0_Y(height)			((((height) - 1) & 0x7ff) << 0)
> +
> +#define SUN4I_TCON0_BASIC1_REG			0x4c
> +#define SUN4I_TCON0_BASIC1_H_TOTAL(total)		(((total) - 1) << 16)
> +#define SUN4I_TCON0_BASIC1_H_BACKPORCH(bp)		(((bp) - 1) << 0)
> +
> +#define SUN4I_TCON0_BASIC2_REG			0x50
> +#define SUN4I_TCON0_BASIC2_V_TOTAL(total)		(((total) * 2) << 16)
> +#define SUN4I_TCON0_BASIC2_V_BACKPORCH(bp)		(((bp) - 1) << 0)
> +
> +#define SUN4I_TCON0_BASIC3_REG			0x54
> +#define SUN4I_TCON0_BASIC3_H_SYNC(width)		((((width) - 1) & 0x3ff) << 16)
> +#define SUN4I_TCON0_BASIC3_V_SYNC(height)		((((height) - 1) & 0x3ff) << 0)
> +
> +#define SUN4I_TCON0_HV_IF_REG			0x58
> +#define SUN4I_TCON0_CPU_IF_REG			0x60
> +#define SUN4I_TCON0_CPU_WR_REG			0x64
> +#define SUN4I_TCON0_CPU_RD0_REG			0x68
> +#define SUN4I_TCON0_CPU_RDA_REG			0x6c
> +#define SUN4I_TCON0_TTL0_REG			0x70
> +#define SUN4I_TCON0_TTL1_REG			0x74
> +#define SUN4I_TCON0_TTL2_REG			0x78
> +#define SUN4I_TCON0_TTL3_REG			0x7c
> +#define SUN4I_TCON0_TTL4_REG			0x80
> +#define SUN4I_TCON0_LVDS_IF_REG			0x84
> +#define SUN4I_TCON0_IO_POL_REG			0x88
> +#define SUN4I_TCON0_IO_POL_DCLK_PHASE(phase)		((phase & 3) << 28)
> +#define SUN4I_TCON0_IO_POL_HSYNC_POSITIVE		BIT(25)
> +#define SUN4I_TCON0_IO_POL_VSYNC_POSITIVE		BIT(24)
> +
> +#define SUN4I_TCON0_IO_TRI_REG			0x8c
> +#define SUN4I_TCON0_IO_TRI_HSYNC_DISABLE		BIT(25)
> +#define SUN4I_TCON0_IO_TRI_VSYNC_DISABLE		BIT(24)
> +#define SUN4I_TCON0_IO_TRI_DATA_PINS_DISABLE(pins)	GENMASK(pins, 0)
> +
> +#define SUN4I_TCON1_CTL_REG			0x90
> +#define SUN4I_TCON1_CTL_TCON_ENABLE			BIT(31)
> +#define SUN4I_TCON1_CTL_INTERLACE_ENABLE		BIT(20)
> +#define SUN4I_TCON1_CTL_CLK_DELAY_MASK			GENMASK(8, 4)
> +#define SUN4I_TCON1_CTL_CLK_DELAY(delay)		((delay << 4) & SUN4I_TCON1_CTL_CLK_DELAY_MASK)
> +
> +#define SUN4I_TCON1_BASIC0_REG			0x94
> +#define SUN4I_TCON1_BASIC0_X(width)			((((width) - 1) & 0x7ff) << 16)
> +#define SUN4I_TCON1_BASIC0_Y(height)			((((height) - 1) & 0x7ff) << 0)
> +
> +#define SUN4I_TCON1_BASIC1_REG			0x98
> +#define SUN4I_TCON1_BASIC1_X(width)			((((width) - 1) & 0x7ff) << 16)
> +#define SUN4I_TCON1_BASIC1_Y(height)			((((height) - 1) & 0x7ff) << 0)
> +
> +#define SUN4I_TCON1_BASIC2_REG			0x9c
> +#define SUN4I_TCON1_BASIC2_X(width)			((((width) - 1) & 0x7ff) << 16)
> +#define SUN4I_TCON1_BASIC2_Y(height)			((((height) - 1) & 0x7ff) << 0)
> +
> +#define SUN4I_TCON1_BASIC3_REG			0xa0
> +#define SUN4I_TCON1_BASIC3_H_TOTAL(total)		(((total) - 1) << 16)
> +#define SUN4I_TCON1_BASIC3_H_BACKPORCH(bp)		(((bp) - 1) << 0)
> +
> +#define SUN4I_TCON1_BASIC4_REG			0xa4
> +#define SUN4I_TCON1_BASIC4_V_TOTAL(total)		((total) << 16)
> +#define SUN4I_TCON1_BASIC4_V_BACKPORCH(bp)		(((bp) - 1) << 0)
> +
> +#define SUN4I_TCON1_BASIC5_REG			0xa8
> +#define SUN4I_TCON1_BASIC5_H_SYNC(width)		((((width) - 1) & 0x3ff) << 16)
> +#define SUN4I_TCON1_BASIC5_V_SYNC(height)		((((height) - 1) & 0x3ff) << 0)
> +
> +#define SUN4I_TCON1_IO_POL_REG			0xf0
> +#define SUN4I_TCON1_IO_TRI_REG			0xf4
> +#define SUN4I_TCON_CEU_CTL_REG			0x100
> +#define SUN4I_TCON_CEU_MUL_RR_REG		0x110
> +#define SUN4I_TCON_CEU_MUL_RG_REG		0x114
> +#define SUN4I_TCON_CEU_MUL_RB_REG		0x118
> +#define SUN4I_TCON_CEU_ADD_RC_REG		0x11c
> +#define SUN4I_TCON_CEU_MUL_GR_REG		0x120
> +#define SUN4I_TCON_CEU_MUL_GG_REG		0x124
> +#define SUN4I_TCON_CEU_MUL_GB_REG		0x128
> +#define SUN4I_TCON_CEU_ADD_GC_REG		0x12c
> +#define SUN4I_TCON_CEU_MUL_BR_REG		0x130
> +#define SUN4I_TCON_CEU_MUL_BG_REG		0x134
> +#define SUN4I_TCON_CEU_MUL_BB_REG		0x138
> +#define SUN4I_TCON_CEU_ADD_BC_REG		0x13c
> +#define SUN4I_TCON_CEU_RANGE_R_REG		0x140
> +#define SUN4I_TCON_CEU_RANGE_G_REG		0x144
> +#define SUN4I_TCON_CEU_RANGE_B_REG		0x148
> +#define SUN4I_TCON1_FILL_CTL_REG		0x300
> +#define SUN4I_TCON1_FILL_BEG0_REG		0x304
> +#define SUN4I_TCON1_FILL_END0_REG		0x308
> +#define SUN4I_TCON1_FILL_DATA0_REG		0x30c
> +#define SUN4I_TCON1_FILL_BEG1_REG		0x310
> +#define SUN4I_TCON1_FILL_END1_REG		0x314
> +#define SUN4I_TCON1_FILL_DATA1_REG		0x318
> +#define SUN4I_TCON1_FILL_BEG2_REG		0x31c
> +#define SUN4I_TCON1_FILL_END2_REG		0x320
> +#define SUN4I_TCON1_FILL_DATA2_REG		0x324
> +#define SUN4I_TCON1_GAMMA_TABLE_REG		0x400
> +
> +#define SUN4I_TCON_MAX_CHANNELS		2
> +
> +struct sun4i_tcon {
> +	struct sun4i_de			*de;
> +
> +	struct regmap			*regs;
> +
> +	/* Main bus clock */
> +	struct clk			*clk;
> +
> +	/* Clocks for the TCON channels */
> +	struct clk			*sclk0;
> +	struct clk			*sclk1;
> +
> +	/* Pixel clock */
> +	struct clk			*dclk;
> +
> +	bool				enabled;
> +};
> +
> +struct sun4i_tcon *sun4i_tcon_init(struct drm_device *drm);
> +void sun4i_tcon_free(struct sun4i_tcon *tcon);
> +
> +/* Global Control */
> +void sun4i_tcon_disable(struct sun4i_tcon *tcon);
> +void sun4i_tcon_enable(struct sun4i_tcon *tcon);
> +
> +/* Channel Control */
> +void sun4i_tcon_disable_channel(struct sun4i_tcon *tcon, int channel);
> +void sun4i_tcon_enable_channel(struct sun4i_tcon *tcon, int channel);
> +
> +void sun4i_tcon_enable_vblank(struct sun4i_tcon *tcon, bool enable);
> +
> +/* Mode Related Controls */
> +void sun4i_tcon_switch_interlace(struct sun4i_tcon *tcon,
> +				 bool enable);
> +void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
> +			  struct drm_display_mode *mode);
> +void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
> +			  struct drm_display_mode *mode);
> +
> +#endif /* __SUN4I_TCON_H__ */
> -- 
> 2.6.2
> 

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

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

* Re: [PATCH 00/19] drm: Add Allwinner A10 display engine support
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (18 preceding siblings ...)
  2015-10-30 14:21 ` [PATCH 19/19] ARM: sun5i: chip: Enable the TV Encoder Maxime Ripard
@ 2015-10-30 14:52 ` Daniel Vetter
  2015-11-12  5:12   ` Maxime Ripard
  2015-11-09  3:43 ` Chen-Yu Tsai
  20 siblings, 1 reply; 57+ messages in thread
From: Daniel Vetter @ 2015-10-30 14:52 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 03:20:46PM +0100, Maxime Ripard wrote:
> Hi everyone,
> 
> The Allwinner SoCs (except for the very latest ones) all share the
> same set of controllers, loosely coupled together to form the display
> pipeline.
> 
> Depending on the SoC, the number of instances of the controller will
> change (2 instances of each in the A10, only one in the A13, for
> example), and the output availables will change too (HDMI, composite,
> VGA on the A20, none of them on the A13).
> 
> On most featured SoCs, it looks like that:
> 
>  +--------------------------------------------+
>  |                    RAM                     |
>  +--------------------------------------------+
>        |            |      |            |
>        v            |      |            v
>  +----------------+ |      | +----------------+
>  |    Frontend    | |      | |    Frontend    |
>  +----------------+ |      | +----------------+
>          |          |      |         |
>          v          |      |         v
>  +----------------+ |      | +----------------+
>  |    Backend     |<+      +>|    Backend     |
>  +----------------+          +----------------+
>          |                           |
>          v                           v
>  +----------------+          +----------------+---> LVDS
>  |      TCON      |          |      TCON      |---> RGB
>  +----------------+          +----------------+
>        |       +---+       +---+          |
>        |           |       |              |
>        v           v       v              v
>  +------------+  +------------+  +------------+---> VGA
>  | TV Encoder |  |    HDMI    |  | TV Encoder |---> Composite
>  +------------+  +------------+  +------------+
> 
> The current code only assumes that there is a single instance of all
> the controllers. It also supports only the RGB and Composite
> interfaces.
> 
> A few more things are missing though, and will be supported
> eventually:
>   - Overscan support
>   - Asynchronous page flip
>   - Multiple plane support
>   - Composite / VGA Hotplug detection
>   - More outputs
>   - Support for several videos pipelines
> 
> And there's one big gotcha: thhe code to parse the mode from the
> kernel commandline doesn't seem to support named modes. Since we
> expose the various TV standards through named modes, it means that
> there's no way to use a particular standard to display something
> during the kernel boot. The default will always be used, in other
> words, PAL.

Simply not done yet.

> A few more questions that are probably going to be raised during the
> review:
>   - How do you associate private data to a mode, for example to deal
>     with the non-generic, driver-specific settings required to deal
>     with the various TV standards? drm_display_mode seems to have a
>     private field, but it isn't always preserved.

Analog TV in general is a giant mess, and there's not really all that much
of a standardized solution. I also don't have much clue at all about what
needs to be tuned with analog TV. Probably the best would be to look at
existing drivers with TV-out support and what kind of properties they
support. Then standardize them (with relevant helper code in drm core) and
use that. Additional flags on the mode, especially using the private stuff
is kinda the deprecated non-atomic approach. If you need private data
beyond the mode and any additional properties on the crtc (for derived
state) then just subclass drm_crtc_state and put it there.

>   - How do you setup properties in the kernel command line? In order
>     to have a decent display during boot on relevant interfaces, you
>     probably want to setup the overscan beforehand. Overscan seems to
>     be handled through properties, and afaik, there's no way to set
>     that from the cmdline. Should we use a kernel parameter to set the
>     default value instead?

One idea tossed around is to expose them to DT somehow and then just load
a DT-blob to set them all. That would e.g. also allow to specify firmware
blob paths to e.g. load the boot splash image (if uboot or similar haven't
done that yet). I'm personally not sure how much use there is in exposing
a generic drm property cmdline option ...

What's needed for sure is some generic way to do one initial (atomic)
modeset to hammer all these settings into the driver. That would be really
useful to have, since currently that's tied to the fbdev emulation, which
means if you don't have that it will be simply lost.

Cheers, Daniel

> 
> Thanks!
> Maxime
> 
> Maxime Ripard (19):
>   clk: sunxi: Add display clock
>   clk: sunxi: Add PLL3 clock
>   clk: sunxi: Add TCON channel0 clock
>   clk: sunxi: Add TCON channel1 clock
>   clk: sunxi: add DRAM gates
>   clk: sunxi: Add Allwinner R8 AHB gates support
>   drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
>   drm: Add Allwinner A10 Display Engine support
>   drm: sun4i: Add DT bindings documentation
>   drm: sun4i: Add RGB output
>   drm: sun4i: Add composite output
>   drm: sun4i: tv: Add PAL output standard
>   drm: sun4i: tv: Add NTSC output standard
>   ARM: sun5i: dt: Add pll3 and pll7 clocks
>   ARM: sun5i: dt: Add display and TCON clocks
>   ARM: sun5i: dt: Add DRAM gates
>   ARM: sun5i: dt: Add display blocks to the DTSI
>   ARM: sun5i: r8: Add AHB gates to the DTSI
>   ARM: sun5i: chip: Enable the TV Encoder
> 
>  .../devicetree/bindings/drm/sunxi/sun4i-drm.txt    | 122 ++++
>  arch/arm/boot/dts/sun5i-a10s.dtsi                  |   9 +-
>  arch/arm/boot/dts/sun5i-a13.dtsi                   |   3 +-
>  arch/arm/boot/dts/sun5i-r8.dtsi                    |  46 +-
>  arch/arm/boot/dts/sun5i.dtsi                       | 137 +++++
>  drivers/clk/sunxi/Makefile                         |   4 +
>  drivers/clk/sunxi/clk-simple-gates.c               |   4 +
>  drivers/clk/sunxi/clk-sun4i-display.c              | 199 +++++++
>  drivers/clk/sunxi/clk-sun4i-pll3.c                 |  84 +++
>  drivers/clk/sunxi/clk-sun4i-tcon-ch0.c             | 173 ++++++
>  drivers/clk/sunxi/clk-sun4i-tcon-ch1.c             | 167 ++++++
>  drivers/gpu/drm/Kconfig                            |   2 +
>  drivers/gpu/drm/Makefile                           |   3 +-
>  drivers/gpu/drm/panel/panel-simple.c               |  26 +
>  drivers/gpu/drm/sun4i/Kconfig                      |  14 +
>  drivers/gpu/drm/sun4i/Makefile                     |  11 +
>  drivers/gpu/drm/sun4i/sun4i_backend.c              | 271 +++++++++
>  drivers/gpu/drm/sun4i/sun4i_backend.h              | 159 ++++++
>  drivers/gpu/drm/sun4i/sun4i_crtc.c                 | 117 ++++
>  drivers/gpu/drm/sun4i/sun4i_crtc.h                 |  31 ++
>  drivers/gpu/drm/sun4i/sun4i_drv.c                  | 296 ++++++++++
>  drivers/gpu/drm/sun4i/sun4i_drv.h                  |  30 +
>  drivers/gpu/drm/sun4i/sun4i_framebuffer.c          |  54 ++
>  drivers/gpu/drm/sun4i/sun4i_framebuffer.h          |  19 +
>  drivers/gpu/drm/sun4i/sun4i_layer.c                | 111 ++++
>  drivers/gpu/drm/sun4i/sun4i_layer.h                |  30 +
>  drivers/gpu/drm/sun4i/sun4i_rgb.c                  | 243 ++++++++
>  drivers/gpu/drm/sun4i/sun4i_rgb.h                  |  18 +
>  drivers/gpu/drm/sun4i/sun4i_tcon.c                 | 478 ++++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_tcon.h                 | 182 ++++++
>  drivers/gpu/drm/sun4i/sun4i_tv.c                   | 619 +++++++++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_tv.h                   |  18 +
>  32 files changed, 3673 insertions(+), 7 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-pll3.c
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch0.c
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
>  create mode 100644 drivers/gpu/drm/sun4i/Kconfig
>  create mode 100644 drivers/gpu/drm/sun4i/Makefile
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_backend.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_backend.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_crtc.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_crtc.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_drv.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_drv.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_framebuffer.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_framebuffer.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_layer.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_layer.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_rgb.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_rgb.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_tcon.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_tcon.h
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.h
> 
> -- 
> 2.6.2
> 

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

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

* Re: [PATCH 19/19] ARM: sun5i: chip: Enable the TV Encoder
  2015-10-30 14:21 ` [PATCH 19/19] ARM: sun5i: chip: Enable the TV Encoder Maxime Ripard
@ 2015-10-30 15:20   ` Chen-Yu Tsai
  2015-11-06 19:37     ` Maxime Ripard
  0 siblings, 1 reply; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-10-30 15:20 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 10:21 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The TV encoder is used to drive VGA and composite display.
>
> Enable it on the CHIP

The commit message does not match the contents. Missing a patch? :)

ChenYu

>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  arch/arm/boot/dts/sun5i-r8.dtsi | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun5i-r8.dtsi b/arch/arm/boot/dts/sun5i-r8.dtsi
> index d69df3a73cbf..e39c903da864 100644
> --- a/arch/arm/boot/dts/sun5i-r8.dtsi
> +++ b/arch/arm/boot/dts/sun5i-r8.dtsi
> @@ -86,4 +86,16 @@
>                                              "ahb_mali400";
>                 };
>         };
> +
> +       soc@01c00000 {
> +               tve: encoder@01c0a000 {
> +                       compatible = "allwinner,sun4i-a10-tv-encoder";
> +                       reg = <0x01c0a000 0x1000>;
> +                       clocks = <&ahb_gates 34>;
> +               };
> +       };
> +};
> +
> +&de {
> +       allwinner,tv-encoder = <&tve>;
>  };
> --
> 2.6.2
>

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

* Re: [PATCH 06/19] clk: sunxi: Add Allwinner R8 AHB gates support
  2015-10-30 14:20 ` [PATCH 06/19] clk: sunxi: Add Allwinner R8 AHB gates support Maxime Ripard
@ 2015-10-30 16:01   ` Chen-Yu Tsai
  2015-10-30 16:33     ` Hans de Goede
  0 siblings, 1 reply; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-10-30 16:01 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The R8 has yet another array of gates for AHB. Let's add it to the list of
> compatibles we can deal with.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/clk/sunxi/clk-simple-gates.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
> index 5666c767fa14..e3190a8687a8 100644
> --- a/drivers/clk/sunxi/clk-simple-gates.c
> +++ b/drivers/clk/sunxi/clk-simple-gates.c
> @@ -158,5 +158,7 @@ CLK_OF_DECLARE(sun5i_a10s_ahb, "allwinner,sun5i-a10s-ahb-gates-clk",
>                sun4i_a10_ahb_init);
>  CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner,sun5i-a13-ahb-gates-clk",
>                sun4i_a10_ahb_init);
> +CLK_OF_DECLARE(sun5i_r8_ahb, "allwinner,sun5i-r8-ahb-gates-clk",
> +              sun4i_a10_ahb_init);
>  CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
>                sun4i_a10_ahb_init);
> --
> 2.6.2
>

Please also update Documentation/devicetree/bindings/clock/sunxi.txt

Otherwise,

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

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

* Re: [PATCH 06/19] clk: sunxi: Add Allwinner R8 AHB gates support
  2015-10-30 16:01   ` Chen-Yu Tsai
@ 2015-10-30 16:33     ` Hans de Goede
  0 siblings, 0 replies; 57+ messages in thread
From: Hans de Goede @ 2015-10-30 16:33 UTC (permalink / raw)
  To: Chen-Yu Tsai, Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Alexander Kaplan, Wynter Woods,
	Boris Brezillon, Thomas Petazzoni, Rob Clark, Daniel Vetter

Hi,

On 30-10-15 17:01, Chen-Yu Tsai wrote:
> On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> The R8 has yet another array of gates for AHB. Let's add it to the list of
>> compatibles we can deal with.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> ---
>>   drivers/clk/sunxi/clk-simple-gates.c | 2 ++
>>   1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
>> index 5666c767fa14..e3190a8687a8 100644
>> --- a/drivers/clk/sunxi/clk-simple-gates.c
>> +++ b/drivers/clk/sunxi/clk-simple-gates.c
>> @@ -158,5 +158,7 @@ CLK_OF_DECLARE(sun5i_a10s_ahb, "allwinner,sun5i-a10s-ahb-gates-clk",
>>                 sun4i_a10_ahb_init);
>>   CLK_OF_DECLARE(sun5i_a13_ahb, "allwinner,sun5i-a13-ahb-gates-clk",
>>                 sun4i_a10_ahb_init);
>> +CLK_OF_DECLARE(sun5i_r8_ahb, "allwinner,sun5i-r8-ahb-gates-clk",
>> +              sun4i_a10_ahb_init);
>>   CLK_OF_DECLARE(sun7i_a20_ahb, "allwinner,sun7i-a20-ahb-gates-clk",
>>                 sun4i_a10_ahb_init);
>> --
>> 2.6.2
>>
>
> Please also update Documentation/devicetree/bindings/clock/sunxi.txt
>
> Otherwise,
>
> Acked-by: Chen-Yu Tsai <wens@csie.org>

I wonder if this patch really is a good idea. We've confirmation from
Allwinner that all of the sun5i SoCs are using the same die. Sure some
peripherals are not connected to the outside but it is still the same
die. This patch feels to me like it just grows the kernel and dts size
without serving any purpose.

Regards,

Hans

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

* Re: [PATCH 09/19] drm: sun4i: Add DT bindings documentation
  2015-10-30 14:20 ` [PATCH 09/19] drm: sun4i: Add DT bindings documentation Maxime Ripard
@ 2015-10-30 16:40   ` Rob Herring
  2015-10-30 17:37     ` Thierry Reding
  2015-11-06 22:32     ` Maxime Ripard
  0 siblings, 2 replies; 57+ messages in thread
From: Rob Herring @ 2015-10-30 16:40 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 9:20 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The display pipeline of the Allwinner A10 is involving several loosely
> coupled components.
>
> Add a documentation for the bindings.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  .../devicetree/bindings/drm/sunxi/sun4i-drm.txt    | 122 +++++++++++++++++++++

bindings/display/sunxi/ please.

>  1 file changed, 122 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt
>
> diff --git a/Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt
> new file mode 100644
> index 000000000000..dbdccef787b4
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/drm/sunxi/sun4i-drm.txt
> @@ -0,0 +1,122 @@
> +Allwinner A10 Display Pipeline
> +==============================
> +
> +The Allwinner A10 Display pipeline is composed of several components
> +that are going to be documented below:
> +
> +TV Encoder
> +----------
> +
> +The TV Encoder supports the composite and VGA output. It is one end of
> +the pipeline.
> +
> +Required properties:
> + - compatible: value should be "allwinner,sun4i-a10-tv-encoder".
> + - reg: base address and size of memory-mapped region
> + - clocks: the clocks driving the TV encoder
> +
> +TCON
> +----
> +
> +The TCON acts as a CRTC and encoder for RGB / LVDS interfaces.

Lets not carry DRMs old CRTC name into DT bindings. Just say "display
controller."

> +
> +Required properties:
> + - compatible: value should be "allwinner,sun4i-a10-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:
> +   - 'ahb': the interface clocks
> +   - 'tcon-ch0': The clock driving the TCON channel 0
> +   - 'tcon-ch1': The clock driving the TCON channel 0
> +
> + - clock-names: the clock names mentionned above

typo

> + - clock-output-names: Name of the pixel clock created
> +
> +
> +Display Engine Backend
> +----------------------
> +
> +The display engine backend exposes layers and sprites to the
> +system. It's split into two components, the frontend and backend, the
> +frontend doing formats conversion, scaling, deinterlacing, while the
> +backend actually manages the layers.
> +
> +Required properties:
> +  - compatible: value must be one of:
> +    * allwinner,sun5i-a13-display-engine
> +
> +  - reg: base address and size of the memory-mapped region. Two are needed:
> +    * backend0: registers of the display engine backend
> +    * frontend0: registers of the display engine frontend

Why the zeros? I think they should be dropped.

> +  - reg_names: the region names mentionned above.

typo

> +
> +  - interrupts: frontend interrupt phandle
> +
> +  - clocks: phandles to the clocks feeding the frontend and backend
> +    * backend0-bus: the backend interface clock
> +    * backend0-mod: the backend module clock
> +    * backend0-ram: the backend DRAM clock
> +    * frontend0-bus: the frontend interface clock
> +    * frontend0-mod: the frontend module clock
> +    * frontend0-ram: the frontend DRAM clock

Same comment on zeros.

> +  - clock-names: the clock names mentionned above

typo

> +
> +  - resets: phandles to the reset controllers. Two are needed:
> +    * backend0: backend reset controller
> +    * frontend0: frontend reset controller
> +  - reset-names: the reset names mentionned above

typo. At least you are consistent (unlike English grammar rules). ;)

> +
> +  - allwinner,tcon: phandle to the TCON in our pipeline

Use of-graph or just let the relationship live in the driver. If there
is only 1 instance of the blocks, the latter is fine.

> +
> +Optional properties:
> +  - allwinner,tv-encoder: phandle to the TV Encoder in our pipeline
> +  - allwinner,panel: phandle to the panel used in our RGB interface

Use of-graph please.

> +
> +Example:
> +
> +panel: panel {
> +       compatible = "olimex,lcd-olinuxino-43-ts";
> +};
> +
> +tve: encoder@01c0a000 {
> +       compatible = "allwinner,sun4i-a10-tv-encoder";
> +       reg = <0x01c0a000 0x1000>;
> +       clocks = <&ahb_gates 34>;
> +};
> +
> +tcon: lcd-controller@01c0c000 {
> +       compatible = "allwinner,sun4i-a10-tcon";
> +       reg = <0x01c0c000 0x1000>;
> +       interrupts = <44>;
> +       clocks = <&ahb_gates 36>,
> +                <&tcon_ch0_clk>,
> +                <&tcon_ch1_clk>;
> +       clock-names = "ahb",
> +                     "tcon-ch0",
> +                     "tcon-ch1";
> +       clock-output-names = "tcon-pixel-clock";
> +};
> +
> +de: display-engine@01e00000 {
> +       compatible = "allwinner,sun5i-a13-display-engine";
> +       reg = <0x01e00000 0x20000>,
> +             <0x01e60000 0x10000>;
> +       reg-names = "frontend0",
> +                   "backend0";
> +       interrupts = <47>;
> +       interrupt-names = "engine0";
> +       clocks = <&ahb_gates 46>, <&de_fe_clk>,
> +                <&dram_gates 25>, <&ahb_gates 44>,
> +                <&de_be_clk>, <&dram_gates 26>;
> +       clock-names = "frontend0-bus", "frontend0-mod",
> +                     "frontend0-ram", "backend0-bus",
> +                     "backend0-mod", "backend0-ram";
> +       resets = <&de_fe_clk>,
> +                <&de_be_clk>;
> +       reset-names = "frontend0",
> +                     "backend0";
> +
> +       allwinner,tcon = <&tcon>;
> +       allwinner,tv-encoder = <&tve>;
> +       allwinner,panel = <&panel>;
> +};
> --
> 2.6.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 07/19] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
  2015-10-30 14:20 ` [PATCH 07/19] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
@ 2015-10-30 17:32   ` Thierry Reding
  2015-11-07  0:44     ` Maxime Ripard
  0 siblings, 1 reply; 57+ messages in thread
From: Thierry Reding @ 2015-10-30 17:32 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

On Fri, Oct 30, 2015 at 03:20:53PM +0100, Maxime Ripard wrote:
> Add support for the Olimex LCD-OLinuXino-4.3TS panel to the DRM simple
> panel driver.
> 
> It is a 480x272 panel connected through a 24-bits RGB interface.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/panel/panel-simple.c | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)

I don't see a patch adding the DT binding documentation for this panel.

Also, the olimex vendor prefix isn't defined.

> diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
> index f97b73ec4713..3a9ecb64d1e6 100644
> --- a/drivers/gpu/drm/panel/panel-simple.c
> +++ b/drivers/gpu/drm/panel/panel-simple.c
> @@ -1096,6 +1096,29 @@ static const struct panel_desc shelly_sca07010_bfn_lnn = {
>  	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
>  };
>  
> +static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = {
> +	.clock = 9000,
> +	.hdisplay = 480,
> +	.hsync_start = 480 + 5,
> +	.hsync_end = 480 + 5 + 30,
> +	.htotal = 480 + 5 + 30 + 10,
> +	.vdisplay = 272,
> +	.vsync_start = 272 + 8,
> +	.vsync_end = 272 + 8 + 5,
> +	.vtotal = 272 + 8 + 5 + 3,
> +	.vrefresh = 60,
> +};
> +
> +static const struct panel_desc olimex_lcd_olinuxino_43ts = {
> +	.modes = &olimex_lcd_olinuxino_43ts_mode,
> +	.num_modes = 1,
> +	.size = {
> +		.width = 105,
> +		.height = 67,
> +	},
> +	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
> +};
> +

These mode and panel descriptors are all sorted alphabetically (by
vendor, by model), please keep it so.

>  static const struct of_device_id platform_of_match[] = {
>  	{
>  		.compatible = "ampire,am800480r3tmqwa1h",
> @@ -1191,6 +1214,9 @@ static const struct of_device_id platform_of_match[] = {
>  		.compatible = "shelly,sca07010-bfn-lnn",
>  		.data = &shelly_sca07010_bfn_lnn,
>  	}, {
> +		.compatible = "olimex,lcd-olinuxino-43-ts",
> +		.data = &olimex_lcd_olinuxino_43ts,
> +	}, {
>  		/* sentinel */
>  	}

Here as well.

Thierry

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

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

* Re: [PATCH 09/19] drm: sun4i: Add DT bindings documentation
  2015-10-30 16:40   ` Rob Herring
@ 2015-10-30 17:37     ` Thierry Reding
  2015-11-01 14:28       ` Rob Herring
  2015-11-06 22:32     ` Maxime Ripard
  1 sibling, 1 reply; 57+ messages in thread
From: Thierry Reding @ 2015-10-30 17:37 UTC (permalink / raw)
  To: Rob Herring
  Cc: Maxime Ripard, Mike Turquette, Stephen Boyd, David Airlie,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

On Fri, Oct 30, 2015 at 11:40:03AM -0500, Rob Herring wrote:
> On Fri, Oct 30, 2015 at 9:20 AM, Maxime Ripard
[...]
> > +Optional properties:
> > +  - allwinner,tv-encoder: phandle to the TV Encoder in our pipeline
> > +  - allwinner,panel: phandle to the panel used in our RGB interface
> 
> Use of-graph please.

Why? Panels are a really simple resource and a simple phandle is fully
capable of describing the relationship.

Thierry

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

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

* Re: [PATCH 01/19] clk: sunxi: Add display clock
  2015-10-30 14:20 ` [PATCH 01/19] clk: sunxi: Add display clock Maxime Ripard
@ 2015-10-30 21:29   ` Stephen Boyd
  2015-11-06 23:39     ` Maxime Ripard
  2015-10-31 10:28   ` Chen-Yu Tsai
  1 sibling, 1 reply; 57+ messages in thread
From: Stephen Boyd @ 2015-10-30 21:29 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, David Airlie, Thierry Reding, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On 10/30, Maxime Ripard wrote:
> diff --git a/drivers/clk/sunxi/clk-sun4i-display.c b/drivers/clk/sunxi/clk-sun4i-display.c
> new file mode 100644
> index 000000000000..f13b095c6d7a
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun4i-display.c
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright 2015 Maxime Ripard
> + *
> + * 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.
> + *
> + * 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/kernel.h> for container_of?

> +#include <linux/clk-provider.h>
> +#include <linux/of_address.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +#define SUN4I_A10_DISPLAY_PARENTS	3
> +
> +#define SUN4I_A10_DISPLAY_GATE_BIT	31
> +#define SUN4I_A10_DISPLAY_RESET_BIT	30
> +#define SUN4I_A10_DISPLAY_MUX_MASK	3
> +#define SUN4I_A10_DISPLAY_MUX_SHIFT	24
> +#define SUN4I_A10_DISPLAY_DIV_WIDTH	4
> +#define SUN4I_A10_DISPLAY_DIV_SHIFT	0
> +
> +struct reset_data {
> +	void __iomem			*reg;
> +	spinlock_t			*lock;
> +	struct reset_controller_dev	rcdev;
> +};
> +
> +static DEFINE_SPINLOCK(sun4i_a10_display_lock);
> +
> +static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev,
> +				    unsigned long id)
> +{
> +	struct reset_data *data = container_of(rcdev,
> +					       struct reset_data,
> +					       rcdev);

Can this be a macro rcdev_to_reset_data() or something?

> +	unsigned long flags;
[..]
> +
> +static int sun4i_a10_display_status(struct reset_controller_dev *rcdev,
> +				    unsigned long id)
> +{
> +	struct reset_data *data = container_of(rcdev,
> +					       struct reset_data,
> +					       rcdev);
> +
> +	return !(readl(data->reg) & BIT(SUN4I_A10_DISPLAY_RESET_BIT));
> +}
> +
> +static struct reset_control_ops sun4i_a10_display_reset_ops = {

Someone should make it so this can be const...

> +	.assert		= sun4i_a10_display_assert,
> +	.deassert	= sun4i_a10_display_deassert,
> +	.status		= sun4i_a10_display_status,
> +};
> +
> +static int sun4i_a10_display_reset_xlate(struct reset_controller_dev *rcdev,
> +					 const struct of_phandle_args *spec)
> +{
> +	if (WARN_ON(spec->args_count != rcdev->of_reset_n_cells))
> +		return -EINVAL;

Do we really need this check? Seems like something the reset core
should handle.

> +
> +	/* We only have a single reset signal */
> +	return 0;
> +}
> +
> +static void __init sun4i_a10_display_setup(struct device_node *node)
> +{
> +	const char *parents[SUN4I_A10_DISPLAY_PARENTS];
> +	const char *clk_name = node->name;
> +	struct reset_data *reset_data;
> +	struct clk_divider *div;
> +	struct clk_gate *gate;
> +	struct clk_mux *mux;
> +	void __iomem *reg;
> +	struct clk *clk;
> +	int i;
> +
> +	of_property_read_string(node, "clock-output-names", &clk_name);
> +
> +	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> +	if (IS_ERR(reg)) {
> +		pr_err("%s: Could not map the clock registers\n", clk_name);
> +		return;
> +	}
> +
> +	for (i = 0; i < SUN4I_A10_DISPLAY_PARENTS; i++)
> +		parents[i] = of_clk_get_parent_name(node, i);

of_clk_parent_fill()?

> +
> +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
[..]
> +		goto free_reset;
> +	}
> +
> +	return;
> +
> +free_reset:
> +	kfree(reset_data);
> +free_clk:
> +	clk_unregister(clk);

We really ought to have a clk_composite_unregister() API.

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

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

* Re: [PATCH 02/19] clk: sunxi: Add PLL3 clock
  2015-10-30 14:20 ` [PATCH 02/19] clk: sunxi: Add PLL3 clock Maxime Ripard
@ 2015-10-30 21:32   ` Stephen Boyd
  0 siblings, 0 replies; 57+ messages in thread
From: Stephen Boyd @ 2015-10-30 21:32 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, David Airlie, Thierry Reding, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On 10/30, Maxime Ripard wrote:
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index a9e1a5885846..40c32ffd912c 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -9,8 +9,9 @@ obj-y += clk-a10-mod1.o
>  obj-y += clk-a10-pll2.o
>  obj-y += clk-a20-gmac.o
>  obj-y += clk-mod0.o
> -obj-y += clk-sun4i-display.o
>  obj-y += clk-simple-gates.o
> +obj-y += clk-sun4i-display.o

Put this in the right place in patch 1 please.

> +obj-y += clk-sun4i-pll3.o
>  obj-y += clk-sun8i-mbus.o
>  obj-y += clk-sun9i-core.o
>  obj-y += clk-sun9i-mmc.o
> diff --git a/drivers/clk/sunxi/clk-sun4i-pll3.c b/drivers/clk/sunxi/clk-sun4i-pll3.c
> new file mode 100644
> index 000000000000..7ea178bf19fa
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun4i-pll3.c
> @@ -0,0 +1,84 @@
> +/*
> + * Copyright 2015 Maxime Ripard
> + *
> + * 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.
> + *
> + * 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-provider.h>
> +#include <linux/of_address.h>

#include <linux/of.h> for of_property_read_string()

> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +#define SUN4I_A10_PLL3_GATE_BIT	31
[...]
> +
> +	clk = clk_register_composite(NULL, clk_name,
> +				     &parent, 1,
> +				     NULL, NULL,
> +				     &mult->hw, &clk_factor_ops,
> +				     &gate->hw, &clk_gate_ops,
> +				     0);
> +	if (IS_ERR(clk)) {
> +		pr_err("%s: Couldn't register the clock\n", clk_name);
> +		goto free_mult;
> +	}
> +
> +	of_clk_add_provider(node, of_clk_src_simple_get, clk);

I hope this doesn't fail.

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

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

* Re: [PATCH 04/19] clk: sunxi: Add TCON channel1 clock
  2015-10-30 14:20 ` [PATCH 04/19] clk: sunxi: Add TCON channel1 clock Maxime Ripard
@ 2015-10-30 21:37   ` Stephen Boyd
  2015-11-07  0:11     ` Maxime Ripard
  2015-10-31  9:53   ` Chen-Yu Tsai
  1 sibling, 1 reply; 57+ messages in thread
From: Stephen Boyd @ 2015-10-30 21:37 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, David Airlie, Thierry Reding, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On 10/30, Maxime Ripard wrote:
> The TCON is a controller generating the timings to output videos signals,
> acting like both a CRTC and an encoder.
> 
> It has two channels depending on the output, each channel being driven by
> its own clock (and own clock controller).
> 
> Add a driver for the channel 1 clock.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Similar comments apply to patches 3 and 4. Was the same code
copy/pasted two more times and then changed to have different
values? Looks like we should consolidate all that stuff into
something more generic so that we don't have the same problems 3
times.

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

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

* Re: [PATCH 04/19] clk: sunxi: Add TCON channel1 clock
  2015-10-30 14:20 ` [PATCH 04/19] clk: sunxi: Add TCON channel1 clock Maxime Ripard
  2015-10-30 21:37   ` Stephen Boyd
@ 2015-10-31  9:53   ` Chen-Yu Tsai
  2015-11-07  0:01     ` Maxime Ripard
  1 sibling, 1 reply; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-10-31  9:53 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The TCON is a controller generating the timings to output videos signals,
> acting like both a CRTC and an encoder.
>
> It has two channels depending on the output, each channel being driven by
> its own clock (and own clock controller).
>
> Add a driver for the channel 1 clock.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/clk/sunxi/Makefile             |   1 +
>  drivers/clk/sunxi/clk-sun4i-tcon-ch1.c | 167 +++++++++++++++++++++++++++++++++
>  2 files changed, 168 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c

According to the documents I have, this variant of the TCON clock
is specific to sun5i. On sun4i/sun7i, TCON CH1 clock has the same
layout as TCON CH0 and the other display clocks.

>
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index 7821b2b63d58..ed59ee4b3a85 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -13,6 +13,7 @@ obj-y += clk-simple-gates.o
>  obj-y += clk-sun4i-display.o
>  obj-y += clk-sun4i-pll3.o
>  obj-y += clk-sun4i-tcon-ch0.o
> +obj-y += clk-sun4i-tcon-ch1.o
>  obj-y += clk-sun8i-mbus.o
>  obj-y += clk-sun9i-core.o
>  obj-y += clk-sun9i-mmc.o
> diff --git a/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
> new file mode 100644
> index 000000000000..9f2ab52b0bf9
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
> @@ -0,0 +1,167 @@
> +/*
> + * Copyright 2015 Maxime Ripard
> + *
> + * 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.
> + *
> + * 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-provider.h>
> +#include <linux/of_address.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +#define SUN4I_TCON_CH1_SCLK_NAME_LEN   32
> +
> +#define SUN4I_A10_TCON_CH1_SCLK1_PARENTS       2
> +#define SUN4I_A10_TCON_CH1_SCLK2_PARENTS       4
> +
> +#define SUN4I_A10_TCON_CH1_SCLK2_GATE_BIT      31
> +#define SUN4I_A10_TCON_CH1_SCLK2_MUX_MASK      3
> +#define SUN4I_A10_TCON_CH1_SCLK2_MUX_SHIFT     24
> +#define SUN4I_A10_TCON_CH1_SCLK2_DIV_WIDTH     4
> +#define SUN4I_A10_TCON_CH1_SCLK2_DIV_SHIFT     0
> +
> +#define SUN4I_A10_TCON_CH1_SCLK1_GATE_BIT      15
> +#define SUN4I_A10_TCON_CH1_SCLK1_MUX_MASK      1
> +#define SUN4I_A10_TCON_CH1_SCLK1_MUX_SHIFT     11
> +
> +static DEFINE_SPINLOCK(sun4i_a10_tcon_ch1_lock);
> +
> +static void __init sun4i_a10_tcon_ch1_setup(struct device_node *node)
> +{
> +       const char *sclk1_parents[SUN4I_A10_TCON_CH1_SCLK1_PARENTS];
> +       const char *sclk2_parents[SUN4I_A10_TCON_CH1_SCLK2_PARENTS];
> +       const char *sclk1_name = node->name;
> +       char sclk2_name[SUN4I_TCON_CH1_SCLK_NAME_LEN];
> +       char sclk2d2_name[SUN4I_TCON_CH1_SCLK_NAME_LEN];
> +       struct clk_gate *sclk1_gate, *sclk2_gate;
> +       struct clk_mux *sclk1_mux, *sclk2_mux;
> +       struct clk *sclk1, *sclk2, *sclk2d2;
> +       struct clk_divider *sclk2_div;
> +       void __iomem *reg;
> +       int i;
> +
> +       of_property_read_string(node, "clock-output-names",
> +                               &sclk1_name);
> +
> +       snprintf(sclk2_name, SUN4I_TCON_CH1_SCLK_NAME_LEN,
> +                "%s2", sclk1_name);
> +
> +       snprintf(sclk2d2_name, SUN4I_TCON_CH1_SCLK_NAME_LEN,
> +                "%s2d2", sclk1_name);
> +
> +       reg = of_io_request_and_map(node, 0, of_node_full_name(node));
> +       if (IS_ERR(reg)) {
> +               pr_err("%s: Could not map the clock registers\n", sclk2_name);
> +               return;
> +       }
> +
> +       for (i = 0; i < SUN4I_A10_TCON_CH1_SCLK2_PARENTS; i++)
> +               sclk2_parents[i] = of_clk_get_parent_name(node, i);
> +
> +       sclk2_mux = kzalloc(sizeof(*sclk2_mux), GFP_KERNEL);
> +       if (!sclk2_mux)
> +               return;
> +
> +       sclk2_mux->reg = reg;
> +       sclk2_mux->shift = SUN4I_A10_TCON_CH1_SCLK2_MUX_SHIFT;
> +       sclk2_mux->mask = SUN4I_A10_TCON_CH1_SCLK2_MUX_MASK;
> +       sclk2_mux->lock = &sun4i_a10_tcon_ch1_lock;
> +
> +       sclk2_gate = kzalloc(sizeof(*sclk2_gate), GFP_KERNEL);
> +       if (!sclk2_gate)
> +               goto free_sclk2_mux;
> +
> +       sclk2_gate->reg = reg;
> +       sclk2_gate->bit_idx = SUN4I_A10_TCON_CH1_SCLK2_GATE_BIT;
> +       sclk2_gate->lock = &sun4i_a10_tcon_ch1_lock;
> +
> +       sclk2_div = kzalloc(sizeof(*sclk2_div), GFP_KERNEL);
> +       if (!sclk2_div)
> +               goto free_sclk2_gate;
> +
> +       sclk2_div->reg = reg;
> +       sclk2_div->shift = SUN4I_A10_TCON_CH1_SCLK2_DIV_SHIFT;
> +       sclk2_div->width = SUN4I_A10_TCON_CH1_SCLK2_DIV_WIDTH;
> +       sclk2_div->lock = &sun4i_a10_tcon_ch1_lock;
> +
> +       sclk2 = clk_register_composite(NULL, sclk2_name, sclk2_parents,
> +                                      SUN4I_A10_TCON_CH1_SCLK2_PARENTS,
> +                                      &sclk2_mux->hw, &clk_mux_ops,
> +                                      &sclk2_div->hw, &clk_divider_ops,
> +                                      &sclk2_gate->hw, &clk_gate_ops,
> +                                      0);
> +       if (IS_ERR(sclk2)) {
> +               pr_err("%s: Couldn't register the clock\n", sclk2_name);
> +               goto free_sclk2_div;
> +       }
> +
> +       sclk2d2 = clk_register_fixed_factor(NULL, sclk2d2_name, sclk2_name, 0,
> +                                           1, 2);
> +       if (IS_ERR(sclk2d2)) {
> +               pr_err("%s: Couldn't register the clock\n", sclk2d2_name);
> +               goto free_sclk2;
> +       }
> +
> +       sclk1_parents[0] = sclk2_name;
> +       sclk1_parents[1] = sclk2d2_name;

Is there any need to expose these 2 clocks via DT using of_clk_add_provider?

Note that these complex clock trees within a clock node breaks the
assigned-clock-parents mechanism, as you can no longer specify the output
clock's direct parents.


Regards
ChenYu

> +
> +       sclk1_mux = kzalloc(sizeof(*sclk1_mux), GFP_KERNEL);
> +       if (!sclk1_mux)
> +               goto free_sclk2d2;
> +
> +       sclk1_mux->reg = reg;
> +       sclk1_mux->shift = SUN4I_A10_TCON_CH1_SCLK1_MUX_SHIFT;
> +       sclk1_mux->mask = SUN4I_A10_TCON_CH1_SCLK1_MUX_MASK;
> +       sclk1_mux->lock = &sun4i_a10_tcon_ch1_lock;
> +
> +       sclk1_gate = kzalloc(sizeof(*sclk1_gate), GFP_KERNEL);
> +       if (!sclk1_gate)
> +               goto free_sclk1_mux;
> +
> +       sclk1_gate->reg = reg;
> +       sclk1_gate->bit_idx = SUN4I_A10_TCON_CH1_SCLK1_GATE_BIT;
> +       sclk1_gate->lock = &sun4i_a10_tcon_ch1_lock;
> +
> +       sclk1 = clk_register_composite(NULL, sclk1_name, sclk1_parents,
> +                                      SUN4I_A10_TCON_CH1_SCLK1_PARENTS,
> +                                      &sclk1_mux->hw, &clk_mux_ops,
> +                                      NULL, NULL,
> +                                      &sclk1_gate->hw, &clk_gate_ops,
> +                                      0);
> +       if (IS_ERR(sclk1)) {
> +               pr_err("%s: Couldn't register the clock\n", sclk1_name);
> +               goto free_sclk1_gate;
> +       }
> +
> +       of_clk_add_provider(node, of_clk_src_simple_get, sclk1);
> +
> +       return;
> +
> +free_sclk1_gate:
> +       kfree(sclk1_gate);
> +free_sclk1_mux:
> +       kfree(sclk1_mux);
> +free_sclk2d2:
> +       clk_unregister(sclk2d2);
> +free_sclk2:
> +       clk_unregister(sclk2);
> +free_sclk2_div:
> +       kfree(sclk2_div);
> +free_sclk2_gate:
> +       kfree(sclk2_gate);
> +free_sclk2_mux:
> +       kfree(sclk2_mux);
> +}
> +
> +CLK_OF_DECLARE(sun4i_a10_tcon_ch1, "allwinner,sun4i-a10-tcon-ch1-clk",
> +              sun4i_a10_tcon_ch1_setup);
> --
> 2.6.2
>

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

* Re: [PATCH 03/19] clk: sunxi: Add TCON channel0 clock
  2015-10-30 14:20 ` [PATCH 03/19] clk: sunxi: Add TCON channel0 clock Maxime Ripard
@ 2015-10-31 10:19   ` Chen-Yu Tsai
  2015-11-06 22:11     ` Maxime Ripard
  0 siblings, 1 reply; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-10-31 10:19 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

Hi,

On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The TCON is a controller generating the timings to output videos signals,
> acting like both a CRTC and an encoder.
>
> It has two channels depending on the output, each channel being driven by
> its own clock (and own clock controller).
>
> Add a driver for the channel 0 clock.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/clk/sunxi/Makefile             |   1 +
>  drivers/clk/sunxi/clk-sun4i-tcon-ch0.c | 173 +++++++++++++++++++++++++++++++++
>  2 files changed, 174 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch0.c
>
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index 40c32ffd912c..7821b2b63d58 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -12,6 +12,7 @@ obj-y += clk-mod0.o
>  obj-y += clk-simple-gates.o
>  obj-y += clk-sun4i-display.o
>  obj-y += clk-sun4i-pll3.o
> +obj-y += clk-sun4i-tcon-ch0.o
>  obj-y += clk-sun8i-mbus.o
>  obj-y += clk-sun9i-core.o
>  obj-y += clk-sun9i-mmc.o
> diff --git a/drivers/clk/sunxi/clk-sun4i-tcon-ch0.c b/drivers/clk/sunxi/clk-sun4i-tcon-ch0.c
> new file mode 100644
> index 000000000000..db10cfb94a1d
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch0.c
> @@ -0,0 +1,173 @@
> +/*
> + * Copyright 2015 Maxime Ripard
> + *
> + * 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.
> + *
> + * 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-provider.h>
> +#include <linux/of_address.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +#define SUN4I_A10_TCON_CH0_PARENTS     4
> +
> +#define SUN4I_A10_TCON_CH0_GATE_BIT    31
> +#define SUN4I_A10_TCON_CH0_RESET_SHIFT 29

This is sun5i specific.

A10s manual says bit 30 is the LCD reset, while bit 29 is the TV encoder reset.
A13/R8 don't mention TCON_CH0 clock. A10/A20 have no separate TV encoder reset.

Please rename the clock.

ChenYu

> +#define SUN4I_A10_TCON_CH0_MUX_MASK    3
> +#define SUN4I_A10_TCON_CH0_MUX_SHIFT   24
> +
> +struct reset_data {
> +       void __iomem                    *reg;
> +       spinlock_t                      *lock;
> +       struct reset_controller_dev     rcdev;
> +};
> +
> +static DEFINE_SPINLOCK(sun4i_a10_tcon_ch0_lock);
> +

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

* Re: [PATCH 01/19] clk: sunxi: Add display clock
  2015-10-30 14:20 ` [PATCH 01/19] clk: sunxi: Add display clock Maxime Ripard
  2015-10-30 21:29   ` Stephen Boyd
@ 2015-10-31 10:28   ` Chen-Yu Tsai
  2015-11-06 19:42     ` Maxime Ripard
  1 sibling, 1 reply; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-10-31 10:28 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

Hi,

On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The A10 SoCs and its relatives has a special clock controller to drive the
> display engines (both frontend and backend).
>
> Add a driver for it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/clk/sunxi/Makefile            |   1 +
>  drivers/clk/sunxi/clk-sun4i-display.c | 199 ++++++++++++++++++++++++++++++++++
>  2 files changed, 200 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c
>
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index cb4c299214ce..a9e1a5885846 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -9,6 +9,7 @@ obj-y += clk-a10-mod1.o
>  obj-y += clk-a10-pll2.o
>  obj-y += clk-a20-gmac.o
>  obj-y += clk-mod0.o
> +obj-y += clk-sun4i-display.o
>  obj-y += clk-simple-gates.o
>  obj-y += clk-sun8i-mbus.o
>  obj-y += clk-sun9i-core.o
> diff --git a/drivers/clk/sunxi/clk-sun4i-display.c b/drivers/clk/sunxi/clk-sun4i-display.c
> new file mode 100644
> index 000000000000..f13b095c6d7a
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun4i-display.c
> @@ -0,0 +1,199 @@
> +/*
> + * Copyright 2015 Maxime Ripard
> + *
> + * 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.
> + *
> + * 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-provider.h>
> +#include <linux/of_address.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +#define SUN4I_A10_DISPLAY_PARENTS      3

Can we change this to 4, so we can reuse this for TCON clocks on sun4i/sun7i?

Thanks

ChenYu

> +#define SUN4I_A10_DISPLAY_GATE_BIT     31
> +#define SUN4I_A10_DISPLAY_RESET_BIT    30
> +#define SUN4I_A10_DISPLAY_MUX_MASK     3
> +#define SUN4I_A10_DISPLAY_MUX_SHIFT    24
> +#define SUN4I_A10_DISPLAY_DIV_WIDTH    4
> +#define SUN4I_A10_DISPLAY_DIV_SHIFT    0

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

* Re: [PATCH 09/19] drm: sun4i: Add DT bindings documentation
  2015-10-30 17:37     ` Thierry Reding
@ 2015-11-01 14:28       ` Rob Herring
  0 siblings, 0 replies; 57+ messages in thread
From: Rob Herring @ 2015-11-01 14:28 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Maxime Ripard, Mike Turquette, Stephen Boyd, David Airlie,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 12:37 PM, Thierry Reding
<thierry.reding@gmail.com> wrote:
> On Fri, Oct 30, 2015 at 11:40:03AM -0500, Rob Herring wrote:
>> On Fri, Oct 30, 2015 at 9:20 AM, Maxime Ripard
> [...]
>> > +Optional properties:
>> > +  - allwinner,tv-encoder: phandle to the TV Encoder in our pipeline
>> > +  - allwinner,panel: phandle to the panel used in our RGB interface
>>
>> Use of-graph please.
>
> Why? Panels are a really simple resource and a simple phandle is fully
> capable of describing the relationship.

So we can have some consistency in bindings and common parsing code.
It is simple when it is just a panel, but when it can be tv-encoder or
other board level downstream bridge devices it doesn't stay so simple.
Also, we already have a simple way to do panels which is as a child
node. Let's not have a third way.

Rob

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

* Re: [linux-sunxi] [PATCH 11/19] drm: sun4i: Add composite output
  2015-10-30 14:20 ` [PATCH 11/19] drm: sun4i: Add composite output Maxime Ripard
@ 2015-11-02  2:53   ` Jonathan Liu
  2015-11-07  0:35     ` Maxime Ripard
  0 siblings, 1 reply; 57+ messages in thread
From: Jonathan Liu @ 2015-11-02  2:53 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On 31 October 2015 at 01:20, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Some Allwinner SoCs have an IP called the TV encoder that is used to output
> composite and VGA signals. In such a case, we need to use the second TCON
> channel.
>
> Add support for that TV encoder.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/sun4i/Makefile    |   1 +
>  drivers/gpu/drm/sun4i/sun4i_drv.c |  10 +-
>  drivers/gpu/drm/sun4i/sun4i_tv.c  | 532 ++++++++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_tv.h  |  18 ++
>  4 files changed, 560 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.c
>  create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.h
>
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index 4d230b658a05..fc0dc8be82d9 100644
> --- a/drivers/gpu/drm/sun4i/Makefile
> +++ b/drivers/gpu/drm/sun4i/Makefile
> @@ -6,5 +6,6 @@ sun4i-drm-y += sun4i_layer.o
>  sun4i-drm-y += sun4i_tcon.o
>
>  sun4i-drm-y += sun4i_rgb.o
> +sun4i-drm-y += sun4i_tv.o
>
>  obj-$(CONFIG_DRM_SUN4I)                += sun4i-drm.o
> diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
> index f2c9c8a2eb75..3cf7a9e89afa 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_drv.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -22,6 +22,7 @@
>  #include "sun4i_layer.h"
>  #include "sun4i_rgb.h"
>  #include "sun4i_tcon.h"
> +#include "sun4i_tv.h"
>
>  static void sun4i_drv_preclose(struct drm_device *drm,
>                                struct drm_file *file_priv)
> @@ -134,12 +135,18 @@ static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
>                 goto err_free_crtc;
>         }
>
> +       ret = sun4i_tv_init(drm);
> +       if (ret) {
> +               dev_err(drm->dev, "Couldn't create our RGB output\n");

RGB should be composite. Seems like a copy-paste error.

> +               goto err_free_rgb;
> +       }
> +
>         /* Create our framebuffer */
>         drv->fbdev = sun4i_framebuffer_init(drm);
>         if (IS_ERR(drv->fbdev)) {
>                 dev_err(drm->dev, "Couldn't create our framebuffer\n");
>                 ret = PTR_ERR(drv->fbdev);
> -               goto err_free_rgb;
> +               goto err_free_tv;
>         }
>
>         /* Enable connectors polling */

Regards,
Jonathan

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

* Re: [PATCH 19/19] ARM: sun5i: chip: Enable the TV Encoder
  2015-10-30 15:20   ` Chen-Yu Tsai
@ 2015-11-06 19:37     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-06 19:37 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Hans de Goede, Alexander Kaplan,
	Wynter Woods, Boris Brezillon, Thomas Petazzoni, Rob Clark,
	Daniel Vetter

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

Hi Chen-Yu,

On Fri, Oct 30, 2015 at 11:20:41PM +0800, Chen-Yu Tsai wrote:
> On Fri, Oct 30, 2015 at 10:21 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > The TV encoder is used to drive VGA and composite display.
> >
> > Enable it on the CHIP
> 
> The commit message does not match the contents. Missing a patch? :)

No, I changed the commit a bit, and forgot to update the message :)

Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 01/19] clk: sunxi: Add display clock
  2015-10-31 10:28   ` Chen-Yu Tsai
@ 2015-11-06 19:42     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-06 19:42 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Hans de Goede, Alexander Kaplan,
	Wynter Woods, Boris Brezillon, Thomas Petazzoni, Rob Clark,
	Daniel Vetter

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

Hi,

On Sat, Oct 31, 2015 at 06:28:16PM +0800, Chen-Yu Tsai wrote:
> Hi,
> 
> On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > The A10 SoCs and its relatives has a special clock controller to drive the
> > display engines (both frontend and backend).
> >
> > Add a driver for it.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  drivers/clk/sunxi/Makefile            |   1 +
> >  drivers/clk/sunxi/clk-sun4i-display.c | 199 ++++++++++++++++++++++++++++++++++
> >  2 files changed, 200 insertions(+)
> >  create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c
> >
> > diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> > index cb4c299214ce..a9e1a5885846 100644
> > --- a/drivers/clk/sunxi/Makefile
> > +++ b/drivers/clk/sunxi/Makefile
> > @@ -9,6 +9,7 @@ obj-y += clk-a10-mod1.o
> >  obj-y += clk-a10-pll2.o
> >  obj-y += clk-a20-gmac.o
> >  obj-y += clk-mod0.o
> > +obj-y += clk-sun4i-display.o
> >  obj-y += clk-simple-gates.o
> >  obj-y += clk-sun8i-mbus.o
> >  obj-y += clk-sun9i-core.o
> > diff --git a/drivers/clk/sunxi/clk-sun4i-display.c b/drivers/clk/sunxi/clk-sun4i-display.c
> > new file mode 100644
> > index 000000000000..f13b095c6d7a
> > --- /dev/null
> > +++ b/drivers/clk/sunxi/clk-sun4i-display.c
> > @@ -0,0 +1,199 @@
> > +/*
> > + * Copyright 2015 Maxime Ripard
> > + *
> > + * 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.
> > + *
> > + * 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-provider.h>
> > +#include <linux/of_address.h>
> > +#include <linux/reset-controller.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock.h>
> > +
> > +#define SUN4I_A10_DISPLAY_PARENTS      3
> 
> Can we change this to 4, so we can reuse this for TCON clocks on
> sun4i/sun7i?

Good point, I'll change this.

Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 03/19] clk: sunxi: Add TCON channel0 clock
  2015-10-31 10:19   ` Chen-Yu Tsai
@ 2015-11-06 22:11     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-06 22:11 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Hans de Goede, Alexander Kaplan,
	Wynter Woods, Boris Brezillon, Thomas Petazzoni, Rob Clark,
	Daniel Vetter

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

Hi,

On Sat, Oct 31, 2015 at 06:19:59PM +0800, Chen-Yu Tsai wrote:
> > +#define SUN4I_A10_TCON_CH0_RESET_SHIFT 29
> 
> This is sun5i specific.
> 
> A10s manual says bit 30 is the LCD reset, while bit 29 is the TV
> encoder reset.  A13/R8 don't mention TCON_CH0 clock. A10/A20 have no
> separate TV encoder reset.
> 
> Please rename the clock.

This thing with the A10s is odd, the channel 0 is only used for the
LCD interface, and not the tv encoder (and both the A13 and R8 do have
a TCON).

But you're right, I've fixed it.

Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 09/19] drm: sun4i: Add DT bindings documentation
  2015-10-30 16:40   ` Rob Herring
  2015-10-30 17:37     ` Thierry Reding
@ 2015-11-06 22:32     ` Maxime Ripard
  1 sibling, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-06 22:32 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

Hi Rob,

On Fri, Oct 30, 2015 at 11:40:03AM -0500, Rob Herring wrote:
> > +Display Engine Backend
> > +----------------------
> > +
> > +The display engine backend exposes layers and sprites to the
> > +system. It's split into two components, the frontend and backend, the
> > +frontend doing formats conversion, scaling, deinterlacing, while the
> > +backend actually manages the layers.
> > +
> > +Required properties:
> > +  - compatible: value must be one of:
> > +    * allwinner,sun5i-a13-display-engine
> > +
> > +  - reg: base address and size of the memory-mapped region. Two are needed:
> > +    * backend0: registers of the display engine backend
> > +    * frontend0: registers of the display engine frontend
> 
> Why the zeros? I think they should be dropped.

We have SoCs that have two backends and two frontends, hence why I
added 0. I guess I can also add several devices for them, but then I'd
need to move to the component framework I guess (which was the plan anyway).

> > +
> > +  - allwinner,tcon: phandle to the TCON in our pipeline
> 
> Use of-graph or just let the relationship live in the driver. If there
> is only 1 instance of the blocks, the latter is fine.

We can also have several TCON instances in the SoC, and even though
you can on a theorical point of view use any TCON with any backend,
usually you're tied because of how the pins are routed on the boards.

Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 01/19] clk: sunxi: Add display clock
  2015-10-30 21:29   ` Stephen Boyd
@ 2015-11-06 23:39     ` Maxime Ripard
  2015-11-12 20:31       ` Stephen Boyd
  0 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-11-06 23:39 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Mike Turquette, David Airlie, Thierry Reding, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

Hi Stephen,

Thanks for your feedback!

On Fri, Oct 30, 2015 at 02:29:02PM -0700, Stephen Boyd wrote:
> > +
> > +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> > +	if (!mux)
> [..]
> > +		goto free_reset;
> > +	}
> > +
> > +	return;
> > +
> > +free_reset:
> > +	kfree(reset_data);
> > +free_clk:
> > +	clk_unregister(clk);
> 
> We really ought to have a clk_composite_unregister() API.

Can we?

We can always unregister the clock itself, but do we have a way to
retrieve the structure that has been allocated in there?

(note that it also applies to the generic clocks registration: muxes,
dividers, and so on).

Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 04/19] clk: sunxi: Add TCON channel1 clock
  2015-10-31  9:53   ` Chen-Yu Tsai
@ 2015-11-07  0:01     ` Maxime Ripard
  2015-11-09  3:36       ` Chen-Yu Tsai
  0 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-11-07  0:01 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Hans de Goede, Alexander Kaplan,
	Wynter Woods, Boris Brezillon, Thomas Petazzoni, Rob Clark,
	Daniel Vetter

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

Hi,

On Sat, Oct 31, 2015 at 05:53:26PM +0800, Chen-Yu Tsai wrote:
> On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > The TCON is a controller generating the timings to output videos signals,
> > acting like both a CRTC and an encoder.
> >
> > It has two channels depending on the output, each channel being driven by
> > its own clock (and own clock controller).
> >
> > Add a driver for the channel 1 clock.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  drivers/clk/sunxi/Makefile             |   1 +
> >  drivers/clk/sunxi/clk-sun4i-tcon-ch1.c | 167 +++++++++++++++++++++++++++++++++
> >  2 files changed, 168 insertions(+)
> >  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
> 
> According to the documents I have, this variant of the TCON clock
> is specific to sun5i. On sun4i/sun7i, TCON CH1 clock has the same
> layout as TCON CH0 and the other display clocks.

At least for the A20, it's not true.

Make sure you do not confuse LCD1 CH0 (p79, which is a channel 0
clock), with LCD0 CH1 (p81, which is a channel 1 clock).

> > +       sclk1_parents[0] = sclk2_name;
> > +       sclk1_parents[1] = sclk2d2_name;
> 
> Is there any need to expose these 2 clocks via DT using of_clk_add_provider?

No, as far as I'm aware, there's no user external to this clock
driver.

> Note that these complex clock trees within a clock node breaks the
> assigned-clock-parents mechanism, as you can no longer specify the output
> clock's direct parents.

There's no point of changing the parent either. Hardware blocks are
always connected to the leaf clock (sclk1). We could also model it as
an extra 1-bit divider, which would simplify a bit the logic though.

Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 04/19] clk: sunxi: Add TCON channel1 clock
  2015-10-30 21:37   ` Stephen Boyd
@ 2015-11-07  0:11     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-07  0:11 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Mike Turquette, David Airlie, Thierry Reding, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

Hi,

On Fri, Oct 30, 2015 at 02:37:34PM -0700, Stephen Boyd wrote:
> On 10/30, Maxime Ripard wrote:
> > The TCON is a controller generating the timings to output videos signals,
> > acting like both a CRTC and an encoder.
> > 
> > It has two channels depending on the output, each channel being driven by
> > its own clock (and own clock controller).
> > 
> > Add a driver for the channel 1 clock.
> > 
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> 
> Similar comments apply to patches 3 and 4. Was the same code
> copy/pasted two more times and then changed to have different
> values?

I don't really recall, but I probably used the same skeleton yeah.

> Looks like we should consolidate all that stuff into something more
> generic so that we don't have the same problems 3 times.

Does it?

They're both pretty different actually. One is a gate + mux + reset
(patch 3), the other one is actually a combination of two clocks, one
that is the parent of the other, the former being a gate + mux, the
latter a gate + div.

At least at the hardware level, they're very different, and adding
more code to deal with both case would complicate quite a lot the
probe code, for no real reasons.

Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [linux-sunxi] [PATCH 11/19] drm: sun4i: Add composite output
  2015-11-02  2:53   ` [linux-sunxi] " Jonathan Liu
@ 2015-11-07  0:35     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-07  0:35 UTC (permalink / raw)
  To: Jonathan Liu
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

On Mon, Nov 02, 2015 at 01:53:20PM +1100, Jonathan Liu wrote:
> > +       ret = sun4i_tv_init(drm);
> > +       if (ret) {
> > +               dev_err(drm->dev, "Couldn't create our RGB output\n");
> 
> RGB should be composite. Seems like a copy-paste error.

Good catch. Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 07/19] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
  2015-10-30 17:32   ` Thierry Reding
@ 2015-11-07  0:44     ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-07  0:44 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Mike Turquette, Stephen Boyd, David Airlie, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

Hi Thierry,

On Fri, Oct 30, 2015 at 06:32:30PM +0100, Thierry Reding wrote:
> On Fri, Oct 30, 2015 at 03:20:53PM +0100, Maxime Ripard wrote:
> > Add support for the Olimex LCD-OLinuXino-4.3TS panel to the DRM simple
> > panel driver.
> > 
> > It is a 480x272 panel connected through a 24-bits RGB interface.
> > 
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  drivers/gpu/drm/panel/panel-simple.c | 26 ++++++++++++++++++++++++++
> >  1 file changed, 26 insertions(+)
> 
> I don't see a patch adding the DT binding documentation for this panel.
> 
> Also, the olimex vendor prefix isn't defined.
> 
> > diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
> > index f97b73ec4713..3a9ecb64d1e6 100644
> > --- a/drivers/gpu/drm/panel/panel-simple.c
> > +++ b/drivers/gpu/drm/panel/panel-simple.c
> > @@ -1096,6 +1096,29 @@ static const struct panel_desc shelly_sca07010_bfn_lnn = {
> >  	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
> >  };
> >  
> > +static const struct drm_display_mode olimex_lcd_olinuxino_43ts_mode = {
> > +	.clock = 9000,
> > +	.hdisplay = 480,
> > +	.hsync_start = 480 + 5,
> > +	.hsync_end = 480 + 5 + 30,
> > +	.htotal = 480 + 5 + 30 + 10,
> > +	.vdisplay = 272,
> > +	.vsync_start = 272 + 8,
> > +	.vsync_end = 272 + 8 + 5,
> > +	.vtotal = 272 + 8 + 5 + 3,
> > +	.vrefresh = 60,
> > +};
> > +
> > +static const struct panel_desc olimex_lcd_olinuxino_43ts = {
> > +	.modes = &olimex_lcd_olinuxino_43ts_mode,
> > +	.num_modes = 1,
> > +	.size = {
> > +		.width = 105,
> > +		.height = 67,
> > +	},
> > +	.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
> > +};
> > +
> 
> These mode and panel descriptors are all sorted alphabetically (by
> vendor, by model), please keep it so.
> 
> >  static const struct of_device_id platform_of_match[] = {
> >  	{
> >  		.compatible = "ampire,am800480r3tmqwa1h",
> > @@ -1191,6 +1214,9 @@ static const struct of_device_id platform_of_match[] = {
> >  		.compatible = "shelly,sca07010-bfn-lnn",
> >  		.data = &shelly_sca07010_bfn_lnn,
> >  	}, {
> > +		.compatible = "olimex,lcd-olinuxino-43-ts",
> > +		.data = &olimex_lcd_olinuxino_43ts,
> > +	}, {
> >  		/* sentinel */
> >  	}
> 
> Here as well.

Thanks for your feedback, consider it fixed.

Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 04/19] clk: sunxi: Add TCON channel1 clock
  2015-11-07  0:01     ` Maxime Ripard
@ 2015-11-09  3:36       ` Chen-Yu Tsai
  2015-11-19 15:35         ` Maxime Ripard
  0 siblings, 1 reply; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-11-09  3:36 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart,
	Hans de Goede, Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Sat, Nov 7, 2015 at 8:01 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi,
>
> On Sat, Oct 31, 2015 at 05:53:26PM +0800, Chen-Yu Tsai wrote:
>> On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
>> <maxime.ripard@free-electrons.com> wrote:
>> > The TCON is a controller generating the timings to output videos signals,
>> > acting like both a CRTC and an encoder.
>> >
>> > It has two channels depending on the output, each channel being driven by
>> > its own clock (and own clock controller).
>> >
>> > Add a driver for the channel 1 clock.
>> >
>> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> > ---
>> >  drivers/clk/sunxi/Makefile             |   1 +
>> >  drivers/clk/sunxi/clk-sun4i-tcon-ch1.c | 167 +++++++++++++++++++++++++++++++++
>> >  2 files changed, 168 insertions(+)
>> >  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
>>
>> According to the documents I have, this variant of the TCON clock
>> is specific to sun5i. On sun4i/sun7i, TCON CH1 clock has the same
>> layout as TCON CH0 and the other display clocks.
>
> At least for the A20, it's not true.
>
> Make sure you do not confuse LCD1 CH0 (p79, which is a channel 0
> clock), with LCD0 CH1 (p81, which is a channel 1 clock).

Right. The names are great for confusing the reader. :(

>> > +       sclk1_parents[0] = sclk2_name;
>> > +       sclk1_parents[1] = sclk2d2_name;
>>
>> Is there any need to expose these 2 clocks via DT using of_clk_add_provider?
>
> No, as far as I'm aware, there's no user external to this clock
> driver.
>
>> Note that these complex clock trees within a clock node breaks the
>> assigned-clock-parents mechanism, as you can no longer specify the output
>> clock's direct parents.
>
> There's no point of changing the parent either. Hardware blocks are
> always connected to the leaf clock (sclk1). We could also model it as
> an extra 1-bit divider, which would simplify a bit the logic though.

Probably not. You still have a gate to handle. It's just moving the
divider from 1 clock to the other. I think the current approach of
modeling it like the hardware is better.

About reparenting, what I meant was if sclk2 is not exposed through
of_clk_add_provider, then we can't do assigned-clocks stuff on it,
like setting a default parent or making each channel use a different
source pll.

What I'm saying is if it is not expected to work with another core
binding, we should probably note it somewhere.


Regards
ChenYu

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

* Re: [PATCH 00/19] drm: Add Allwinner A10 display engine support
  2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (19 preceding siblings ...)
  2015-10-30 14:52 ` [PATCH 00/19] drm: Add Allwinner A10 display engine support Daniel Vetter
@ 2015-11-09  3:43 ` Chen-Yu Tsai
  20 siblings, 0 replies; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-11-09  3:43 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

Hi Maxime,

On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Maxime Ripard (19):
>   clk: sunxi: Add display clock
>   clk: sunxi: Add PLL3 clock
>   clk: sunxi: Add TCON channel0 clock
>   clk: sunxi: Add TCON channel1 clock
>   clk: sunxi: add DRAM gates
>   clk: sunxi: Add Allwinner R8 AHB gates support
>   drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
>   drm: Add Allwinner A10 Display Engine support
>   drm: sun4i: Add DT bindings documentation
>   drm: sun4i: Add RGB output
>   drm: sun4i: Add composite output
>   drm: sun4i: tv: Add PAL output standard
>   drm: sun4i: tv: Add NTSC output standard
>   ARM: sun5i: dt: Add pll3 and pll7 clocks
>   ARM: sun5i: dt: Add display and TCON clocks
>   ARM: sun5i: dt: Add DRAM gates
>   ARM: sun5i: dt: Add display blocks to the DTSI
>   ARM: sun5i: r8: Add AHB gates to the DTSI
>   ARM: sun5i: chip: Enable the TV Encoder

Can you add a patch adding the clock compatibles to
Documentation/devicetree/bindings/clock/sunxi.txt?

Thanks
ChenYu

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

* Re: [PATCH 05/19] clk: sunxi: add DRAM gates
  2015-10-30 14:20 ` [PATCH 05/19] clk: sunxi: add DRAM gates Maxime Ripard
@ 2015-11-09  4:18   ` Chen-Yu Tsai
  2015-11-13  8:08     ` Chen-Yu Tsai
  0 siblings, 1 reply; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-11-09  4:18 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> The Allwinner SoCs have a gate controller to gate the access to the DRAM
> clock to the some devices that need to access the DRAM directly (mostly
> display / image related IPs).
>
> Use a simple gates driver to support it.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

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

> ---
>  drivers/clk/sunxi/clk-simple-gates.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
> index 0214c6548afd..5666c767fa14 100644
> --- a/drivers/clk/sunxi/clk-simple-gates.c
> +++ b/drivers/clk/sunxi/clk-simple-gates.c
> @@ -112,6 +112,8 @@ CLK_OF_DECLARE(sun5i_a13_apb0, "allwinner,sun5i-a13-apb0-gates-clk",
>                sunxi_simple_gates_init);
>  CLK_OF_DECLARE(sun5i_a13_apb1, "allwinner,sun5i-a13-apb1-gates-clk",
>                sunxi_simple_gates_init);
> +CLK_OF_DECLARE(sun5i_a13_dram, "allwinner,sun5i-a13-dram-gates-clk",
> +              sunxi_simple_gates_init);
>  CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-gates-clk",
>                sunxi_simple_gates_init);
>  CLK_OF_DECLARE(sun6i_a31_apb1, "allwinner,sun6i-a31-apb1-gates-clk",
> --
> 2.6.2
>

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

* Re: [PATCH 14/19] ARM: sun5i: dt: Add pll3 and pll7 clocks
  2015-10-30 14:21 ` [PATCH 14/19] ARM: sun5i: dt: Add pll3 and pll7 clocks Maxime Ripard
@ 2015-11-09  4:24   ` Chen-Yu Tsai
  0 siblings, 0 replies; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-11-09  4:24 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Oct 30, 2015 at 10:21 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Enable the pll3 and pll7 clocks in the DT that are used to drive the
> display-related clocks.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

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

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

* Re: [PATCH 08/19] drm: Add Allwinner A10 Display Engine support
  2015-10-30 14:44   ` Daniel Vetter
@ 2015-11-11 22:14     ` Maxime Ripard
  2015-11-16 15:04       ` Daniel Vetter
  0 siblings, 1 reply; 57+ messages in thread
From: Maxime Ripard @ 2015-11-11 22:14 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark

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

Hi Daniel,

Thanks for your review!

On Fri, Oct 30, 2015 at 03:44:09PM +0100, Daniel Vetter wrote:
> > +static void sun4i_crtc_disable(struct drm_crtc *crtc)
> > +{
> > +	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
> > +	struct sun4i_drv *drv = scrtc->drv;
> > +
> > +	DRM_DEBUG_DRIVER("Disabling the CRTC\n");
> > +
> > +	if (!scrtc->enabled)
> > +		return;
> 
> Please don't do this - the atomic state should always reflect the true hw
> state (fix that up with either hw state readout or reset in the ->reset
> callbacks), and the atomic helpers guarantee that they'll never call you
> when not needed. If you don't trust them do a WARN_ON at least, but no
> early silent returns.
> 
> Personally I'd just rip it out, it's too much trouble. And for debugging
> the atomic helpers already trace it all (or at least should).

Ok. Is there a preferred way to do HW state readout, or should I just
add that to my probe?

> > +static int sun4i_drv_connector_plug_all(struct drm_device *drm)
> 
> Laurent Pinchart has this as a rfc patch for drm core, please coordinate
> with him and rebase on top of his patches.

Ack, I will.

> > +static int sun4i_drv_enable_vblank(struct drm_device *drm, int pipe)
> > +{
> > +	struct sun4i_drv *drv = drm->dev_private;
> > +	struct sun4i_tcon *tcon = drv->tcon;
> > +
> > +	DRM_DEBUG_DRIVER("Enabling VBLANK on pipe %d\n", pipe);
> > +
> > +	sun4i_tcon_enable_vblank(tcon, true);
> > +
> > +	return 0;
> 
> atomic helpers rely on enable_vblank failing correctly when the pipe is
> off and vlbanks will never happen. You probably need a correct error code
> here that checks crtc->state->active (well not that directly but something
> derived from it, since the pointer chase would be racy).

Ok.

> I know it's a bit a mess since we don't have kms-native vblank driver
> hooks yet and really the drm core should get this right for you. It'll
> happen eventually, but drm_irq.c is a bit moldy ;-)

I can't really use drm_irq anyway, since we don't have a single
interrupt for the VBLANK, but two, that we have to use depending on
the output.

> > +static void sun4i_drv_disable_vblank(struct drm_device *drm, int pipe)
> > +{
> > +	struct sun4i_drv *drv = drm->dev_private;
> > +	struct sun4i_tcon *tcon = drv->tcon;
> > +
> > +	DRM_DEBUG_DRIVER("Disabling VBLANK on pipe %d\n", pipe);
> > +
> > +	sun4i_tcon_enable_vblank(tcon, false);
> > +}
> > +
> > +static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
> 
> load/unload callbacks are depracated since fundamentally racy, and we
> can't fix that due to the pile of legacy dri1 drivers. Please use
> drm_dev_alloc/register/unregister/unref functions instead, with the
> load/unload code placed in between to avoid races with userspace seeing
> the device/driver (e.g. in sysfs) while it's in a partially defunct state.
> 
> Relevant kerneldoc has the details, at least in linux-next.

Ok.

> > +static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
> > +					      struct drm_plane_state *old_state)
> > +{
> > +	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
> > +	struct sun4i_drv *drv = layer->drv;
> > +	struct sun4i_backend *backend = drv->backend;
> > +
> > +	sun4i_backend_update_layer_coord(backend, layer->id, plane);
> > +	sun4i_backend_update_layer_formats(backend, layer->id, plane);
> > +	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
> > +	sun4i_backend_layer_enable(backend, layer->id, true);
> > +	sun4i_backend_commit(backend);
> 
> Not idea how exactly your hw works, but the call to sun4i_backend_commit
> probably should be in the crtc->atomic_flush function, to make sure that
> plane updates across multiple planes are indeed atomic.

The hardware will not take the register writes into account until a
bit is set (in the _commit function), so I guess putting it in
atomic_flush makes sense.

Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 00/19] drm: Add Allwinner A10 display engine support
  2015-10-30 14:52 ` [PATCH 00/19] drm: Add Allwinner A10 display engine support Daniel Vetter
@ 2015-11-12  5:12   ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-12  5:12 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark

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

On Fri, Oct 30, 2015 at 03:52:17PM +0100, Daniel Vetter wrote:
> On Fri, Oct 30, 2015 at 03:20:46PM +0100, Maxime Ripard wrote:
> > Hi everyone,
> > 
> > The Allwinner SoCs (except for the very latest ones) all share the
> > same set of controllers, loosely coupled together to form the display
> > pipeline.
> > 
> > Depending on the SoC, the number of instances of the controller will
> > change (2 instances of each in the A10, only one in the A13, for
> > example), and the output availables will change too (HDMI, composite,
> > VGA on the A20, none of them on the A13).
> > 
> > On most featured SoCs, it looks like that:
> > 
> >  +--------------------------------------------+
> >  |                    RAM                     |
> >  +--------------------------------------------+
> >        |            |      |            |
> >        v            |      |            v
> >  +----------------+ |      | +----------------+
> >  |    Frontend    | |      | |    Frontend    |
> >  +----------------+ |      | +----------------+
> >          |          |      |         |
> >          v          |      |         v
> >  +----------------+ |      | +----------------+
> >  |    Backend     |<+      +>|    Backend     |
> >  +----------------+          +----------------+
> >          |                           |
> >          v                           v
> >  +----------------+          +----------------+---> LVDS
> >  |      TCON      |          |      TCON      |---> RGB
> >  +----------------+          +----------------+
> >        |       +---+       +---+          |
> >        |           |       |              |
> >        v           v       v              v
> >  +------------+  +------------+  +------------+---> VGA
> >  | TV Encoder |  |    HDMI    |  | TV Encoder |---> Composite
> >  +------------+  +------------+  +------------+
> > 
> > The current code only assumes that there is a single instance of all
> > the controllers. It also supports only the RGB and Composite
> > interfaces.
> > 
> > A few more things are missing though, and will be supported
> > eventually:
> >   - Overscan support
> >   - Asynchronous page flip
> >   - Multiple plane support
> >   - Composite / VGA Hotplug detection
> >   - More outputs
> >   - Support for several videos pipelines
> > 
> > And there's one big gotcha: thhe code to parse the mode from the
> > kernel commandline doesn't seem to support named modes. Since we
> > expose the various TV standards through named modes, it means that
> > there's no way to use a particular standard to display something
> > during the kernel boot. The default will always be used, in other
> > words, PAL.
> 
> Simply not done yet.

Ok, so I guess there's no fundamental objection to it. I'll do it then
:)

> > A few more questions that are probably going to be raised during the
> > review:
> >   - How do you associate private data to a mode, for example to deal
> >     with the non-generic, driver-specific settings required to deal
> >     with the various TV standards? drm_display_mode seems to have a
> >     private field, but it isn't always preserved.
> 
> Analog TV in general is a giant mess, and there's not really all that much
> of a standardized solution. I also don't have much clue at all about what
> needs to be tuned with analog TV. Probably the best would be to look at
> existing drivers with TV-out support and what kind of properties they
> support.

The intel i915 driver already uses a generic property to support this
(using drm_mode_create_tv_properties), so I guess the generic part is
covered.

That might need some work, for example to support a different overscan
configuration in X and Y, but that's a detail, and we can always
extend it.

However, I'm more interested in actual register and bits that you have
to poke to enable one of the two modes, that are usually not directly
something you can expose through a generic mode field, either because
you don't really know what the bit is doing (because the datasheet
sucks), or because it's simply something completely tied to the
hardware itself, and not really the mode you expose (for example, I
have to enable the DAC0 in PAL and the DAC0 and DAC3 in NTSC).

> Then standardize them (with relevant helper code in drm core) and
> use that. Additional flags on the mode, especially using the private stuff
> is kinda the deprecated non-atomic approach.

Ok.

> If you need private data beyond the mode and any additional
> properties on the crtc (for derived state) then just subclass
> drm_crtc_state and put it there.

Except that it's not really tied to the CRTC in my case, but
encoder. I don't think the CRTC simply knows if it's using an RGB,
LVDS or Composite output, and then if the user wants NTSC or PAL on
the composite output. It just doesn't seem to really fit in the
current way the pipeline is represented.

> >   - How do you setup properties in the kernel command line? In order
> >     to have a decent display during boot on relevant interfaces, you
> >     probably want to setup the overscan beforehand. Overscan seems to
> >     be handled through properties, and afaik, there's no way to set
> >     that from the cmdline. Should we use a kernel parameter to set the
> >     default value instead?
> 
> One idea tossed around is to expose them to DT somehow and then just load
> a DT-blob to set them all. That would e.g. also allow to specify firmware
> blob paths to e.g. load the boot splash image (if uboot or similar haven't
> done that yet). I'm personally not sure how much use there is in exposing
> a generic drm property cmdline option ...

But then, it would also mean that a downstream user plugging its linux
system on a TV would need to adjust its DT? it doesn't feel really
pratical.

> What's needed for sure is some generic way to do one initial (atomic)
> modeset to hammer all these settings into the driver. That would be really
> useful to have, since currently that's tied to the fbdev emulation, which
> means if you don't have that it will be simply lost.

I do have that, and it mostly works except for the things we already
discussed (overscan, text based video mode parsing).

Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 01/19] clk: sunxi: Add display clock
  2015-11-06 23:39     ` Maxime Ripard
@ 2015-11-12 20:31       ` Stephen Boyd
  2015-11-19 15:42         ` Maxime Ripard
  0 siblings, 1 reply; 57+ messages in thread
From: Stephen Boyd @ 2015-11-12 20:31 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, David Airlie, Thierry Reding, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On 11/06, Maxime Ripard wrote:
> Hi Stephen,
> 
> Thanks for your feedback!
> 
> On Fri, Oct 30, 2015 at 02:29:02PM -0700, Stephen Boyd wrote:
> > > +
> > > +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> > > +	if (!mux)
> > [..]
> > > +		goto free_reset;
> > > +	}
> > > +
> > > +	return;
> > > +
> > > +free_reset:
> > > +	kfree(reset_data);
> > > +free_clk:
> > > +	clk_unregister(clk);
> > 
> > We really ought to have a clk_composite_unregister() API.
> 
> Can we?
> 
> We can always unregister the clock itself, but do we have a way to
> retrieve the structure that has been allocated in there?
> 
> (note that it also applies to the generic clocks registration: muxes,
> dividers, and so on).

Yes we have a way. We've done the same sort of design for other
generic clocks. Do the __clk_get_hw() thing like in clk-divider.c

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

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

* Re: [PATCH 05/19] clk: sunxi: add DRAM gates
  2015-11-09  4:18   ` Chen-Yu Tsai
@ 2015-11-13  8:08     ` Chen-Yu Tsai
  2015-11-19 15:43       ` Maxime Ripard
  0 siblings, 1 reply; 57+ messages in thread
From: Chen-Yu Tsai @ 2015-11-13  8:08 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Maxime Ripard, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart,
	Hans de Goede, Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Mon, Nov 9, 2015 at 12:18 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
>> The Allwinner SoCs have a gate controller to gate the access to the DRAM
>> clock to the some devices that need to access the DRAM directly (mostly
>> display / image related IPs).
>>
>> Use a simple gates driver to support it.
>>
>> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>
> Acked-by: Chen-Yu Tsai <wens@csie.org>
>
>> ---
>>  drivers/clk/sunxi/clk-simple-gates.c | 2 ++
>>  1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
>> index 0214c6548afd..5666c767fa14 100644
>> --- a/drivers/clk/sunxi/clk-simple-gates.c
>> +++ b/drivers/clk/sunxi/clk-simple-gates.c
>> @@ -112,6 +112,8 @@ CLK_OF_DECLARE(sun5i_a13_apb0, "allwinner,sun5i-a13-apb0-gates-clk",
>>                sunxi_simple_gates_init);
>>  CLK_OF_DECLARE(sun5i_a13_apb1, "allwinner,sun5i-a13-apb1-gates-clk",
>>                sunxi_simple_gates_init);
>> +CLK_OF_DECLARE(sun5i_a13_dram, "allwinner,sun5i-a13-dram-gates-clk",
>> +              sunxi_simple_gates_init);

Nit: Since the compatible added is sun5i, could you mention it in the
commit message,
to avoid confusion when we do this for the other families?

Thanks

>>  CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-gates-clk",
>>                sunxi_simple_gates_init);
>>  CLK_OF_DECLARE(sun6i_a31_apb1, "allwinner,sun6i-a31-apb1-gates-clk",
>> --
>> 2.6.2
>>

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

* Re: [PATCH 08/19] drm: Add Allwinner A10 Display Engine support
  2015-11-11 22:14     ` Maxime Ripard
@ 2015-11-16 15:04       ` Daniel Vetter
  0 siblings, 0 replies; 57+ messages in thread
From: Daniel Vetter @ 2015-11-16 15:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark

On Wed, Nov 11, 2015 at 02:14:12PM -0800, Maxime Ripard wrote:
> Hi Daniel,
> 
> Thanks for your review!

Back from vacation, sorry for the delay.

> 
> On Fri, Oct 30, 2015 at 03:44:09PM +0100, Daniel Vetter wrote:
> > > +static void sun4i_crtc_disable(struct drm_crtc *crtc)
> > > +{
> > > +	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
> > > +	struct sun4i_drv *drv = scrtc->drv;
> > > +
> > > +	DRM_DEBUG_DRIVER("Disabling the CRTC\n");
> > > +
> > > +	if (!scrtc->enabled)
> > > +		return;
> > 
> > Please don't do this - the atomic state should always reflect the true hw
> > state (fix that up with either hw state readout or reset in the ->reset
> > callbacks), and the atomic helpers guarantee that they'll never call you
> > when not needed. If you don't trust them do a WARN_ON at least, but no
> > early silent returns.
> > 
> > Personally I'd just rip it out, it's too much trouble. And for debugging
> > the atomic helpers already trace it all (or at least should).
> 
> Ok. Is there a preferred way to do HW state readout, or should I just
> add that to my probe?

There's no preferred way yet (i.e. something supported in a standard
fashion through helpers). I'd place it in your various ->reset hooks
though. The idea from atomic helpers is that ->reset should make sure that
atomic state structures (i.e. drm_crtc/connector/plane_state or your
driver-specific subclasses of them) should match with the hw state. Either
by resetting the hw or by reading out the hw state inte freshly-allocated
structures.

> > > +static int sun4i_drv_connector_plug_all(struct drm_device *drm)
> > 
> > Laurent Pinchart has this as a rfc patch for drm core, please coordinate
> > with him and rebase on top of his patches.
> 
> Ack, I will.
> 
> > > +static int sun4i_drv_enable_vblank(struct drm_device *drm, int pipe)
> > > +{
> > > +	struct sun4i_drv *drv = drm->dev_private;
> > > +	struct sun4i_tcon *tcon = drv->tcon;
> > > +
> > > +	DRM_DEBUG_DRIVER("Enabling VBLANK on pipe %d\n", pipe);
> > > +
> > > +	sun4i_tcon_enable_vblank(tcon, true);
> > > +
> > > +	return 0;
> > 
> > atomic helpers rely on enable_vblank failing correctly when the pipe is
> > off and vlbanks will never happen. You probably need a correct error code
> > here that checks crtc->state->active (well not that directly but something
> > derived from it, since the pointer chase would be racy).
> 
> Ok.
> 
> > I know it's a bit a mess since we don't have kms-native vblank driver
> > hooks yet and really the drm core should get this right for you. It'll
> > happen eventually, but drm_irq.c is a bit moldy ;-)
> 
> I can't really use drm_irq anyway, since we don't have a single
> interrupt for the VBLANK, but two, that we have to use depending on
> the output.

drm_irq has 2 parts: irq handling, which only supports 1 hw irq line, and
which is totally optional.

2nd part is the vblank support (all the drm_vblank and drm_crtc_vblank_)
functions, which are completely agnostic to how exactly your hw signals a
vblank for a given output. Those are mandatory if you want to support
vblanks (and really, you want to support vblanks). So whether you have 2
hw irq lines or 1 hw irq line with some additional status register doesn't
matter, since the hw irq -> logical drm_crtc mapping for vblank events is
done in the driver.

Yes I know we should split up the various bits in drm_irq, it's on my todo
;-)

> > > +static void sun4i_drv_disable_vblank(struct drm_device *drm, int pipe)
> > > +{
> > > +	struct sun4i_drv *drv = drm->dev_private;
> > > +	struct sun4i_tcon *tcon = drv->tcon;
> > > +
> > > +	DRM_DEBUG_DRIVER("Disabling VBLANK on pipe %d\n", pipe);
> > > +
> > > +	sun4i_tcon_enable_vblank(tcon, false);
> > > +}
> > > +
> > > +static int sun4i_drv_load(struct drm_device *drm, unsigned long flags)
> > 
> > load/unload callbacks are depracated since fundamentally racy, and we
> > can't fix that due to the pile of legacy dri1 drivers. Please use
> > drm_dev_alloc/register/unregister/unref functions instead, with the
> > load/unload code placed in between to avoid races with userspace seeing
> > the device/driver (e.g. in sysfs) while it's in a partially defunct state.
> > 
> > Relevant kerneldoc has the details, at least in linux-next.
> 
> Ok.
> 
> > > +static void sun4i_backend_layer_atomic_update(struct drm_plane *plane,
> > > +					      struct drm_plane_state *old_state)
> > > +{
> > > +	struct sun4i_layer *layer = plane_to_sun4i_layer(plane);
> > > +	struct sun4i_drv *drv = layer->drv;
> > > +	struct sun4i_backend *backend = drv->backend;
> > > +
> > > +	sun4i_backend_update_layer_coord(backend, layer->id, plane);
> > > +	sun4i_backend_update_layer_formats(backend, layer->id, plane);
> > > +	sun4i_backend_update_layer_buffer(backend, layer->id, plane);
> > > +	sun4i_backend_layer_enable(backend, layer->id, true);
> > > +	sun4i_backend_commit(backend);
> > 
> > Not idea how exactly your hw works, but the call to sun4i_backend_commit
> > probably should be in the crtc->atomic_flush function, to make sure that
> > plane updates across multiple planes are indeed atomic.
> 
> The hardware will not take the register writes into account until a
> bit is set (in the _commit function), so I guess putting it in
> atomic_flush makes sense.

Yeah that's what I suspected, so sun4i_backend_commit definitely needs to
be moved to atomic_flush.

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

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

* Re: [PATCH 04/19] clk: sunxi: Add TCON channel1 clock
  2015-11-09  3:36       ` Chen-Yu Tsai
@ 2015-11-19 15:35         ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-19 15:35 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Hans de Goede, Alexander Kaplan,
	Wynter Woods, Boris Brezillon, Thomas Petazzoni, Rob Clark,
	Daniel Vetter

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

On Mon, Nov 09, 2015 at 11:36:15AM +0800, Chen-Yu Tsai wrote:
> >> > +       sclk1_parents[0] = sclk2_name;
> >> > +       sclk1_parents[1] = sclk2d2_name;
> >>
> >> Is there any need to expose these 2 clocks via DT using of_clk_add_provider?
> >
> > No, as far as I'm aware, there's no user external to this clock
> > driver.
> >
> >> Note that these complex clock trees within a clock node breaks the
> >> assigned-clock-parents mechanism, as you can no longer specify the output
> >> clock's direct parents.
> >
> > There's no point of changing the parent either. Hardware blocks are
> > always connected to the leaf clock (sclk1). We could also model it as
> > an extra 1-bit divider, which would simplify a bit the logic though.
> 
> Probably not. You still have a gate to handle. It's just moving the
> divider from 1 clock to the other. I think the current approach of
> modeling it like the hardware is better.

Not really if you model it using sclk2 being a mux + gate, and sclk1
being a divider + gate. It works great using the composite clocks.

> About reparenting, what I meant was if sclk2 is not exposed through
> of_clk_add_provider, then we can't do assigned-clocks stuff on it,
> like setting a default parent or making each channel use a different
> source pll.

And we don't really want to. Using the divider allow us to simply set
the rate of sclk1, and the mux / divider will do the rest. Since only
sclk1 is exposed to the rest of the system, we do not really care
about the rate of sclk2 anyway.

> What I'm saying is if it is not expected to work with another core
> binding, we should probably note it somewhere.

Indeed.

Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 01/19] clk: sunxi: Add display clock
  2015-11-12 20:31       ` Stephen Boyd
@ 2015-11-19 15:42         ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-19 15:42 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Mike Turquette, David Airlie, Thierry Reding, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Wynter Woods, Boris Brezillon,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

On Thu, Nov 12, 2015 at 12:31:54PM -0800, Stephen Boyd wrote:
> On 11/06, Maxime Ripard wrote:
> > Hi Stephen,
> > 
> > Thanks for your feedback!
> > 
> > On Fri, Oct 30, 2015 at 02:29:02PM -0700, Stephen Boyd wrote:
> > > > +
> > > > +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> > > > +	if (!mux)
> > > [..]
> > > > +		goto free_reset;
> > > > +	}
> > > > +
> > > > +	return;
> > > > +
> > > > +free_reset:
> > > > +	kfree(reset_data);
> > > > +free_clk:
> > > > +	clk_unregister(clk);
> > > 
> > > We really ought to have a clk_composite_unregister() API.
> > 
> > Can we?
> > 
> > We can always unregister the clock itself, but do we have a way to
> > retrieve the structure that has been allocated in there?
> > 
> > (note that it also applies to the generic clocks registration: muxes,
> > dividers, and so on).
> 
> Yes we have a way. We've done the same sort of design for other
> generic clocks. Do the __clk_get_hw() thing like in clk-divider.c

Ack. I'll cook up a patch for this then.

Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

* Re: [PATCH 05/19] clk: sunxi: add DRAM gates
  2015-11-13  8:08     ` Chen-Yu Tsai
@ 2015-11-19 15:43       ` Maxime Ripard
  0 siblings, 0 replies; 57+ messages in thread
From: Maxime Ripard @ 2015-11-19 15:43 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Hans de Goede, Alexander Kaplan,
	Wynter Woods, Boris Brezillon, Thomas Petazzoni, Rob Clark,
	Daniel Vetter

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

On Fri, Nov 13, 2015 at 04:08:53PM +0800, Chen-Yu Tsai wrote:
> On Mon, Nov 9, 2015 at 12:18 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> > On Fri, Oct 30, 2015 at 10:20 PM, Maxime Ripard
> > <maxime.ripard@free-electrons.com> wrote:
> >> The Allwinner SoCs have a gate controller to gate the access to the DRAM
> >> clock to the some devices that need to access the DRAM directly (mostly
> >> display / image related IPs).
> >>
> >> Use a simple gates driver to support it.
> >>
> >> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> >
> > Acked-by: Chen-Yu Tsai <wens@csie.org>
> >
> >> ---
> >>  drivers/clk/sunxi/clk-simple-gates.c | 2 ++
> >>  1 file changed, 2 insertions(+)
> >>
> >> diff --git a/drivers/clk/sunxi/clk-simple-gates.c b/drivers/clk/sunxi/clk-simple-gates.c
> >> index 0214c6548afd..5666c767fa14 100644
> >> --- a/drivers/clk/sunxi/clk-simple-gates.c
> >> +++ b/drivers/clk/sunxi/clk-simple-gates.c
> >> @@ -112,6 +112,8 @@ CLK_OF_DECLARE(sun5i_a13_apb0, "allwinner,sun5i-a13-apb0-gates-clk",
> >>                sunxi_simple_gates_init);
> >>  CLK_OF_DECLARE(sun5i_a13_apb1, "allwinner,sun5i-a13-apb1-gates-clk",
> >>                sunxi_simple_gates_init);
> >> +CLK_OF_DECLARE(sun5i_a13_dram, "allwinner,sun5i-a13-dram-gates-clk",
> >> +              sunxi_simple_gates_init);
> 
> Nit: Since the compatible added is sun5i, could you mention it in the
> commit message,
> to avoid confusion when we do this for the other families?

It will be fixed in the v2.

Thanks!
Maxime

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

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

end of thread, other threads:[~2015-11-19 15:43 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-30 14:20 [PATCH 00/19] drm: Add Allwinner A10 display engine support Maxime Ripard
2015-10-30 14:20 ` [PATCH 01/19] clk: sunxi: Add display clock Maxime Ripard
2015-10-30 21:29   ` Stephen Boyd
2015-11-06 23:39     ` Maxime Ripard
2015-11-12 20:31       ` Stephen Boyd
2015-11-19 15:42         ` Maxime Ripard
2015-10-31 10:28   ` Chen-Yu Tsai
2015-11-06 19:42     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 02/19] clk: sunxi: Add PLL3 clock Maxime Ripard
2015-10-30 21:32   ` Stephen Boyd
2015-10-30 14:20 ` [PATCH 03/19] clk: sunxi: Add TCON channel0 clock Maxime Ripard
2015-10-31 10:19   ` Chen-Yu Tsai
2015-11-06 22:11     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 04/19] clk: sunxi: Add TCON channel1 clock Maxime Ripard
2015-10-30 21:37   ` Stephen Boyd
2015-11-07  0:11     ` Maxime Ripard
2015-10-31  9:53   ` Chen-Yu Tsai
2015-11-07  0:01     ` Maxime Ripard
2015-11-09  3:36       ` Chen-Yu Tsai
2015-11-19 15:35         ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 05/19] clk: sunxi: add DRAM gates Maxime Ripard
2015-11-09  4:18   ` Chen-Yu Tsai
2015-11-13  8:08     ` Chen-Yu Tsai
2015-11-19 15:43       ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 06/19] clk: sunxi: Add Allwinner R8 AHB gates support Maxime Ripard
2015-10-30 16:01   ` Chen-Yu Tsai
2015-10-30 16:33     ` Hans de Goede
2015-10-30 14:20 ` [PATCH 07/19] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
2015-10-30 17:32   ` Thierry Reding
2015-11-07  0:44     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 08/19] drm: Add Allwinner A10 Display Engine support Maxime Ripard
2015-10-30 14:44   ` Daniel Vetter
2015-11-11 22:14     ` Maxime Ripard
2015-11-16 15:04       ` Daniel Vetter
2015-10-30 14:20 ` [PATCH 09/19] drm: sun4i: Add DT bindings documentation Maxime Ripard
2015-10-30 16:40   ` Rob Herring
2015-10-30 17:37     ` Thierry Reding
2015-11-01 14:28       ` Rob Herring
2015-11-06 22:32     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 10/19] drm: sun4i: Add RGB output Maxime Ripard
2015-10-30 14:20 ` [PATCH 11/19] drm: sun4i: Add composite output Maxime Ripard
2015-11-02  2:53   ` [linux-sunxi] " Jonathan Liu
2015-11-07  0:35     ` Maxime Ripard
2015-10-30 14:20 ` [PATCH 12/19] drm: sun4i: tv: Add PAL output standard Maxime Ripard
2015-10-30 14:20 ` [PATCH 13/19] drm: sun4i: tv: Add NTSC " Maxime Ripard
2015-10-30 14:21 ` [PATCH 14/19] ARM: sun5i: dt: Add pll3 and pll7 clocks Maxime Ripard
2015-11-09  4:24   ` Chen-Yu Tsai
2015-10-30 14:21 ` [PATCH 15/19] ARM: sun5i: dt: Add display and TCON clocks Maxime Ripard
2015-10-30 14:21 ` [PATCH 16/19] ARM: sun5i: dt: Add DRAM gates Maxime Ripard
2015-10-30 14:21 ` [PATCH 17/19] ARM: sun5i: dt: Add display blocks to the DTSI Maxime Ripard
2015-10-30 14:21 ` [PATCH 18/19] ARM: sun5i: r8: Add AHB gates " Maxime Ripard
2015-10-30 14:21 ` [PATCH 19/19] ARM: sun5i: chip: Enable the TV Encoder Maxime Ripard
2015-10-30 15:20   ` Chen-Yu Tsai
2015-11-06 19:37     ` Maxime Ripard
2015-10-30 14:52 ` [PATCH 00/19] drm: Add Allwinner A10 display engine support Daniel Vetter
2015-11-12  5:12   ` Maxime Ripard
2015-11-09  3:43 ` Chen-Yu Tsai

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