LKML Archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/26] drm: Add Allwinner A10 display engine support
@ 2016-01-14 15:24 Maxime Ripard
  2016-01-14 15:24 ` [PATCH v2 01/26] reset: Move DT cell size check to the core Maxime Ripard
                   ` (26 more replies)
  0 siblings, 27 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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.

Let me know what you think,
Maxime

Changes from v1:
  - Rebased on top of 4.4

  - Merged the clock drivers for the display and TCON channel 0 clocks
  - Replaced the container_of calls in the display reset clocks to an
    inline function
  - Checked the return code of of_clk_parent_fill in the clocks
    drivers
  - Checked the return code of of_clk_add_provider in the tcon-ch1 and
    PLL3 clocks
  - Added missing clocks headers
  - Created a composite clock unregister function

  - Moved the binding documentation to
    Documentation/devicetree/bindings/display
  - Added the clocks binding documentation
  - Added the Olimex vendor to the list of DT vendors
  - Moved to the OF graph representation and the component framework

  - Moved the reset cells count check into the reset framework to
    avoid duplicating the code in every xlate implementation.
  - Made the reset_ops const

  - Reworked the DRM cmdline mode parsing code to allow named mode
  - Fixed the TV mode lookup when the mode name is not present (for
    example because it was given by the userspace)

  - Made the driver outputs optional (to avoid crashing when a board
    doesn't have either a panel or a composite output enabled)
  - Added multiple plane support with transparency
  - Moved the backend registers writes commit in the CRTC atomic_flush
    callback
  - Removed the load / unload functions
  - Removed the enabled booleans in my private structure and removed
    the implicit call to disable_unused_functions in the DRM core to
    push it in the drivers.
  - Fixed a few bitmasks on some bitfields definition
  - Fixed the RGB connector mode validation that was not testing the
    right values

Matthias Brugger (1):
  clk: Add regmap support

Maxime Ripard (25):
  reset: Move DT cell size check to the core
  reset: Make reset_control_ops const
  clk: composite: Add unregister function
  clk: sunxi: Add display and TCON0 clocks driver
  clk: sunxi: Add PLL3 clock
  clk: sunxi: Add TCON channel1 clock
  clk: sun5i: add DRAM gates
  ARM: sun5i: dt: Add pll3 and pll7 clocks
  ARM: sun5i: a13: Add display and TCON clocks
  ARM: sun5i: Add DRAM gates
  ARM: sun5i: Add TV encoder gate to the DTSI
  drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  drm/modes: Rewrite the command line parser
  drm/modes: Support modes names on the command line
  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: r8: Add display blocks to the DTSI
  ARM: sun5i: chip: Enable the TV Encoder
  devicetree: Add olimex vendor prefix
  drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
  DO NOT MERGE: ARM: sun5i: chip: Enable the LCD panel

 Documentation/devicetree/bindings/clock/sunxi.txt  |   5 +
 .../display/panel/olimex,lcd-olinuxino-43-ts.txt   |   7 +
 .../bindings/display/sunxi/sun4i-drm.txt           | 228 +++++++
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 arch/arm/boot/dts/sun5i-a10s.dtsi                  |   7 +-
 arch/arm/boot/dts/sun5i-a13.dtsi                   |  46 +-
 arch/arm/boot/dts/sun5i-r8-chip.dts                |  17 +
 arch/arm/boot/dts/sun5i-r8.dtsi                    | 139 ++++-
 arch/arm/boot/dts/sun5i.dtsi                       |  62 ++
 drivers/clk/Makefile                               |   1 +
 drivers/clk/clk-composite.c                        |  15 +
 drivers/clk/clk-divider.c                          |  68 ++-
 drivers/clk/clk-gate.c                             |  54 +-
 drivers/clk/clk-io.c                               |  48 ++
 drivers/clk/clk-io.h                               |  22 +
 drivers/clk/clk-mux.c                              |  94 ++-
 drivers/clk/sunxi/Makefile                         |   3 +
 drivers/clk/sunxi/clk-simple-gates.c               |   2 +
 drivers/clk/sunxi/clk-sun4i-display.c              | 241 ++++++++
 drivers/clk/sunxi/clk-sun4i-pll3.c                 |  90 +++
 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c             | 154 +++++
 drivers/gpu/drm/Kconfig                            |   2 +
 drivers/gpu/drm/Makefile                           |   3 +-
 drivers/gpu/drm/drm_crtc.c                         |   3 +-
 drivers/gpu/drm/drm_fb_cma_helper.c                |   3 -
 drivers/gpu/drm/drm_fb_helper.c                    |   4 +
 drivers/gpu/drm/drm_modes.c                        | 327 ++++++----
 drivers/gpu/drm/imx/imx-drm-core.c                 |   1 +
 drivers/gpu/drm/panel/panel-simple.c               |  26 +
 drivers/gpu/drm/sti/sti_drv.c                      |   1 +
 drivers/gpu/drm/sun4i/Kconfig                      |  14 +
 drivers/gpu/drm/sun4i/Makefile                     |  12 +
 drivers/gpu/drm/sun4i/sun4i_backend.c              | 321 ++++++++++
 drivers/gpu/drm/sun4i/sun4i_backend.h              | 160 +++++
 drivers/gpu/drm/sun4i/sun4i_crtc.c                 | 120 ++++
 drivers/gpu/drm/sun4i/sun4i_crtc.h                 |  30 +
 drivers/gpu/drm/sun4i/sun4i_drv.c                  | 325 ++++++++++
 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                | 160 +++++
 drivers/gpu/drm/sun4i/sun4i_layer.h                |  30 +
 drivers/gpu/drm/sun4i/sun4i_rgb.c                  | 229 +++++++
 drivers/gpu/drm/sun4i/sun4i_rgb.h                  |  18 +
 drivers/gpu/drm/sun4i/sun4i_tcon.c                 | 521 ++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_tcon.h                 | 177 ++++++
 drivers/gpu/drm/sun4i/sun4i_tv.c                   | 675 +++++++++++++++++++++
 drivers/gpu/drm/tilcdc/tilcdc_drv.c                |   1 +
 drivers/reset/core.c                               |   6 +-
 include/drm/drm_modes.h                            |   1 +
 include/linux/clk-provider.h                       |  55 +-
 include/linux/reset-controller.h                   |   2 +-
 52 files changed, 4455 insertions(+), 179 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt
 create mode 100644 Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
 create mode 100644 drivers/clk/clk-io.c
 create mode 100644 drivers/clk/clk-io.h
 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-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

-- 
2.6.4

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

* [PATCH v2 01/26] reset: Move DT cell size check to the core
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-15 15:50   ` Philipp Zabel
  2016-01-14 15:24 ` [PATCH v2 02/26] reset: Make reset_control_ops const Maxime Ripard
                   ` (25 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

The core currently doesn't check that the DT cell size matches what the
driver declares, which means that every xlate function needs to duplicate
that check.

Make sure that of_reset_control_get checks for this to avoid duplication
and errors.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/reset/core.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 7955e00d04d4..d53b2b980bdd 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -46,9 +46,6 @@ struct reset_control {
 static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
 			  const struct of_phandle_args *reset_spec)
 {
-	if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
-		return -EINVAL;
-
 	if (reset_spec->args[0] >= rcdev->nr_resets)
 		return -EINVAL;
 
@@ -182,6 +179,9 @@ struct reset_control *of_reset_control_get(struct device_node *node,
 		return ERR_PTR(-EPROBE_DEFER);
 	}
 
+	if (WARN_ON(args.args_count != rcdev->of_reset_n_cells))
+		return ERR_PTR(-EINVAL);
+
 	rstc_id = rcdev->of_xlate(rcdev, &args);
 	if (rstc_id < 0) {
 		mutex_unlock(&reset_controller_list_mutex);
-- 
2.6.4

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

* [PATCH v2 02/26] reset: Make reset_control_ops const
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
  2016-01-14 15:24 ` [PATCH v2 01/26] reset: Move DT cell size check to the core Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-15 15:50   ` Philipp Zabel
  2016-01-14 15:24 ` [PATCH v2 03/26] clk: Add regmap support Maxime Ripard
                   ` (24 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

The ops pointer is holding a pointer to a structure that is usually not
modified. Make it const.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 include/linux/reset-controller.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index ce6b962ffed4..a3a5bcdb1d02 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -38,7 +38,7 @@ struct of_phandle_args;
  * @nr_resets: number of reset controls in this reset controller device
  */
 struct reset_controller_dev {
-	struct reset_control_ops *ops;
+	const struct reset_control_ops *ops;
 	struct module *owner;
 	struct list_head list;
 	struct device_node *of_node;
-- 
2.6.4

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

* [PATCH v2 03/26] clk: Add regmap support
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
  2016-01-14 15:24 ` [PATCH v2 01/26] reset: Move DT cell size check to the core Maxime Ripard
  2016-01-14 15:24 ` [PATCH v2 02/26] reset: Make reset_control_ops const Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-28  7:56   ` Stephen Boyd
  2016-01-14 15:24 ` [PATCH v2 04/26] clk: composite: Add unregister function Maxime Ripard
                   ` (23 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Matthias Brugger, Maxime Ripard

From: Matthias Brugger <matthias.bgg@gmail.com>

Some devices like SoCs from Mediatek need to use the clock
through a regmap interface.
This patch adds regmap support for the simple multiplexer clock,
the divider clock and the clock gate code.

Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/Makefile         |  1 +
 drivers/clk/clk-divider.c    | 68 +++++++++++++++++++++++++-------
 drivers/clk/clk-gate.c       | 54 +++++++++++++++++++------
 drivers/clk/clk-io.c         | 48 ++++++++++++++++++++++
 drivers/clk/clk-io.h         | 22 +++++++++++
 drivers/clk/clk-mux.c        | 94 +++++++++++++++++++++++++++++++++++++-------
 include/linux/clk-provider.h | 54 +++++++++++++++++++++++--
 7 files changed, 298 insertions(+), 43 deletions(-)
 create mode 100644 drivers/clk/clk-io.c
 create mode 100644 drivers/clk/clk-io.h

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 820714c72d36..31a888c0c182 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_COMMON_CLK)	+= clk-mux.o
 obj-$(CONFIG_COMMON_CLK)	+= clk-composite.o
 obj-$(CONFIG_COMMON_CLK)	+= clk-fractional-divider.o
 obj-$(CONFIG_COMMON_CLK)	+= clk-gpio.o
+obj-$(CONFIG_COMMON_CLK)	+= clk-io.o
 ifeq ($(CONFIG_OF), y)
 obj-$(CONFIG_COMMON_CLK)	+= clk-conf.o
 endif
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index 3ace102a2a0a..1ddb353b3fff 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -18,6 +18,8 @@
 #include <linux/string.h>
 #include <linux/log2.h>
 
+#include "clk-io.h"
+
 /*
  * DOC: basic adjustable divider clock that cannot gate
  *
@@ -142,7 +144,8 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
 	struct clk_divider *divider = to_clk_divider(hw);
 	unsigned int val;
 
-	val = clk_readl(divider->reg) >> divider->shift;
+	val = clk_io_readl(hw, divider->reg, divider->regmap, divider->offset);
+	val >>= divider->shift;
 	val &= div_mask(divider->width);
 
 	return divider_recalc_rate(hw, parent_rate, val, divider->table,
@@ -354,7 +357,10 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
 
 	/* if read only, just return current value */
 	if (divider->flags & CLK_DIVIDER_READ_ONLY) {
-		bestdiv = readl(divider->reg) >> divider->shift;
+		bestdiv = clk_io_readl(hw, divider->reg, divider->regmap,
+				       divider->offset);
+
+		bestdiv >>= divider->shift;
 		bestdiv &= div_mask(divider->width);
 		bestdiv = _get_div(divider->table, bestdiv, divider->flags,
 			divider->width);
@@ -400,12 +406,16 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
 
 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
 		val = div_mask(divider->width) << (divider->shift + 16);
+		val |= value << divider->shift;
+		clk_io_writel(hw, divider->reg, divider->regmap,
+			      divider->offset, val);
 	} else {
-		val = clk_readl(divider->reg);
-		val &= ~(div_mask(divider->width) << divider->shift);
+		u32 mask = div_mask(divider->width) << divider->shift;
+
+		val = value << divider->shift;
+		clk_io_update_bits(hw, divider->reg, divider->regmap,
+				   divider->offset, mask, val);
 	}
-	val |= value << divider->shift;
-	clk_writel(val, divider->reg);
 
 	if (divider->lock)
 		spin_unlock_irqrestore(divider->lock, flags);
@@ -424,9 +434,9 @@ EXPORT_SYMBOL_GPL(clk_divider_ops);
 
 static struct clk *_register_divider(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
-		void __iomem *reg, u8 shift, u8 width,
-		u8 clk_divider_flags, const struct clk_div_table *table,
-		spinlock_t *lock)
+		void __iomem *reg, struct regmap *regmap, u32 offset,
+		u8 shift, u8 width, u8 clk_divider_flags,
+		const struct clk_div_table *table, spinlock_t *lock)
 {
 	struct clk_divider *div;
 	struct clk *clk;
@@ -451,7 +461,12 @@ static struct clk *_register_divider(struct device *dev, const char *name,
 	init.num_parents = (parent_name ? 1 : 0);
 
 	/* struct clk_divider assignments */
-	div->reg = reg;
+	if (flags & CLK_USE_REGMAP)
+		div->regmap = regmap;
+	else
+		div->reg = reg;
+
+	div->offset = offset;
 	div->shift = shift;
 	div->width = width;
 	div->flags = clk_divider_flags;
@@ -485,8 +500,8 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
 		void __iomem *reg, u8 shift, u8 width,
 		u8 clk_divider_flags, spinlock_t *lock)
 {
-	return _register_divider(dev, name, parent_name, flags, reg, shift,
-			width, clk_divider_flags, NULL, lock);
+	return _register_divider(dev, name, parent_name, flags, reg, NULL, 0,
+			shift, width, clk_divider_flags, NULL, lock);
 }
 EXPORT_SYMBOL_GPL(clk_register_divider);
 
@@ -510,8 +525,8 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
 		u8 clk_divider_flags, const struct clk_div_table *table,
 		spinlock_t *lock)
 {
-	return _register_divider(dev, name, parent_name, flags, reg, shift,
-			width, clk_divider_flags, table, lock);
+	return _register_divider(dev, name, parent_name, flags, reg, NULL, 0,
+			shift, width, clk_divider_flags, table, lock);
 }
 EXPORT_SYMBOL_GPL(clk_register_divider_table);
 
@@ -530,3 +545,28 @@ void clk_unregister_divider(struct clk *clk)
 	kfree(div);
 }
 EXPORT_SYMBOL_GPL(clk_unregister_divider);
+
+struct clk *clk_regm_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		struct regmap *regmap, u32 offset, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock)
+{
+	flags |= CLK_USE_REGMAP;
+
+	return _register_divider(dev, name, parent_name, flags, NULL, regmap,
+			offset,	shift, width, clk_divider_flags, NULL, lock);
+}
+EXPORT_SYMBOL_GPL(clk_regm_register_divider);
+
+struct clk *clk_regm_register_divider_table(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		struct regmap *regmap, u32 offset, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table,
+		spinlock_t *lock)
+{
+	flags |= CLK_USE_REGMAP;
+
+	return _register_divider(dev, name, parent_name, flags, NULL, regmap,
+			offset,	shift, width, clk_divider_flags, table, lock);
+}
+EXPORT_SYMBOL_GPL(clk_regm_register_divider_table);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index de0b322f5f58..38b558397631 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -16,6 +16,8 @@
 #include <linux/err.h>
 #include <linux/string.h>
 
+#include "clk-io.h"
+
 /**
  * DOC: basic gatable clock which can gate and ungate it's ouput
  *
@@ -46,7 +48,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 	struct clk_gate *gate = to_clk_gate(hw);
 	int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
 	unsigned long uninitialized_var(flags);
-	u32 reg;
+	u32 reg, mask;
 
 	set ^= enable;
 
@@ -59,16 +61,20 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
 		reg = BIT(gate->bit_idx + 16);
 		if (set)
 			reg |= BIT(gate->bit_idx);
-	} else {
-		reg = clk_readl(gate->reg);
 
+		clk_io_writel(hw, gate->reg, gate->regmap, gate->offset, reg);
+	} else {
 		if (set)
-			reg |= BIT(gate->bit_idx);
+			reg = BIT(gate->bit_idx);
 		else
-			reg &= ~BIT(gate->bit_idx);
+			reg = 0x0;
+
+		mask = BIT(gate->bit_idx);
+
+		clk_io_update_bits(hw, gate->reg, gate->regmap, gate->offset,
+				   mask, reg);
 	}
 
-	clk_writel(reg, gate->reg);
 
 	if (gate->lock)
 		spin_unlock_irqrestore(gate->lock, flags);
@@ -93,7 +99,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
 	u32 reg;
 	struct clk_gate *gate = to_clk_gate(hw);
 
-	reg = clk_readl(gate->reg);
+	reg = clk_io_readl(hw, gate->reg, gate->regmap, gate->offset);
 
 	/* if a set bit disables this clk, flip it before masking */
 	if (gate->flags & CLK_GATE_SET_TO_DISABLE)
@@ -122,10 +128,10 @@ EXPORT_SYMBOL_GPL(clk_gate_ops);
  * @clk_gate_flags: gate-specific flags for this clock
  * @lock: shared register lock for this clock
  */
-struct clk *clk_register_gate(struct device *dev, const char *name,
+struct clk *__clk_register_gate(struct device *dev, const char *name,
 		const char *parent_name, unsigned long flags,
-		void __iomem *reg, u8 bit_idx,
-		u8 clk_gate_flags, spinlock_t *lock)
+		void __iomem *reg, struct regmap *regmap, u32 offset,
+		u8 bit_idx, u8 clk_gate_flags, spinlock_t *lock)
 {
 	struct clk_gate *gate;
 	struct clk *clk;
@@ -150,7 +156,12 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 	init.num_parents = (parent_name ? 1 : 0);
 
 	/* struct clk_gate assignments */
-	gate->reg = reg;
+	if (flags & CLK_USE_REGMAP)
+		gate->regmap = regmap;
+	else
+		gate->reg = reg;
+
+	gate->offset = offset;
 	gate->bit_idx = bit_idx;
 	gate->flags = clk_gate_flags;
 	gate->lock = lock;
@@ -163,6 +174,15 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
 	return clk;
 }
+
+struct clk *clk_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	return __clk_register_gate(dev, name, parent_name, flags,
+			reg, NULL, 0, bit_idx, clk_gate_flags, lock);
+}
 EXPORT_SYMBOL_GPL(clk_register_gate);
 
 void clk_unregister_gate(struct clk *clk)
@@ -180,3 +200,15 @@ void clk_unregister_gate(struct clk *clk)
 	kfree(gate);
 }
 EXPORT_SYMBOL_GPL(clk_unregister_gate);
+
+struct clk *clk_regm_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		struct regmap *regmap, u32 offset, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock)
+{
+	flags |= CLK_USE_REGMAP;
+
+	return __clk_register_gate(dev, name, parent_name, flags,
+			NULL, regmap, offset, bit_idx, clk_gate_flags, lock);
+}
+EXPORT_SYMBOL_GPL(clk_regm_register_gate);
diff --git a/drivers/clk/clk-io.c b/drivers/clk/clk-io.c
new file mode 100644
index 000000000000..ceeb64e15ddb
--- /dev/null
+++ b/drivers/clk/clk-io.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 Matthias Brugger <matthias.bgg@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk-provider.h>
+
+void clk_io_writel(struct clk_hw *hw, void __iomem *reg, struct regmap *regmap,
+		   u32 offset, u32 val)
+{
+	if (__clk_get_flags(hw->clk) & CLK_USE_REGMAP)
+		regmap_write(regmap, offset, val);
+	else
+		clk_writel(val, reg);
+}
+
+u32 clk_io_readl(struct clk_hw *hw, void __iomem *reg, struct regmap *regmap,
+		 u32 offset)
+{
+	u32 val;
+
+	if (__clk_get_flags(hw->clk) & CLK_USE_REGMAP)
+		regmap_read(regmap, offset, &val);
+	else
+		val = clk_readl(reg);
+
+	return val;
+}
+
+int clk_io_update_bits(struct clk_hw *hw, void __iomem *reg,
+		       struct regmap *regmap, u32 offset, u32 mask, u32 val)
+{
+	unsigned int tmp;
+
+	if (__clk_get_flags(hw->clk) & CLK_USE_REGMAP)
+		return regmap_update_bits(regmap, offset, mask, val);
+
+	tmp = clk_readl(reg);
+	tmp &= ~mask;
+	tmp |= val;
+	clk_writel(tmp, reg);
+
+	return 0;
+}
diff --git a/drivers/clk/clk-io.h b/drivers/clk/clk-io.h
new file mode 100644
index 000000000000..b5599ba02084
--- /dev/null
+++ b/drivers/clk/clk-io.h
@@ -0,0 +1,22 @@
+/*
+ * linux/drivers/clk/clk-io.h
+ *
+ * Copyright (C) 2015 Matthias Brugger <matthias.bgg@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_CLK_IO_H
+#define __LINUX_CLK_IO_H
+
+#include <linux/clk-provider.h>
+
+void clk_io_writel(struct clk_hw *hw, void __iomem *reg, struct regmap *regmap,
+		   u32 offset, u32 val);
+u32 clk_io_readl(struct clk_hw *hw, void __iomem *reg, struct regmap *regmap,
+		 u32 offset);
+int clk_io_update_bits(struct clk_hw *hw, void __iomem *reg,
+		       struct regmap *regmap, u32 offset, u32 mask, u32 val);
+
+#endif
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 7129c86a79db..d3831eca8b56 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -16,6 +16,8 @@
 #include <linux/io.h>
 #include <linux/err.h>
 
+#include "clk-io.h"
+
 /*
  * DOC: basic adjustable multiplexer clock that cannot gate
  *
@@ -41,7 +43,9 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
 	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
 	 * val = 0x4 really means "bit 2, index starts at bit 0"
 	 */
-	val = clk_readl(mux->reg) >> mux->shift;
+	val = clk_io_readl(hw, mux->reg, mux->regmap, mux->offset);
+
+	val >>= mux->shift;
 	val &= mux->mask;
 
 	if (mux->table) {
@@ -70,6 +74,7 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 	struct clk_mux *mux = to_clk_mux(hw);
 	u32 val;
 	unsigned long flags = 0;
+	int ret = 0;
 
 	if (mux->table)
 		index = mux->table[index];
@@ -89,19 +94,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 
 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
 		val = mux->mask << (mux->shift + 16);
+		val |= index << mux->shift;
+		clk_io_writel(hw, mux->reg, mux->regmap, mux->offset, val);
 	} else {
-		val = clk_readl(mux->reg);
-		val &= ~(mux->mask << mux->shift);
+		u32 mask = mux->mask << mux->shift;
+
+		val = index << mux->shift;
+		ret = clk_io_update_bits(hw, mux->reg, mux->regmap,
+					 mux->offset, mask, val);
 	}
-	val |= index << mux->shift;
-	clk_writel(val, mux->reg);
 
 	if (mux->lock)
 		spin_unlock_irqrestore(mux->lock, flags);
 	else
 		__release(mux->lock);
 
-	return 0;
+	return ret;
 }
 
 const struct clk_ops clk_mux_ops = {
@@ -116,10 +124,11 @@ const struct clk_ops clk_mux_ro_ops = {
 };
 EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
 
-struct clk *clk_register_mux_table(struct device *dev, const char *name,
+struct clk *__clk_register_mux_table(struct device *dev, const char *name,
 		const char * const *parent_names, u8 num_parents,
 		unsigned long flags,
-		void __iomem *reg, u8 shift, u32 mask,
+		void __iomem *reg, struct regmap *regmap,
+		u32 offset, u8 shift, u32 mask,
 		u8 clk_mux_flags, u32 *table, spinlock_t *lock)
 {
 	struct clk_mux *mux;
@@ -152,7 +161,12 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
 	init.num_parents = num_parents;
 
 	/* struct clk_mux assignments */
-	mux->reg = reg;
+	if (flags & CLK_USE_REGMAP)
+		mux->regmap = regmap;
+	else
+		mux->reg = reg;
+
+	mux->offset = offset;
 	mux->shift = shift;
 	mux->mask = mask;
 	mux->flags = clk_mux_flags;
@@ -167,19 +181,40 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
 
 	return clk;
 }
+
+struct clk *clk_register_mux_table(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags, void __iomem *reg, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table, spinlock_t *lock)
+{
+	return __clk_register_mux_table(dev, name, parent_names, num_parents,
+						flags, reg, NULL, 0,
+						shift, mask, clk_mux_flags,
+						table, lock);
+}
 EXPORT_SYMBOL_GPL(clk_register_mux_table);
 
-struct clk *clk_register_mux(struct device *dev, const char *name,
+struct clk *__clk_register_mux(struct device *dev, const char *name,
 		const char * const *parent_names, u8 num_parents,
-		unsigned long flags,
-		void __iomem *reg, u8 shift, u8 width,
+		unsigned long flags, void __iomem *reg, struct regmap *regmap,
+		u32 offset, u8 shift, u8 width,
 		u8 clk_mux_flags, spinlock_t *lock)
 {
 	u32 mask = BIT(width) - 1;
 
-	return clk_register_mux_table(dev, name, parent_names, num_parents,
-				      flags, reg, shift, mask, clk_mux_flags,
-				      NULL, lock);
+	return __clk_register_mux_table(dev, name, parent_names, num_parents,
+					flags, reg, regmap, offset, shift, mask,
+					clk_mux_flags, NULL, lock);
+}
+
+struct clk *clk_register_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags, void __iomem *reg, u8 shift, u8 width,
+		u8 clk_mux_flags, spinlock_t *lock)
+{
+	return __clk_register_mux(dev, name, parent_names, num_parents, flags,
+					reg, NULL, 0, shift, width,
+					clk_mux_flags, lock);
 }
 EXPORT_SYMBOL_GPL(clk_register_mux);
 
@@ -198,3 +233,32 @@ void clk_unregister_mux(struct clk *clk)
 	kfree(mux);
 }
 EXPORT_SYMBOL_GPL(clk_unregister_mux);
+
+struct clk *clk_regm_register_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags, struct regmap *regmap,
+		u32 offset, u8 shift, u8 width,
+		u8 clk_mux_flags, spinlock_t *lock)
+{
+	flags |= CLK_USE_REGMAP;
+
+	return __clk_register_mux(dev, name, parent_names, num_parents, flags,
+					NULL, regmap, offset, shift, width,
+					clk_mux_flags, lock);
+}
+EXPORT_SYMBOL_GPL(clk_regm_register_mux);
+
+struct clk *clk_regm_register_mux_table(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags, struct regmap *regmap,
+		u32 offset, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table, spinlock_t *lock)
+{
+	flags |= CLK_USE_REGMAP;
+
+	return __clk_register_mux_table(dev, name, parent_names, num_parents,
+					flags, NULL, regmap, offset,
+					shift, mask, clk_mux_flags,
+					table, lock);
+}
+EXPORT_SYMBOL_GPL(clk_regm_register_mux_table);
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index c56988ac63f7..0c55a37cf8f7 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -13,6 +13,7 @@
 
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/regmap.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -31,6 +32,7 @@
 #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
 #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
 #define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after notifications */
+#define CLK_USE_REGMAP		BIT(10) /* uses regmap to access registers */
 
 struct clk;
 struct clk_hw;
@@ -290,6 +292,8 @@ void of_fixed_clk_setup(struct device_node *np);
  *
  * @hw:		handle between common and hardware-specific interfaces
  * @reg:	register controlling gate
+ * @regmap:	regmap used to control the gate
+ * @offset:	offset inside the regmap
  * @bit_idx:	single bit controlling gate
  * @flags:	hardware-specific flags
  * @lock:	register lock
@@ -307,7 +311,11 @@ void of_fixed_clk_setup(struct device_node *np);
  */
 struct clk_gate {
 	struct clk_hw hw;
-	void __iomem	*reg;
+	union {
+		void __iomem	*reg;
+		struct regmap	*regmap;
+	};
+	u32		offset;
 	u8		bit_idx;
 	u8		flags;
 	spinlock_t	*lock;
@@ -323,6 +331,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 		u8 clk_gate_flags, spinlock_t *lock);
 void clk_unregister_gate(struct clk *clk);
 
+struct clk *clk_regm_register_gate(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		struct regmap *regmap, u32 offset, u8 bit_idx,
+		u8 clk_gate_flags, spinlock_t *lock);
+
 struct clk_div_table {
 	unsigned int	val;
 	unsigned int	div;
@@ -333,6 +346,8 @@ struct clk_div_table {
  *
  * @hw:		handle between common and hardware-specific interfaces
  * @reg:	register containing the divider
+ * @regmap:	regmap used to access the divider
+ * @offest:	offset inside the regmap
  * @shift:	shift to the divider bit field
  * @width:	width of the divider bit field
  * @table:	array of value/divider pairs, last entry should have div = 0
@@ -367,7 +382,11 @@ struct clk_div_table {
  */
 struct clk_divider {
 	struct clk_hw	hw;
-	void __iomem	*reg;
+	union {
+		void __iomem	*reg;
+		struct regmap	*regmap;
+	};
+	u32		offset;
 	u8		shift;
 	u8		width;
 	u8		flags;
@@ -406,11 +425,24 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
 		spinlock_t *lock);
 void clk_unregister_divider(struct clk *clk);
 
+struct clk *clk_regm_register_divider(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		struct regmap *regmap, u32 offset, u8 shift, u8 width,
+		u8 clk_divider_flags, spinlock_t *lock);
+
+struct clk *clk_regm_register_divider_table(struct device *dev,
+		const char *name, const char *parent_name, unsigned long flags,
+		struct regmap *regmap, u32 offset, u8 shift, u8 width,
+		u8 clk_divider_flags, const struct clk_div_table *table,
+		spinlock_t *lock);
+
 /**
  * struct clk_mux - multiplexer clock
  *
  * @hw:		handle between common and hardware-specific interfaces
  * @reg:	register controlling multiplexer
+ * @regmap:	regmap for controlling multiplexer
+ * @offset:	offset inside the regmap
  * @shift:	shift to multiplexer bit field
  * @width:	width of mutliplexer bit field
  * @flags:	hardware-specific flags
@@ -431,8 +463,12 @@ void clk_unregister_divider(struct clk *clk);
  */
 struct clk_mux {
 	struct clk_hw	hw;
-	void __iomem	*reg;
+	union {
+		void __iomem	*reg;
+		struct regmap	*regmap;
+	};
 	u32		*table;
+	u32		offset;
 	u32		mask;
 	u8		shift;
 	u8		flags;
@@ -462,6 +498,18 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
 
 void clk_unregister_mux(struct clk *clk);
 
+struct clk *clk_regm_register_mux_table(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags, struct regmap *regmap,
+		u32 offset, u8 shift, u32 mask,
+		u8 clk_mux_flags, u32 *table, spinlock_t *lock);
+
+struct clk *clk_regm_register_mux(struct device *dev, const char *name,
+		const char * const *parent_names, u8 num_parents,
+		unsigned long flags, struct regmap *regmap,
+		u32 offset, u8 shift, u8 width,
+		u8 clk_mux_flags, spinlock_t *lock);
+
 void of_fixed_factor_clk_setup(struct device_node *node);
 
 /**
-- 
2.6.4

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

* [PATCH v2 04/26] clk: composite: Add unregister function
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (2 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 03/26] clk: Add regmap support Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-14 15:24 ` [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver Maxime Ripard
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

The composite clock didn't have any unregistration function, which forced
us to use clk_unregister directly on it.

While it was already not great from an API point of view, it also meant
that we were leaking the clk_composite structure allocated in
clk_register_composite.

Add a clk_unregister_composite function to fix this.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/clk-composite.c  | 15 +++++++++++++++
 include/linux/clk-provider.h |  1 +
 2 files changed, 16 insertions(+)

diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 4735de0660cc..f4c38f209594 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -288,3 +288,18 @@ err:
 	kfree(composite);
 	return clk;
 }
+
+void clk_unregister_composite(struct clk *clk)
+{
+	struct clk_composite *composite;
+	struct clk_hw *hw;
+
+	hw = __clk_get_hw(clk);
+	if (!hw)
+		return;
+
+	composite = to_clk_composite(hw);
+
+	clk_unregister(clk);
+	kfree(composite);
+}
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 0c55a37cf8f7..76c34a9622db 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -632,6 +632,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
 		struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
 		struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
 		unsigned long flags);
+void clk_unregister_composite(struct clk *clk);
 
 /***
  * struct clk_gpio_gate - gpio gated clock
-- 
2.6.4

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

* [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (3 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 04/26] clk: composite: Add unregister function Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-15  3:01   ` Rob Herring
                     ` (2 more replies)
  2016-01-14 15:24 ` [PATCH v2 06/26] clk: sunxi: Add PLL3 clock Maxime Ripard
                   ` (21 subsequent siblings)
  26 siblings, 3 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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), that have a lot in common with
the clock to drive the first TCON channel.

Add a driver to support both.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 Documentation/devicetree/bindings/clock/sunxi.txt |   2 +
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-sun4i-display.c             | 241 ++++++++++++++++++++++
 3 files changed, 244 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 8a47b77abfca..5360554a7d3f 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -55,6 +55,7 @@ Required properties:
 	"allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
 	"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
 	"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
+	"allwinner,sun4i-a10-display-clk" - for the display clocks on the A10
 	"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
 	"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
 	"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
@@ -64,6 +65,7 @@ Required properties:
 	"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
 	"allwinner,sun7i-a20-out-clk" - for the external output clocks
 	"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
+	"allwinner,sun4i-a10-tcon-ch0-clk" - for the TCON channel 0 clock on the A10
 	"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
 	"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
 	"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index cb4c299214ce..a991cd8ca509 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -10,6 +10,7 @@ obj-y += clk-a10-pll2.o
 obj-y += clk-a20-gmac.o
 obj-y += clk-mod0.o
 obj-y += clk-simple-gates.o
+obj-y += clk-sun4i-display.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-display.c b/drivers/clk/sunxi/clk-sun4i-display.c
new file mode 100644
index 000000000000..9dc6894f0934
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun4i-display.c
@@ -0,0 +1,241 @@
+/*
+ * 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/kernel.h>
+#include <linux/of_address.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+struct sun4i_a10_display_clk_data {
+	bool	has_div;
+	bool	has_rst;
+	u8	parents;
+
+	u8	offset_en;
+	u8	offset_div;
+	u8	offset_mux;
+	u8	offset_rst;
+
+	u8	width_div;
+	u8	width_mux;
+};
+
+struct reset_data {
+	void __iomem			*reg;
+	spinlock_t			*lock;
+	struct reset_controller_dev	rcdev;
+	u8				offset;
+};
+
+static DEFINE_SPINLOCK(sun4i_a10_display_lock);
+
+static inline struct reset_data *rcdev_to_reset_data(struct reset_controller_dev *rcdev)
+{
+	return container_of(rcdev, struct reset_data, rcdev);
+};
+
+static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev,
+				    unsigned long id)
+{
+	struct reset_data *data = rcdev_to_reset_data(rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg & ~BIT(data->offset), 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 = rcdev_to_reset_data(rcdev);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(data->lock, flags);
+
+	reg = readl(data->reg);
+	writel(reg | BIT(data->offset), 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 = rcdev_to_reset_data(rcdev);
+
+	return !(readl(data->reg) & BIT(data->offset));
+}
+
+static const 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)
+{
+	/* We only have a single reset signal */
+	return 0;
+}
+
+static void __init sun4i_a10_display_init(struct device_node *node,
+					  struct sun4i_a10_display_clk_data *data)
+{
+	const char *parents[data->parents];
+	const char *clk_name = node->name;
+	struct reset_data *reset_data;
+	struct clk_divider *div = NULL;
+	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;
+	}
+
+	of_clk_parent_fill(node, parents, data->parents);
+
+	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+	if (!mux)
+		return;
+
+	mux->reg = reg;
+	mux->shift = data->offset_mux;
+	mux->mask = (1 << data->width_mux) - 1;
+	mux->lock = &sun4i_a10_display_lock;
+
+	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+	if (!gate)
+		goto free_mux;
+
+	gate->reg = reg;
+	gate->bit_idx = data->offset_en;
+	gate->lock = &sun4i_a10_display_lock;
+
+	if (data->has_div) {
+		div = kzalloc(sizeof(*div), GFP_KERNEL);
+		if (!div)
+			goto free_gate;
+
+		div->reg = reg;
+		div->shift = data->offset_div;
+		div->width = data->width_div;
+		div->lock = &sun4i_a10_display_lock;
+	}
+
+	clk = clk_register_composite(NULL, clk_name,
+				     parents, data->parents,
+				     &mux->hw, &clk_mux_ops,
+				     data->has_div ? &div->hw : NULL,
+				     data->has_div ? &clk_divider_ops : NULL,
+				     &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);
+
+	if (!data->has_rst)
+		return;
+
+	reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
+	if (!reset_data)
+		goto free_clk;
+
+	reset_data->reg = reg;
+	reset_data->offset = data->offset_rst;
+	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:
+	if (data->has_div)
+		kfree(div);
+free_gate:
+	kfree(gate);
+free_mux:
+	kfree(mux);
+}
+
+static struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data = {
+	.has_rst	= true,
+	.parents	= 4,
+	.offset_en	= 31,
+	.offset_rst	= 29,
+	.offset_mux	= 24,
+	.width_mux	= 2,
+};
+
+static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node)
+{
+	sun4i_a10_display_init(node, &sun4i_a10_tcon_ch0_data);
+}
+CLK_OF_DECLARE(sun4i_a10_tcon_ch0, "allwinner,sun4i-a10-tcon-ch0-clk",
+	       sun4i_a10_tcon_ch0_setup);
+
+static struct sun4i_a10_display_clk_data sun4i_a10_display_data = {
+	.has_div	= true,
+	.parents	= 3,
+	.offset_en	= 31,
+	.offset_rst	= 30,
+	.offset_mux	= 24,
+	.offset_div	= 0,
+	.width_mux	= 2,
+	.width_div	= 4,
+};
+
+static void __init sun4i_a10_display_setup(struct device_node *node)
+{
+	sun4i_a10_display_init(node, &sun4i_a10_display_data);
+}
+CLK_OF_DECLARE(sun4i_a10_display, "allwinner,sun4i-a10-display-clk",
+	       sun4i_a10_display_setup);
-- 
2.6.4

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

* [PATCH v2 06/26] clk: sunxi: Add PLL3 clock
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (4 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-15  3:02   ` Rob Herring
  2016-01-16 16:05   ` Chen-Yu Tsai
  2016-01-14 15:24 ` [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock Maxime Ripard
                   ` (20 subsequent siblings)
  26 siblings, 2 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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>
---
 Documentation/devicetree/bindings/clock/sunxi.txt |  1 +
 drivers/clk/sunxi/Makefile                        |  1 +
 drivers/clk/sunxi/clk-sun4i-pll3.c                | 90 +++++++++++++++++++++++
 3 files changed, 92 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun4i-pll3.c

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index 5360554a7d3f..bb9fb78dcff8 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -10,6 +10,7 @@ Required properties:
 	"allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
 	"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
 	"allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
+	"allwinner,sun4i-a10-pll3-clk" - for the video PLL clock on A10
 	"allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80
 	"allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
 	"allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index a991cd8ca509..40c32ffd912c 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -11,6 +11,7 @@ obj-y += clk-a20-gmac.o
 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-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..6c9c2210b6b2
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun4i-pll3.c
@@ -0,0 +1,90 @@
+/*
+ * 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.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_multiplier *mult;
+	struct clk_gate *gate;
+	void __iomem *reg;
+	struct clk *clk;
+	int ret;
+
+	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 err_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_multiplier_ops,
+				     &gate->hw, &clk_gate_ops,
+				     0);
+	if (IS_ERR(clk)) {
+		pr_err("%s: Couldn't register the clock\n", clk_name);
+		goto err_free_mult;
+	}
+
+	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
+	if (WARN_ON(ret))
+		goto err_clk_unregister;
+
+	return;
+
+err_clk_unregister:
+	clk_unregister_composite(clk);
+err_free_mult:
+	kfree(mult);
+err_free_gate:
+	kfree(gate);
+}
+
+CLK_OF_DECLARE(sun4i_a10_pll3, "allwinner,sun4i-a10-pll3-clk",
+	       sun4i_a10_pll3_setup);
-- 
2.6.4

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

* [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (5 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 06/26] clk: sunxi: Add PLL3 clock Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-15  3:03   ` Rob Herring
  2016-01-16 16:36   ` Chen-Yu Tsai
  2016-01-14 15:24 ` [PATCH v2 08/26] clk: sun5i: add DRAM gates Maxime Ripard
                   ` (19 subsequent siblings)
  26 siblings, 2 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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>
---
 Documentation/devicetree/bindings/clock/sunxi.txt |   1 +
 drivers/clk/sunxi/Makefile                        |   1 +
 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c            | 154 ++++++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index bb9fb78dcff8..fe34fc56e803 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -67,6 +67,7 @@ Required properties:
 	"allwinner,sun7i-a20-out-clk" - for the external output clocks
 	"allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
 	"allwinner,sun4i-a10-tcon-ch0-clk" - for the TCON channel 0 clock on the A10
+	"allwinner,sun4i-a10-tcon-ch1-clk" - for the TCON channel 1 clock on the A10
 	"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
 	"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
 	"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 40c32ffd912c..0a20873cd103 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-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..51ddc38821f7
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
@@ -0,0 +1,154 @@
+/*
+ * 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.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_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_DIV_WIDTH	1
+#define SUN4I_A10_TCON_CH1_SCLK1_DIV_SHIFT	11
+
+static DEFINE_SPINLOCK(sun4i_a10_tcon_ch1_lock);
+
+static void __init sun4i_a10_tcon_ch1_setup(struct device_node *node)
+{
+	const char *sclk2_parents[SUN4I_A10_TCON_CH1_SCLK2_PARENTS];
+	const char *sclk1_name = node->name;
+	const char *sclk2_name;
+	struct clk_divider *sclk1_div, *sclk2_div;
+	struct clk_gate *sclk1_gate, *sclk2_gate;
+	struct clk_mux *sclk2_mux;
+	struct clk *sclk1, *sclk2;
+	void __iomem *reg;
+	int i, ret;
+
+	of_property_read_string(node, "clock-output-names",
+				&sclk1_name);
+
+	sclk2_name = kasprintf(GFP_KERNEL, "%s2", sclk1_name);
+	if (!sclk2_name)
+		return;
+
+	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;
+	}
+
+	sclk1_div = kzalloc(sizeof(*sclk1_div), GFP_KERNEL);
+	if (!sclk1_div)
+		goto free_sclk2;
+
+	sclk1_div->reg = reg;
+	sclk1_div->shift = SUN4I_A10_TCON_CH1_SCLK1_DIV_SHIFT;
+	sclk1_div->width = SUN4I_A10_TCON_CH1_SCLK1_DIV_WIDTH;
+	sclk1_div->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, &sclk2_name, 1,
+				       NULL, NULL,
+				       &sclk1_div->hw, &clk_divider_ops,
+				       &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;
+	}
+
+	ret = of_clk_add_provider(node, of_clk_src_simple_get, sclk1);
+	if (WARN_ON(ret))
+		goto free_sclk1;
+
+	return;
+
+free_sclk1:
+	clk_unregister_composite(sclk1);
+free_sclk1_gate:
+	kfree(sclk1_gate);
+free_sclk1_mux:
+	kfree(sclk1_div);
+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.4

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

* [PATCH v2 08/26] clk: sun5i: add DRAM gates
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (6 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-15  3:04   ` Rob Herring
  2016-01-14 15:24 ` [PATCH v2 09/26] ARM: sun5i: dt: Add pll3 and pll7 clocks Maxime Ripard
                   ` (18 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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 the one found in the A13 / R8 SoCs.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Chen-Yu Tsai <wens@csie.org>
---
 Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
 drivers/clk/sunxi/clk-simple-gates.c              | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
index fe34fc56e803..2a76cc3718d4 100644
--- a/Documentation/devicetree/bindings/clock/sunxi.txt
+++ b/Documentation/devicetree/bindings/clock/sunxi.txt
@@ -57,6 +57,7 @@ Required properties:
 	"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
 	"allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
 	"allwinner,sun4i-a10-display-clk" - for the display clocks on the A10
+	"allwinner,sun5i-a13-dram-gates-clk" - for the DRAM gates on A13
 	"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
 	"allwinner,sun4i-a10-mmc-clk" - for the MMC clock
 	"allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
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.4

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

* [PATCH v2 09/26] ARM: sun5i: dt: Add pll3 and pll7 clocks
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (7 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 08/26] clk: sun5i: add DRAM gates Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-14 15:24 ` [PATCH v2 10/26] ARM: sun5i: a13: Add display and TCON clocks Maxime Ripard
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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>
Acked-by: Chen-Yu Tsai <wens@csie.org>
---
 arch/arm/boot/dts/sun5i.dtsi | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index 59a9426e3bd4..0840612b5ed6 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,23 @@
 					     "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";
+		};
+
+		pll3x2: pll3x2_clk {
+			compatible = "fixed-factor-clock";
+			#clock-cells = <0>;
+			clock-div = <1>;
+			clock-mult = <2>;
+			clocks = <&pll3>;
+			clock-output-names = "pll3-2x";
+		};
+
 		pll4: clk@01c20018 {
 			#clock-cells = <0>;
 			compatible = "allwinner,sun4i-a10-pll1-clk";
@@ -136,6 +162,23 @@
 			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";
+		};
+
+		pll7x2: pll7x2_clk {
+			compatible = "fixed-factor-clock";
+			#clock-cells = <0>;
+			clock-div = <1>;
+			clock-mult = <2>;
+			clocks = <&pll7>;
+			clock-output-names = "pll7-2x";
+		};
+
 		/* dummy is 200M */
 		cpu: cpu@01c20054 {
 			#clock-cells = <0>;
-- 
2.6.4

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

* [PATCH v2 10/26] ARM: sun5i: a13: Add display and TCON clocks
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (8 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 09/26] ARM: sun5i: dt: Add pll3 and pll7 clocks Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-16 17:06   ` Chen-Yu Tsai
  2016-01-14 15:24 ` [PATCH v2 11/26] ARM: sun5i: Add DRAM gates Maxime Ripard
                   ` (16 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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-a13.dtsi | 38 +++++++++++++++++++++++++++++++++++++-
 arch/arm/boot/dts/sun5i-r8.dtsi  |  5 +++--
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index d910d3a6c41c..9669b03f20f3 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";
 		};
 	};
@@ -149,6 +150,41 @@
 					     "apb1_i2c2", "apb1_uart1",
 					     "apb1_uart3";
 		};
+
+		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";
+		};
 	};
 
 	soc@01c00000 {
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";
 		};
 	};
-- 
2.6.4

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

* [PATCH v2 11/26] ARM: sun5i: Add DRAM gates
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (9 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 10/26] ARM: sun5i: a13: Add display and TCON clocks Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-16 17:10   ` Chen-Yu Tsai
  2016-01-14 15:24 ` [PATCH v2 12/26] ARM: sun5i: Add TV encoder gate to the DTSI Maxime Ripard
                   ` (15 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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 |  7 ++++---
 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, 25 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index bddd0de88af6..52d2c79cb37b 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -66,7 +66,7 @@
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0-hdmi";
 			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
-				 <&ahb_gates 44>;
+				 <&ahb_gates 44>, <&dram_gates 26>;
 			status = "disabled";
 		};
 
@@ -74,7 +74,8 @@
 			compatible = "allwinner,simple-framebuffer",
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0";
-			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
+			clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
+				 <&dram_gates 26>;
 			status = "disabled";
 		};
 
@@ -83,7 +84,7 @@
 				     "simple-framebuffer";
 			allwinner,pipeline = "de_be0-lcd0-tve0";
 			clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
-				 <&ahb_gates 44>;
+				 <&ahb_gates 44>, <&dram_gates 26>;
 			status = "disabled";
 		};
 	};
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index 9669b03f20f3..f29163650ca8 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 0840612b5ed6..c72d94228915 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";
+		};
+
 		codec_clk: clk@01c20140 {
 			#clock-cells = <0>;
 			compatible = "allwinner,sun4i-a10-codec-clk";
-- 
2.6.4

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

* [PATCH v2 12/26] ARM: sun5i: Add TV encoder gate to the DTSI
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (10 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 11/26] ARM: sun5i: Add DRAM gates Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-16 17:12   ` Chen-Yu Tsai
  2016-01-14 15:24 ` [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions Maxime Ripard
                   ` (14 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

It turns out that the A13 / R8 also have a tve encoder block, and a gate
for it.

Add it to the DT.

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

diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index f29163650ca8..618086e0694c 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -111,8 +111,8 @@
 					<10>, <13>,
 					<14>, <20>,
 					<21>, <22>,
-				        <28>, <32>, <36>,
-				        <40>, <44>,
+					<28>, <32>, <34>,
+					<36>, <40>, <44>,
 					<46>, <51>,
 					<52>;
 			clock-output-names = "ahb_usbotg", "ahb_ehci",
@@ -121,8 +121,8 @@
 					     "ahb_mmc2", "ahb_nand",
 					     "ahb_sdram", "ahb_spi0",
 					     "ahb_spi1", "ahb_spi2",
-					     "ahb_stimer", "ahb_ve", "ahb_lcd",
-					     "ahb_csi", "ahb_de_be",
+					     "ahb_stimer", "ahb_ve", "ahb_tve",
+					     "ahb_lcd", "ahb_csi", "ahb_de_be",
 					     "ahb_de_fe", "ahb_iep",
 					     "ahb_mali400";
 		};
-- 
2.6.4

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

* [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (11 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 12/26] ARM: sun5i: Add TV encoder gate to the DTSI Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-14 23:13   ` Laurent Pinchart
  2016-01-14 15:24 ` [PATCH v2 14/26] drm/modes: Rewrite the command line parser Maxime Ripard
                   ` (13 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

The drm_fbdev_cma_init function always calls the
drm_helper_disable_unused_functions. Since it's part of the usual probe
process, all the drivers using that helper will end up having their encoder
and CRTC disable functions called at probe if their device has not been
reported as enabled.

This could be fixed by reading out from the registers the current state of
the device if it is enabled, but even that will not handle the case where
the device is actually disabled.

Moreover, the drivers using the atomic modesetting expect that their enable
and disable callback to be called when the device is already enabled or
disabled (respectively).

We can however fix this issue by moving the call to
drm_helper_disable_unused_functions out of drm_fbdev_cma_init and make the
drivers needing it (all the drivers calling drm_fbdev_cma_init and not
using the atomic modesetting) explicitly call it.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/drm_fb_cma_helper.c | 3 ---
 drivers/gpu/drm/imx/imx-drm-core.c  | 1 +
 drivers/gpu/drm/sti/sti_drv.c       | 1 +
 drivers/gpu/drm/tilcdc/tilcdc_drv.c | 1 +
 4 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index c19a62561183..daa98d881142 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -348,9 +348,6 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct drm_device *dev,
 
 	}
 
-	/* disable all the possible outputs/crtcs before entering KMS mode */
-	drm_helper_disable_unused_functions(dev);
-
 	ret = drm_fb_helper_initial_config(helper, preferred_bpp);
 	if (ret < 0) {
 		dev_err(dev->dev, "Failed to set initial hw configuration.\n");
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 7b990b4e96d2..e1db57791fc9 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -312,6 +312,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
 		legacyfb_depth = 16;
 	}
+	drm_helper_disable_unused_functions(drm);
 	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
 				drm->mode_config.num_crtc, MAX_CRTC);
 	if (IS_ERR(imxdrm->fbhelper)) {
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index 1469987949d8..506b5626f3ed 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -160,6 +160,7 @@ static int sti_load(struct drm_device *dev, unsigned long flags)
 
 	drm_mode_config_reset(dev);
 
+	drm_helper_disable_unused_functions(dev);
 	drm_fbdev_cma_init(dev, 32,
 			   dev->mode_config.num_crtc,
 			   dev->mode_config.num_connector);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 876cad58b1f9..24be31d69701 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -294,6 +294,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
 			break;
 	}
 
+	drm_helper_disable_unused_functions(dev);
 	priv->fbdev = drm_fbdev_cma_init(dev, bpp,
 			dev->mode_config.num_crtc,
 			dev->mode_config.num_connector);
-- 
2.6.4

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

* [PATCH v2 14/26] drm/modes: Rewrite the command line parser
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (12 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-14 15:24 ` [PATCH v2 15/26] drm/modes: Support modes names on the command line Maxime Ripard
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

Rewrite the command line parser in order to get away from the state machine
parsing the video mode lines.

Hopefully, this will allow to extend it more easily to support named modes
and / or properties set directly on the command line.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/drm_modes.c | 308 +++++++++++++++++++++++++++-----------------
 1 file changed, 191 insertions(+), 117 deletions(-)

diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index cd74a0953f42..5b1921b22dd6 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -30,6 +30,7 @@
  * authorization from the copyright holder(s) and author(s).
  */
 
+#include <linux/ctype.h>
 #include <linux/list.h>
 #include <linux/list_sort.h>
 #include <linux/export.h>
@@ -1199,6 +1200,131 @@ void drm_mode_connector_list_update(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_mode_connector_list_update);
 
+static int drm_mode_parse_cmdline_bpp(const char *str, char **end_ptr,
+				      struct drm_cmdline_mode *mode)
+{
+	if (str[0] != '-')
+		return -EINVAL;
+
+	mode->bpp = simple_strtol(str + 1, end_ptr, 10);
+	mode->bpp_specified = true;
+
+	return 0;
+}
+
+static int drm_mode_parse_cmdline_refresh(const char *str, char **end_ptr,
+					  struct drm_cmdline_mode *mode)
+{
+	if (str[0] != '@')
+		return -EINVAL;
+
+	mode->refresh = simple_strtol(str + 1, end_ptr, 10);
+	mode->refresh_specified = true;
+
+	return 0;
+}
+
+static int drm_mode_parse_cmdline_extra(const char *str, int length,
+					struct drm_connector *connector,
+					struct drm_cmdline_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < length; i++) {
+		switch (str[i]) {
+		case 'i':
+			mode->interlace = true;
+			break;
+		case 'm':
+			mode->margins = true;
+			break;
+		case 'D':
+			if (mode->force != DRM_FORCE_UNSPECIFIED)
+				return -EINVAL;
+
+			if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+			    (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+				mode->force = DRM_FORCE_ON;
+			else
+				mode->force = DRM_FORCE_ON_DIGITAL;
+			break;
+		case 'd':
+			if (mode->force != DRM_FORCE_UNSPECIFIED)
+				return -EINVAL;
+
+			mode->force = DRM_FORCE_OFF;
+			break;
+		case 'e':
+			if (mode->force != DRM_FORCE_UNSPECIFIED)
+				return -EINVAL;
+
+			mode->force = DRM_FORCE_ON;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int drm_mode_parse_cmdline_res_mode(const char *str, unsigned int length,
+					   bool extras,
+					   struct drm_connector *connector,
+					   struct drm_cmdline_mode *mode)
+{
+	bool rb = false, cvt = false;
+	int xres = 0, yres = 0;
+	int remaining, i;
+	char *end_ptr;
+
+	xres = simple_strtol(str, &end_ptr, 10);
+
+	if (end_ptr[0] != 'x')
+		return -EINVAL;
+	end_ptr++;
+
+	yres = simple_strtol(end_ptr, &end_ptr, 10);
+
+	remaining = length - (end_ptr - str);
+	if (remaining < 0)
+		return -EINVAL;
+
+	for (i = 0; i < remaining; i++) {
+		switch (end_ptr[i]) {
+		case 'M':
+			cvt = true;
+			break;
+		case 'R':
+			rb = true;
+			break;
+		default:
+			/*
+			 * Try to pass that to our extras parsing
+			 * function to handle the case where the
+			 * extras are directly after the resolution
+			 */
+			if (extras) {
+				int ret = drm_mode_parse_cmdline_extra(end_ptr + i,
+								       1,
+								       connector,
+								       mode);
+				if (ret)
+					return ret;
+			} else {
+				return -EINVAL;
+			}
+		}
+	}
+
+	mode->xres = xres;
+	mode->yres = yres;
+	mode->cvt = cvt;
+	mode->rb = rb;
+
+	return 0;
+}
+
 /**
  * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
  * @mode_option: optional per connector mode option
@@ -1225,13 +1351,12 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 					       struct drm_cmdline_mode *mode)
 {
 	const char *name;
-	unsigned int namelen;
-	bool res_specified = false, bpp_specified = false, refresh_specified = false;
-	unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
-	bool yres_specified = false, cvt = false, rb = false;
-	bool interlace = false, margins = false, was_digit = false;
-	int i;
-	enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
+	bool parse_extras = false;
+	unsigned int bpp_off = 0, refresh_off = 0;
+	unsigned int mode_end = 0;
+	char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
+	char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
+	int ret;
 
 #ifdef CONFIG_FB
 	if (!mode_option)
@@ -1244,128 +1369,77 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 	}
 
 	name = mode_option;
-	namelen = strlen(name);
-	for (i = namelen-1; i >= 0; i--) {
-		switch (name[i]) {
-		case '@':
-			if (!refresh_specified && !bpp_specified &&
-			    !yres_specified && !cvt && !rb && was_digit) {
-				refresh = simple_strtol(&name[i+1], NULL, 10);
-				refresh_specified = true;
-				was_digit = false;
-			} else
-				goto done;
-			break;
-		case '-':
-			if (!bpp_specified && !yres_specified && !cvt &&
-			    !rb && was_digit) {
-				bpp = simple_strtol(&name[i+1], NULL, 10);
-				bpp_specified = true;
-				was_digit = false;
-			} else
-				goto done;
-			break;
-		case 'x':
-			if (!yres_specified && was_digit) {
-				yres = simple_strtol(&name[i+1], NULL, 10);
-				yres_specified = true;
-				was_digit = false;
-			} else
-				goto done;
-			break;
-		case '0' ... '9':
-			was_digit = true;
-			break;
-		case 'M':
-			if (yres_specified || cvt || was_digit)
-				goto done;
-			cvt = true;
-			break;
-		case 'R':
-			if (yres_specified || cvt || rb || was_digit)
-				goto done;
-			rb = true;
-			break;
-		case 'm':
-			if (cvt || yres_specified || was_digit)
-				goto done;
-			margins = true;
-			break;
-		case 'i':
-			if (cvt || yres_specified || was_digit)
-				goto done;
-			interlace = true;
-			break;
-		case 'e':
-			if (yres_specified || bpp_specified || refresh_specified ||
-			    was_digit || (force != DRM_FORCE_UNSPECIFIED))
-				goto done;
 
-			force = DRM_FORCE_ON;
-			break;
-		case 'D':
-			if (yres_specified || bpp_specified || refresh_specified ||
-			    was_digit || (force != DRM_FORCE_UNSPECIFIED))
-				goto done;
+	if (!isdigit(name[0]))
+		return false;
 
-			if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
-			    (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
-				force = DRM_FORCE_ON;
-			else
-				force = DRM_FORCE_ON_DIGITAL;
-			break;
-		case 'd':
-			if (yres_specified || bpp_specified || refresh_specified ||
-			    was_digit || (force != DRM_FORCE_UNSPECIFIED))
-				goto done;
+	/* Try to locate the bpp and refresh specifiers, if any */
+	bpp_ptr = strchr(name, '-');
+	if (bpp_ptr) {
+		bpp_off = bpp_ptr - name;
+		mode->bpp_specified = true;
+	}
 
-			force = DRM_FORCE_OFF;
-			break;
-		default:
-			goto done;
-		}
+	refresh_ptr = strchr(name, '@');
+	if (refresh_ptr) {
+		refresh_off = refresh_ptr - name;
+		mode->refresh_specified = true;
 	}
 
-	if (i < 0 && yres_specified) {
-		char *ch;
-		xres = simple_strtol(name, &ch, 10);
-		if ((ch != NULL) && (*ch == 'x'))
-			res_specified = true;
-		else
-			i = ch - name;
-	} else if (!yres_specified && was_digit) {
-		/* catch mode that begins with digits but has no 'x' */
-		i = 0;
+	/* Locate the end of the name / resolution, and parse it */
+	if (bpp_ptr && refresh_ptr) {
+		mode_end = min(bpp_off, refresh_off);
+	} else if (bpp_ptr) {
+		mode_end = bpp_off;
+	} else if (refresh_ptr) {
+		mode_end = refresh_off;
+	} else {
+		mode_end = strlen(name);
+		parse_extras = true;
 	}
-done:
-	if (i >= 0) {
-		printk(KERN_WARNING
-			"parse error at position %i in video mode '%s'\n",
-			i, name);
-		mode->specified = false;
+
+	ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+					      parse_extras,
+					      connector,
+					      mode);
+	if (ret)
 		return false;
-	}
+	mode->specified = true;
 
-	if (res_specified) {
-		mode->specified = true;
-		mode->xres = xres;
-		mode->yres = yres;
+	if (bpp_ptr) {
+		ret = drm_mode_parse_cmdline_bpp(bpp_ptr, &bpp_end_ptr, mode);
+		if (ret)
+			return false;
 	}
 
-	if (refresh_specified) {
-		mode->refresh_specified = true;
-		mode->refresh = refresh;
+	if (refresh_ptr) {
+		ret = drm_mode_parse_cmdline_refresh(refresh_ptr,
+						     &refresh_end_ptr, mode);
+		if (ret)
+			return false;
 	}
 
-	if (bpp_specified) {
-		mode->bpp_specified = true;
-		mode->bpp = bpp;
+	/*
+	 * Locate the end of the bpp / refresh, and parse the extras
+	 * if relevant
+	 */
+	if (bpp_ptr && refresh_ptr)
+		extra_ptr = max(bpp_end_ptr, refresh_end_ptr);
+	else if (bpp_ptr)
+		extra_ptr = bpp_end_ptr;
+	else if (refresh_ptr)
+		extra_ptr = refresh_end_ptr;
+
+	if (extra_ptr) {
+		int remaining = strlen(name) - (extra_ptr - name);
+
+		/*
+		 * We still have characters to process, while
+		 * we shouldn't have any
+		 */
+		if (remaining > 0)
+			return false;
 	}
-	mode->rb = rb;
-	mode->cvt = cvt;
-	mode->interlace = interlace;
-	mode->margins = margins;
-	mode->force = force;
 
 	return true;
 }
@@ -1491,4 +1565,4 @@ int drm_mode_convert_umode(struct drm_display_mode *out,
 
 out:
 	return ret;
-}
\ No newline at end of file
+}
-- 
2.6.4

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

* [PATCH v2 15/26] drm/modes: Support modes names on the command line
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (13 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 14/26] drm/modes: Rewrite the command line parser Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-14 15:24 ` [PATCH v2 16/26] drm: Add Allwinner A10 Display Engine support Maxime Ripard
                   ` (11 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

The drm subsystem also uses the video= kernel parameter, and in the
documentation refers to the fbdev documentation for that parameter.

However, that documentation also says that instead of giving the mode using
its resolution we can also give a name. However, DRM doesn't handle that
case at the moment. Even though in most case it shouldn't make any
difference, it might be useful for analog modes, where different standards
might have the same resolution, but still have a few different parameters
that are not encoded in the modes (NTSC vs NTSC-J vs PAL-M for example).

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/gpu/drm/drm_crtc.c      |  3 ++-
 drivers/gpu/drm/drm_fb_helper.c |  4 ++++
 drivers/gpu/drm/drm_modes.c     | 49 ++++++++++++++++++++++++++++-------------
 include/drm/drm_modes.h         |  1 +
 4 files changed, 41 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 24c5434abd1c..c3267d695e4e 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -846,8 +846,9 @@ static void drm_connector_get_cmdline_mode(struct drm_connector *connector)
 		connector->force = mode->force;
 	}
 
-	DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+	DRM_DEBUG_KMS("cmdline mode for connector %s %s %dx%d@%dHz%s%s%s\n",
 		      connector->name,
+		      mode->name ? mode->name : "",
 		      mode->xres, mode->yres,
 		      mode->refresh_specified ? mode->refresh : 60,
 		      mode->rb ? " reduced blanking" : "",
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 69cbab5e5c81..fcb7ba796202 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1649,6 +1649,10 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f
 	prefer_non_interlace = !cmdline_mode->interlace;
 again:
 	list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
+		/* Check (optional) mode name first */
+		if (!strcmp(mode->name, cmdline_mode->name))
+			return mode;
+
 		/* check width/height */
 		if (mode->hdisplay != cmdline_mode->xres ||
 		    mode->vdisplay != cmdline_mode->yres)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 5b1921b22dd6..bbb23000eb5b 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -1351,7 +1351,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 					       struct drm_cmdline_mode *mode)
 {
 	const char *name;
-	bool parse_extras = false;
+	bool named_mode = false, parse_extras = false;
 	unsigned int bpp_off = 0, refresh_off = 0;
 	unsigned int mode_end = 0;
 	char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
@@ -1370,8 +1370,14 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 
 	name = mode_option;
 
+	/*
+	 * If the first character is not a digit, then it means that
+	 * we have a named mode.
+	 */
 	if (!isdigit(name[0]))
-		return false;
+		named_mode = true;
+	else
+		named_mode = false;
 
 	/* Try to locate the bpp and refresh specifiers, if any */
 	bpp_ptr = strchr(name, '-');
@@ -1398,12 +1404,16 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 		parse_extras = true;
 	}
 
-	ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
-					      parse_extras,
-					      connector,
-					      mode);
-	if (ret)
-		return false;
+	if (named_mode) {
+		strncpy(mode->name, name, mode_end);
+	} else {
+		ret = drm_mode_parse_cmdline_res_mode(name, mode_end,
+						      parse_extras,
+						      connector,
+						      mode);
+		if (ret)
+			return false;
+	}
 	mode->specified = true;
 
 	if (bpp_ptr) {
@@ -1431,14 +1441,23 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option,
 		extra_ptr = refresh_end_ptr;
 
 	if (extra_ptr) {
-		int remaining = strlen(name) - (extra_ptr - name);
+		if (!named_mode) {
+			int len = strlen(name) - (extra_ptr - name);
 
-		/*
-		 * We still have characters to process, while
-		 * we shouldn't have any
-		 */
-		if (remaining > 0)
-			return false;
+			ret = drm_mode_parse_cmdline_extra(extra_ptr, len,
+							   connector, mode);
+			if (ret)
+				return false;
+		} else {
+			int remaining = strlen(name) - (extra_ptr - name);
+
+			/*
+			 * We still have characters to process, while
+			 * we shouldn't have any
+			 */
+			if (remaining > 0)
+				return false;
+		}
 	}
 
 	return true;
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
index 08a8cac9e555..709d43f3515e 100644
--- a/include/drm/drm_modes.h
+++ b/include/drm/drm_modes.h
@@ -151,6 +151,7 @@ struct drm_display_mode {
 
 /* mode specified on the command line */
 struct drm_cmdline_mode {
+	char name[DRM_DISPLAY_MODE_LEN];
 	bool specified;
 	bool refresh_specified;
 	bool bpp_specified;
-- 
2.6.4

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

* [PATCH v2 16/26] drm: Add Allwinner A10 Display Engine support
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (14 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 15/26] drm/modes: Support modes names on the command line Maxime Ripard
@ 2016-01-14 15:24 ` Maxime Ripard
  2016-01-16 15:11   ` [linux-sunxi] " Priit Laes
  2016-01-14 15:25 ` [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation Maxime Ripard
                   ` (10 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:24 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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.

Add a driver with a limited set of features for now, and we will hopefully
support all of them eventually

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            |   9 +
 drivers/gpu/drm/sun4i/sun4i_backend.c     | 321 +++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_backend.h     | 160 ++++++++++
 drivers/gpu/drm/sun4i/sun4i_crtc.c        | 120 ++++++++
 drivers/gpu/drm/sun4i/sun4i_crtc.h        |  30 ++
 drivers/gpu/drm/sun4i/sun4i_drv.c         | 325 +++++++++++++++++++
 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       | 160 ++++++++++
 drivers/gpu/drm/sun4i/sun4i_layer.h       |  30 ++
 drivers/gpu/drm/sun4i/sun4i_tcon.c        | 497 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_tcon.h        | 175 +++++++++++
 16 files changed, 1948 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 c4bf9a1cf4a6..ea029f1534fe 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 1e9ff4c3e3db..d8ea25dabca9 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.
 
@@ -62,6 +62,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..7b0e83bae867
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -0,0 +1,9 @@
+sun4i-drm-y += sun4i_crtc.o
+sun4i-drm-y += sun4i_drv.o
+sun4i-drm-y += sun4i_framebuffer.o
+sun4i-drm-y += sun4i_layer.o
+
+obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o
+
+obj-$(CONFIG_DRM_SUN4I)		+= sun4i_backend.o
+obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tcon.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..082fef60dd3e
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -0,0 +1,321 @@
+/*
+ * 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 <linux/component.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_ARGB8888:
+		*mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888;
+		break;
+
+	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,
+};
+
+static int sun4i_backend_bind(struct device *dev, struct device *master,
+			      void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_backend *backend;
+	struct resource *res;
+	void __iomem *regs;
+	int i;
+
+	backend = devm_kzalloc(dev, sizeof(*backend), GFP_KERNEL);
+	if (!backend)
+		return -ENOMEM;
+	dev_set_drvdata(dev, backend);
+	drv->backend = backend;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs)) {
+		dev_err(dev, "Couldn't map the backend registers\n");
+		return PTR_ERR(regs);
+	}
+
+	backend->regs = devm_regmap_init_mmio(dev, regs,
+					      &sun4i_backend_regmap_config);
+	if (IS_ERR(backend->regs)) {
+		dev_err(dev, "Couldn't create the backend0 regmap\n");
+		return PTR_ERR(backend->regs);
+	}
+
+	backend->bus_clk = devm_clk_get(dev, "ahb");
+	if (IS_ERR(backend->bus_clk)) {
+		dev_err(dev, "Couldn't get the backend bus clock\n");
+		return PTR_ERR(backend->bus_clk);
+	}
+	clk_prepare_enable(backend->bus_clk);
+
+	backend->mod_clk = devm_clk_get(dev, "mod");
+	if (IS_ERR(backend->mod_clk)) {
+		dev_err(dev, "Couldn't get the backend module clock\n");
+		return PTR_ERR(backend->mod_clk);
+	}
+	clk_prepare_enable(backend->mod_clk);
+
+	backend->ram_clk = devm_clk_get(dev, "ram");
+	if (IS_ERR(backend->ram_clk)) {
+		dev_err(dev, "Couldn't get the backend RAM clock\n");
+		return PTR_ERR(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 0;
+}
+
+static void sun4i_backend_unbind(struct device *dev, struct device *master,
+				 void *data)
+{
+	struct sun4i_backend *backend = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(backend->ram_clk);
+	clk_disable_unprepare(backend->mod_clk);
+	clk_disable_unprepare(backend->bus_clk);
+}
+
+static struct component_ops sun4i_backend_ops = {
+	.bind	= sun4i_backend_bind,
+	.unbind	= sun4i_backend_unbind,
+};
+
+static int sun4i_backend_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun4i_backend_ops);
+}
+
+static int sun4i_backend_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun4i_backend_ops);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_backend_of_table[] = {
+	{ .compatible = "allwinner,sun5i-a13-display-backend" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_backend_of_table);
+
+static struct platform_driver sun4i_backend_platform_driver = {
+	.probe		= sun4i_backend_probe,
+	.remove		= sun4i_backend_remove,
+	.driver		= {
+		.name		= "sun4i-backend",
+		.of_match_table	= sun4i_backend_of_table,
+	},
+};
+module_platform_driver(sun4i_backend_platform_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 Display Backend Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h
new file mode 100644
index 000000000000..60f6a200fa73
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -0,0 +1,160 @@
+/*
+ * 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_REG0_LAY_PIPESEL_MASK	BIT(15)
+#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x) << 15)
+#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11, 10)
+#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			((x) << 10)
+
+#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);
+
+#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..82611084ef45
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -0,0 +1,120 @@
+/*
+ * 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_backend.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_atomic_flush(struct drm_crtc *crtc,
+				    struct drm_crtc_state *old_state)
+{
+	struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
+	struct sun4i_drv *drv = scrtc->drv;
+
+	DRM_DEBUG_DRIVER("Committing plane changes\n");
+
+	sun4i_backend_commit(drv->backend);
+}
+
+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");
+
+	sun4i_tcon_disable(drv->tcon);
+}
+
+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");
+
+	sun4i_tcon_enable(drv->tcon);
+}
+
+static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
+	.atomic_begin	= sun4i_crtc_atomic_begin,
+	.atomic_flush	= sun4i_crtc_atomic_flush,
+	.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..dec8ce4d9b25
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.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_CRTC_H_
+#define _SUN4I_CRTC_H_
+
+struct sun4i_crtc {
+	struct drm_crtc			crtc;
+	struct drm_pending_vblank_event	*event;
+
+	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..cc7dedc5d256
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -0,0 +1,325 @@
+/*
+ * 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/component.h>
+#include <linux/of_graph.h>
+
+#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_crtc.h"
+#include "sun4i_drv.h"
+#include "sun4i_framebuffer.h"
+#include "sun4i_layer.h"
+#include "sun4i_tcon.h"
+
+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, unsigned 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, unsigned 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 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 | DRIVER_ATOMIC,
+
+	/* Generic Operations */
+	.fops			= &sun4i_drv_fops,
+	.name			= "sun4i-drm",
+	.desc			= "Allwinner sun4i Display Engine",
+	.date			= "20150629",
+	.major			= 1,
+	.minor			= 0,
+
+	/* GEM Operations */
+	.dumb_create		= drm_gem_cma_dumb_create,
+	.dumb_destroy		= drm_gem_dumb_destroy,
+	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
+	.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 */
+
+	/* VBlank Operations */
+	.get_vblank_counter	= drm_vblank_count,
+	.enable_vblank		= sun4i_drv_enable_vblank,
+	.disable_vblank		= sun4i_drv_disable_vblank,
+};
+
+static int sun4i_drv_bind(struct device *dev)
+{
+	struct drm_device *drm;
+	struct sun4i_drv *drv;
+	int ret;
+
+	drm = drm_dev_alloc(&sun4i_drv_driver, dev);
+	if (!drm)
+		return -ENOMEM;
+
+	ret = drm_dev_set_unique(drm, dev_name(drm->dev));
+	if (ret)
+		goto free_drm;
+
+	drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL);
+	if (!drv) {
+		ret = -ENOMEM;
+		goto free_drm;
+	}
+	drm->dev_private = drv;
+
+	drm_vblank_init(drm, 1);
+	drm_mode_config_init(drm);
+
+	ret = component_bind_all(drm->dev, drm);
+	if (ret) {
+		dev_err(drm->dev, "Couldn't bind all pipelines components\n");
+		goto free_drm;
+	}
+
+	/* 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 free_drm;
+	}
+
+	/* 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 free_drm;
+	}
+
+	/* 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 free_drm;
+	}
+
+	/* Enable connectors polling */
+	drm_kms_helper_poll_init(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 void sun4i_drv_unbind(struct device *dev)
+{
+	struct drm_device *drm = dev_get_drvdata(dev);
+
+	drm_dev_unregister(drm);
+	drm_kms_helper_poll_fini(drm);
+	sun4i_framebuffer_free(drm);
+	drm_vblank_cleanup(drm);
+	drm_dev_unref(drm);
+}
+
+static const struct component_master_ops sun4i_drv_master_ops = {
+	.bind	= sun4i_drv_bind,
+	.unbind	= sun4i_drv_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+	DRM_DEBUG_DRIVER("Comparing of node %s with %s\n",
+			 of_node_full_name(dev->of_node),
+			 of_node_full_name(data));
+
+	return dev->of_node == data;
+}
+
+static int sun4i_drv_add_endpoints(struct device *dev,
+				   struct component_match **match,
+				   struct device_node *node)
+{
+	struct device_node *port, *ep, *remote;
+	int count = 0;
+
+	/* Add current component */
+	component_match_add(dev, match, compare_of, node);
+	count++;
+
+	/* Inputs are listed first, then outputs */
+	port = of_graph_get_port_by_id(node, 1);
+	if (!port) {
+		DRM_DEBUG_DRIVER("No output to bind\n");
+		return count;
+	}
+
+	for_each_child_of_node(port, ep) {
+		remote = of_graph_get_remote_port_parent(ep);
+		if (!remote) {
+			DRM_DEBUG_DRIVER("Error retrieving the output node\n");
+			of_node_put(remote);
+			continue;
+		}
+
+		if (!of_device_is_available(remote)) {
+			DRM_DEBUG_DRIVER("Output node %s disabled\n",
+					 remote->full_name);
+			of_node_put(remote);
+			continue;
+		}
+
+		/* Walk down our tree */
+		count += sun4i_drv_add_endpoints(dev, match, remote);
+
+		of_node_put(remote);
+	}
+
+	return count;
+}
+
+static int sun4i_drv_probe(struct platform_device *pdev)
+{
+	struct component_match *match = NULL;
+	struct device_node *np = pdev->dev.of_node;
+	int i, count = 0;
+
+	for (i = 0;; i++) {
+		struct device_node *pipeline = of_parse_phandle(np, "pipelines",
+								i);
+		if (!pipeline)
+			break;
+
+		if (!of_device_is_available(pipeline)) {
+			of_node_put(pipeline);
+			continue;
+		}
+
+		count += sun4i_drv_add_endpoints(&pdev->dev, &match,
+						pipeline);
+
+		DRM_DEBUG_DRIVER("Queued %d outputs on pipeline %d\n",
+				 count, i);
+	}
+
+	if (count)
+		return component_master_add_with_match(&pdev->dev,
+						       &sun4i_drv_master_ops,
+						       match);
+	else
+		return 0;
+}
+
+static int sun4i_drv_remove(struct platform_device *pdev)
+{
+	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..597353eab728
--- /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..2af710003b30
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_layer.c
@@ -0,0 +1,160 @@
+/*
+ * 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"
+
+#define SUN4I_NUM_LAYERS	2
+
+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);
+}
+
+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);
+}
+
+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_ARGB8888,
+	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_drv *drv = drm->dev_private;
+	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, BIT(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);
+	layer->drv = drv;
+
+	if (type == DRM_PLANE_TYPE_PRIMARY)
+		drv->primary = &layer->plane;
+
+	return layer;
+}
+
+struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
+{
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_layer **layers;
+	int i;
+
+	layers = devm_kcalloc(drm->dev, SUN4I_NUM_LAYERS, sizeof(**layers),
+			      GFP_KERNEL);
+	if (!layers)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * The hardware is a bit unusual here.
+	 *
+	 * Even though it supports 4 layers, it does the composition
+	 * in two separate steps.
+	 *
+	 * The first one is assigning a layer to one of its two
+	 * pipes. If more that 1 layer is assigned to the same pipe,
+	 * and if pixels overlaps, the pipe will take the pixel from
+	 * the layer with the highest priority.
+	 *
+	 * The second step is the actual alpha blending, that takes
+	 * the two pipes as input, and uses the eventual alpha
+	 * component to do the transparency between the two.
+	 *
+	 * This two steps scenario makes us unable to guarantee a
+	 * robust alpha blending between the 4 layers in all
+	 * situations. So we just expose two layers, one per pipe. On
+	 * SoCs that support it, sprites could fill the need for more
+	 * layers.
+	 */
+	for (i = 0; i < SUN4I_NUM_LAYERS; i++) {
+		enum drm_plane_type type = (i == 0)
+					 ? DRM_PLANE_TYPE_PRIMARY
+					 : DRM_PLANE_TYPE_OVERLAY;
+		struct sun4i_layer *layer = layers[i];
+
+		layer = sun4i_layer_init_one(drm, type);
+		if (IS_ERR(layer)) {
+			dev_err(drm->dev, "Couldn't initialize %s plane\n",
+				i ? "overlay" : "primary");
+			return ERR_CAST(layer);
+		};
+
+		DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n",
+				 i ? "overlay" : "primary", i);
+		regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
+				   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK,
+				   SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(i));
+
+		layer->id = i;
+	};
+
+	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..a2f65d7a3f4e
--- /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..e253818b711b
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -0,0 +1,497 @@
+/*
+ * 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/component.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)
+{
+	DRM_DEBUG_DRIVER("Disabling TCON\n");
+
+	/* Disable the TCON */
+	regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
+			   SUN4I_TCON_GCTL_TCON_ENABLE, 0);
+}
+
+void sun4i_tcon_enable(struct sun4i_tcon *tcon)
+{
+	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);
+}
+
+void sun4i_tcon_channel_disable(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_channel_enable(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;
+
+	regmap_write(tcon->regs, SUN4I_TCON0_IO_POL_REG, val);
+
+	/* 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);
+
+	/* 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);
+}
+
+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 device *dev,
+					 struct sun4i_tcon *tcon)
+{
+	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(dev->of_node, "clock-output-names", 0,
+				      &pixel_clk_name);
+
+	div = devm_kzalloc(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(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(dev, pixel_clk_name,
+					    &sclk_name, 1,
+					    NULL, NULL,
+					    &div->hw, &clk_divider_ops,
+					    &gate->hw, &clk_gate_ops,
+					    CLK_USE_REGMAP);
+	if (IS_ERR(tcon->dclk))
+		return PTR_ERR(tcon->dclk);
+
+	return 0;
+}
+
+static int sun4i_tcon_init_clocks(struct device *dev,
+				  struct sun4i_tcon *tcon)
+{
+	tcon->clk = devm_clk_get(dev, "ahb");
+	if (IS_ERR(tcon->clk)) {
+		dev_err(dev, "Couldn't get the TCON bus clock\n");
+		return PTR_ERR(tcon->clk);
+	}
+	clk_prepare_enable(tcon->clk);
+
+	tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
+	if (IS_ERR(tcon->sclk0)) {
+		dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
+		return PTR_ERR(tcon->sclk0);
+	}
+
+	tcon->sclk1 = devm_clk_get(dev, "tcon-ch1");
+	if (IS_ERR(tcon->sclk1)) {
+		dev_err(dev, "Couldn't get the TCON channel 1 clock\n");
+		return PTR_ERR(tcon->sclk1);
+	}
+
+	return sun4i_tcon_create_pixel_clock(dev, tcon);
+}
+
+static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
+{
+	clk_unregister_composite(tcon->dclk);
+	clk_disable_unprepare(tcon->clk);
+}
+
+static int sun4i_tcon_init_irq(struct device *dev,
+			       struct sun4i_tcon *tcon)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(dev, "Couldn't retrieve the TCON interrupt\n");
+		return irq;
+	}
+
+	ret = devm_request_irq(dev, irq, sun4i_tcon_handler, 0,
+			       dev_name(dev), tcon);
+	if (ret) {
+		dev_err(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,
+};
+
+static int sun4i_tcon_init_regmap(struct device *dev,
+				  struct sun4i_tcon *tcon)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res;
+	void __iomem *regs;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs)) {
+		dev_err(dev, "Couldn't map the TCON registers\n");
+		return PTR_ERR(regs);
+	}
+
+	tcon->regs = devm_regmap_init_mmio(dev, regs,
+					   &sun4i_tcon_regmap_config);
+	if (IS_ERR(tcon->regs)) {
+		dev_err(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;
+}
+
+static int sun4i_tcon_bind(struct device *dev, struct device *master,
+			   void *data)
+{
+	struct drm_device *drm = data;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_tcon *tcon;
+	int ret;
+
+	tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
+	if (!tcon)
+		return -ENOMEM;
+	dev_set_drvdata(dev, tcon);
+	drv->tcon = tcon;
+
+	ret = sun4i_tcon_init_regmap(dev, tcon);
+	if (ret) {
+		dev_err(dev, "Couldn't init our TCON regmap\n");
+		return ret;
+	}
+
+	ret = sun4i_tcon_init_clocks(dev, tcon);
+	if (ret) {
+		dev_err(dev, "Couldn't init our TCON clocks\n");
+		return ret;
+	}
+
+	ret = sun4i_tcon_init_irq(dev, tcon);
+	if (ret) {
+		dev_err(dev, "Couldn't init our TCON interrupts\n");
+		goto err_free_clocks;
+	}
+
+	return 0;
+
+err_free_clocks:
+	sun4i_tcon_free_clocks(tcon);
+	return ret;
+}
+
+static void sun4i_tcon_unbind(struct device *dev, struct device *master,
+			      void *data)
+{
+	struct sun4i_tcon *tcon = dev_get_drvdata(dev);
+
+	sun4i_tcon_free_clocks(tcon);
+}
+
+static struct component_ops sun4i_tcon_ops = {
+	.bind	= sun4i_tcon_bind,
+	.unbind	= sun4i_tcon_unbind,
+};
+
+static int sun4i_tcon_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun4i_tcon_ops);
+}
+
+static int sun4i_tcon_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun4i_tcon_ops);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_tcon_of_table[] = {
+	{ .compatible = "allwinner,sun4i-a10-tcon" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_tcon_of_table);
+
+static struct platform_driver sun4i_tcon_platform_driver = {
+	.probe		= sun4i_tcon_probe,
+	.remove		= sun4i_tcon_remove,
+	.driver		= {
+		.name		= "sun4i-tcon",
+		.of_match_table	= sun4i_tcon_of_table,
+	},
+};
+module_platform_driver(sun4i_tcon_platform_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 Timing Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
new file mode 100644
index 000000000000..6fa093bce974
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -0,0 +1,175 @@
+/*
+ * 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) & 0xfff) << 16)
+#define SUN4I_TCON0_BASIC0_Y(height)			(((height) - 1) & 0xfff)
+
+#define SUN4I_TCON0_BASIC1_REG			0x4c
+#define SUN4I_TCON0_BASIC1_H_TOTAL(total)		((((total) - 1) & 0x1fff) << 16)
+#define SUN4I_TCON0_BASIC1_H_BACKPORCH(bp)		(((bp) - 1) & 0xfff)
+
+#define SUN4I_TCON0_BASIC2_REG			0x50
+#define SUN4I_TCON0_BASIC2_V_TOTAL(total)		((((total) * 2) & 0x1fff) << 16)
+#define SUN4I_TCON0_BASIC2_V_BACKPORCH(bp)		(((bp) - 1) & 0xfff)
+
+#define SUN4I_TCON0_BASIC3_REG			0x54
+#define SUN4I_TCON0_BASIC3_H_SYNC(width)		((((width) - 1) & 0x7ff) << 16)
+#define SUN4I_TCON0_BASIC3_V_SYNC(height)		(((height) - 1) & 0x7ff)
+
+#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) & 0xfff) << 16)
+#define SUN4I_TCON1_BASIC0_Y(height)			(((height) - 1) & 0xfff)
+
+#define SUN4I_TCON1_BASIC1_REG			0x98
+#define SUN4I_TCON1_BASIC1_X(width)			((((width) - 1) & 0xfff) << 16)
+#define SUN4I_TCON1_BASIC1_Y(height)			(((height) - 1) & 0xfff)
+
+#define SUN4I_TCON1_BASIC2_REG			0x9c
+#define SUN4I_TCON1_BASIC2_X(width)			((((width) - 1) & 0xfff) << 16)
+#define SUN4I_TCON1_BASIC2_Y(height)			(((height) - 1) & 0xfff)
+
+#define SUN4I_TCON1_BASIC3_REG			0xa0
+#define SUN4I_TCON1_BASIC3_H_TOTAL(total)		((((total) - 1) & 0x1fff) << 16)
+#define SUN4I_TCON1_BASIC3_H_BACKPORCH(bp)		(((bp) - 1) & 0xfff)
+
+#define SUN4I_TCON1_BASIC4_REG			0xa4
+#define SUN4I_TCON1_BASIC4_V_TOTAL(total)		(((total) & 0x1fff) << 16)
+#define SUN4I_TCON1_BASIC4_V_BACKPORCH(bp)		(((bp) - 1) & 0xfff)
+
+#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)
+
+#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 regmap			*regs;
+
+	/* Main bus clock */
+	struct clk			*clk;
+
+	/* Clocks for the TCON channels */
+	struct clk			*sclk0;
+	struct clk			*sclk1;
+
+	/* Pixel clock */
+	struct clk			*dclk;
+};
+
+/* Global Control */
+void sun4i_tcon_disable(struct sun4i_tcon *tcon);
+void sun4i_tcon_enable(struct sun4i_tcon *tcon);
+
+/* Channel Control */
+void sun4i_tcon_channel_disable(struct sun4i_tcon *tcon, int channel);
+void sun4i_tcon_channel_enable(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.4

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

* [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (15 preceding siblings ...)
  2016-01-14 15:24 ` [PATCH v2 16/26] drm: Add Allwinner A10 Display Engine support Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-15  3:15   ` Rob Herring
  2016-01-14 15:25 ` [PATCH v2 18/26] drm: sun4i: Add RGB output Maxime Ripard
                   ` (9 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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>
---
 .../bindings/display/sunxi/sun4i-drm.txt           | 228 +++++++++++++++++++++
 1 file changed, 228 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt

diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
new file mode 100644
index 000000000000..061bc87147a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -0,0 +1,228 @@
+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
+
+- ports: A ports node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt. The
+  first port should be the input endpoint.
+
+TCON
+----
+
+The TCON acts as a timing controller for RGB, LVDS and TV 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 1
+
+ - clock-names: the clock names mentioned above
+ - clock-output-names: Name of the pixel clock created
+
+- ports: A ports node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt. The
+  first port should be the input endpoint, the second one the output
+
+Optional properties:
+  - allwinner,panel: phandle to the panel used in our RGB interface
+
+
+Display Engine Backend
+----------------------
+
+The display engine backend exposes layers and sprites to the
+system.
+
+Required properties:
+  - compatible: value must be one of:
+    * allwinner,sun5i-a13-display-backend
+  - reg: base address and size of the memory-mapped region.
+  - clocks: phandles to the clocks feeding the frontend and backend
+    * ahb: the backend interface clock
+    * mod: the backend module clock
+    * ram: the backend DRAM clock
+  - clock-names: the clock names mentioned above
+  - resets: phandles to the reset controllers driving the backend
+
+- ports: A ports node with endpoint definitions as defined in
+  Documentation/devicetree/bindings/media/video-interfaces.txt. The
+  first port should be the input endpoints, the second one the output
+
+Display Engine Frontend
+-----------------------
+
+The display engine frontend does formats conversion, scaling,
+deinterlacing and color space conversion.
+
+Required properties:
+  - compatible: value must be one of:
+    * allwinner,sun5i-a13-display-frontend
+  - reg: base address and size of the memory-mapped region.
+  - interrupts: interrupt associated to this IP
+  - clocks: phandles to the clocks feeding the frontend and backend
+    * ahb: the backend interface clock
+    * mod: the backend module clock
+    * ram: the backend DRAM clock
+  - clock-names: the clock names mentioned above
+  - resets: phandles to the reset controllers driving the backend
+
+Display Engine Pipeline
+-----------------------
+
+The display engine pipeline (and its entry point, since it can be
+either directly the backend or the frontend) is represented as an
+extra node.
+
+Required properties:
+  - compatible: value must be one of:
+    * allwinner,sun5i-a13-display-engine
+  - allwinner,pipelines: list of phandle to the entry points of the
+    pipelines (either to the frontend or backend)
+
+Example:
+
+panel: panel {
+	compatible = "olimex,lcd-olinuxino-43-ts";
+};
+
+tve0: tv-encoder@01c0a000 {
+	compatible = "allwinner,sun4i-a10-tv-encoder";
+	reg = <0x01c0a000 0x1000>;
+	clocks = <&ahb_gates 34>;
+
+	port {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		tve0_in_tcon0: endpoint@0 {
+			reg = <0>;
+			remote-endpoint = <&tcon0_out_tve0>;
+		};
+	};
+};
+
+tcon0: 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";
+	allwinner,panel = <&panel>;
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		tcon0_in: port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			tcon0_in_be0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&be0_out_tcon0>;
+			};
+		};
+
+		tcon0_out: port@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			tcon0_out_tve0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&tve0_in_tcon0>;
+			};
+		};
+	};
+};
+
+fe0: display-frontend@01e00000 {
+	compatible = "allwinner,sun5i-a13-display-frontend";
+	reg = <0x01e00000 0x20000>;
+	interrupts = <47>;
+	clocks = <&ahb_gates 46>, <&de_fe_clk>,
+		 <&dram_gates 25>;
+	clock-names = "ahb", "mod",
+		      "ram";
+	resets = <&de_fe_clk>;
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		fe0_out: port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			fe0_out_be0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&be0_in_fe0>;
+			};
+		};
+	};
+};
+
+be0: display-backend@01e60000 {
+	compatible = "allwinner,sun5i-a13-display-backend";
+	reg = <0x01e60000 0x10000>;
+	clocks = <&ahb_gates 44>, <&de_be_clk>,
+		 <&dram_gates 26>;
+	clock-names = "ahb", "mod",
+		      "ram";
+	resets = <&de_be_clk>;
+
+	ports {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		be0_in: port@0 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0>;
+
+			be0_in_fe0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&fe0_out_be0>;
+			};
+		};
+
+		be0_out: port@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			be0_out_tcon0: endpoint@0 {
+				reg = <0>;
+				remote-endpoint = <&tcon0_in_be0>;
+		};
+	};
+};
+
+display-engine {
+	compatible = "allwinner,sun5i-a13-display-engine";
+	pipelines = <&be0>;
+};
-- 
2.6.4

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

* [PATCH v2 18/26] drm: sun4i: Add RGB output
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (16 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-14 15:25 ` [PATCH v2 19/26] drm: sun4i: Add composite output Maxime Ripard
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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_rgb.c  | 229 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/sun4i/sun4i_rgb.h  |  18 +++
 drivers/gpu/drm/sun4i/sun4i_tcon.c |  26 ++++-
 drivers/gpu/drm/sun4i/sun4i_tcon.h |   2 +
 5 files changed, 276 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 7b0e83bae867..a7c9e7fd5a26 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -3,6 +3,8 @@ sun4i-drm-y += sun4i_drv.o
 sun4i-drm-y += sun4i_framebuffer.o
 sun4i-drm-y += sun4i_layer.o
 
+sun4i-drm-y += sun4i_rgb.o
+
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o
 
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_backend.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
new file mode 100644
index 000000000000..c2b366e39749
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -0,0 +1,229 @@
+/*
+ * 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 sun4i_drv	*drv;
+};
+
+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);
+	struct sun4i_drv *drv = rgb->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	return drm_panel_get_modes(tcon->panel);
+}
+
+static int sun4i_rgb_mode_valid(struct drm_connector *connector,
+				struct drm_display_mode *mode)
+{
+	u32 hsync = mode->hsync_end - mode->hsync_start;
+	u32 vsync = mode->vsync_end - mode->vsync_start;
+
+	DRM_DEBUG_DRIVER("Validating modes...\n");
+
+	if ((hsync < 1) || (hsync > 0x3ff) ||
+	    (mode->htotal < 1) || (mode->htotal > 0xfff))
+		return MODE_H_ILLEGAL;
+
+	DRM_DEBUG_DRIVER("Horizontal parameters OK\n");
+
+	if ((vsync < 1) || (vsync > 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);
+	struct sun4i_drv *drv = rgb->drv;
+	struct sun4i_tcon *tcon = drv->tcon;
+
+	drm_panel_detach(tcon->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;
+
+	DRM_DEBUG_DRIVER("Enabling RGB output\n");
+
+	drm_panel_enable(tcon->panel);
+	sun4i_tcon_channel_enable(tcon, 0);
+}
+
+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;
+
+	DRM_DEBUG_DRIVER("Disabling RGB output\n");
+
+	sun4i_tcon_channel_disable(tcon, 0);
+	drm_panel_disable(tcon->panel);
+}
+
+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_tcon *tcon = drv->tcon;
+	struct sun4i_rgb *rgb;
+	int ret;
+
+	/* If we don't have a panel, there's no point in going on */
+	if (!tcon->panel)
+		return -ENODEV;
+
+	rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL);
+	if (!rgb)
+		return -ENOMEM;
+	rgb->drv = drv;
+
+	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(tcon->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_ */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index e253818b711b..6a6dc47a3b42 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -15,6 +15,7 @@
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
 
 #include <linux/clk-provider.h>
 #include <linux/component.h>
@@ -25,6 +26,7 @@
 
 #include "sun4i_crtc.h"
 #include "sun4i_drv.h"
+#include "sun4i_rgb.h"
 #include "sun4i_tcon.h"
 
 void sun4i_tcon_disable(struct sun4i_tcon *tcon)
@@ -418,6 +420,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
 	struct drm_device *drm = data;
 	struct sun4i_drv *drv = drm->dev_private;
 	struct sun4i_tcon *tcon;
+	struct device_node *np;
 	int ret;
 
 	tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
@@ -444,7 +447,20 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
 		goto err_free_clocks;
 	}
 
-	return 0;
+	np = of_parse_phandle(dev->of_node, "allwinner,panel", 0);
+	if (!np) {
+		dev_info(dev, "No panel found... RGB output disabled\n");
+		return 0;
+	}
+
+	tcon->panel = of_drm_find_panel(np);
+	if (!tcon->panel) {
+		dev_err(dev, "Couldn't find our panel\n");
+		ret = -ENODEV;
+		goto err_free_clocks;
+	}
+
+	return sun4i_rgb_init(drm);
 
 err_free_clocks:
 	sun4i_tcon_free_clocks(tcon);
@@ -466,6 +482,14 @@ static struct component_ops sun4i_tcon_ops = {
 
 static int sun4i_tcon_probe(struct platform_device *pdev)
 {
+	struct device_node *np;
+
+	np = of_parse_phandle(pdev->dev.of_node, "allwinner,panel", 0);
+	if (np) {
+		if (!of_drm_find_panel(np))
+			return -EPROBE_DEFER;
+	}
+
 	return component_add(&pdev->dev, &sun4i_tcon_ops);
 }
 
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index 6fa093bce974..9496912b6484 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -152,6 +152,8 @@ struct sun4i_tcon {
 
 	/* Pixel clock */
 	struct clk			*dclk;
+
+	struct drm_panel		*panel;
 };
 
 /* Global Control */
-- 
2.6.4

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

* [PATCH v2 19/26] drm: sun4i: Add composite output
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (17 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 18/26] drm: sun4i: Add RGB output Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-14 15:25 ` [PATCH v2 20/26] drm: sun4i: tv: Add PAL output standard Maxime Ripard
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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_tv.c | 588 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 589 insertions(+)
 create mode 100644 drivers/gpu/drm/sun4i/sun4i_tv.c

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index a7c9e7fd5a26..c458b09181fe 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_DRM_SUN4I)		+= sun4i-drm.o
 
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_backend.o
 obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tcon.o
+obj-$(CONFIG_DRM_SUN4I)		+= sun4i_tv.o
diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c
new file mode 100644
index 000000000000..4f10f8b6b07c
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -0,0 +1,588 @@
+/*
+ * 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/component.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;
+
+	/* First try to identify the mode by name */
+	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+		struct tv_mode *tv_mode = &tv_modes[i];
+
+		DRM_DEBUG_DRIVER("Comparing mode %s vs %s",
+				 mode->name, tv_mode->name);
+
+		if (!strcmp(mode->name, tv_mode->name))
+			return tv_mode;
+	}
+
+	/* Then by number of lines */
+	for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
+		struct tv_mode *tv_mode = &tv_modes[i];
+
+		DRM_DEBUG_DRIVER("Comparing mode %s vs %s (X: %d vs %d)",
+				 mode->name, tv_mode->name,
+				 mode->vdisplay, tv_mode->vdisplay);
+
+		if (mode->vdisplay == tv_mode->vdisplay)
+			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_channel_disable(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_channel_enable(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 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,
+};
+
+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_bind(struct device *dev, struct device *master,
+			 void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
+	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_tv *tv;
+	struct resource *res;
+	void __iomem *regs;
+	int ret;
+
+	tv = devm_kzalloc(dev, sizeof(*tv), GFP_KERNEL);
+	if (!tv)
+		return -ENOMEM;
+	tv->drv = drv;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(regs)) {
+		dev_err(dev, "Couldn't map the TV encoder registers\n");
+		return PTR_ERR(regs);
+	}
+
+	tv->regs = devm_regmap_init_mmio(dev, regs,
+					 &sun4i_tv_regmap_config);
+	if (IS_ERR(tv->regs)) {
+		dev_err(dev, "Couldn't create the TV encoder regmap\n");
+		return PTR_ERR(tv->regs);
+	}
+
+	tv->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(tv->clk)) {
+		dev_err(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(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(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;
+}
+
+static void sun4i_tv_unbind(struct device *dev, struct device *master,
+			    void *data)
+{
+#warning FIXME
+}
+
+static struct component_ops sun4i_tv_ops = {
+	.bind	= sun4i_tv_bind,
+	.unbind	= sun4i_tv_unbind,
+};
+
+static int sun4i_tv_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &sun4i_tv_ops);
+}
+
+static int sun4i_tv_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &sun4i_tv_ops);
+
+	return 0;
+}
+
+static const struct of_device_id sun4i_tv_of_table[] = {
+	{ .compatible = "allwinner,sun4i-a10-tv-encoder" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_tv_of_table);
+
+static struct platform_driver sun4i_tv_platform_driver = {
+	.probe		= sun4i_tv_probe,
+	.remove		= sun4i_tv_remove,
+	.driver		= {
+		.name		= "sun4i-tve",
+		.of_match_table	= sun4i_tv_of_table,
+	},
+};
+module_platform_driver(sun4i_tv_platform_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A10 TV Encoder Driver");
+MODULE_LICENSE("GPL");
-- 
2.6.4

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

* [PATCH v2 20/26] drm: sun4i: tv: Add PAL output standard
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (18 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 19/26] drm: sun4i: Add composite output Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-14 15:25 ` [PATCH v2 21/26] drm: sun4i: tv: Add NTSC " Maxime Ripard
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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 4f10f8b6b07c..4f369de2a1fc 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -176,7 +176,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.4

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

* [PATCH v2 21/26] drm: sun4i: tv: Add NTSC output standard
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (19 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 20/26] drm: sun4i: tv: Add PAL output standard Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-14 15:25 ` [PATCH v2 22/26] ARM: sun5i: r8: Add display blocks to the DTSI Maxime Ripard
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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 4f369de2a1fc..46331087b0e9 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tv.c
@@ -176,24 +176,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.4

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

* [PATCH v2 22/26] ARM: sun5i: r8: Add display blocks to the DTSI
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (20 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 21/26] drm: sun4i: tv: Add NTSC " Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-14 15:25 ` [PATCH v2 23/26] ARM: sun5i: chip: Enable the TV Encoder Maxime Ripard
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

The TCON, tv-encoder and display engine backends and frontends are combined
to create our display pipeline.

Add them to the R8 DTSI. It's supposed to be perfectly compatible with the
A10s and A13, but since we haven't tested it on them yet, it's safer to
just enable it on the R8. Eventually, it should be moved to sun5i.dtsi

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

diff --git a/arch/arm/boot/dts/sun5i-r8.dtsi b/arch/arm/boot/dts/sun5i-r8.dtsi
index 691d3de75b35..b3bf91516a80 100644
--- a/arch/arm/boot/dts/sun5i-r8.dtsi
+++ b/arch/arm/boot/dts/sun5i-r8.dtsi
@@ -57,4 +57,138 @@
 			status = "disabled";
 		};
 	};
+
+	soc@01c00000 {
+		tve0: tv-encoder@01c0a000 {
+			compatible = "allwinner,sun4i-a10-tv-encoder";
+			reg = <0x01c0a000 0x1000>;
+			clocks = <&ahb_gates 34>;
+			status = "disabled";
+
+			port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tve0_in_tcon0: endpoint@0 {
+					reg = <0>;
+					remote-endpoint = <&tcon0_out_tve0>;
+				};
+			};
+		};
+
+		tcon0: 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";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				tcon0_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					tcon0_in_be0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&be0_out_tcon0>;
+					};
+				};
+
+				tcon0_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					tcon0_out_tve0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tve0_in_tcon0>;
+					};
+				};
+			};
+		};
+
+		fe0: display-frontend@01e00000 {
+			compatible = "allwinner,sun5i-a13-display-frontend";
+			reg = <0x01e00000 0x20000>;
+			interrupts = <47>;
+			clocks = <&ahb_gates 46>, <&de_fe_clk>,
+				 <&dram_gates 25>;
+			clock-names = "ahb", "mod",
+				      "ram";
+			resets = <&de_fe_clk>;
+			status = "disabled";
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				fe0_out: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					fe0_out_be0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&be0_in_fe0>;
+					};
+				};
+			};
+		};
+
+		be0: display-backend@01e60000 {
+			compatible = "allwinner,sun5i-a13-display-backend";
+			reg = <0x01e60000 0x10000>;
+			clocks = <&ahb_gates 44>, <&de_be_clk>,
+				 <&dram_gates 26>;
+			clock-names = "ahb", "mod",
+				      "ram";
+			resets = <&de_be_clk>;
+			status = "disabled";
+
+			assigned-clocks = <&de_be_clk>;
+			assigned-clock-rates = <300000000>;
+
+			ports {
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				be0_in: port@0 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <0>;
+
+					be0_in_fe0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&fe0_out_be0>;
+					};
+				};
+
+				be0_out: port@1 {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					reg = <1>;
+
+					be0_out_tcon0: endpoint@0 {
+						reg = <0>;
+						remote-endpoint = <&tcon0_in_be0>;
+					};
+				};
+			};
+		};
+	};
+
+	display-engine {
+		compatible = "allwinner,sun5i-a13-display-engine";
+		pipelines = <&be0>;
+	};
 };
-- 
2.6.4

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

* [PATCH v2 23/26] ARM: sun5i: chip: Enable the TV Encoder
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (21 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 22/26] ARM: sun5i: r8: Add display blocks to the DTSI Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-14 15:25 ` [PATCH v2 24/26] devicetree: Add olimex vendor prefix Maxime Ripard
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

The CHIP has a composite output available muxed with the microphone in the
micro-jack plug.

Enable the composite output in its DTS.

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

diff --git a/arch/arm/boot/dts/sun5i-r8-chip.dts b/arch/arm/boot/dts/sun5i-r8-chip.dts
index c976c7618118..c26c095b42c6 100644
--- a/arch/arm/boot/dts/sun5i-r8-chip.dts
+++ b/arch/arm/boot/dts/sun5i-r8-chip.dts
@@ -84,6 +84,10 @@
 	};
 };
 
+&be0 {
+	status = "okay";
+};
+
 &codec {
 	status = "okay";
 };
@@ -230,6 +234,14 @@
 	status = "okay";
 };
 
+&tcon0 {
+	status = "okay";
+};
+
+&tve0 {
+	status = "okay";
+};
+
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&uart1_pins_b>;
-- 
2.6.4

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

* [PATCH v2 24/26] devicetree: Add olimex vendor prefix
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (22 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 23/26] ARM: sun5i: chip: Enable the TV Encoder Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-15  3:15   ` Rob Herring
  2016-01-14 15:25 ` [PATCH v2 25/26] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
                   ` (2 subsequent siblings)
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

Olimex is an open source hardware boards vendors based in Bulgaria.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 55df1d444e9f..de4eb72b3adc 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -161,6 +161,7 @@ nuvoton	Nuvoton Technology Corporation
 nvidia	NVIDIA
 nxp	NXP Semiconductors
 okaya	Okaya Electric America, Inc.
+olimex	Olimex
 onnn	ON Semiconductor Corp.
 opencores	OpenCores.org
 option	Option NV
-- 
2.6.4

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

* [PATCH v2 25/26] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (23 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 24/26] devicetree: Add olimex vendor prefix Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-01-15  3:17   ` Rob Herring
  2016-01-14 15:25 ` [PATCH v2 26/26] DO NOT MERGE: ARM: sun5i: chip: Enable the LCD panel Maxime Ripard
  2016-02-20 13:45 ` [linux-sunxi] [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Priit Laes
  26 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, 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>
---
 .../display/panel/olimex,lcd-olinuxino-43-ts.txt   |  7 ++++++
 drivers/gpu/drm/panel/panel-simple.c               | 26 ++++++++++++++++++++++
 2 files changed, 33 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt

diff --git a/Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt b/Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt
new file mode 100644
index 000000000000..74540a090669
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt
@@ -0,0 +1,7 @@
+Olimex 4.3" TFT LCD panel
+
+Required properties:
+- compatible: should be "olimex,lcd-olinuxino-43-ts"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index f97b73ec4713..3ae22e0a7f38 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -1003,6 +1003,29 @@ static const struct panel_desc okaya_rs800480t_7x0gp = {
 	.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 drm_display_mode ortustech_com43h4m85ulc_mode  = {
 	.clock = 25000,
 	.hdisplay = 480,
@@ -1179,6 +1202,9 @@ static const struct of_device_id platform_of_match[] = {
 		.compatible = "okaya,rs800480t-7x0gp",
 		.data = &okaya_rs800480t_7x0gp,
 	}, {
+		.compatible = "olimex,lcd-olinuxino-43-ts",
+		.data = &olimex_lcd_olinuxino_43ts,
+	}, {
 		.compatible = "ortustech,com43h4m85ulc",
 		.data = &ortustech_com43h4m85ulc,
 	}, {
-- 
2.6.4

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

* [PATCH v2 26/26] DO NOT MERGE: ARM: sun5i: chip: Enable the LCD panel
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (24 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 25/26] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
@ 2016-01-14 15:25 ` Maxime Ripard
  2016-02-20 13:45 ` [linux-sunxi] [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Priit Laes
  26 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-14 15:25 UTC (permalink / raw)
  To: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Maxime Ripard

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

diff --git a/arch/arm/boot/dts/sun5i-r8-chip.dts b/arch/arm/boot/dts/sun5i-r8-chip.dts
index c26c095b42c6..147c39106f63 100644
--- a/arch/arm/boot/dts/sun5i-r8-chip.dts
+++ b/arch/arm/boot/dts/sun5i-r8-chip.dts
@@ -82,6 +82,10 @@
 		vin0-supply = <&reg_ldo3>;
 		vin1-supply = <&reg_ldo4>;
 	};
+
+	panel: panel {
+		compatible = "olimex,lcd-olinuxino-43-ts";
+	};
 };
 
 &be0 {
@@ -236,6 +240,7 @@
 
 &tcon0 {
 	status = "okay";
+	allwinner,panel = <&panel>;
 };
 
 &tve0 {
-- 
2.6.4

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

* Re: [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  2016-01-14 15:24 ` [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions Maxime Ripard
@ 2016-01-14 23:13   ` Laurent Pinchart
  2016-01-15 10:17     ` Daniel Vetter
  0 siblings, 1 reply; 64+ messages in thread
From: Laurent Pinchart @ 2016-01-14 23:13 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter

Hi Maxime,

Thank you for the patch.

On Thursday 14 January 2016 16:24:56 Maxime Ripard wrote:
> The drm_fbdev_cma_init function always calls the
> drm_helper_disable_unused_functions. Since it's part of the usual probe
> process, all the drivers using that helper will end up having their encoder
> and CRTC disable functions called at probe if their device has not been
> reported as enabled.
> 
> This could be fixed by reading out from the registers the current state of
> the device if it is enabled, but even that will not handle the case where
> the device is actually disabled.
> 
> Moreover, the drivers using the atomic modesetting expect that their enable
> and disable callback to be called when the device is already enabled or
> disabled (respectively).
> 
> We can however fix this issue by moving the call to
> drm_helper_disable_unused_functions out of drm_fbdev_cma_init and make the
> drivers needing it (all the drivers calling drm_fbdev_cma_init and not
> using the atomic modesetting) explicitly call it.

I'd rather add it to all drivers that call drm_fbdev_cma_init(). All the 
atomic ones must have special code to cope with it that could be rendered 
useless by the removal of the drm_helper_disable_unused_functions() call. That 
code should be removed too, and it would be easier to check drivers one by one 
and fixing them individually (outside of this patch series, unless you insist 
;-)) when removing the explicit drm_helper_disable_unused_functions() call. 
Other than that the patch looks fine to me.

> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/gpu/drm/drm_fb_cma_helper.c | 3 ---
>  drivers/gpu/drm/imx/imx-drm-core.c  | 1 +
>  drivers/gpu/drm/sti/sti_drv.c       | 1 +
>  drivers/gpu/drm/tilcdc/tilcdc_drv.c | 1 +
>  4 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c
> b/drivers/gpu/drm/drm_fb_cma_helper.c index c19a62561183..daa98d881142
> 100644
> --- a/drivers/gpu/drm/drm_fb_cma_helper.c
> +++ b/drivers/gpu/drm/drm_fb_cma_helper.c
> @@ -348,9 +348,6 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct
> drm_device *dev,
> 
>  	}
> 
> -	/* disable all the possible outputs/crtcs before entering KMS mode */
> -	drm_helper_disable_unused_functions(dev);
> -
>  	ret = drm_fb_helper_initial_config(helper, preferred_bpp);
>  	if (ret < 0) {
>  		dev_err(dev->dev, "Failed to set initial hw configuration.\n");
> diff --git a/drivers/gpu/drm/imx/imx-drm-core.c
> b/drivers/gpu/drm/imx/imx-drm-core.c index 7b990b4e96d2..e1db57791fc9
> 100644
> --- a/drivers/gpu/drm/imx/imx-drm-core.c
> +++ b/drivers/gpu/drm/imx/imx-drm-core.c
> @@ -312,6 +312,7 @@ static int imx_drm_driver_load(struct drm_device *drm,
> unsigned long flags) dev_warn(drm->dev, "Invalid legacyfb_depth. 
> Defaulting to 16bpp\n"); legacyfb_depth = 16;
>  	}
> +	drm_helper_disable_unused_functions(drm);
>  	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
>  				drm->mode_config.num_crtc, MAX_CRTC);
>  	if (IS_ERR(imxdrm->fbhelper)) {
> diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
> index 1469987949d8..506b5626f3ed 100644
> --- a/drivers/gpu/drm/sti/sti_drv.c
> +++ b/drivers/gpu/drm/sti/sti_drv.c
> @@ -160,6 +160,7 @@ static int sti_load(struct drm_device *dev, unsigned
> long flags)
> 
>  	drm_mode_config_reset(dev);
> 
> +	drm_helper_disable_unused_functions(dev);
>  	drm_fbdev_cma_init(dev, 32,
>  			   dev->mode_config.num_crtc,
>  			   dev->mode_config.num_connector);
> diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
> b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 876cad58b1f9..24be31d69701
> 100644
> --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
> +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
> @@ -294,6 +294,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned
> long flags) break;
>  	}
> 
> +	drm_helper_disable_unused_functions(dev);
>  	priv->fbdev = drm_fbdev_cma_init(dev, bpp,
>  			dev->mode_config.num_crtc,
>  			dev->mode_config.num_connector);

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver
  2016-01-14 15:24 ` [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver Maxime Ripard
@ 2016-01-15  3:01   ` Rob Herring
  2016-01-16 14:08   ` [linux-sunxi] " Priit Laes
  2016-01-16 15:29   ` Chen-Yu Tsai
  2 siblings, 0 replies; 64+ messages in thread
From: Rob Herring @ 2016-01-15  3:01 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, Thomas Petazzoni, devicetree, Boris Brezillon,
	Wynter Woods, linux-kernel, dri-devel, Hans de Goede, linux-sunxi,
	Rob Clark, Laurent Pinchart, Daniel Vetter, Alexander Kaplan,
	Chen-Yu Tsai, linux-clk, linux-arm-kernel

On Thu, Jan 14, 2016 at 04:24:48PM +0100, Maxime Ripard wrote:
> The A10 SoCs and its relatives has a special clock controller to drive the
> display engines (both frontend and backend), that have a lot in common with
> the clock to drive the first TCON channel.
> 
> Add a driver to support both.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt |   2 +

Can't someone read the datasheet and add these compatible strings in one 
pass instead of one at a time?

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/clk/sunxi/Makefile                        |   1 +
>  drivers/clk/sunxi/clk-sun4i-display.c             | 241 ++++++++++++++++++++++
>  3 files changed, 244 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c

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

* Re: [PATCH v2 06/26] clk: sunxi: Add PLL3 clock
  2016-01-14 15:24 ` [PATCH v2 06/26] clk: sunxi: Add PLL3 clock Maxime Ripard
@ 2016-01-15  3:02   ` Rob Herring
  2016-01-16 16:05   ` Chen-Yu Tsai
  1 sibling, 0 replies; 64+ messages in thread
From: Rob Herring @ 2016-01-15  3:02 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Thu, Jan 14, 2016 at 04:24:49PM +0100, Maxime Ripard wrote:
> 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>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt |  1 +

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/clk/sunxi/Makefile                        |  1 +
>  drivers/clk/sunxi/clk-sun4i-pll3.c                | 90 +++++++++++++++++++++++
>  3 files changed, 92 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-pll3.c

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

* Re: [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock
  2016-01-14 15:24 ` [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock Maxime Ripard
@ 2016-01-15  3:03   ` Rob Herring
  2016-01-16 16:36   ` Chen-Yu Tsai
  1 sibling, 0 replies; 64+ messages in thread
From: Rob Herring @ 2016-01-15  3:03 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, Thomas Petazzoni, devicetree, Boris Brezillon,
	Wynter Woods, linux-kernel, dri-devel, Hans de Goede, linux-sunxi,
	Rob Clark, Laurent Pinchart, Daniel Vetter, Alexander Kaplan,
	Chen-Yu Tsai, linux-clk, linux-arm-kernel

On Thu, Jan 14, 2016 at 04:24:50PM +0100, 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>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt |   1 +

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/clk/sunxi/Makefile                        |   1 +
>  drivers/clk/sunxi/clk-sun4i-tcon-ch1.c            | 154 ++++++++++++++++++++++
>  3 files changed, 156 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c

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

* Re: [PATCH v2 08/26] clk: sun5i: add DRAM gates
  2016-01-14 15:24 ` [PATCH v2 08/26] clk: sun5i: add DRAM gates Maxime Ripard
@ 2016-01-15  3:04   ` Rob Herring
  0 siblings, 0 replies; 64+ messages in thread
From: Rob Herring @ 2016-01-15  3:04 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Thu, Jan 14, 2016 at 04:24:51PM +0100, Maxime Ripard 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 the one found in the A13 / R8 SoCs.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> Acked-by: Chen-Yu Tsai <wens@csie.org>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt | 1 +

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/clk/sunxi/clk-simple-gates.c              | 2 ++
>  2 files changed, 3 insertions(+)

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

* Re: [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation
  2016-01-14 15:25 ` [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation Maxime Ripard
@ 2016-01-15  3:15   ` Rob Herring
  2016-02-03 19:59     ` Maxime Ripard
  0 siblings, 1 reply; 64+ messages in thread
From: Rob Herring @ 2016-01-15  3:15 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Thu, Jan 14, 2016 at 04:25:00PM +0100, Maxime Ripard 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>
> ---
>  .../bindings/display/sunxi/sun4i-drm.txt           | 228 +++++++++++++++++++++

drm is a linuxism. It shouldn't be used for binding doc.

>  1 file changed, 228 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> 
> diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> new file mode 100644
> index 000000000000..061bc87147a3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> @@ -0,0 +1,228 @@
> +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
> +
> +- ports: A ports node with endpoint definitions as defined in
> +  Documentation/devicetree/bindings/media/video-interfaces.txt. The
> +  first port should be the input endpoint.
> +
> +TCON
> +----
> +
> +The TCON acts as a timing controller for RGB, LVDS and TV 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 1
> +
> + - clock-names: the clock names mentioned above
> + - clock-output-names: Name of the pixel clock created
> +
> +- ports: A ports node with endpoint definitions as defined in
> +  Documentation/devicetree/bindings/media/video-interfaces.txt. The
> +  first port should be the input endpoint, the second one the output
> +
> +Optional properties:
> +  - allwinner,panel: phandle to the panel used in our RGB interface
> +
> +
> +Display Engine Backend
> +----------------------
> +
> +The display engine backend exposes layers and sprites to the
> +system.
> +
> +Required properties:
> +  - compatible: value must be one of:
> +    * allwinner,sun5i-a13-display-backend
> +  - reg: base address and size of the memory-mapped region.
> +  - clocks: phandles to the clocks feeding the frontend and backend
> +    * ahb: the backend interface clock
> +    * mod: the backend module clock
> +    * ram: the backend DRAM clock
> +  - clock-names: the clock names mentioned above
> +  - resets: phandles to the reset controllers driving the backend
> +
> +- ports: A ports node with endpoint definitions as defined in
> +  Documentation/devicetree/bindings/media/video-interfaces.txt. The
> +  first port should be the input endpoints, the second one the output
> +
> +Display Engine Frontend
> +-----------------------
> +
> +The display engine frontend does formats conversion, scaling,
> +deinterlacing and color space conversion.
> +
> +Required properties:
> +  - compatible: value must be one of:
> +    * allwinner,sun5i-a13-display-frontend
> +  - reg: base address and size of the memory-mapped region.
> +  - interrupts: interrupt associated to this IP
> +  - clocks: phandles to the clocks feeding the frontend and backend

> +    * ahb: the backend interface clock
> +    * mod: the backend module clock
> +    * ram: the backend DRAM clock

should be frontend?

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

ditto

> +
> +Display Engine Pipeline
> +-----------------------
> +
> +The display engine pipeline (and its entry point, since it can be
> +either directly the backend or the frontend) is represented as an
> +extra node.
> +
> +Required properties:
> +  - compatible: value must be one of:
> +    * allwinner,sun5i-a13-display-engine
> +  - allwinner,pipelines: list of phandle to the entry points of the
> +    pipelines (either to the frontend or backend)
> +
> +Example:
> +
> +panel: panel {
> +	compatible = "olimex,lcd-olinuxino-43-ts";

This should either be a child of what it is attached to or use of-graph.

> +};
> +
> +tve0: tv-encoder@01c0a000 {
> +	compatible = "allwinner,sun4i-a10-tv-encoder";
> +	reg = <0x01c0a000 0x1000>;
> +	clocks = <&ahb_gates 34>;
> +
> +	port {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		tve0_in_tcon0: endpoint@0 {
> +			reg = <0>;

I would drop the reg where you only have 1 node for ports or endpoints.

> +			remote-endpoint = <&tcon0_out_tve0>;
> +		};
> +	};
> +};
> +
> +tcon0: 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";
> +	allwinner,panel = <&panel>;
> +
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		tcon0_in: port@0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +
> +			tcon0_in_be0: endpoint@0 {
> +				reg = <0>;
> +				remote-endpoint = <&be0_out_tcon0>;
> +			};
> +		};
> +
> +		tcon0_out: port@1 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <1>;
> +
> +			tcon0_out_tve0: endpoint@0 {
> +				reg = <0>;
> +				remote-endpoint = <&tve0_in_tcon0>;
> +			};
> +		};
> +	};
> +};
> +
> +fe0: display-frontend@01e00000 {
> +	compatible = "allwinner,sun5i-a13-display-frontend";
> +	reg = <0x01e00000 0x20000>;
> +	interrupts = <47>;
> +	clocks = <&ahb_gates 46>, <&de_fe_clk>,
> +		 <&dram_gates 25>;
> +	clock-names = "ahb", "mod",
> +		      "ram";
> +	resets = <&de_fe_clk>;
> +
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		fe0_out: port@0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +
> +			fe0_out_be0: endpoint@0 {
> +				reg = <0>;
> +				remote-endpoint = <&be0_in_fe0>;
> +			};
> +		};
> +	};
> +};
> +
> +be0: display-backend@01e60000 {
> +	compatible = "allwinner,sun5i-a13-display-backend";
> +	reg = <0x01e60000 0x10000>;
> +	clocks = <&ahb_gates 44>, <&de_be_clk>,
> +		 <&dram_gates 26>;
> +	clock-names = "ahb", "mod",
> +		      "ram";
> +	resets = <&de_be_clk>;
> +
> +	ports {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		be0_in: port@0 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <0>;
> +
> +			be0_in_fe0: endpoint@0 {
> +				reg = <0>;
> +				remote-endpoint = <&fe0_out_be0>;
> +			};
> +		};
> +
> +		be0_out: port@1 {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +			reg = <1>;
> +
> +			be0_out_tcon0: endpoint@0 {
> +				reg = <0>;
> +				remote-endpoint = <&tcon0_in_be0>;
> +		};
> +	};
> +};
> +
> +display-engine {
> +	compatible = "allwinner,sun5i-a13-display-engine";
> +	pipelines = <&be0>;
> +};
> -- 
> 2.6.4
> 
> --
> 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] 64+ messages in thread

* Re: [PATCH v2 24/26] devicetree: Add olimex vendor prefix
  2016-01-14 15:25 ` [PATCH v2 24/26] devicetree: Add olimex vendor prefix Maxime Ripard
@ 2016-01-15  3:15   ` Rob Herring
  2016-01-15  6:41     ` Stefan Wahren
  0 siblings, 1 reply; 64+ messages in thread
From: Rob Herring @ 2016-01-15  3:15 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Thu, Jan 14, 2016 at 04:25:07PM +0100, Maxime Ripard wrote:
> Olimex is an open source hardware boards vendors based in Bulgaria.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH v2 25/26] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
  2016-01-14 15:25 ` [PATCH v2 25/26] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
@ 2016-01-15  3:17   ` Rob Herring
  0 siblings, 0 replies; 64+ messages in thread
From: Rob Herring @ 2016-01-15  3:17 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Thu, Jan 14, 2016 at 04:25:08PM +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>
> ---
>  .../display/panel/olimex,lcd-olinuxino-43-ts.txt   |  7 ++++++

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/gpu/drm/panel/panel-simple.c               | 26 ++++++++++++++++++++++
>  2 files changed, 33 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-43-ts.txt

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

* Re: [PATCH v2 24/26] devicetree: Add olimex vendor prefix
  2016-01-15  3:15   ` Rob Herring
@ 2016-01-15  6:41     ` Stefan Wahren
  2016-01-15  8:05       ` Maxime Ripard
  0 siblings, 1 reply; 64+ messages in thread
From: Stefan Wahren @ 2016-01-15  6:41 UTC (permalink / raw)
  To: Maxime Ripard, Rob Herring
  Cc: linux-clk, Rob Clark, Wynter Woods, Boris Brezillon, linux-sunxi,
	David Airlie, Alexander Kaplan, Daniel Vetter, Philipp Zabel,
	Stephen Boyd, linux-arm-kernel, dri-devel, linux-kernel,
	Hans de Goede, Mike Turquette, Thierry Reding, Laurent Pinchart,
	Thomas Petazzoni, Chen-Yu Tsai, devicetree


> Rob Herring <robh@kernel.org> hat am 15. Januar 2016 um 04:15 geschrieben:
>
>
> On Thu, Jan 14, 2016 at 04:25:07PM +0100, Maxime Ripard wrote:
> > Olimex is an open source hardware boards vendors based in Bulgaria.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> > Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
> > 1 file changed, 1 insertion(+)
>
> Acked-by: Rob Herring <robh@kernel.org>
>

I don't think we need this twice.

It's already committed:

2193377bdade ("DT: add Olimex to vendor prefixes")

Regards
Stefan

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

* Re: [PATCH v2 24/26] devicetree: Add olimex vendor prefix
  2016-01-15  6:41     ` Stefan Wahren
@ 2016-01-15  8:05       ` Maxime Ripard
  0 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-15  8:05 UTC (permalink / raw)
  To: Stefan Wahren
  Cc: Rob Herring, linux-clk, Rob Clark, Wynter Woods, Boris Brezillon,
	linux-sunxi, David Airlie, Alexander Kaplan, Daniel Vetter,
	Philipp Zabel, Stephen Boyd, linux-arm-kernel, dri-devel,
	linux-kernel, Hans de Goede, Mike Turquette, Thierry Reding,
	Laurent Pinchart, Thomas Petazzoni, Chen-Yu Tsai, devicetree

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

Hi,

On Fri, Jan 15, 2016 at 07:41:35AM +0100, Stefan Wahren wrote:
> 
> > Rob Herring <robh@kernel.org> hat am 15. Januar 2016 um 04:15 geschrieben:
> >
> >
> > On Thu, Jan 14, 2016 at 04:25:07PM +0100, Maxime Ripard wrote:
> > > Olimex is an open source hardware boards vendors based in Bulgaria.
> > >
> > > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > > ---
> > > Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
> > > 1 file changed, 1 insertion(+)
> >
> > Acked-by: Rob Herring <robh@kernel.org>
> >
> 
> I don't think we need this twice.
> 
> It's already committed:
> 
> 2193377bdade ("DT: add Olimex to vendor prefixes")

Hmm, indeed.

Sorry for the noise, I'll drop the commit.

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] 64+ messages in thread

* Re: [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  2016-01-14 23:13   ` Laurent Pinchart
@ 2016-01-15 10:17     ` Daniel Vetter
  2016-01-24 22:19       ` Laurent Pinchart
  0 siblings, 1 reply; 64+ messages in thread
From: Daniel Vetter @ 2016-01-15 10:17 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Maxime Ripard, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, Philipp Zabel, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, dri-devel, linux-sunxi, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Fri, Jan 15, 2016 at 01:13:05AM +0200, Laurent Pinchart wrote:
> Hi Maxime,
> 
> Thank you for the patch.
> 
> On Thursday 14 January 2016 16:24:56 Maxime Ripard wrote:
> > The drm_fbdev_cma_init function always calls the
> > drm_helper_disable_unused_functions. Since it's part of the usual probe
> > process, all the drivers using that helper will end up having their encoder
> > and CRTC disable functions called at probe if their device has not been
> > reported as enabled.
> > 
> > This could be fixed by reading out from the registers the current state of
> > the device if it is enabled, but even that will not handle the case where
> > the device is actually disabled.
> > 
> > Moreover, the drivers using the atomic modesetting expect that their enable
> > and disable callback to be called when the device is already enabled or
> > disabled (respectively).
> > 
> > We can however fix this issue by moving the call to
> > drm_helper_disable_unused_functions out of drm_fbdev_cma_init and make the
> > drivers needing it (all the drivers calling drm_fbdev_cma_init and not
> > using the atomic modesetting) explicitly call it.
> 
> I'd rather add it to all drivers that call drm_fbdev_cma_init(). All the 
> atomic ones must have special code to cope with it that could be rendered 
> useless by the removal of the drm_helper_disable_unused_functions() call. That 
> code should be removed too, and it would be easier to check drivers one by one 
> and fixing them individually (outside of this patch series, unless you insist 
> ;-)) when removing the explicit drm_helper_disable_unused_functions() call. 

I had the same thought, but figured there's really no good reason ever to
do this. I suspect most of that disable_unused_function stuff we have all
over is supreme cargo-cult anyway ;-)

> Other than that the patch looks fine to me.

So went ahead and applied to drm-misc.
-Daniel

> 
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  drivers/gpu/drm/drm_fb_cma_helper.c | 3 ---
> >  drivers/gpu/drm/imx/imx-drm-core.c  | 1 +
> >  drivers/gpu/drm/sti/sti_drv.c       | 1 +
> >  drivers/gpu/drm/tilcdc/tilcdc_drv.c | 1 +
> >  4 files changed, 3 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c
> > b/drivers/gpu/drm/drm_fb_cma_helper.c index c19a62561183..daa98d881142
> > 100644
> > --- a/drivers/gpu/drm/drm_fb_cma_helper.c
> > +++ b/drivers/gpu/drm/drm_fb_cma_helper.c
> > @@ -348,9 +348,6 @@ struct drm_fbdev_cma *drm_fbdev_cma_init(struct
> > drm_device *dev,
> > 
> >  	}
> > 
> > -	/* disable all the possible outputs/crtcs before entering KMS mode */
> > -	drm_helper_disable_unused_functions(dev);
> > -
> >  	ret = drm_fb_helper_initial_config(helper, preferred_bpp);
> >  	if (ret < 0) {
> >  		dev_err(dev->dev, "Failed to set initial hw configuration.\n");
> > diff --git a/drivers/gpu/drm/imx/imx-drm-core.c
> > b/drivers/gpu/drm/imx/imx-drm-core.c index 7b990b4e96d2..e1db57791fc9
> > 100644
> > --- a/drivers/gpu/drm/imx/imx-drm-core.c
> > +++ b/drivers/gpu/drm/imx/imx-drm-core.c
> > @@ -312,6 +312,7 @@ static int imx_drm_driver_load(struct drm_device *drm,
> > unsigned long flags) dev_warn(drm->dev, "Invalid legacyfb_depth. 
> > Defaulting to 16bpp\n"); legacyfb_depth = 16;
> >  	}
> > +	drm_helper_disable_unused_functions(drm);
> >  	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
> >  				drm->mode_config.num_crtc, MAX_CRTC);
> >  	if (IS_ERR(imxdrm->fbhelper)) {
> > diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
> > index 1469987949d8..506b5626f3ed 100644
> > --- a/drivers/gpu/drm/sti/sti_drv.c
> > +++ b/drivers/gpu/drm/sti/sti_drv.c
> > @@ -160,6 +160,7 @@ static int sti_load(struct drm_device *dev, unsigned
> > long flags)
> > 
> >  	drm_mode_config_reset(dev);
> > 
> > +	drm_helper_disable_unused_functions(dev);
> >  	drm_fbdev_cma_init(dev, 32,
> >  			   dev->mode_config.num_crtc,
> >  			   dev->mode_config.num_connector);
> > diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
> > b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 876cad58b1f9..24be31d69701
> > 100644
> > --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
> > +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
> > @@ -294,6 +294,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned
> > long flags) break;
> >  	}
> > 
> > +	drm_helper_disable_unused_functions(dev);
> >  	priv->fbdev = drm_fbdev_cma_init(dev, bpp,
> >  			dev->mode_config.num_crtc,
> >  			dev->mode_config.num_connector);
> 
> -- 
> Regards,
> 
> Laurent Pinchart
> 

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

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

* Re: [PATCH v2 01/26] reset: Move DT cell size check to the core
  2016-01-14 15:24 ` [PATCH v2 01/26] reset: Move DT cell size check to the core Maxime Ripard
@ 2016-01-15 15:50   ` Philipp Zabel
  0 siblings, 0 replies; 64+ messages in thread
From: Philipp Zabel @ 2016-01-15 15:50 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, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter

Hi Maxime,

Am Donnerstag, den 14.01.2016, 16:24 +0100 schrieb Maxime Ripard:
> The core currently doesn't check that the DT cell size matches what the
> driver declares, which means that every xlate function needs to duplicate
> that check.
> 
> Make sure that of_reset_control_get checks for this to avoid duplication
> and errors.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  drivers/reset/core.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/reset/core.c b/drivers/reset/core.c
> index 7955e00d04d4..d53b2b980bdd 100644
> --- a/drivers/reset/core.c
> +++ b/drivers/reset/core.c
> @@ -46,9 +46,6 @@ struct reset_control {
>  static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
>  			  const struct of_phandle_args *reset_spec)
>  {
> -	if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
> -		return -EINVAL;
> -
>  	if (reset_spec->args[0] >= rcdev->nr_resets)
>  		return -EINVAL;
>  
> @@ -182,6 +179,9 @@ struct reset_control *of_reset_control_get(struct device_node *node,
>  		return ERR_PTR(-EPROBE_DEFER);
>  	}
>  
> +	if (WARN_ON(args.args_count != rcdev->of_reset_n_cells))
> +		return ERR_PTR(-EINVAL);
> +

Applied with this fix:
 
-	if (WARN_ON(args.args_count != rcdev->of_reset_n_cells))
+	if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
+		mutex_unlock(&reset_controller_list_mutex);
 		return ERR_PTR(-EINVAL);
+	}
 
No further action needed if you agree, otherwise let me know and I'll
back it out.

best regards
Philipp

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

* Re: [PATCH v2 02/26] reset: Make reset_control_ops const
  2016-01-14 15:24 ` [PATCH v2 02/26] reset: Make reset_control_ops const Maxime Ripard
@ 2016-01-15 15:50   ` Philipp Zabel
  0 siblings, 0 replies; 64+ messages in thread
From: Philipp Zabel @ 2016-01-15 15:50 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, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter

Am Donnerstag, den 14.01.2016, 16:24 +0100 schrieb Maxime Ripard:
> The ops pointer is holding a pointer to a structure that is usually not
> modified. Make it const.
> 
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  include/linux/reset-controller.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
> index ce6b962ffed4..a3a5bcdb1d02 100644
> --- a/include/linux/reset-controller.h
> +++ b/include/linux/reset-controller.h
> @@ -38,7 +38,7 @@ struct of_phandle_args;
>   * @nr_resets: number of reset controls in this reset controller device
>   */
>  struct reset_controller_dev {
> -	struct reset_control_ops *ops;
> +	const struct reset_control_ops *ops;
>  	struct module *owner;
>  	struct list_head list;
>  	struct device_node *of_node;

Applied, thanks.

regards
Philipp

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

* Re: [linux-sunxi] [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver
  2016-01-14 15:24 ` [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver Maxime Ripard
  2016-01-15  3:01   ` Rob Herring
@ 2016-01-16 14:08   ` Priit Laes
  2016-01-16 15:29   ` Chen-Yu Tsai
  2 siblings, 0 replies; 64+ messages in thread
From: Priit Laes @ 2016-01-16 14:08 UTC (permalink / raw)
  To: maxime.ripard, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter

On Thu, 2016-01-14 at 16:24 +0100, Maxime Ripard wrote:
> The A10 SoCs and its relatives has a special clock controller to drive the
> display engines (both frontend and backend), that have a lot in common with
> the clock to drive the first TCON channel.
> 
> Add a driver to support both.

...

> +static void __init sun4i_a10_display_init(struct device_node *node,
> +					  struct sun4i_a10_display_clk_data *data)
> +{
> +	const char *parents[data->parents];
> +	const char *clk_name = node->name;
> +	struct reset_data *reset_data;
> +	struct clk_divider *div = NULL;
> +	struct clk_gate *gate;
> +	struct clk_mux *mux;
> +	void __iomem *reg;
> +	struct clk *clk;
> +	int i;

warning: unused variable '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;
> +	}

...

Thanks for working on this feature ;)

Päikest,
Priit Laes

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

* Re: [linux-sunxi] [PATCH v2 16/26] drm: Add Allwinner A10 Display Engine support
  2016-01-14 15:24 ` [PATCH v2 16/26] drm: Add Allwinner A10 Display Engine support Maxime Ripard
@ 2016-01-16 15:11   ` Priit Laes
  2016-01-17 12:58     ` Priit Laes
  2016-01-19 15:38     ` Maxime Ripard
  0 siblings, 2 replies; 64+ messages in thread
From: Priit Laes @ 2016-01-16 15:11 UTC (permalink / raw)
  To: maxime.ripard, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter

On Thu, 2016-01-14 at 16:24 +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.
> 
> Add a driver with a limited set of features for now, and we will hopefully
> support all of them eventually
> 

[..]

> diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h
> b/drivers/gpu/drm/sun4i/sun4i_backend.h
> new file mode 100644
> index 000000000000..60f6a200fa73
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
> @@ -0,0 +1,160 @@
> +/*
> + * 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)			((v
> al) << ((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_REG0_LAY_PIPESEL_MASK	BIT(15)
> +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(x)		((x)
> << 15)
> +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL_MASK	GENMASK(11,
> 10)
> +#define SUN4I_BACKEND_ATTCTL_REG0_LAY_PRISEL(x)			
> ((x) << 10)
> +
> +#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(1
> 1, 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)))

WITDTH ?

This isn't used anyway...

> +#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);
> +
> +#endif /* _SUN4I_BACKEND_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..cc7dedc5d256
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
> @@ -0,0 +1,325 @@
> +/*
> + * 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/component.h>
> +#include <linux/of_graph.h>
> +
> +#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_crtc.h"
> +#include "sun4i_drv.h"
> +#include "sun4i_framebuffer.h"
> +#include "sun4i_layer.h"
> +#include "sun4i_tcon.h"

[...]

> +static struct drm_driver sun4i_drv_driver = {
> +	.driver_features	= DRIVER_GEM | DRIVER_MODESET |
> DRIVER_PRIME | DRIVER_ATOMIC,
> +
> +	/* Generic Operations */
> +	.fops			= &sun4i_drv_fops,
> +	.name			= "sun4i-drm",
> +	.desc			= "Allwinner sun4i Display
> Engine",
> +	.date			= "20150629",

2016something ?

> +	.major			= 1,
> +	.minor			= 0,
> +
> +	/* GEM Operations */
> +	.dumb_create		= drm_gem_cma_dumb_create,
> +	.dumb_destroy		= drm_gem_dumb_destroy,
> +	.dumb_map_offset	= drm_gem_cma_dumb_map_offset,
> +	.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 */
> +
> +	/* VBlank Operations */
> +	.get_vblank_counter	= drm_vblank_count,
> +	.enable_vblank		= sun4i_drv_enable_vblank,
> +	.disable_vblank		= sun4i_drv_disable_vblank,
> +};
> +
[...]
> 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;

Shouldn't these be 1920 x 1080 as per A10 User manual?

> +
> +	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);
> +}
[...]

Päikest,
Priit Laes :)

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

* Re: [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver
  2016-01-14 15:24 ` [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver Maxime Ripard
  2016-01-15  3:01   ` Rob Herring
  2016-01-16 14:08   ` [linux-sunxi] " Priit Laes
@ 2016-01-16 15:29   ` Chen-Yu Tsai
  2016-02-03 20:18     ` Maxime Ripard
  2 siblings, 1 reply; 64+ messages in thread
From: Chen-Yu Tsai @ 2016-01-16 15:29 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

Hi,

On Thu, Jan 14, 2016 at 11:24 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), that have a lot in common with
> the clock to drive the first TCON channel.
>
> Add a driver to support both.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt |   2 +
>  drivers/clk/sunxi/Makefile                        |   1 +
>  drivers/clk/sunxi/clk-sun4i-display.c             | 241 ++++++++++++++++++++++
>  3 files changed, 244 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index 8a47b77abfca..5360554a7d3f 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -55,6 +55,7 @@ Required properties:
>         "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
>         "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
>         "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
> +       "allwinner,sun4i-a10-display-clk" - for the display clocks on the A10
>         "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
>         "allwinner,sun4i-a10-mmc-clk" - for the MMC clock
>         "allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
> @@ -64,6 +65,7 @@ Required properties:
>         "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
>         "allwinner,sun7i-a20-out-clk" - for the external output clocks
>         "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
> +       "allwinner,sun4i-a10-tcon-ch0-clk" - for the TCON channel 0 clock on the A10
>         "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
>         "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
>         "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index cb4c299214ce..a991cd8ca509 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -10,6 +10,7 @@ obj-y += clk-a10-pll2.o
>  obj-y += clk-a20-gmac.o
>  obj-y += clk-mod0.o
>  obj-y += clk-simple-gates.o
> +obj-y += clk-sun4i-display.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-display.c b/drivers/clk/sunxi/clk-sun4i-display.c
> new file mode 100644
> index 000000000000..9dc6894f0934
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun4i-display.c
> @@ -0,0 +1,241 @@
> +/*
> + * 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/kernel.h>
> +#include <linux/of_address.h>
> +#include <linux/reset-controller.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +
> +struct sun4i_a10_display_clk_data {
> +       bool    has_div;
> +       bool    has_rst;
> +       u8      parents;
> +
> +       u8      offset_en;
> +       u8      offset_div;
> +       u8      offset_mux;
> +       u8      offset_rst;
> +
> +       u8      width_div;
> +       u8      width_mux;
> +};
> +
> +struct reset_data {
> +       void __iomem                    *reg;
> +       spinlock_t                      *lock;
> +       struct reset_controller_dev     rcdev;
> +       u8                              offset;
> +};
> +
> +static DEFINE_SPINLOCK(sun4i_a10_display_lock);
> +
> +static inline struct reset_data *rcdev_to_reset_data(struct reset_controller_dev *rcdev)
> +{
> +       return container_of(rcdev, struct reset_data, rcdev);
> +};
> +
> +static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev,
> +                                   unsigned long id)
> +{
> +       struct reset_data *data = rcdev_to_reset_data(rcdev);
> +       unsigned long flags;
> +       u32 reg;
> +
> +       spin_lock_irqsave(data->lock, flags);
> +
> +       reg = readl(data->reg);
> +       writel(reg & ~BIT(data->offset), 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 = rcdev_to_reset_data(rcdev);
> +       unsigned long flags;
> +       u32 reg;
> +
> +       spin_lock_irqsave(data->lock, flags);
> +
> +       reg = readl(data->reg);
> +       writel(reg | BIT(data->offset), 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 = rcdev_to_reset_data(rcdev);
> +
> +       return !(readl(data->reg) & BIT(data->offset));
> +}
> +
> +static const 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)
> +{
> +       /* We only have a single reset signal */
> +       return 0;
> +}
> +
> +static void __init sun4i_a10_display_init(struct device_node *node,
> +                                         struct sun4i_a10_display_clk_data *data)
> +{
> +       const char *parents[data->parents];
> +       const char *clk_name = node->name;
> +       struct reset_data *reset_data;
> +       struct clk_divider *div = NULL;
> +       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;
> +       }
> +
> +       of_clk_parent_fill(node, parents, data->parents);

What if someone uses an incorrect DT that has less parents described?

> +
> +       mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> +       if (!mux)
> +               return;
> +
> +       mux->reg = reg;
> +       mux->shift = data->offset_mux;
> +       mux->mask = (1 << data->width_mux) - 1;
> +       mux->lock = &sun4i_a10_display_lock;
> +
> +       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> +       if (!gate)
> +               goto free_mux;
> +
> +       gate->reg = reg;
> +       gate->bit_idx = data->offset_en;
> +       gate->lock = &sun4i_a10_display_lock;
> +
> +       if (data->has_div) {
> +               div = kzalloc(sizeof(*div), GFP_KERNEL);
> +               if (!div)
> +                       goto free_gate;
> +
> +               div->reg = reg;
> +               div->shift = data->offset_div;
> +               div->width = data->width_div;
> +               div->lock = &sun4i_a10_display_lock;
> +       }
> +
> +       clk = clk_register_composite(NULL, clk_name,
> +                                    parents, data->parents,
> +                                    &mux->hw, &clk_mux_ops,
> +                                    data->has_div ? &div->hw : NULL,
> +                                    data->has_div ? &clk_divider_ops : NULL,
> +                                    &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);

Check for errors?

> +
> +       if (!data->has_rst)
> +               return;
> +
> +       reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
> +       if (!reset_data)
> +               goto free_clk;
> +
> +       reset_data->reg = reg;
> +       reset_data->offset = data->offset_rst;
> +       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:
> +       if (data->has_div)
> +               kfree(div);
> +free_gate:
> +       kfree(gate);
> +free_mux:
> +       kfree(mux);

Cleanup after of_io_request_and_map()?

> +}
> +
> +static struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data = {
> +       .has_rst        = true,
> +       .parents        = 4,
> +       .offset_en      = 31,
> +       .offset_rst     = 29,

My datasheets (A10 v1.5, A20 v1.4), say bit 30 for LCD0 ch0 reset.

A13 and R8 manuals do not list this clock, but A10s does, which has
bit 30 for LCD reset and bit 29 for TV encoder reset.

I suggest changing has_rst to int, and for sun5i variant, have
has_rst = 2, reset_cells = 1, for 2 separate reset controls.
The tcon and tv encoder bits of the DTSI should be updated as
well.

I assume your tests work because U-boot already de-asserted the
resets (both if you're using composite output).

> +       .offset_mux     = 24,
> +       .width_mux      = 2,
> +};
> +
> +static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node)
> +{
> +       sun4i_a10_display_init(node, &sun4i_a10_tcon_ch0_data);
> +}
> +CLK_OF_DECLARE(sun4i_a10_tcon_ch0, "allwinner,sun4i-a10-tcon-ch0-clk",
> +              sun4i_a10_tcon_ch0_setup);
> +
> +static struct sun4i_a10_display_clk_data sun4i_a10_display_data = {
> +       .has_div        = true,

Missing .has_rst = true.

> +       .parents        = 3,
> +       .offset_en      = 31,
> +       .offset_rst     = 30,
> +       .offset_mux     = 24,
> +       .offset_div     = 0,

This is already implied.

> +       .width_mux      = 2,
> +       .width_div      = 4,
> +};
> +
> +static void __init sun4i_a10_display_setup(struct device_node *node)
> +{
> +       sun4i_a10_display_init(node, &sun4i_a10_display_data);
> +}
> +CLK_OF_DECLARE(sun4i_a10_display, "allwinner,sun4i-a10-display-clk",
> +              sun4i_a10_display_setup);
> --
> 2.6.4

Thanks for working on this!

Regards
ChenYu

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

* Re: [PATCH v2 06/26] clk: sunxi: Add PLL3 clock
  2016-01-14 15:24 ` [PATCH v2 06/26] clk: sunxi: Add PLL3 clock Maxime Ripard
  2016-01-15  3:02   ` Rob Herring
@ 2016-01-16 16:05   ` Chen-Yu Tsai
  2016-02-03 20:27     ` Maxime Ripard
  1 sibling, 1 reply; 64+ messages in thread
From: Chen-Yu Tsai @ 2016-01-16 16:05 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

Hi,

On Thu, Jan 14, 2016 at 11:24 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> 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>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt |  1 +
>  drivers/clk/sunxi/Makefile                        |  1 +
>  drivers/clk/sunxi/clk-sun4i-pll3.c                | 90 +++++++++++++++++++++++
>  3 files changed, 92 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-pll3.c
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index 5360554a7d3f..bb9fb78dcff8 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -10,6 +10,7 @@ Required properties:
>         "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
>         "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
>         "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
> +       "allwinner,sun4i-a10-pll3-clk" - for the video PLL clock on A10
>         "allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80
>         "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
>         "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index a991cd8ca509..40c32ffd912c 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -11,6 +11,7 @@ obj-y += clk-a20-gmac.o
>  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-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..6c9c2210b6b2
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun4i-pll3.c
> @@ -0,0 +1,90 @@
> +/*
> + * 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.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_multiplier *mult;
> +       struct clk_gate *gate;
> +       void __iomem *reg;
> +       struct clk *clk;
> +       int ret;
> +
> +       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 err_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_multiplier_ops,
> +                                    &gate->hw, &clk_gate_ops,
> +                                    0);
> +       if (IS_ERR(clk)) {
> +               pr_err("%s: Couldn't register the clock\n", clk_name);
> +               goto err_free_mult;
> +       }
> +
> +       ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> +       if (WARN_ON(ret))

Any particular reason for WARN_ON instead of pr_err like above?

> +               goto err_clk_unregister;
> +
> +       return;
> +
> +err_clk_unregister:
> +       clk_unregister_composite(clk);
> +err_free_mult:
> +       kfree(mult);
> +err_free_gate:
> +       kfree(gate);

Clean up after of_io_request_and_map(), otherwise

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

Thanks!

> +}
> +
> +CLK_OF_DECLARE(sun4i_a10_pll3, "allwinner,sun4i-a10-pll3-clk",
> +              sun4i_a10_pll3_setup);
> --
> 2.6.4
>

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

* Re: [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock
  2016-01-14 15:24 ` [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock Maxime Ripard
  2016-01-15  3:03   ` Rob Herring
@ 2016-01-16 16:36   ` Chen-Yu Tsai
  2016-02-03 20:29     ` Maxime Ripard
  1 sibling, 1 reply; 64+ messages in thread
From: Chen-Yu Tsai @ 2016-01-16 16:36 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

Hi,

On Thu, Jan 14, 2016 at 11:24 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>
> ---
>  Documentation/devicetree/bindings/clock/sunxi.txt |   1 +
>  drivers/clk/sunxi/Makefile                        |   1 +
>  drivers/clk/sunxi/clk-sun4i-tcon-ch1.c            | 154 ++++++++++++++++++++++
>  3 files changed, 156 insertions(+)
>  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
>
> diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> index bb9fb78dcff8..fe34fc56e803 100644
> --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> @@ -67,6 +67,7 @@ Required properties:
>         "allwinner,sun7i-a20-out-clk" - for the external output clocks
>         "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
>         "allwinner,sun4i-a10-tcon-ch0-clk" - for the TCON channel 0 clock on the A10
> +       "allwinner,sun4i-a10-tcon-ch1-clk" - for the TCON channel 1 clock on the A10
>         "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
>         "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
>         "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index 40c32ffd912c..0a20873cd103 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-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..51ddc38821f7
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
> @@ -0,0 +1,154 @@
> +/*
> + * 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.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_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_DIV_WIDTH     1
> +#define SUN4I_A10_TCON_CH1_SCLK1_DIV_SHIFT     11
> +
> +static DEFINE_SPINLOCK(sun4i_a10_tcon_ch1_lock);
> +
> +static void __init sun4i_a10_tcon_ch1_setup(struct device_node *node)
> +{
> +       const char *sclk2_parents[SUN4I_A10_TCON_CH1_SCLK2_PARENTS];
> +       const char *sclk1_name = node->name;
> +       const char *sclk2_name;
> +       struct clk_divider *sclk1_div, *sclk2_div;
> +       struct clk_gate *sclk1_gate, *sclk2_gate;
> +       struct clk_mux *sclk2_mux;
> +       struct clk *sclk1, *sclk2;
> +       void __iomem *reg;
> +       int i, ret;
> +
> +       of_property_read_string(node, "clock-output-names",
> +                               &sclk1_name);
> +
> +       sclk2_name = kasprintf(GFP_KERNEL, "%s2", sclk1_name);
> +       if (!sclk2_name)
> +               return;
> +
> +       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);

of_clk_parent_fill?

> +
> +       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,

Placement of the "&" is very weird.

> +                                      &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;
> +       }
> +
> +       sclk1_div = kzalloc(sizeof(*sclk1_div), GFP_KERNEL);
> +       if (!sclk1_div)
> +               goto free_sclk2;
> +
> +       sclk1_div->reg = reg;
> +       sclk1_div->shift = SUN4I_A10_TCON_CH1_SCLK1_DIV_SHIFT;
> +       sclk1_div->width = SUN4I_A10_TCON_CH1_SCLK1_DIV_WIDTH;
> +       sclk1_div->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, &sclk2_name, 1,
> +                                      NULL, NULL,
> +                                      &sclk1_div->hw, &clk_divider_ops,
> +                                      &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;
> +       }
> +
> +       ret = of_clk_add_provider(node, of_clk_src_simple_get, sclk1);
> +       if (WARN_ON(ret))
> +               goto free_sclk1;
> +
> +       return;
> +
> +free_sclk1:
> +       clk_unregister_composite(sclk1);
> +free_sclk1_gate:
> +       kfree(sclk1_gate);
> +free_sclk1_mux:
> +       kfree(sclk1_div);
> +free_sclk2:
> +       clk_unregister(sclk2);
> +free_sclk2_div:
> +       kfree(sclk2_div);
> +free_sclk2_gate:
> +       kfree(sclk2_gate);
> +free_sclk2_mux:
> +       kfree(sclk2_mux);

Cleanup after of_io_request_and_map?


Regards
ChenYu

> +}
> +
> +CLK_OF_DECLARE(sun4i_a10_tcon_ch1, "allwinner,sun4i-a10-tcon-ch1-clk",
> +              sun4i_a10_tcon_ch1_setup);
> --
> 2.6.4
>

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

* Re: [PATCH v2 10/26] ARM: sun5i: a13: Add display and TCON clocks
  2016-01-14 15:24 ` [PATCH v2 10/26] ARM: sun5i: a13: Add display and TCON clocks Maxime Ripard
@ 2016-01-16 17:06   ` Chen-Yu Tsai
  2016-02-03 20:31     ` Maxime Ripard
  0 siblings, 1 reply; 64+ messages in thread
From: Chen-Yu Tsai @ 2016-01-16 17:06 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

Hi,

On Thu, Jan 14, 2016 at 11:24 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> 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-a13.dtsi | 38 +++++++++++++++++++++++++++++++++++++-
>  arch/arm/boot/dts/sun5i-r8.dtsi  |  5 +++--
>  2 files changed, 40 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
> index d910d3a6c41c..9669b03f20f3 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";
>                 };
>         };
> @@ -149,6 +150,41 @@
>                                              "apb1_i2c2", "apb1_uart1",
>                                              "apb1_uart3";
>                 };
> +
> +               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>;

You got it right here...

> +                       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";
> +               };

I suggest moving these to sun5i.dtsi, as they are shared amongst them.

ChenYu

>         };
>
>         soc@01c00000 {
> 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";
>                 };
>         };
> --
> 2.6.4
>

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

* Re: [PATCH v2 11/26] ARM: sun5i: Add DRAM gates
  2016-01-14 15:24 ` [PATCH v2 11/26] ARM: sun5i: Add DRAM gates Maxime Ripard
@ 2016-01-16 17:10   ` Chen-Yu Tsai
  2016-02-03 20:36     ` Maxime Ripard
  0 siblings, 1 reply; 64+ messages in thread
From: Chen-Yu Tsai @ 2016-01-16 17:10 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Thu, Jan 14, 2016 at 11:24 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> 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 |  7 ++++---
>  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, 25 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
> index bddd0de88af6..52d2c79cb37b 100644
> --- a/arch/arm/boot/dts/sun5i-a10s.dtsi
> +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
> @@ -66,7 +66,7 @@
>                                      "simple-framebuffer";
>                         allwinner,pipeline = "de_be0-lcd0-hdmi";
>                         clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
> -                                <&ahb_gates 44>;
> +                                <&ahb_gates 44>, <&dram_gates 26>;
>                         status = "disabled";
>                 };
>
> @@ -74,7 +74,8 @@
>                         compatible = "allwinner,simple-framebuffer",
>                                      "simple-framebuffer";
>                         allwinner,pipeline = "de_be0-lcd0";
> -                       clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
> +                       clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
> +                                <&dram_gates 26>;
>                         status = "disabled";
>                 };
>
> @@ -83,7 +84,7 @@
>                                      "simple-framebuffer";
>                         allwinner,pipeline = "de_be0-lcd0-tve0";
>                         clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
> -                                <&ahb_gates 44>;
> +                                <&ahb_gates 44>, <&dram_gates 26>;
>                         status = "disabled";
>                 };
>         };
> diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
> index 9669b03f20f3..f29163650ca8 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 0840612b5ed6..c72d94228915 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>,

According to A10s manual, bit 3 is DRAM clock for TS (transport stream
decoder), while bit 5 is for the TV encoder.

The others look good.

ChenYu

> +                                       <25>,
> +                                       <26>,
> +                                       <29>,
> +                                       <31>;
> +                       clock-output-names = "dram_ve",
> +                                            "dram_csi",
> +                                            "dram_de_fe",
> +                                            "dram_de_be",
> +                                            "dram_ace",
> +                                            "dram_iep";
> +               };
> +
>                 codec_clk: clk@01c20140 {
>                         #clock-cells = <0>;
>                         compatible = "allwinner,sun4i-a10-codec-clk";
> --
> 2.6.4
>

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

* Re: [PATCH v2 12/26] ARM: sun5i: Add TV encoder gate to the DTSI
  2016-01-14 15:24 ` [PATCH v2 12/26] ARM: sun5i: Add TV encoder gate to the DTSI Maxime Ripard
@ 2016-01-16 17:12   ` Chen-Yu Tsai
  0 siblings, 0 replies; 64+ messages in thread
From: Chen-Yu Tsai @ 2016-01-16 17:12 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Thu, Jan 14, 2016 at 11:24 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> It turns out that the A13 / R8 also have a tve encoder block, and a gate
> for it.
>
> Add it to the DT.
>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

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

> ---
>  arch/arm/boot/dts/sun5i-a13.dtsi | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)

[...]

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

* Re: [linux-sunxi] [PATCH v2 16/26] drm: Add Allwinner A10 Display Engine support
  2016-01-16 15:11   ` [linux-sunxi] " Priit Laes
@ 2016-01-17 12:58     ` Priit Laes
  2016-01-19 15:38     ` Maxime Ripard
  1 sibling, 0 replies; 64+ messages in thread
From: Priit Laes @ 2016-01-17 12:58 UTC (permalink / raw)
  To: maxime.ripard, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter

On Sat, 2016-01-16 at 17:11 +0200, Priit Laes wrote:
> On Thu, 2016-01-14 at 16:24 +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.
[...]
> > 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;
> 
> Shouldn't these be 1920 x 1080 as per A10 User manual?

I was wrong here. 8192x8192 it is.

>

Päikest,
Priit Laes :)

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

* Re: [linux-sunxi] [PATCH v2 16/26] drm: Add Allwinner A10 Display Engine support
  2016-01-16 15:11   ` [linux-sunxi] " Priit Laes
  2016-01-17 12:58     ` Priit Laes
@ 2016-01-19 15:38     ` Maxime Ripard
  1 sibling, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-01-19 15:38 UTC (permalink / raw)
  To: Priit Laes
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

Hi,

On Sat, Jan 16, 2016 at 05:11:44PM +0200, Priit Laes wrote:
> > +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;
> 
> Shouldn't these be 1920 x 1080 as per A10 User manual?

1080p is what the SoC can output. However, to create its output, it
uses a combination of planes of 8192x8192, that you'll obviously have
to crop. This is the size of the plane that we are exposing here, not
what we can output (which is listed in the various connectors).

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] 64+ messages in thread

* Re: [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  2016-01-15 10:17     ` Daniel Vetter
@ 2016-01-24 22:19       ` Laurent Pinchart
  2016-01-25  7:29         ` Daniel Vetter
  0 siblings, 1 reply; 64+ messages in thread
From: Laurent Pinchart @ 2016-01-24 22:19 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Maxime Ripard, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, Philipp Zabel, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, dri-devel, linux-sunxi, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark

Hi Daniel,

On Friday 15 January 2016 11:17:30 Daniel Vetter wrote:
> On Fri, Jan 15, 2016 at 01:13:05AM +0200, Laurent Pinchart wrote:
> > On Thursday 14 January 2016 16:24:56 Maxime Ripard wrote:
> >> The drm_fbdev_cma_init function always calls the
> >> drm_helper_disable_unused_functions. Since it's part of the usual probe
> >> process, all the drivers using that helper will end up having their
> >> encoder and CRTC disable functions called at probe if their device has
> >> not been reported as enabled.
> >> 
> >> This could be fixed by reading out from the registers the current state
> >> of the device if it is enabled, but even that will not handle the case
> >> where the device is actually disabled.
> >> 
> >> Moreover, the drivers using the atomic modesetting expect that their
> >> enable and disable callback to be called when the device is already
> >> enabled or disabled (respectively).
> >> 
> >> We can however fix this issue by moving the call to
> >> drm_helper_disable_unused_functions out of drm_fbdev_cma_init and make
> >> the drivers needing it (all the drivers calling drm_fbdev_cma_init and
> >> not using the atomic modesetting) explicitly call it.
> > 
> > I'd rather add it to all drivers that call drm_fbdev_cma_init(). All the
> > atomic ones must have special code to cope with it that could be rendered
> > useless by the removal of the drm_helper_disable_unused_functions() call.
> > That code should be removed too, and it would be easier to check drivers
> > one by one and fixing them individually (outside of this patch series,
> > unless you insist ;-)) when removing the explicit
> > drm_helper_disable_unused_functions() call.
>
> I had the same thought, but figured there's really no good reason ever to
> do this. I suspect most of that disable_unused_function stuff we have all
> over is supreme cargo-cult anyway ;-)

I'm not sure you got my point. Yes, the drm_helper_disable_unused_functions() 
call should be removed from atomic drivers, but that will leave support code 
added for the sole reason of avoiding the crash in the drivers. That code will 
likely not be noticed and will stay there rotting. If we added 
drm_helper_disable_unused_functions() calls to all atomic drivers then driver 
authors will hopefully check carefully if there's any support code that can be 
removed when removing the function call. It would act as a kind of FIXME 
reminder.

> > Other than that the patch looks fine to me.
> 
> So went ahead and applied to drm-misc.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  2016-01-24 22:19       ` Laurent Pinchart
@ 2016-01-25  7:29         ` Daniel Vetter
  2016-01-25 19:02           ` Laurent Pinchart
  0 siblings, 1 reply; 64+ messages in thread
From: Daniel Vetter @ 2016-01-25  7:29 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Daniel Vetter, Maxime Ripard, Mike Turquette, Stephen Boyd,
	David Airlie, Thierry Reding, Philipp Zabel, devicetree,
	linux-arm-kernel, linux-kernel, linux-clk, dri-devel, linux-sunxi,
	Chen-Yu Tsai, Hans de Goede, Alexander Kaplan, Boris Brezillon,
	Wynter Woods, Thomas Petazzoni, Rob Clark

On Mon, Jan 25, 2016 at 12:19:27AM +0200, Laurent Pinchart wrote:
> Hi Daniel,
> 
> On Friday 15 January 2016 11:17:30 Daniel Vetter wrote:
> > On Fri, Jan 15, 2016 at 01:13:05AM +0200, Laurent Pinchart wrote:
> > > On Thursday 14 January 2016 16:24:56 Maxime Ripard wrote:
> > >> The drm_fbdev_cma_init function always calls the
> > >> drm_helper_disable_unused_functions. Since it's part of the usual probe
> > >> process, all the drivers using that helper will end up having their
> > >> encoder and CRTC disable functions called at probe if their device has
> > >> not been reported as enabled.
> > >> 
> > >> This could be fixed by reading out from the registers the current state
> > >> of the device if it is enabled, but even that will not handle the case
> > >> where the device is actually disabled.
> > >> 
> > >> Moreover, the drivers using the atomic modesetting expect that their
> > >> enable and disable callback to be called when the device is already
> > >> enabled or disabled (respectively).
> > >> 
> > >> We can however fix this issue by moving the call to
> > >> drm_helper_disable_unused_functions out of drm_fbdev_cma_init and make
> > >> the drivers needing it (all the drivers calling drm_fbdev_cma_init and
> > >> not using the atomic modesetting) explicitly call it.
> > > 
> > > I'd rather add it to all drivers that call drm_fbdev_cma_init(). All the
> > > atomic ones must have special code to cope with it that could be rendered
> > > useless by the removal of the drm_helper_disable_unused_functions() call.
> > > That code should be removed too, and it would be easier to check drivers
> > > one by one and fixing them individually (outside of this patch series,
> > > unless you insist ;-)) when removing the explicit
> > > drm_helper_disable_unused_functions() call.
> >
> > I had the same thought, but figured there's really no good reason ever to
> > do this. I suspect most of that disable_unused_function stuff we have all
> > over is supreme cargo-cult anyway ;-)
> 
> I'm not sure you got my point. Yes, the drm_helper_disable_unused_functions() 
> call should be removed from atomic drivers, but that will leave support code 
> added for the sole reason of avoiding the crash in the drivers. That code will 
> likely not be noticed and will stay there rotting. If we added 
> drm_helper_disable_unused_functions() calls to all atomic drivers then driver 
> authors will hopefully check carefully if there's any support code that can be 
> removed when removing the function call. It would act as a kind of FIXME 
> reminder.

drm_helper_disable_unused_functions() already prefers the ->disable
callbacks over dpms, like atomic helpers. I don't think there's any dead
code due to this change. The problem was that driver/hw blew up since it
was disabled when the hw was off already.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

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

* Re: [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions
  2016-01-25  7:29         ` Daniel Vetter
@ 2016-01-25 19:02           ` Laurent Pinchart
  0 siblings, 0 replies; 64+ messages in thread
From: Laurent Pinchart @ 2016-01-25 19:02 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Maxime Ripard, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, Philipp Zabel, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, dri-devel, linux-sunxi, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark

Hi Daniel,

On Monday 25 January 2016 08:29:38 Daniel Vetter wrote:
> On Mon, Jan 25, 2016 at 12:19:27AM +0200, Laurent Pinchart wrote:
> > On Friday 15 January 2016 11:17:30 Daniel Vetter wrote:
> >> On Fri, Jan 15, 2016 at 01:13:05AM +0200, Laurent Pinchart wrote:
> >>> On Thursday 14 January 2016 16:24:56 Maxime Ripard wrote:
> >>>> The drm_fbdev_cma_init function always calls the
> >>>> drm_helper_disable_unused_functions. Since it's part of the usual
> >>>> probe process, all the drivers using that helper will end up having
> >>>> their encoder and CRTC disable functions called at probe if their
> >>>> device has not been reported as enabled.
> >>>> 
> >>>> This could be fixed by reading out from the registers the current
> >>>> state of the device if it is enabled, but even that will not handle
> >>>> the case where the device is actually disabled.
> >>>> 
> >>>> Moreover, the drivers using the atomic modesetting expect that their
> >>>> enable and disable callback to be called when the device is already
> >>>> enabled or disabled (respectively).
> >>>> 
> >>>> We can however fix this issue by moving the call to
> >>>> drm_helper_disable_unused_functions out of drm_fbdev_cma_init and
> >>>> make the drivers needing it (all the drivers calling
> >>>> drm_fbdev_cma_init and not using the atomic modesetting) explicitly
> >>>> call it.
> >>> 
> >>> I'd rather add it to all drivers that call drm_fbdev_cma_init(). All
> >>> the atomic ones must have special code to cope with it that could be
> >>> rendered useless by the removal of the
> >>> drm_helper_disable_unused_functions() call. That code should be
> >>> removed too, and it would be easier to check drivers one by one and
> >>> fixing them individually (outside of this patch series, unless you
> >>> insist ;-)) when removing the explicit
> >>> drm_helper_disable_unused_functions() call.
> >> 
> >> I had the same thought, but figured there's really no good reason ever
> >> to do this. I suspect most of that disable_unused_function stuff we have
> >> all over is supreme cargo-cult anyway ;-)
> > 
> > I'm not sure you got my point. Yes, the
> > drm_helper_disable_unused_functions() call should be removed from atomic
> > drivers, but that will leave support code added for the sole reason of
> > avoiding the crash in the drivers. That code will likely not be noticed
> > and will stay there rotting. If we added
> > drm_helper_disable_unused_functions() calls to all atomic drivers then
> > driver authors will hopefully check carefully if there's any support code
> > that can be removed when removing the function call. It would act as a
> > kind of FIXME reminder.
> 
> drm_helper_disable_unused_functions() already prefers the ->disable
> callbacks over dpms, like atomic helpers. I don't think there's any dead
> code due to this change. The problem was that driver/hw blew up since it
> was disabled when the hw was off already.

The rcar-du-drm driver keeps an internal CRTC enabled state for just this 
purpose. I expect other drivers to implement something similar that can be 
removed after dropping the drm_helper_disable_unused_functions() calls.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 03/26] clk: Add regmap support
  2016-01-14 15:24 ` [PATCH v2 03/26] clk: Add regmap support Maxime Ripard
@ 2016-01-28  7:56   ` Stephen Boyd
  0 siblings, 0 replies; 64+ messages in thread
From: Stephen Boyd @ 2016-01-28  7:56 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, David Airlie, Thierry Reding, Philipp Zabel,
	devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter, Matthias Brugger

On 01/14, Maxime Ripard wrote:
> From: Matthias Brugger <matthias.bgg@gmail.com>
> 
> Some devices like SoCs from Mediatek need to use the clock
> through a regmap interface.
> This patch adds regmap support for the simple multiplexer clock,
> the divider clock and the clock gate code.
> 
> Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>

Nak.

The whole anonymous union thing and clk-io.c file is not
appealing at all. I'd prefer we remove clk_readl/writel, not add
to it. Plus we're bloating the basic clock types and adding a
bunch of parallel registration APIs to assign a regmap pointer.
Really, let's stop adding stuff to the basic clock types, it's
getting out of hand.

To move forward on making regmap clks generic for everyone, let's
make sure that regmap clk code is a library that any driver can
use. No OF_CLK_DECLARE should exist because it doesn't make any
sense. No clk_register_regmap_{div,mux,gate}() functions, just a
clk_register_regmap() function to assign the regmap pointer from
the device. Drivers that want to use the code should need to
select a Kconfig symbol, so that we don't compile in support for
regmap clocks unless we really need them.

If we had a clk_regmap structure with a regmap pointer and a
clk_hw inside it I think that's all we would need. Once we had
that, we could let driver writers wrap that in their own
structures for dividers, muxes, gates, etc. and then have them
call library functions from their clk_ops that takes a regmap (or
clk_regmap struct), and offset to do the get_div/set_div,
get_parent/set_parent, enable/disable stuff.

The policy part can be shared with the basic clock types, because
we've already started libifying them. For example, we can ask the
divider code what the hardware value should be for a particular
divider type and it will tell us without writing any registers.
I had a patch for libifying muxes, not sure where it went. The
point being to leave the I/O part to the regmap code without
putting it behind another layer of indirection buried inside the
basic types. Make things flat and easy to follow.

I haven't thought through making new structs to hold the data for
offsets, masks, etc. but I guess we would want those so that we
could assign functions directly to clk_ops and not require any
boiler plate clk_ops implementations in drivers. There are a few
approaches here: different regmap structs for different basic
types, one mega struct that combines all the needs of the basic
types, or some private void pointer inside struct clk_regmap that
points to different basic type structs. Let's see how that goes.

Maybe we can lift drivers/clk/qcom/clk-regmap.c up into the
drivers/clk/ directory too. In the qcom design I put the
enable/disable bits (gate functionality) directly into the
clk_regmap structure. That may need some more thought if it was
the right idea to force enable/disable on every regmap clock
though. If we remove that and introduce a clk_regmap_gate things
should turn out alright.

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

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

* Re: [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation
  2016-01-15  3:15   ` Rob Herring
@ 2016-02-03 19:59     ` Maxime Ripard
  2016-02-03 20:19       ` Rob Herring
  0 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-02-03 19:59 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart, Chen-Yu Tsai,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

Hi Rob,

On Thu, Jan 14, 2016 at 09:15:15PM -0600, Rob Herring wrote:
> On Thu, Jan 14, 2016 at 04:25:00PM +0100, Maxime Ripard 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>
> > ---
> >  .../bindings/display/sunxi/sun4i-drm.txt           | 228 +++++++++++++++++++++
> 
> drm is a linuxism. It shouldn't be used for binding doc.

Ack

> >  1 file changed, 228 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > new file mode 100644
> > index 000000000000..061bc87147a3
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
> > @@ -0,0 +1,228 @@
> > +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
> > +
> > +- ports: A ports node with endpoint definitions as defined in
> > +  Documentation/devicetree/bindings/media/video-interfaces.txt. The
> > +  first port should be the input endpoint.
> > +
> > +TCON
> > +----
> > +
> > +The TCON acts as a timing controller for RGB, LVDS and TV 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 1
> > +
> > + - clock-names: the clock names mentioned above
> > + - clock-output-names: Name of the pixel clock created
> > +
> > +- ports: A ports node with endpoint definitions as defined in
> > +  Documentation/devicetree/bindings/media/video-interfaces.txt. The
> > +  first port should be the input endpoint, the second one the output
> > +
> > +Optional properties:
> > +  - allwinner,panel: phandle to the panel used in our RGB interface
> > +
> > +
> > +Display Engine Backend
> > +----------------------
> > +
> > +The display engine backend exposes layers and sprites to the
> > +system.
> > +
> > +Required properties:
> > +  - compatible: value must be one of:
> > +    * allwinner,sun5i-a13-display-backend
> > +  - reg: base address and size of the memory-mapped region.
> > +  - clocks: phandles to the clocks feeding the frontend and backend
> > +    * ahb: the backend interface clock
> > +    * mod: the backend module clock
> > +    * ram: the backend DRAM clock
> > +  - clock-names: the clock names mentioned above
> > +  - resets: phandles to the reset controllers driving the backend
> > +
> > +- ports: A ports node with endpoint definitions as defined in
> > +  Documentation/devicetree/bindings/media/video-interfaces.txt. The
> > +  first port should be the input endpoints, the second one the output
> > +
> > +Display Engine Frontend
> > +-----------------------
> > +
> > +The display engine frontend does formats conversion, scaling,
> > +deinterlacing and color space conversion.
> > +
> > +Required properties:
> > +  - compatible: value must be one of:
> > +    * allwinner,sun5i-a13-display-frontend
> > +  - reg: base address and size of the memory-mapped region.
> > +  - interrupts: interrupt associated to this IP
> > +  - clocks: phandles to the clocks feeding the frontend and backend
> 
> > +    * ahb: the backend interface clock
> > +    * mod: the backend module clock
> > +    * ram: the backend DRAM clock
> 
> should be frontend?

Yeah, stupid copy/paste mistake :/

> 
> > +  - clock-names: the clock names mentioned above
> > +  - resets: phandles to the reset controllers driving the backend
> 
> ditto
> 
> > +
> > +Display Engine Pipeline
> > +-----------------------
> > +
> > +The display engine pipeline (and its entry point, since it can be
> > +either directly the backend or the frontend) is represented as an
> > +extra node.
> > +
> > +Required properties:
> > +  - compatible: value must be one of:
> > +    * allwinner,sun5i-a13-display-engine
> > +  - allwinner,pipelines: list of phandle to the entry points of the
> > +    pipelines (either to the frontend or backend)
> > +
> > +Example:
> > +
> > +panel: panel {
> > +	compatible = "olimex,lcd-olinuxino-43-ts";
> 
> This should either be a child of what it is attached to or use of-graph.

You had a similar discussion with Thierry last time I sent it, and it
seemed to settle on keeping that property:

http://lists.infradead.org/pipermail/linux-arm-kernel/2015-October/382115.html

Has that changed?

> > +};
> > +
> > +tve0: tv-encoder@01c0a000 {
> > +	compatible = "allwinner,sun4i-a10-tv-encoder";
> > +	reg = <0x01c0a000 0x1000>;
> > +	clocks = <&ahb_gates 34>;
> > +
> > +	port {
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		tve0_in_tcon0: endpoint@0 {
> > +			reg = <0>;
> 
> I would drop the reg where you only have 1 node for ports or endpoints.

Ok

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] 64+ messages in thread

* Re: [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver
  2016-01-16 15:29   ` Chen-Yu Tsai
@ 2016-02-03 20:18     ` Maxime Ripard
  0 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-02-03 20:18 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

On Sat, Jan 16, 2016 at 11:29:41PM +0800, Chen-Yu Tsai wrote:
> Hi,
> 
> On Thu, Jan 14, 2016 at 11:24 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), that have a lot in common with
> > the clock to drive the first TCON channel.
> >
> > Add a driver to support both.
> >
> > Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
> > ---
> >  Documentation/devicetree/bindings/clock/sunxi.txt |   2 +
> >  drivers/clk/sunxi/Makefile                        |   1 +
> >  drivers/clk/sunxi/clk-sun4i-display.c             | 241 ++++++++++++++++++++++
> >  3 files changed, 244 insertions(+)
> >  create mode 100644 drivers/clk/sunxi/clk-sun4i-display.c
> >
> > diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> > index 8a47b77abfca..5360554a7d3f 100644
> > --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> > +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> > @@ -55,6 +55,7 @@ Required properties:
> >         "allwinner,sun9i-a80-apb1-gates-clk" - for the APB1 gates on A80
> >         "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
> >         "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
> > +       "allwinner,sun4i-a10-display-clk" - for the display clocks on the A10
> >         "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13
> >         "allwinner,sun4i-a10-mmc-clk" - for the MMC clock
> >         "allwinner,sun9i-a80-mmc-clk" - for mmc module clocks on A80
> > @@ -64,6 +65,7 @@ Required properties:
> >         "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
> >         "allwinner,sun7i-a20-out-clk" - for the external output clocks
> >         "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
> > +       "allwinner,sun4i-a10-tcon-ch0-clk" - for the TCON channel 0 clock on the A10
> >         "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
> >         "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
> >         "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
> > diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> > index cb4c299214ce..a991cd8ca509 100644
> > --- a/drivers/clk/sunxi/Makefile
> > +++ b/drivers/clk/sunxi/Makefile
> > @@ -10,6 +10,7 @@ obj-y += clk-a10-pll2.o
> >  obj-y += clk-a20-gmac.o
> >  obj-y += clk-mod0.o
> >  obj-y += clk-simple-gates.o
> > +obj-y += clk-sun4i-display.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-display.c b/drivers/clk/sunxi/clk-sun4i-display.c
> > new file mode 100644
> > index 000000000000..9dc6894f0934
> > --- /dev/null
> > +++ b/drivers/clk/sunxi/clk-sun4i-display.c
> > @@ -0,0 +1,241 @@
> > +/*
> > + * 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/kernel.h>
> > +#include <linux/of_address.h>
> > +#include <linux/reset-controller.h>
> > +#include <linux/slab.h>
> > +#include <linux/spinlock.h>
> > +
> > +struct sun4i_a10_display_clk_data {
> > +       bool    has_div;
> > +       bool    has_rst;
> > +       u8      parents;
> > +
> > +       u8      offset_en;
> > +       u8      offset_div;
> > +       u8      offset_mux;
> > +       u8      offset_rst;
> > +
> > +       u8      width_div;
> > +       u8      width_mux;
> > +};
> > +
> > +struct reset_data {
> > +       void __iomem                    *reg;
> > +       spinlock_t                      *lock;
> > +       struct reset_controller_dev     rcdev;
> > +       u8                              offset;
> > +};
> > +
> > +static DEFINE_SPINLOCK(sun4i_a10_display_lock);
> > +
> > +static inline struct reset_data *rcdev_to_reset_data(struct reset_controller_dev *rcdev)
> > +{
> > +       return container_of(rcdev, struct reset_data, rcdev);
> > +};
> > +
> > +static int sun4i_a10_display_assert(struct reset_controller_dev *rcdev,
> > +                                   unsigned long id)
> > +{
> > +       struct reset_data *data = rcdev_to_reset_data(rcdev);
> > +       unsigned long flags;
> > +       u32 reg;
> > +
> > +       spin_lock_irqsave(data->lock, flags);
> > +
> > +       reg = readl(data->reg);
> > +       writel(reg & ~BIT(data->offset), 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 = rcdev_to_reset_data(rcdev);
> > +       unsigned long flags;
> > +       u32 reg;
> > +
> > +       spin_lock_irqsave(data->lock, flags);
> > +
> > +       reg = readl(data->reg);
> > +       writel(reg | BIT(data->offset), 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 = rcdev_to_reset_data(rcdev);
> > +
> > +       return !(readl(data->reg) & BIT(data->offset));
> > +}
> > +
> > +static const 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)
> > +{
> > +       /* We only have a single reset signal */
> > +       return 0;
> > +}
> > +
> > +static void __init sun4i_a10_display_init(struct device_node *node,
> > +                                         struct sun4i_a10_display_clk_data *data)
> > +{
> > +       const char *parents[data->parents];
> > +       const char *clk_name = node->name;
> > +       struct reset_data *reset_data;
> > +       struct clk_divider *div = NULL;
> > +       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;
> > +       }
> > +
> > +       of_clk_parent_fill(node, parents, data->parents);
> 
> What if someone uses an incorrect DT that has less parents described?

Then here be dragons ? :)

I'll fix that.

> > +
> > +       mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> > +       if (!mux)
> > +               return;
> > +
> > +       mux->reg = reg;
> > +       mux->shift = data->offset_mux;
> > +       mux->mask = (1 << data->width_mux) - 1;
> > +       mux->lock = &sun4i_a10_display_lock;
> > +
> > +       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> > +       if (!gate)
> > +               goto free_mux;
> > +
> > +       gate->reg = reg;
> > +       gate->bit_idx = data->offset_en;
> > +       gate->lock = &sun4i_a10_display_lock;
> > +
> > +       if (data->has_div) {
> > +               div = kzalloc(sizeof(*div), GFP_KERNEL);
> > +               if (!div)
> > +                       goto free_gate;
> > +
> > +               div->reg = reg;
> > +               div->shift = data->offset_div;
> > +               div->width = data->width_div;
> > +               div->lock = &sun4i_a10_display_lock;
> > +       }
> > +
> > +       clk = clk_register_composite(NULL, clk_name,
> > +                                    parents, data->parents,
> > +                                    &mux->hw, &clk_mux_ops,
> > +                                    data->has_div ? &div->hw : NULL,
> > +                                    data->has_div ? &clk_divider_ops : NULL,
> > +                                    &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);
> 
> Check for errors?

Yep.

> > +
> > +       if (!data->has_rst)
> > +               return;
> > +
> > +       reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
> > +       if (!reset_data)
> > +               goto free_clk;
> > +
> > +       reset_data->reg = reg;
> > +       reset_data->offset = data->offset_rst;
> > +       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:
> > +       if (data->has_div)
> > +               kfree(div);
> > +free_gate:
> > +       kfree(gate);
> > +free_mux:
> > +       kfree(mux);
> 
> Cleanup after of_io_request_and_map()?

Hmm, indeed...

> 
> > +}
> > +
> > +static struct sun4i_a10_display_clk_data sun4i_a10_tcon_ch0_data = {
> > +       .has_rst        = true,
> > +       .parents        = 4,
> > +       .offset_en      = 31,
> > +       .offset_rst     = 29,
> 
> My datasheets (A10 v1.5, A20 v1.4), say bit 30 for LCD0 ch0 reset.
> 
> A13 and R8 manuals do not list this clock, but A10s does, which has
> bit 30 for LCD reset and bit 29 for TV encoder reset.
> 
> I suggest changing has_rst to int, and for sun5i variant, have
> has_rst = 2, reset_cells = 1, for 2 separate reset controls.
> The tcon and tv encoder bits of the DTSI should be updated as
> well.
> 
> I assume your tests work because U-boot already de-asserted the
> resets (both if you're using composite output).

You're right, I'll fix it as you suggested.

> > +       .offset_mux     = 24,
> > +       .width_mux      = 2,
> > +};
> > +
> > +static void __init sun4i_a10_tcon_ch0_setup(struct device_node *node)
> > +{
> > +       sun4i_a10_display_init(node, &sun4i_a10_tcon_ch0_data);
> > +}
> > +CLK_OF_DECLARE(sun4i_a10_tcon_ch0, "allwinner,sun4i-a10-tcon-ch0-clk",
> > +              sun4i_a10_tcon_ch0_setup);
> > +
> > +static struct sun4i_a10_display_clk_data sun4i_a10_display_data = {
> > +       .has_div        = true,
> 
> Missing .has_rst = true.

Indeed

> > +       .parents        = 3,
> > +       .offset_en      = 31,
> > +       .offset_rst     = 30,
> > +       .offset_mux     = 24,
> > +       .offset_div     = 0,
> 
> This is already implied.

Because the structure would already by initialised to 0?

Yeah, true, but I wanted to make that explicit that the div offset is
actually 0, and not something that got forgotten.

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] 64+ messages in thread

* Re: [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation
  2016-02-03 19:59     ` Maxime Ripard
@ 2016-02-03 20:19       ` Rob Herring
  2016-02-03 20:47         ` Maxime Ripard
  0 siblings, 1 reply; 64+ messages in thread
From: Rob Herring @ 2016-02-03 20:19 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-clk, dri-devel, linux-sunxi,
	Laurent Pinchart, Chen-Yu Tsai, Hans de Goede, Alexander Kaplan,
	Boris Brezillon, Wynter Woods, Thomas Petazzoni, Rob Clark,
	Daniel Vetter

On Wed, Feb 3, 2016 at 1:59 PM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi Rob,
>
> On Thu, Jan 14, 2016 at 09:15:15PM -0600, Rob Herring wrote:
>> On Thu, Jan 14, 2016 at 04:25:00PM +0100, Maxime Ripard 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>
>> > ---
>> >  .../bindings/display/sunxi/sun4i-drm.txt           | 228 +++++++++++++++++++++

[...]

>> > +Required properties:
>> > +  - compatible: value must be one of:
>> > +    * allwinner,sun5i-a13-display-engine
>> > +  - allwinner,pipelines: list of phandle to the entry points of the
>> > +    pipelines (either to the frontend or backend)
>> > +
>> > +Example:
>> > +
>> > +panel: panel {
>> > +   compatible = "olimex,lcd-olinuxino-43-ts";
>>
>> This should either be a child of what it is attached to or use of-graph.
>
> You had a similar discussion with Thierry last time I sent it, and it
> seemed to settle on keeping that property:
>
> http://lists.infradead.org/pipermail/linux-arm-kernel/2015-October/382115.html
>
> Has that changed?

No, I still disagree. We already have 2 ways to describe panels: as a
child node of its controller or with of-graph. We don't need a 3rd way
even if it is simple. The problem with of-graph today is too much of
the parsing is left to the individual drivers. We need to fix that and
make it be handled by common code.

Rob

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

* Re: [PATCH v2 06/26] clk: sunxi: Add PLL3 clock
  2016-01-16 16:05   ` Chen-Yu Tsai
@ 2016-02-03 20:27     ` Maxime Ripard
  0 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-02-03 20:27 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

On Sun, Jan 17, 2016 at 12:05:06AM +0800, Chen-Yu Tsai wrote:
> Hi,
> 
> On Thu, Jan 14, 2016 at 11:24 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > 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>
> > ---
> >  Documentation/devicetree/bindings/clock/sunxi.txt |  1 +
> >  drivers/clk/sunxi/Makefile                        |  1 +
> >  drivers/clk/sunxi/clk-sun4i-pll3.c                | 90 +++++++++++++++++++++++
> >  3 files changed, 92 insertions(+)
> >  create mode 100644 drivers/clk/sunxi/clk-sun4i-pll3.c
> >
> > diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> > index 5360554a7d3f..bb9fb78dcff8 100644
> > --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> > +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> > @@ -10,6 +10,7 @@ Required properties:
> >         "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
> >         "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
> >         "allwinner,sun8i-a23-pll1-clk" - for the main PLL clock on A23
> > +       "allwinner,sun4i-a10-pll3-clk" - for the video PLL clock on A10
> >         "allwinner,sun9i-a80-pll4-clk" - for the peripheral PLLs on A80
> >         "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
> >         "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
> > diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> > index a991cd8ca509..40c32ffd912c 100644
> > --- a/drivers/clk/sunxi/Makefile
> > +++ b/drivers/clk/sunxi/Makefile
> > @@ -11,6 +11,7 @@ obj-y += clk-a20-gmac.o
> >  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-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..6c9c2210b6b2
> > --- /dev/null
> > +++ b/drivers/clk/sunxi/clk-sun4i-pll3.c
> > @@ -0,0 +1,90 @@
> > +/*
> > + * 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.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_multiplier *mult;
> > +       struct clk_gate *gate;
> > +       void __iomem *reg;
> > +       struct clk *clk;
> > +       int ret;
> > +
> > +       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 err_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_multiplier_ops,
> > +                                    &gate->hw, &clk_gate_ops,
> > +                                    0);
> > +       if (IS_ERR(clk)) {
> > +               pr_err("%s: Couldn't register the clock\n", clk_name);
> > +               goto err_free_mult;
> > +       }
> > +
> > +       ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
> > +       if (WARN_ON(ret))
> 
> Any particular reason for WARN_ON instead of pr_err like above?

I guess not, I'll change that.

> 
> > +               goto err_clk_unregister;
> > +
> > +       return;
> > +
> > +err_clk_unregister:
> > +       clk_unregister_composite(clk);
> > +err_free_mult:
> > +       kfree(mult);
> > +err_free_gate:
> > +       kfree(gate);
> 
> Clean up after of_io_request_and_map(), otherwise

Ack

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

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] 64+ messages in thread

* Re: [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock
  2016-01-16 16:36   ` Chen-Yu Tsai
@ 2016-02-03 20:29     ` Maxime Ripard
  0 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-02-03 20:29 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

Hi,

On Sun, Jan 17, 2016 at 12:36:20AM +0800, Chen-Yu Tsai wrote:
> Hi,
> 
> On Thu, Jan 14, 2016 at 11:24 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>
> > ---
> >  Documentation/devicetree/bindings/clock/sunxi.txt |   1 +
> >  drivers/clk/sunxi/Makefile                        |   1 +
> >  drivers/clk/sunxi/clk-sun4i-tcon-ch1.c            | 154 ++++++++++++++++++++++
> >  3 files changed, 156 insertions(+)
> >  create mode 100644 drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
> >
> > diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
> > index bb9fb78dcff8..fe34fc56e803 100644
> > --- a/Documentation/devicetree/bindings/clock/sunxi.txt
> > +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
> > @@ -67,6 +67,7 @@ Required properties:
> >         "allwinner,sun7i-a20-out-clk" - for the external output clocks
> >         "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
> >         "allwinner,sun4i-a10-tcon-ch0-clk" - for the TCON channel 0 clock on the A10
> > +       "allwinner,sun4i-a10-tcon-ch1-clk" - for the TCON channel 1 clock on the A10
> >         "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
> >         "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
> >         "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
> > diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> > index 40c32ffd912c..0a20873cd103 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-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..51ddc38821f7
> > --- /dev/null
> > +++ b/drivers/clk/sunxi/clk-sun4i-tcon-ch1.c
> > @@ -0,0 +1,154 @@
> > +/*
> > + * 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.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_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_DIV_WIDTH     1
> > +#define SUN4I_A10_TCON_CH1_SCLK1_DIV_SHIFT     11
> > +
> > +static DEFINE_SPINLOCK(sun4i_a10_tcon_ch1_lock);
> > +
> > +static void __init sun4i_a10_tcon_ch1_setup(struct device_node *node)
> > +{
> > +       const char *sclk2_parents[SUN4I_A10_TCON_CH1_SCLK2_PARENTS];
> > +       const char *sclk1_name = node->name;
> > +       const char *sclk2_name;
> > +       struct clk_divider *sclk1_div, *sclk2_div;
> > +       struct clk_gate *sclk1_gate, *sclk2_gate;
> > +       struct clk_mux *sclk2_mux;
> > +       struct clk *sclk1, *sclk2;
> > +       void __iomem *reg;
> > +       int i, ret;
> > +
> > +       of_property_read_string(node, "clock-output-names",
> > +                               &sclk1_name);
> > +
> > +       sclk2_name = kasprintf(GFP_KERNEL, "%s2", sclk1_name);
> > +       if (!sclk2_name)
> > +               return;
> > +
> > +       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);
> 
> of_clk_parent_fill?

Indeed

> 
> > +
> > +       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,
> 
> Placement of the "&" is very weird.

Hmm, right. I don't know what happened here, but it's obviously wrong :)

> 
> > +                                      &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;
> > +       }
> > +
> > +       sclk1_div = kzalloc(sizeof(*sclk1_div), GFP_KERNEL);
> > +       if (!sclk1_div)
> > +               goto free_sclk2;
> > +
> > +       sclk1_div->reg = reg;
> > +       sclk1_div->shift = SUN4I_A10_TCON_CH1_SCLK1_DIV_SHIFT;
> > +       sclk1_div->width = SUN4I_A10_TCON_CH1_SCLK1_DIV_WIDTH;
> > +       sclk1_div->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, &sclk2_name, 1,
> > +                                      NULL, NULL,
> > +                                      &sclk1_div->hw, &clk_divider_ops,
> > +                                      &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;
> > +       }
> > +
> > +       ret = of_clk_add_provider(node, of_clk_src_simple_get, sclk1);
> > +       if (WARN_ON(ret))
> > +               goto free_sclk1;
> > +
> > +       return;
> > +
> > +free_sclk1:
> > +       clk_unregister_composite(sclk1);
> > +free_sclk1_gate:
> > +       kfree(sclk1_gate);
> > +free_sclk1_mux:
> > +       kfree(sclk1_div);
> > +free_sclk2:
> > +       clk_unregister(sclk2);
> > +free_sclk2_div:
> > +       kfree(sclk2_div);
> > +free_sclk2_gate:
> > +       kfree(sclk2_gate);
> > +free_sclk2_mux:
> > +       kfree(sclk2_mux);
> 
> Cleanup after of_io_request_and_map?

Indeed.

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] 64+ messages in thread

* Re: [PATCH v2 10/26] ARM: sun5i: a13: Add display and TCON clocks
  2016-01-16 17:06   ` Chen-Yu Tsai
@ 2016-02-03 20:31     ` Maxime Ripard
  2016-02-05  9:49       ` Chen-Yu Tsai
  0 siblings, 1 reply; 64+ messages in thread
From: Maxime Ripard @ 2016-02-03 20:31 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

Hi,

On Sun, Jan 17, 2016 at 01:06:07AM +0800, Chen-Yu Tsai wrote:
> > +                       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";
> > +               };
> 
> I suggest moving these to sun5i.dtsi, as they are shared amongst them.

Eventually, yes, but I don't have an a10s board handy, and I couldn't
test the clocks that needs to be taken by simplefb.

Once properly tested, they can definitely be moved to sun5i.dtsi.

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] 64+ messages in thread

* Re: [PATCH v2 11/26] ARM: sun5i: Add DRAM gates
  2016-01-16 17:10   ` Chen-Yu Tsai
@ 2016-02-03 20:36     ` Maxime Ripard
  0 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-02-03 20:36 UTC (permalink / raw)
  To: Chen-Yu Tsai
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, dri-devel, linux-sunxi, Laurent Pinchart,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

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

On Sun, Jan 17, 2016 at 01:10:02AM +0800, Chen-Yu Tsai wrote:
> On Thu, Jan 14, 2016 at 11:24 PM, Maxime Ripard
> <maxime.ripard@free-electrons.com> wrote:
> > 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 |  7 ++++---
> >  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, 25 insertions(+), 5 deletions(-)
> >
> > diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
> > index bddd0de88af6..52d2c79cb37b 100644
> > --- a/arch/arm/boot/dts/sun5i-a10s.dtsi
> > +++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
> > @@ -66,7 +66,7 @@
> >                                      "simple-framebuffer";
> >                         allwinner,pipeline = "de_be0-lcd0-hdmi";
> >                         clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
> > -                                <&ahb_gates 44>;
> > +                                <&ahb_gates 44>, <&dram_gates 26>;
> >                         status = "disabled";
> >                 };
> >
> > @@ -74,7 +74,8 @@
> >                         compatible = "allwinner,simple-framebuffer",
> >                                      "simple-framebuffer";
> >                         allwinner,pipeline = "de_be0-lcd0";
> > -                       clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
> > +                       clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>,
> > +                                <&dram_gates 26>;
> >                         status = "disabled";
> >                 };
> >
> > @@ -83,7 +84,7 @@
> >                                      "simple-framebuffer";
> >                         allwinner,pipeline = "de_be0-lcd0-tve0";
> >                         clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
> > -                                <&ahb_gates 44>;
> > +                                <&ahb_gates 44>, <&dram_gates 26>;
> >                         status = "disabled";
> >                 };
> >         };
> > diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
> > index 9669b03f20f3..f29163650ca8 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 0840612b5ed6..c72d94228915 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>,
> 
> According to A10s manual, bit 3 is DRAM clock for TS (transport stream
> decoder), while bit 5 is for the TV encoder.
> 
> The others look good.

I'll fix that, 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] 64+ messages in thread

* Re: [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation
  2016-02-03 20:19       ` Rob Herring
@ 2016-02-03 20:47         ` Maxime Ripard
  0 siblings, 0 replies; 64+ messages in thread
From: Maxime Ripard @ 2016-02-03 20:47 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mike Turquette, Stephen Boyd, David Airlie, Thierry Reding,
	Philipp Zabel, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, linux-clk, dri-devel, linux-sunxi,
	Laurent Pinchart, Chen-Yu Tsai, Hans de Goede, Alexander Kaplan,
	Boris Brezillon, Wynter Woods, Thomas Petazzoni, Rob Clark,
	Daniel Vetter

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

On Wed, Feb 03, 2016 at 02:19:31PM -0600, Rob Herring wrote:
> >> > +Required properties:
> >> > +  - compatible: value must be one of:
> >> > +    * allwinner,sun5i-a13-display-engine
> >> > +  - allwinner,pipelines: list of phandle to the entry points of the
> >> > +    pipelines (either to the frontend or backend)
> >> > +
> >> > +Example:
> >> > +
> >> > +panel: panel {
> >> > +   compatible = "olimex,lcd-olinuxino-43-ts";
> >>
> >> This should either be a child of what it is attached to or use of-graph.
> >
> > You had a similar discussion with Thierry last time I sent it, and it
> > seemed to settle on keeping that property:
> >
> > http://lists.infradead.org/pipermail/linux-arm-kernel/2015-October/382115.html
> >
> > Has that changed?
> 
> No, I still disagree. We already have 2 ways to describe panels: as a
> child node of its controller or with of-graph. We don't need a 3rd way
> even if it is simple. The problem with of-graph today is too much of
> the parsing is left to the individual drivers. We need to fix that and
> make it be handled by common code.

Ok. I'm guessing from your answer you prefer of-graph over a child
node ?

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] 64+ messages in thread

* Re: [PATCH v2 10/26] ARM: sun5i: a13: Add display and TCON clocks
  2016-02-03 20:31     ` Maxime Ripard
@ 2016-02-05  9:49       ` Chen-Yu Tsai
  0 siblings, 0 replies; 64+ messages in thread
From: Chen-Yu Tsai @ 2016-02-05  9:49 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: Chen-Yu Tsai, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, Philipp Zabel, devicetree, linux-arm-kernel,
	linux-kernel, linux-clk, dri-devel, linux-sunxi, Laurent Pinchart,
	Hans de Goede, Alexander Kaplan, Boris Brezillon, Wynter Woods,
	Thomas Petazzoni, Rob Clark, Daniel Vetter

On Thu, Feb 4, 2016 at 4:31 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi,
>
> On Sun, Jan 17, 2016 at 01:06:07AM +0800, Chen-Yu Tsai wrote:
>> > +                       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";
>> > +               };
>>
>> I suggest moving these to sun5i.dtsi, as they are shared amongst them.
>
> Eventually, yes, but I don't have an a10s board handy, and I couldn't
> test the clocks that needs to be taken by simplefb.
>
> Once properly tested, they can definitely be moved to sun5i.dtsi.

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

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

* Re: [linux-sunxi] [PATCH v2 00/26] drm: Add Allwinner A10 display engine support
  2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
                   ` (25 preceding siblings ...)
  2016-01-14 15:25 ` [PATCH v2 26/26] DO NOT MERGE: ARM: sun5i: chip: Enable the LCD panel Maxime Ripard
@ 2016-02-20 13:45 ` Priit Laes
  26 siblings, 0 replies; 64+ messages in thread
From: Priit Laes @ 2016-02-20 13:45 UTC (permalink / raw)
  To: maxime.ripard, Mike Turquette, Stephen Boyd, David Airlie,
	Thierry Reding, Philipp Zabel
  Cc: devicetree, linux-arm-kernel, linux-kernel, linux-clk, dri-devel,
	linux-sunxi, Laurent Pinchart, Chen-Yu Tsai, Hans de Goede,
	Alexander Kaplan, Boris Brezillon, Wynter Woods, Thomas Petazzoni,
	Rob Clark, Daniel Vetter

On Thu, 2016-01-14 at 16:24 +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.

I found some time to play with it (with intention to get it running
also on sun7i and sun4i) and ran into this when trying to build
sun4i_drm as module:

ERROR: "sun4i_tcon1_mode_set" [drivers/gpu/drm/sun4i/sun4i_tv.ko] undefined!
ERROR: "sun4i_backend_apply_color_correction" [drivers/gpu/drm/sun4i/sun4i_tv.ko] undefined!
ERROR: "sun4i_tcon_channel_disable" [drivers/gpu/drm/sun4i/sun4i_tv.ko] undefined!
ERROR: "sun4i_tcon_channel_enable" [drivers/gpu/drm/sun4i/sun4i_tv.ko] undefined!
ERROR: "clk_unregister_composite" [drivers/gpu/drm/sun4i/sun4i_tcon.ko] undefined!
ERROR: "sun4i_rgb_init" [drivers/gpu/drm/sun4i/sun4i_tcon.ko] undefined!
ERROR: "clk_register_composite" [drivers/gpu/drm/sun4i/sun4i_tcon.ko] undefined!
ERROR: "sun4i_backend_update_layer_coord" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_backend_update_layer_formats" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_tcon_channel_disable" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_tcon_enable_vblank" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_backend_update_layer_buffer" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_backend_layer_enable" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_tcon_channel_enable" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_tcon_enable" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_tcon_disable" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_tcon0_mode_set" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
ERROR: "sun4i_backend_commit" [drivers/gpu/drm/sun4i/sun4i-drm.ko] undefined!
scripts/Makefile.modpost:91: recipe for target '__modpost' failed



> 
> Let me know what you think,
> Maxime
> 
> Changes from v1:
>   - Rebased on top of 4.4
> 
>   - Merged the clock drivers for the display and TCON channel 0
> clocks
>   - Replaced the container_of calls in the display reset clocks to an
>     inline function
>   - Checked the return code of of_clk_parent_fill in the clocks
>     drivers
>   - Checked the return code of of_clk_add_provider in the tcon-ch1
> and
>     PLL3 clocks
>   - Added missing clocks headers
>   - Created a composite clock unregister function
> 
>   - Moved the binding documentation to
>     Documentation/devicetree/bindings/display
>   - Added the clocks binding documentation
>   - Added the Olimex vendor to the list of DT vendors
>   - Moved to the OF graph representation and the component framework
> 
>   - Moved the reset cells count check into the reset framework to
>     avoid duplicating the code in every xlate implementation.
>   - Made the reset_ops const
> 
>   - Reworked the DRM cmdline mode parsing code to allow named mode
>   - Fixed the TV mode lookup when the mode name is not present (for
>     example because it was given by the userspace)
> 
>   - Made the driver outputs optional (to avoid crashing when a board
>     doesn't have either a panel or a composite output enabled)
>   - Added multiple plane support with transparency
>   - Moved the backend registers writes commit in the CRTC
> atomic_flush
>     callback
>   - Removed the load / unload functions
>   - Removed the enabled booleans in my private structure and removed
>     the implicit call to disable_unused_functions in the DRM core to
>     push it in the drivers.
>   - Fixed a few bitmasks on some bitfields definition
>   - Fixed the RGB connector mode validation that was not testing the
>     right values
> 
> Matthias Brugger (1):
>   clk: Add regmap support
> 
> Maxime Ripard (25):
>   reset: Move DT cell size check to the core
>   reset: Make reset_control_ops const
>   clk: composite: Add unregister function
>   clk: sunxi: Add display and TCON0 clocks driver
>   clk: sunxi: Add PLL3 clock
>   clk: sunxi: Add TCON channel1 clock
>   clk: sun5i: add DRAM gates
>   ARM: sun5i: dt: Add pll3 and pll7 clocks
>   ARM: sun5i: a13: Add display and TCON clocks
>   ARM: sun5i: Add DRAM gates
>   ARM: sun5i: Add TV encoder gate to the DTSI
>   drm/fb_cma_helper: Remove implicit call to disable_unused_functions
>   drm/modes: Rewrite the command line parser
>   drm/modes: Support modes names on the command line
>   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: r8: Add display blocks to the DTSI
>   ARM: sun5i: chip: Enable the TV Encoder
>   devicetree: Add olimex vendor prefix
>   drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS
>   DO NOT MERGE: ARM: sun5i: chip: Enable the LCD panel
> 
>  Documentation/devicetree/bindings/clock/sunxi.txt  |   5 +
>  .../display/panel/olimex,lcd-olinuxino-43-ts.txt   |   7 +
>  .../bindings/display/sunxi/sun4i-drm.txt           | 228 +++++++
>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>  arch/arm/boot/dts/sun5i-a10s.dtsi                  |   7 +-
>  arch/arm/boot/dts/sun5i-a13.dtsi                   |  46 +-
>  arch/arm/boot/dts/sun5i-r8-chip.dts                |  17 +
>  arch/arm/boot/dts/sun5i-r8.dtsi                    | 139 ++++-
>  arch/arm/boot/dts/sun5i.dtsi                       |  62 ++
>  drivers/clk/Makefile                               |   1 +
>  drivers/clk/clk-composite.c                        |  15 +
>  drivers/clk/clk-divider.c                          |  68 ++-
>  drivers/clk/clk-gate.c                             |  54 +-
>  drivers/clk/clk-io.c                               |  48 ++
>  drivers/clk/clk-io.h                               |  22 +
>  drivers/clk/clk-mux.c                              |  94 ++-
>  drivers/clk/sunxi/Makefile                         |   3 +
>  drivers/clk/sunxi/clk-simple-gates.c               |   2 +
>  drivers/clk/sunxi/clk-sun4i-display.c              | 241 ++++++++
>  drivers/clk/sunxi/clk-sun4i-pll3.c                 |  90 +++
>  drivers/clk/sunxi/clk-sun4i-tcon-ch1.c             | 154 +++++
>  drivers/gpu/drm/Kconfig                            |   2 +
>  drivers/gpu/drm/Makefile                           |   3 +-
>  drivers/gpu/drm/drm_crtc.c                         |   3 +-
>  drivers/gpu/drm/drm_fb_cma_helper.c                |   3 -
>  drivers/gpu/drm/drm_fb_helper.c                    |   4 +
>  drivers/gpu/drm/drm_modes.c                        | 327 ++++++----
>  drivers/gpu/drm/imx/imx-drm-core.c                 |   1 +
>  drivers/gpu/drm/panel/panel-simple.c               |  26 +
>  drivers/gpu/drm/sti/sti_drv.c                      |   1 +
>  drivers/gpu/drm/sun4i/Kconfig                      |  14 +
>  drivers/gpu/drm/sun4i/Makefile                     |  12 +
>  drivers/gpu/drm/sun4i/sun4i_backend.c              | 321 ++++++++++
>  drivers/gpu/drm/sun4i/sun4i_backend.h              | 160 +++++
>  drivers/gpu/drm/sun4i/sun4i_crtc.c                 | 120 ++++
>  drivers/gpu/drm/sun4i/sun4i_crtc.h                 |  30 +
>  drivers/gpu/drm/sun4i/sun4i_drv.c                  | 325 ++++++++++
>  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                | 160 +++++
>  drivers/gpu/drm/sun4i/sun4i_layer.h                |  30 +
>  drivers/gpu/drm/sun4i/sun4i_rgb.c                  | 229 +++++++
>  drivers/gpu/drm/sun4i/sun4i_rgb.h                  |  18 +
>  drivers/gpu/drm/sun4i/sun4i_tcon.c                 | 521
> ++++++++++++++++
>  drivers/gpu/drm/sun4i/sun4i_tcon.h                 | 177 ++++++
>  drivers/gpu/drm/sun4i/sun4i_tv.c                   | 675
> +++++++++++++++++++++
>  drivers/gpu/drm/tilcdc/tilcdc_drv.c                |   1 +
>  drivers/reset/core.c                               |   6 +-
>  include/drm/drm_modes.h                            |   1 +
>  include/linux/clk-provider.h                       |  55 +-
>  include/linux/reset-controller.h                   |   2 +-
>  52 files changed, 4455 insertions(+), 179 deletions(-)
>  create mode 100644
> Documentation/devicetree/bindings/display/panel/olimex,lcd-olinuxino-
> 43-ts.txt
>  create mode 100644
> Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
>  create mode 100644 drivers/clk/clk-io.c
>  create mode 100644 drivers/clk/clk-io.h
>  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-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
> 
> -- 
> 2.6.4
> 

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

end of thread, other threads:[~2016-02-20 13:45 UTC | newest]

Thread overview: 64+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-01-14 15:24 [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 01/26] reset: Move DT cell size check to the core Maxime Ripard
2016-01-15 15:50   ` Philipp Zabel
2016-01-14 15:24 ` [PATCH v2 02/26] reset: Make reset_control_ops const Maxime Ripard
2016-01-15 15:50   ` Philipp Zabel
2016-01-14 15:24 ` [PATCH v2 03/26] clk: Add regmap support Maxime Ripard
2016-01-28  7:56   ` Stephen Boyd
2016-01-14 15:24 ` [PATCH v2 04/26] clk: composite: Add unregister function Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 05/26] clk: sunxi: Add display and TCON0 clocks driver Maxime Ripard
2016-01-15  3:01   ` Rob Herring
2016-01-16 14:08   ` [linux-sunxi] " Priit Laes
2016-01-16 15:29   ` Chen-Yu Tsai
2016-02-03 20:18     ` Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 06/26] clk: sunxi: Add PLL3 clock Maxime Ripard
2016-01-15  3:02   ` Rob Herring
2016-01-16 16:05   ` Chen-Yu Tsai
2016-02-03 20:27     ` Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 07/26] clk: sunxi: Add TCON channel1 clock Maxime Ripard
2016-01-15  3:03   ` Rob Herring
2016-01-16 16:36   ` Chen-Yu Tsai
2016-02-03 20:29     ` Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 08/26] clk: sun5i: add DRAM gates Maxime Ripard
2016-01-15  3:04   ` Rob Herring
2016-01-14 15:24 ` [PATCH v2 09/26] ARM: sun5i: dt: Add pll3 and pll7 clocks Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 10/26] ARM: sun5i: a13: Add display and TCON clocks Maxime Ripard
2016-01-16 17:06   ` Chen-Yu Tsai
2016-02-03 20:31     ` Maxime Ripard
2016-02-05  9:49       ` Chen-Yu Tsai
2016-01-14 15:24 ` [PATCH v2 11/26] ARM: sun5i: Add DRAM gates Maxime Ripard
2016-01-16 17:10   ` Chen-Yu Tsai
2016-02-03 20:36     ` Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 12/26] ARM: sun5i: Add TV encoder gate to the DTSI Maxime Ripard
2016-01-16 17:12   ` Chen-Yu Tsai
2016-01-14 15:24 ` [PATCH v2 13/26] drm/fb_cma_helper: Remove implicit call to disable_unused_functions Maxime Ripard
2016-01-14 23:13   ` Laurent Pinchart
2016-01-15 10:17     ` Daniel Vetter
2016-01-24 22:19       ` Laurent Pinchart
2016-01-25  7:29         ` Daniel Vetter
2016-01-25 19:02           ` Laurent Pinchart
2016-01-14 15:24 ` [PATCH v2 14/26] drm/modes: Rewrite the command line parser Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 15/26] drm/modes: Support modes names on the command line Maxime Ripard
2016-01-14 15:24 ` [PATCH v2 16/26] drm: Add Allwinner A10 Display Engine support Maxime Ripard
2016-01-16 15:11   ` [linux-sunxi] " Priit Laes
2016-01-17 12:58     ` Priit Laes
2016-01-19 15:38     ` Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 17/26] drm: sun4i: Add DT bindings documentation Maxime Ripard
2016-01-15  3:15   ` Rob Herring
2016-02-03 19:59     ` Maxime Ripard
2016-02-03 20:19       ` Rob Herring
2016-02-03 20:47         ` Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 18/26] drm: sun4i: Add RGB output Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 19/26] drm: sun4i: Add composite output Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 20/26] drm: sun4i: tv: Add PAL output standard Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 21/26] drm: sun4i: tv: Add NTSC " Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 22/26] ARM: sun5i: r8: Add display blocks to the DTSI Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 23/26] ARM: sun5i: chip: Enable the TV Encoder Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 24/26] devicetree: Add olimex vendor prefix Maxime Ripard
2016-01-15  3:15   ` Rob Herring
2016-01-15  6:41     ` Stefan Wahren
2016-01-15  8:05       ` Maxime Ripard
2016-01-14 15:25 ` [PATCH v2 25/26] drm/panel: simple: Add timings for the Olimex LCD-OLinuXino-4.3TS Maxime Ripard
2016-01-15  3:17   ` Rob Herring
2016-01-14 15:25 ` [PATCH v2 26/26] DO NOT MERGE: ARM: sun5i: chip: Enable the LCD panel Maxime Ripard
2016-02-20 13:45 ` [linux-sunxi] [PATCH v2 00/26] drm: Add Allwinner A10 display engine support Priit Laes

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 read-only IMAP folder(s) and NNTP newsgroup(s).